Search code examples
javasslsha1sslhandshakeexception

SSLHandshakeException after deleting SHA1 cert: Received fatal alert: bad_certificate. Server log: SEC_ERROR_REUSED_ISSUER_AND_SERIAL


Our Java Swing + Visual Basic APP let users authenticate against server with SSL connection. Now two user in the same entity client sharing a smart card suddenly encounter a problem: they cannot connect to the server with Java part, but with VB modules it is normal.

At server side we formerly had both ancert SHA1 and SHA256 root. It was when server admins deleted ANCERT SHA1 root and sub-root certs, we began to have the problem of "bad_certificate".

After we added -Djavax.net.debug=all, at last of the generated log we see the error happens after CertificateVerify and Client Finish:

...
*** CertificateVerify
[write] MD5 and SHA1 hashes:  len = 262
0000: 0F 00 01 02 01 00 0C F5   8A 0A 9C 38 E9 6B E4 B6  ...........8.k..
0010: AC 2D 35 26 61 E3 56 72   66 DE B9 E0 AE CD B2 7B  .-5&a.Vrf.......
0020: 41 AF EB 66 9B 48 05 11   94 75 0D 0F 01 4B CA E6  A..f.H...u...K..
0030: 64 60 B7 5D 85 5D 61 1B   EA 7F 38 F1 5D D4 91 AE  d`.].]a...8.]...
0040: 04 84 19 3A 76 75 1E 87   4D C7 42 AB 16 9E 07 AD  ...:vu..M.B.....
0050: 7D 60 9A A2 A8 94 B9 2F   08 79 40 AA 96 14 2E F4  .`...../.y@.....
0060: 88 CA 72 00 46 8F EF D5   A2 6D 6B 7C B9 99 44 52  ..r.F....mk...DR
0070: FB CA F8 F8 00 D1 95 5E   15 B9 AD C6 1B 51 71 FB  .......^.....Qq.
0080: 6E 34 17 EC 0D D0 1B 8E   49 D7 DF F0 96 82 E6 27  n4......I......'
0090: F7 1B 2B 39 42 D5 CE 92   30 27 E5 07 7D 6C 87 6F  ..+9B...0'...l.o
00A0: CE CD 81 DD 8A 04 D6 F2   EE 36 D4 2D FC 3B 00 58  .........6.-.;.X
00B0: 93 D5 85 D9 EB C4 DC 30   FC 91 E5 CB 44 8B 6A A2  .......0....D.j.
00C0: 38 96 DD 21 B0 C5 C3 27   34 FC 55 97 00 26 5F 17  8..!...'4.U..&_.
00D0: F3 53 05 45 23 81 00 C2   36 FC C1 0B B7 45 8B 87  .S.E#...6....E..
00E0: 61 F1 21 65 AA F6 34 B4   15 85 AF A5 B2 21 C3 65  a.!e..4......!.e
00F0: 7E 9D B1 F3 F8 13 8D 58   14 1A F1 CE 9A 7F 53 6C  .......X......Sl
0100: 6F 96 A3 77 8F 9F                                  o..w..
Thread-7, WRITE: TLSv1.1 Handshake, length = 262
[Raw write]: length = 267
0000: 16 03 02 01 06 0F 00 01   02 01 00 0C F5 8A 0A 9C  ................
0010: 38 E9 6B E4 B6 AC 2D 35   26 61 E3 56 72 66 DE B9  8.k...-5&a.Vrf..
0020: E0 AE CD B2 7B 41 AF EB   66 9B 48 05 11 94 75 0D  .....A..f.H...u.
0030: 0F 01 4B CA E6 64 60 B7   5D 85 5D 61 1B EA 7F 38  ..K..d`.].]a...8
0040: F1 5D D4 91 AE 04 84 19   3A 76 75 1E 87 4D C7 42  .]......:vu..M.B
0050: AB 16 9E 07 AD 7D 60 9A   A2 A8 94 B9 2F 08 79 40  ......`...../.y@
0060: AA 96 14 2E F4 88 CA 72   00 46 8F EF D5 A2 6D 6B  .......r.F....mk
0070: 7C B9 99 44 52 FB CA F8   F8 00 D1 95 5E 15 B9 AD  ...DR.......^...
0080: C6 1B 51 71 FB 6E 34 17   EC 0D D0 1B 8E 49 D7 DF  ..Qq.n4......I..
0090: F0 96 82 E6 27 F7 1B 2B   39 42 D5 CE 92 30 27 E5  ....'..+9B...0'.
00A0: 07 7D 6C 87 6F CE CD 81   DD 8A 04 D6 F2 EE 36 D4  ..l.o.........6.
00B0: 2D FC 3B 00 58 93 D5 85   D9 EB C4 DC 30 FC 91 E5  -.;.X.......0...
00C0: CB 44 8B 6A A2 38 96 DD   21 B0 C5 C3 27 34 FC 55  .D.j.8..!...'4.U
00D0: 97 00 26 5F 17 F3 53 05   45 23 81 00 C2 36 FC C1  ..&_..S.E#...6..
00E0: 0B B7 45 8B 87 61 F1 21   65 AA F6 34 B4 15 85 AF  ..E..a.!e..4....
00F0: A5 B2 21 C3 65 7E 9D B1   F3 F8 13 8D 58 14 1A F1  ..!.e.......X...
0100: CE 9A 7F 53 6C 6F 96 A3   77 8F 9F                 ...Slo..w..
Thread-7, WRITE: TLSv1.1 Change Cipher Spec, length = 1
[Raw write]: length = 6
0000: 14 03 02 00 01 01                                  ......
*** Finished
verify_data:  { 54, 35, 53, 118, 12, 242, 190, 4, 226, 234, 192, 46 }
***
[write] MD5 and SHA1 hashes:  len = 16
0000: 14 00 00 0C 36 23 35 76   0C F2 BE 04 E2 EA C0 2E  ....6#5v........
Padded plaintext before ENCRYPTION:  len = 64
0000: A9 E5 26 50 4D 1D BE 8B   92 2E 77 12 24 0E DB C5  ..&PM.....w.$...
0010: 14 00 00 0C 36 23 35 76   0C F2 BE 04 E2 EA C0 2E  ....6#5v........
0020: A5 44 16 F6 70 AC 7F 9A   40 CD 5B 4C B9 CD 88 7D  .D..p...@.[L....
0030: 42 78 85 30 0B 0B 0B 0B   0B 0B 0B 0B 0B 0B 0B 0B  Bx.0............
Thread-7, WRITE: TLSv1.1 Handshake, length = 64
[Raw write]: length = 69
0000: 16 03 02 00 40 0C A2 DA   FC 1A 9E CE B0 D6 2F 7B  ....@........./.
0010: 23 9E A9 00 D3 3B FC 2A   C7 DD 5D 22 A6 36 B3 E1  #....;.*..]".6..
0020: CE EB FD 48 C7 55 D3 5B   AF FC 37 3E 49 86 9A 6F  ...H.U.[..7>I..o
0030: 79 A5 FD 5B 60 06 F4 A9   89 CD F4 26 D9 FE F3 9B  y..[`......&....
0040: 78 E0 65 2D 56                                     x.e-V
[Raw read]: length = 5
0000: 15 03 02 00 02                                     .....
[Raw read]: length = 2
0000: 02 2A                                              .*
Thread-7, READ: TLSv1.1 Alert, length = 2
Thread-7, RECV TLSv1.1 ALERT:  fatal, bad_certificate
%% Invalidated:  [Session-1, TLS_RSA_WITH_AES_128_CBC_SHA]
Thread-7, called closeSocket()
Thread-7, handling exception: javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate

At server side, when the client connects, this error occurs:

[07/Jul/2017:13:33:18] failure (3354): HTTP3068: Error receiving request from 37.222.168.137 (SEC_ERROR_REUSED_ISSUER_AND_SERIAL: Attempting to import a cert which conflicts with issuer/serial of existing cert.)

We have no clue why it stops working.

  • VB modules also connect to the same server, same URL and it works. I don't have VB codes. So I guess the card is good.
  • The trust store file in the application has included the issuer ANCERT Certificados para empleados V2(sub-root), as well as the root ANCERT CGN V2 (root).

Why it is happening?

EDIT:

In the local trust store we have these certs:

ancert root cert (sha1)
        |
        - ancert sub-root cert (sha1) 

And how the chain was built before the problem:

ancert root cert (sha1)
        |
        - ancert sub-root cert (sha1) 
                    |
                    - user cert (sha256)

At server side, the SHA1 root cert has the same serial number as the SHA256 root cert.

So I thought it was because when building the chain, Java looks into the chain in the user cert, and wants to find a chain in server as indicated in this chain, so it expects intermediate SHA1 and root SHA256, but now when all SHA1 cert are deleted, it can only find SHA256 with same serial number, so that could be the cause, but I was wrong.

Because now we have another user with this chain as shown in his cert's public part:

ancert root cert (sha256)
        |
        - ancert sub-root cert (sha256) 
                    |
                    - user cert (sha256)

If my theory stands, this user will not complain because SHA256 certs are always present at server side, but now he complains too.

So what is the reason?


Solution

  • I have found the answer: it turns out that after deleting the SHA1 root CA cert in the IE truststore, which has the same serial number as that of SHA256 at server side, all began to work again. The intermediate CA certs' serial numbers don't repeat.

    I believe that my former guessing stands partially: when authenticating, while building the user cert chain, instead of trying to build a chain as the user cert indicates, Java seems to look up intermediate and root cert from Windows system cert store, i.e., the one we can see with certmgr, in the part "trusted intermediate/root CAs". And, unfortunately, when installing the user cert, the installer adds both SHA1 and SHA256 root cert into this store.

    And, Java seems to assume that in this store everything is in order and does not expect any repetition, as that of serial number; and it sees SHA1 cert before seeing SHA256 root cert. So, it builds the chain with it, and send it to server; but at server side it sees SHA2 with same serial number, thus the conflict.

    As for VB side, I guess it is because that MS builds the cert chain in another way (and with another ideology in mind: assuming that the first chain found is not necessarily the best, and sometimes, it is prone to fail), trying to build all possible chains and at last, picks the correct one. According to this answer:

    If we talk about Microsoft implementation (just an example which I'm familiar with), their CCE builds one or more chains (as much as possible) without performing immediate validation. They just fetch certificates and attempt to perform basic rules to bind each certificate at the correct place in the chain. When all chains are built, each of them are validated according to rules described in RFC5280. Once validated, there might be a case that there are multiple trusted and valid chains. CCE uses its own selection logic to select only one chain from a collection of chains.

    So, the VB code stays immune to this kind of error/repetition, while Java is more vulnerable at this moment.

    Revision of this problem:

    I guess the repetition of serial number is by attention, forcing users to update certs, without being aware of possible confusion as consequence;

    And, the server admin should inform us about this change earlier; we got this information one week after the user report.

    At last, it is another evidence for the long-lasting dispute between proactive-reactive programming. I think Java favors the former one, as I have encountered another problem related to repeated alias for different certs in one cert store, where I saw that the way Java reads certs (by iterating among all alias and picks up the first it sees, which is alike to here)strongly suggests that Java guys think that there should not be duplicated alias in a cert store. This is a known bug, described here. But, I think it all depends on who your target are, experienced web admins, or regular users.