1
votes

I am on a team that is are trying to connect a Java J2SE application to a secure corporate web services site using certificates. None of the team members have prior experience creating certificates and coding for this type of connection.

We prepared and submitted a CSR and received a .p7b certificate from the web service site. The .p7b contains two certificates: one for us issued by the web services site and a second for the web services site issued by the corporate owner’s own CA. Both appear in the keystore list below. The keystore is referenced in a custom SSLContext and the Java code creates an Apache HttpClient with that SSLContext without error.

When the Java code attempts to execute an HttpGet, the web service site rejects the SSLHandshake and terminates the connection with the error:

javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake

In the handshake debug trace, in step 13 of the handshake, is the message:

ServerHelloDone
Warning: no suitable certificate found - continuing without client authentication
Certificate chain
Empty

Keytool lists the contensts of the keystore as: (corporate identities redacted)

Keystore type: PKCS12
Keystore provider: SUN

Your keystore contains 1 entry

Alias name: server
Creation date: Mar 28, 2019
Entry type: PrivateKeyEntry
Certificate chain length: 2
Certificate[1]:
Owner: ...
Issuer: ...
Serial number: ...
Valid from: Mon Mar 11 19:00:00 CDT 2019 until: Wed Mar 11 18:59:59 CDT 2020
Certificate fingerprints:
     SHA1: ...
     SHA256: ...
Signature algorithm name: SHA1withRSA
Subject Public Key Algorithm: 2048-bit RSA key
Version: 3

Extensions: 

#1: ObjectId: 2.16.840.1.113733.1.6.9 Criticality=false
0000: 01 01 FF                                           ...


#2: ObjectId: 2.5.29.19 Criticality=false
BasicConstraints:[
  CA:false
  PathLen: undefined
]

#3: ObjectId: 2.5.29.31 Criticality=false
CRLDistributionPoints [
  [DistributionPoint:
     [URIName: http://onsite-crl.pki.digicert.com/ATTServicesIncApplicationCertificates/LatestCRL.crl]
]]

#4: ObjectId: 2.5.29.15 Criticality=false
KeyUsage [
  DigitalSignature
  Key_Encipherment
]

#5: ObjectId: 2.16.840.1.113730.1.1 Criticality=false
NetscapeCertType [
   SSL client
]

Certificate[2]:
Owner: ...
Issuer: ...
Serial number: ...
Valid from: Wed Feb 23 18:00:00 CST 2011 until: Tue Feb 23 17:59:59 CST 2021
Certificate fingerprints:
     SHA1: ...
     SHA256: ...
Signature algorithm name: SHA1withRSA
Subject Public Key Algorithm: 2048-bit RSA key
Version: 3

Extensions: 

#1: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: 97 20 99 C2 73 2A 45 EB   E0 02 7F 47 DA 7B AB 7C  . ..s*E....G....
0010: EB 1F AF 6E                                        ...n
]
]

#2: ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
  CA:true
  PathLen:0
]

#3: ObjectId: 2.5.29.31 Criticality=false
CRLDistributionPoints [
  [DistributionPoint:
     [URIName: http://onsitecrl.verisign.com/offlineca/ATTServicesIncATTServicesIncRootCA.crl]
]]

#4: ObjectId: 2.5.29.15 Criticality=true
KeyUsage [
  Key_CertSign
  Crl_Sign
]

#5: ObjectId: 2.5.29.17 Criticality=false
SubjectAlternativeName [
  CN=VeriSignMPKI-2-51
]

#6: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 25 64 37 69 DB DC 57 99   43 80 79 29 90 6C B8 13  %d7i..W.C.y).l..
0010: 58 EE B6 D0                                        X...
]
]



*******************************************
*******************************************

]
}

It appears that the keystore includes an entry for our private key but not a client certificate; only the two certificates from the .p7b from the web services site are listed.

The StackOverflow post at:

why doesn't java send the client certificate during SSL handshake?

suggests exporting the client certificate from the keystore and editing the certificate chain. This does not relieve the problem, apparently because the keystore contains our private key but not our signed certificate.

I do not have an artifact that identifies as the client certificate. The Oracle procedure given at:

https://docs.oracle.com/cd/E19509-01/820-3503/ggezu/index.html

suggests the signed client certificate should have been created in the process of preparing the original CSR (step 3 of the procedure) , however we do not appear to have that certificate file as a separate artifact.

I think we need to reconstruct the client certificate and import it into the proper location of the certificate chain in the keystore. Since we do not appear to have the original file created when the CSR was created, can the client certificate be re-created now from scratch (step 3 - 5 of the Oracle procedure) and edited back into the chain? Is there a way to extract or reconstitute the client certificate from the original CSR?

Any questions, insights or suggestions very much appreciated. Thanks.

1
I think I saw a similar problem to this a few years ago, and there was odd behavior because of PKCS12 keystore code in the JVM, where the chain wouldn’t be handled properly but putting every individual certificate in would work properly. It didn’t happen with JKS stores. My memory is fuzzy so I’ll check my notes and see if I have anything useful that might be an answer.Joe

1 Answers

1
votes

It appears that the keystore includes an entry for our private key but not a client certificate; only the two certificates from the .p7b from the web services site are listed.

The PrivateKeyEntry you show listed by keytool does contain a client certificate (by BC, KU and NCT), and a CA certificate that presumably is the issuing (parent) cert for that client cert. (If you imported these certs to this keystore with keytool, the CA cert is definitely the issuer because keytool verifies that; if you used another tool it should enforce the same requirement, but might not.) You describe the p7b as containing "second for the web services site issued by the corporate owner’s own CA" but (1) if that were the case keytool would not have imported it as part of the same chain and (2) it would make no sense, because the client does not need a CA-issued (i.e. not self-signed) server cert in its keystore or truststore, only the cert of the server's CA in its truststore, and that as a separate entry not in the client's PrivateKeyEntry even if it's a shared file.

Per your description you are getting a javax.net.debug=ssl trace, so look at the part of that trace where it loads the keystore and make sure this entry is getting loaded, and look at the server's *** CertificateRequest under Cert Authorities to see what CA(s) it is asking for (immediately before *** ServerHelloDone) and compare that(those) to the actual CA for the chain in your keystore (unredacted). Since you are using Apache HttpClient, if you are using one of the overloads that specifies a PrivateKeyStrategy make sure it selects the alias correctly.