I'm getting an error "Chain issues: Incorrect order, Extra certs" from https://www.ssllabs.com/ssltest/analyze.html?d=api.quotecrunchers.com when I test the SSL for my website.
I've built the https mechanism into a spring boot application using the following:
The acme4j library to communicate with the Let's Encrypt CA.
Java code to write the Let's Encrypt certificate to a java keystore.
Java code to cause the embedded Tomcat server to apply for a certificate from Let's Encrypt over HTTP and then restart using HTTPS once it has the certificate.
I'm planning on open sourcing this code once I've got it tidied up.
Currently though, I'm only achieving a B rating using ssllabs.com
See https://www.ssllabs.com/ssltest/analyze.html?d=api.quotecrunchers.com
There are several issues with my https, but the issue I am concerned about is where it says "Chain issues: Incorrect order, Extra certs".
Why am I getting this, and what should I be doing instead?
Any help is greatly appreciated!
When one connects to your site, here is what is sent by it as seen by openssl s_client:
Certificate chain
0 s:/CN=api.quotecrunchers.com
i:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
1 s:/CN=api.quotecrunchers.com
i:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
2 s:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
i:/O=Digital Signature Trust Co./CN=DST Root CA X3
As you can see the first certificate is duplicated which is exactly the reason of the rating and error message.
When you configure a TLS server you specify typically on one end the end (server) certificate, that is one certificate, and it would appear in position 0 in a trace like above, and then you (optionnally, but very frequently) provide a potential list of chained certificates, called "intermediate" that links your end certificate to some root (CA) certificate, the CA certificate itself may be the last one in the chain or be skipped altogether.
That would have been in position 1 and later in the trace above.
But as you can see, at position 1, hence as intermediate certificate, we find again your end certificate.
This is not correct per the TLS standard so you need to change your configuration or the file containing the intermediate certificates to remove your end certificate from this spot, so that you finally manage to get:
Certificate chain
0 s:/CN=api.quotecrunchers.com
i:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
1 s:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
i:/O=Digital Signature Trust Co./CN=DST Root CA X3
Related
This question already has answers here:
SSL working in chrome but sometimes in Firefox and not on IOS, Android or Blackberry
(2 answers)
Closed 1 year ago.
I've put together a Linux (Centos 7) server to serve eye-n-sky.net.
Serving content from that site to browsers on Win10 and Linux systems works beautifully. However, when I use openssl to access the site,
openssl s_client -connect eye-n-sky.net:443
the site certificate is rejected,
Verify return code: 21 (unable to verify the first certificate)
I've concluded that the way a browser verifies the certificate is different from what openssl does. Am I on the right track?
I've tested this on three different openssl instances (Debian, Centos, FreeBSD) and have consistent results.
Openssl as a client to other sites, e.g. www.godaddy.com, microsoft.com, work fine, being able to verify the certificate against the installed CA chain.
Believing that I was missing a CA cert, I used the -CAfile option to specify the possibly missing cert, to no effect.
What am I missing? I'm guessing that openssl has a stricter verification discipline, but I don't know where that gets configured.
Thanks,
Andy
Summary: yes, eye-n-sky was providing only it's cert when it needed to include the intermediate and root certs.
However, it took me forever to figure out that my Apache version did not support including the chain in the server cert file. Instead, I had to provide the chain file separately in an SSLCertificateChainFile directive.
OpenSSL's command-line s_client utility has nothing built in to validate the server's certificate. Browsers have a built-in list of trusted certificates to verify the server certificate against.
You have to supply the trusted certificates using options such as -CAfile file or -CApath directory. Per the OpenSSL 1.1.1 s_client man page:
-CApath directory
The directory to use for server certificate verification. This
directory must be in "hash format", see verify(1) for more
information. These are also used when building the client certificate
chain.
-CAfile file
A file containing trusted certificates to use during server
authentication and to use when attempting to build the client
certificate chain.
Note the use of words such as "certificate chain". If you go to godaddy.com you'll see that the server's cert is for *.godaddy.com, but it was signed by Go Daddy Secure Certificate Authority - G2, and that intermediate certificate was signed by Go Daddy Root Certificate Authority - G2 - a different certificate. There's a total of three certificates in that chain.
Verify return code 21 is "no signatures could be verified because the chain contains only one certificate and it is not self signed", so if your CA file only had the certificate from Go Daddy Root Certificate Authority - G2 and not the one from Go Daddy Secure Certificate Authority - G2, OpenSSL would see from the server's cert itself that it was signed by Go Daddy Secure Certificate Authority - G2 and could go no further - it doesn't have that cert to see who signed it.
When a TLS handshake takes place, the server sends in his ServerHello message, his digital certificate. This digital certificate is digitally signed by a intermediate CA named A and CA A also has a certificate which is signed by CA named root whose certificate is self signed, thus forming a certificate chain. The client then has to establish a trust, validating the server certificate. To perform that validation the client has to validate the entire chain correct?
Must the client have in a truststore all the certificates (A and Root) or the client will download them?
The client usually has only the root CA in the local trust store. The leaf certificate and the intermediate certificate leading to the root CA need to be provided by the server. The intermediate certificates are usually send in addition to the leaf certificate within the TLS handshake.
But it is a typical misconfiguration to only have the leaf certificate send by the server. In this case the certificate validation will fail unless the client has already knowledge of the intermediate certificates or can obtain these somehow. Since often the same intermediate certificates are used, some browsers like Firefox will cache the intermediate certificates they'll got when communicating with server A and fill these in when a broken server B is not sending the required intermediate certificates. Other browsers (like Google Chrome) will try to download the missing intermediate certificates from the internet. Most simpler clients (i.e. apps written in Python, Java ... or curl) will instead just fail with a certificate validation error.
A
/ \
B C
| |
D E
when E (or C) is verifying D's certificate he needs to trust B also.
is there a way to avoid having to explicitly add B's cert to E's CA store?
using openssl, is there the way to automate the retrieval of B's cert either from the client or another source (maybe a field like issuerDistributionPoint in D's certificate)?
is there a way to avoid having to explicitly add B's cert to E's CA store?
The common way is to send all intermediate certificates along with the leaf certificate inside the TLS handshake. For instance if you connect to google.com you get the following certificate chain provided by the server within the TLS handshake:
0 s:/C=US/ST=California/L=Mountain View/O=Google Inc/CN=*.google.com
1 s:/C=US/O=Google Inc/CN=Google Internet Authority G2
2 s:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
Using the intermediate certificates (1,2) the client then can build the trust chain from the leaf certificate (0) up to the locally stored trusted CA (/C=US/O=Equifax/OU=Equifax Secure Certificate Authority in this case).
Of course you might also add the intermediate certificates as trusted in the clients. But since there are a lot more which also change more often than the trusted root certificates you would need a bit more memory but you would also update your clients regularly with the new intermediate certificates.
using openssl, is there the way to automate the retrieval of B's cert either from the client or another source (maybe a field like issuerDistributionPoint in D's certificate)?
openssl does not provide specific tools to deal with this. The desktop browser Google Chrome will actually try to download missing intermediate certificates from the internet, probably based on the information in the Authority Information Access part of the certificate. But I'm not aware of other browsers (apart from other Chromium derivates like Opera) doing this.
In accordance with Microsoft a minimum key length for a certificate should be of 1024 bits since August 2012. I have created a self-signed certificate having a key length of 4096 bits. But the certificate information shows the following error:
When I inspected the public key length it shows the following screen:
But instead of having "This certificate is OK." as a status, I am getting the following error:
How can I resolve this issue?
Thanks...
Where do you see a self-signed certificate? Self-signed certificate is the certificate where Subject and Issuer fields are the same. In your case, it is not self-signed.
I can suspect, that the certificate was either, not signed by InfoValley Inc., or signature algorithm is not recognized on your system. Can you tell us the following information:
Authority Key Identifier extension value from leaf certificate
Signature algorithm used to sign leaf certificate (2nd and 3rd fields)
Subject Key Identifier extension value from InfoValley Inc. certificate
I'll explain at least one other way that you can get an invalid digital signature that happened to me. I have a set of scripts that build may certificates and a set of scripts that installs certificates in the windows certificate store. The script that installs the certificates first deletes the certificates that I'm going to install and then installs the new certificates. I thought the script was working just fine, but it turns out I had little bug in the script. I have one Trusted Root CA certificate that is used to sign my Intermediary Trusted Root CA certificates. The problem was that I chose the wrong "certificatestorename" for the trusted root certificate. So, instead actually deleting my trusted root certificate before I installed it, I ended up creating a second trusted root ca certificate in the Trusted Root Certificate Authorities store with the same distinguished name. And that's what cause my 2nd level intermediary CA certificates to report that they had an invalid digital signature.
What made this problem a little difficult to spot was that if I looked at installed 2nd level intermediary CA certificates after being install in the windows certificate store, those 2nd level intermediary CA certificates all showed that the "This certificate is "OK" and no issues with the certificate chain. The problem caused by the two trusted root certificates with the same distinguished name didn't exhibit any problems until I tried to validate a certificate that was signed by one of my 2nd level intermediary CA certificates. It's when I look at those certificates that I saw my 2nd level intermediary CA certificates all had an invalid digital signature.
So, this is at least one way that I observed that you can get this error message. Technically speaking, the error means that the issuer of the certificate cannot validate the signature of the given certificate, which is not the same thing as not finding the issuer certificate in the trusted store. Others have reported that this problem can occur in windows if you generate a certificate whose key length is 512.
I am trying to verify an SSL connection to Experian in Ubuntu 10.10 with OpenSSL client.
openssl s_client -CApath /etc/ssl/certs/ -connect dm1.experian.com:443
The problem is that the connection closes with a Verify return code: 21 (unable to verify the first certificate).
I've checked the certificate list, and the Certificate used to sign Experian (VeriSign Class 3 Secure Server CA - G3) is included in the list.
/etc/ssl/certs/ca-certificates.crt
Yet I don't know why it is not able to verify the first certificate.
The entire response could be seen here:
https://gist.github.com/1248790
The first error message is telling you more about the problem:
verify error:num=20:unable to get local issuer certificate
The issuing certificate authority of the end entity server certificate is
VeriSign Class 3 Secure Server CA - G3
Look closely in your CA file - you will not find this certificate since it is an intermediary CA - what you found was a similar-named G3 Public Primary CA of VeriSign.
But why does the other connection succeed, but this one doesn't? The problem is a misconfiguration of the servers (see for yourself using the -debug option). The "good" server sends the entire certificate chain during the handshake, therefore providing you with the necessary intermediate certificates.
But the server that is failing sends you only the end entity certificate, and OpenSSL is not capable of downloading the missing intermediate certificate "on the fly" (which would be possible by interpreting the Authority Information Access extension). Therefore your attempt fails using s_client but it would succeed nevertheless if you browse to the same URL using e.g. FireFox (which does support the "certificate discovery" feature).
Your options to solve the problem are either fixing this on the server side by making the server send the entire chain, too, or by passing the missing intermediate certificate to OpenSSL as a client-side parameter.
Adding additional information to emboss's answer.
To put it simply, there is an incorrect cert in your certificate chain.
For example, your certificate authority will have most likely given you 3 files.
your_domain_name.crt
DigiCertCA.crt # (Or whatever the name of your certificate authority is)
TrustedRoot.crt
You most likely combined all of these files into one bundle.
-----BEGIN CERTIFICATE-----
(Your Primary SSL certificate: your_domain_name.crt)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
(Your Intermediate certificate: DigiCertCA.crt)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
(Your Root certificate: TrustedRoot.crt)
-----END CERTIFICATE-----
If you create the bundle, but use an old, or an incorrect version of your Intermediate Cert (DigiCertCA.crt in my example), you will get the exact symptoms you are describing.
SSL connections appear to work from browser
SSL connections fail from other clients
Curl fails with error: "curl: (60) SSL certificate : unable to get local issuer certificate"
openssl s_client -connect gives error "verify error:num=20:unable to get local issuer certificate"
Redownload all certs from your certificate authority and make a fresh bundle.
I came across the same issue installing my signed certificate on an Amazon Elastic Load Balancer instance.
All seemed find via a browser (Chrome) but accessing the site via my java client produced the exception javax.net.ssl.SSLPeerUnverifiedException
What I had not done was provide a "certificate chain" file when installing my certificate on my ELB instance (see https://serverfault.com/questions/419432/install-ssl-on-amazon-elastic-load-balancer-with-godaddy-wildcard-certificate)
We were only sent our signed public key from the signing authority so I had to create my own certificate chain file. Using my browser's certificate viewer panel I exported each certificate in the signing chain. (The order of the certificate chain in important, see https://forums.aws.amazon.com/message.jspa?messageID=222086)
Here is what you can do:-
Exim SSL certificates
By default, the /etc/exim.conf will use the cert/key files:
/etc/exim.cert
/etc/exim.key
so if you're wondering where to set your files, that's where.
They're controlled by the exim.conf's options:
tls_certificate = /etc/exim.cert
tls_privatekey = /etc/exim.key
Intermediate Certificates
If you have a CA Root certificate (ca bundle, chain, etc.) you'll add the contents of your CA into the exim.cert, after your actual certificate.
Probably a good idea to make sure you have a copy of everything elsewhere in case you make an error.
Dovecot and ProFtpd should also read it correctly, so dovecot no longer needs the ssl_ca option.
So for both cases, there is no need to make any changes to either the exim.conf or dovecot.conf(/etc/dovecot/conf/ssl.conf)
If you are using MacOS use:
sudo cp /usr/local/etc/openssl/cert.pem /etc/ssl/certs
after this Trust anchor not found error disappears
For those using zerossl.com certificates, drag and drop all certificates (as is) to their respective folders.
Cut and pasting text into existing files, may cause utf8 issues - depending upon OS, format and character spacings.