0

There is a Python client app connecting to a Java server app via a secure socket. The connection works great with a self-signed certificate, however, it fails when I attempt to utilize a given valid certificate signed via a CA. I'm suspicious of the latter certificate's format (certificate structure is brought at the end of the question)

This is the structure used in the python client app:

  • mycert.crt
  • mycert.key
  • cacerts.pem

And this is the structure used in the java server app:

  • mycert.p12
  • cacerts

When using the self-signed certificate, I just use the appropriate version (p12 or crt & key) in client and server apps, then import the crt file into cacerts on both sides to recognize the requester certificate:

In the Python client app:

cat mycert >> cacert.pem

In the Java server app:

keytool -import -trustcacerts -keystore cacerts -storepass changeit -noprompt -alias selfSigned -file mycert.crt

...AND THAT WORKS FINE. However, I'm going to replace the self-signed certificate with a CA-signed valid certificate on both client/server sides. I'm given a valid certificate (pfx) which is signed by a global CA, but after extracting its crt and key and importing its crt to the cacerts (the same way stated above), I get generally a handshake error:

python client app error:

Error [[Errno 1] _ssl.c:504: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed] in SSl socket

java server app error:

[StackTrace: {sun.security.ssl.Alerts.getSSLException(Alerts.java:192)} , {sun.security.ssl.Alerts.getSSLException(Alerts.java:154)} , {sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:2023)} , {sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1125)} , {sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)} , {sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:928)} , {sun.security.ssl.AppInputStream.read(AppInputStream.java:105)}

Received fatal alert: unknown_ca

As I said at the beginning, there's an obvious difference between the culprit (so-called valid certificate) and my self-signed certificate. The CA-signed certificate comprises many extensions. How could I find out if the issue isn't with the given CA-signed certificate?


Here are the certificates structures to compare (rephrased):

(The output of keytool -printcert -file mycert.crt)

self-signed certificate: (Which worked fine when was used as the certificate on both sides and also was imported in both cacerts)

Owner: CN=my.cn
Issuer: CN=my.cn
Serial number: <some_numbers>
Valid from: Thu May 07 18:56:50 AEST 2020 until: Mon May 05 18:56:50 AEST 2030
Certificate fingerprints:
     MD5:  <hash:phrase>
     SHA1: <hash:phrase>
     SHA256: <hash:phrase>
     Signature algorithm name: SHA1withRSA
     Version: 1

CA-signed certificate: (ERROR CAUSE, When replaced the self-signed certificate on both sides and also was imported in both cacerts)

Owner: CN=*.example.com, C=AU
Issuer: CN=Certum Domain Validation CA SHA2, OU=Certum Certification Authority, O=Unizeto Technologies S.A., C=PL
Serial number: <some_numbers>
Valid from: Tue May 14 08:35:01 AEST 2019 until: Thu May 13 08:35:01 AEST 2021
Certificate fingerprints:
     MD5:  <hash:phrase>
     SHA1: <hash:phrase>
     SHA256: <hash:phrase>
     Signature algorithm name: SHA256withRSA
     Version: 3

Extensions: 

#1: ObjectId: <some_numbers> Criticality=false
<long_multi_lines_key>


#2: ObjectId: <some_numbers> Criticality=false
AuthorityInfoAccess [
  [
   accessMethod: ocsp
   accessLocation: URIName: http://dvcasha2.ocsp-certum.com
, 
   accessMethod: caIssuers
   accessLocation: URIName: http://repository.certum.pl/dvcasha2.cer
]
]

#3: ObjectId: <some_numbers> Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
<key_here>
]
]

#4: ObjectId: <some_numbers> Criticality=true
BasicConstraints:[
  CA:false
  PathLen: undefined
]

#5: ObjectId: <some_numbers> Criticality=false
CRLDistributionPoints [
  [DistributionPoint:
     [URIName: http://crl.certum.pl/dvcasha2.crl]
]]

#6: ObjectId: <some_numbers> Criticality=false
CertificatePolicies [
  [CertificatePolicyId: [<some_numbers>]
[]  ]
  [CertificatePolicyId: [<some_numbers>]
[PolicyQualifierInfo: [
  qualifierID: <some_numbers>
  qualifier: <phrases_here>

]]  ]
]

#7: ObjectId: <some_numbers> Criticality=false
ExtendedKeyUsages [
  serverAuth
  clientAuth
]

#8: ObjectId: <some_numbers> Criticality=false
IssuerAlternativeName [
  RFC822Name: [email protected]
]

#9: ObjectId: <some_numbers> Criticality=true
KeyUsage [
  DigitalSignature
  Key_Encipherment
]

#10: ObjectId: <some_numbers> Criticality=false
SubjectAlternativeName [
  DNSName: *.example.com
  DNSName: example.com
]

#11: ObjectId: <some_numbers> Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
<key_here>
]
]

Also, Is it possible to use the above Ca-signed certificate as a CA itself to sign my self-signed certificates?

2
  • 'Certum Domain Validation CA SHA2' is decidedly not a root CA, so using this cert requires the server also use the appropriate chain cert, probably this one: crt.sh/?id=5623969 . Do you have that in the correct entry in the server's p12 file? May 9, 2020 at 0:45
  • Thanks @dave_thompson_085. I created sever's p12 file based on the crt file using this command: openssl pkcs12 -export -in mycert.crt -inkey mycert.key.pem -out mycert.p12 -name mycert-alias, So Its content is similar to mycert.crt file which is mentioned at the end of the above post. It also has this information before the certificate detailes: Keystore type: JKS, Keystore provider: SUN, Your keystore contains 1 entry, Alias name: mycert-alias, Creation date: May 9, 2020, Entry type: PrivateKeyEntry, Certificate chain length: 1, Certificate[1]: What's the workaround? Thanks May 9, 2020 at 6:50

2 Answers 2

1

I would not assume that any of the certificate extensions are the error cause in this case. For me, the errors look like both sides don't trust the certificate of the other side.

You could use a packet sniffer like wireshark to take a closer look at the handshakes. Do both client and server send exactly the certificate you expect them to?

Also, do verify that both sides trust the CA certificate of the other side. In your java app, you have to set your self-signed certificate as trusted (it looks like you did this already) and on the python side, verify that the public CA is trusted.

To your last question: You can't sign any other certificate with the one you got.

ObjectId: <some_numbers> Criticality=true
BasicConstraints:[
CA:false
PathLen: undefined
]

This block means that your certificate is not a certificate authority ("CA:false") and thus not allowed to issue any ohter certificates. (It would be a security issue if you could do this.)

2
  • Thanks Lukas. About packet Monitoring, I'll check and get back to you after 1 day or 2. Regarding your 3rd paragraph verifying that both sides trust the CA certificate of the other side; As I'm going to use exactly the same certificate on both sides, I assume I should set the CA-signed certificate trusted on both sides, not the self-signed certificate. Am I right? The self-signed certificate thing was just to test the entire procedure and make sure if I could get the SSLsocket to work by a simple certificate (At that stage,I used the same certificate on both sides, no CA-signed cert) May 8, 2020 at 21:29
  • for debugging reasons, i would change only one thing at a time. At first, change the server certificate to the official one and get it working and then play around with the client certificate. However, I'm not sure if the client certificate part will work (but I have almost no experience with client certs)
    – Lukas
    May 8, 2020 at 21:51
1

Based on info added in comments:

Are you using late-ish java 8 i.e. after about 8u90? In those versions keytool -list with storetype defaulted to JKS will actually read PKCS12 but still show JKS. Assuming so, 'chain length: 1' means you did NOT put the chain cert in the keystore, thus the server's cert chain is incomplete and can't be validated. So:

  • Get the appropriate chain cert (for Certum) from the link I gave https://crt.sh/?id=5623969 which gives PEM, or more authoritatively the caIssuer link in AIA in the cert http://repository.certum.pl/dvcasha2.cer which gives DER and convert that to PEM with openssl x509 -inform der <derfile >pemfile (or with keytool by import to scratch then export, but since you clearly have OpenSSL go with the easier way).

  • Then combine your server cert with that chain cert to create the PKCS12 like

    cat mycert.pem chaincert.pem >combined
    openssl pkcs12 -export -in combined -key mykey.pem  -out myp12
    

    or more simply

    cat mycert.pem chaincert.pem | openssl pkcs12 -export -key mykey.pem -out myp12
    # openssl -in defaults to stdin which here is piped from cat
    
2
  • Thanks Dave. I tried to create a full-chained certificate as you pointed (with the commands in your answer), but got a handshake error as before, complaining unknown_ca. You could see the more detailed error I mentioned here: stackoverflow.com/q/61711998 Also I have written what steps I have taken including contents of the cert files in each step, so you might see what exactly is going wrong. It's here: (It would be more legible in a markdown viewer) paste.ubuntu.com/p/wfxcDGrJpH . I would really appreciate. Thank you May 10, 2020 at 22:20
  • Dummy: your steps for the server look right; your steps for the client are entirely wrong. First, never copy the server's privatekey anywhere, including the client. Second, except for selfsigned which is a different case not applicable here, do not use server-specific data for the client truststore. Use only CA root certs for the client truststore, and normally only standard ones. Your Q said you already had 'cacerts.pem', a name often used for standard roots. What is this file and where did you get it? If it is a standard set, it should have the Certum root(s) in it. May 16, 2020 at 0:50

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .