SSL Certificate - Certification Path in browser different from Certificate Chain File - ssl

I recently purchased a free SSL certificate from Comodo. It came with a certification authority bundle file that contains all of the intermediate certificates as well as the root certificate. When I run the command "openssl s_client -connect www.mydomain.com:443 -showcerts" it shows a certificate path that looks like this:
depth=4 C = SE, O = AddTrust AB, OU = AddTrust External TTP Network, CN = AddTrust External CA Root
verify return:1
depth=3 C = US, ST = UT, L = Salt Lake City, O = The USERTRUST Network, OU = http://www.usertrust.com, CN = UTN-USERFirst-Hardware
verify return:1
depth=2 C = GB, ST = Greater Manchester, L = Salford, O = COMODO CA Limited, CN = COMODO Certification Authority
verify return:1
depth=1 C = GB, ST = Greater Manchester, L = Salford, O = COMODO CA Limited, CN = EssentialSSL CA
verify return:1
depth=0 OU = Domain Control Validated, OU = Free SSL, CN = www.mydomain.com
verify return:1
However, when I go to www.mydomain.com in any browser and look at the certificate presented by the server, it shows the following certificate path (taken from IE9 certificate window):
COMODO
EssentialSSL CA
www.mydomain.com
Notice that there are fewer certificates in the chain (depth of 2 versus 4 from the openssl command), and that the root certificate is the COMODO certificate as opposed to the AddTrust External CA Root certificate. Can someone explain why the browser shows a different path than the openssl command?
Note, in both cases the certificate chain presented by the server passes validation (verify result 0 from openssl, no warnings in the browser).

IE9 has the comodo ca as a trusted authority in its trust chain, and therefore doesn't show the signers of the comodo ca.
OpenSSL s_client -showcerts shows the whole certificate chain.

Related

Openssl Certificate Chain

Executed the command:
openssl s_client -connect (redacted):443
and I get the output
depth=1 C = US, O = Let's Encrypt, CN = R3
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 CN = *.(redacted)
verify return:1
---
Certificate chain
0 s:CN = *.(redacted)
i:C = US, O = Let's Encrypt, CN = R3
1 s:C = US, O = Let's Encrypt, CN = R3
i:O = Digital Signature Trust Co., CN = DST Root CA X3
---
What does the error "unable to get local issuer certificate" mean? From the above I can see that the full chain is there, and that the root CA "DST Root CA X3" signed the "R3" cert. So surely that R3 cert does not need to be explicitly trusted? Is this good enough?
Is this cause for concern?
verify error:num=20:unable to get local issuer certificate
The trust chain from the leaf (server certificate) via the intermediate chain certificates (R3) must end in a locally trusted root CA (DST Root CA X3). Obviously this root CA is not locally trusted in the CA store used by your openssl setup (or maybe you have explicitly used -CApath or -CAfile).

How to build a correct CA chain using cloudflare oigin certificates?

Use Case
this is my use case: I have a page available trough cloudflare (proxied), let's call it example.com.
I created a Origin Certificate with Cloudflare and linked it in my nginx config, works fine. Cloudflare works in "Full" SSL mode.
Now I want to be able to basically add 127.0.0.1 example.com to my /etc/hosts so the server itself can directly access the page (it is not really an option to use a different domain with software running on this server to circumvent this).
Now obviously when I curl -v https://example.com I get a ssl error.
What I did so far
So basically, did some research and learned about CA chains and so on.
I found the Cloudflare Origin root CA's (Cloudflare Documentation, Step 4) and included that in the cert chain in my nginx server (basically first the Cloudflare Origin cert they generated for me, then the Root CA). I also installed the Root CA to /usr/share/ca-certificates (and /usr/local/share/ca-certificates) and ran dpkg-reconfigure ca-certificates and it was properly added to the /etc/ssl/certs dir. So far so good?
Result: Does not work.
Further research
Stumbling upon this guide I looked the following up:
cert.pem is my Cloudflare issued certificate
ca.pem is the cloudflare root CA (the ecc file)
root#host:~/ssltest# openssl verify cert.pem
O = "CloudFlare, Inc.", OU = CloudFlare Origin CA, CN = CloudFlare Origin Certificate
error 20 at 0 depth lookup: unable to get local issuer certificate
error cert.pem: verification failed
root#host:~/ssltest# openssl x509 -noout -issuer -in cert.pem
issuer=C = US, O = "CloudFlare, Inc.", OU = CloudFlare Origin SSL Certificate Authority, L = San Francisco, ST = California
root#host:~/ssltest# openssl x509 -noout -issuer -in ca.pem
issuer=C = US, ST = California, L = San Francisco, O = "CloudFlare, Inc.", OU = CloudFlare Origin SSL ECC Certificate Authority
root#host:~/ssltest# openssl verify -CAfile ca.pem cert.pem
O = "CloudFlare, Inc.", OU = CloudFlare Origin CA, CN = CloudFlare Origin Certificate
error 20 at 0 depth lookup: unable to get local issuer certificate
error cert.pem: verification failed
So basically the Issuer of cert.pem and Subject of ca.pem do not match up.
This means for me: Either there is an Intermediate Cert that I do not know how to get, or Cloudflare gave me a cert that is not from the root CA they gave me.
Also the difference between Issuer and Subject is super small:
CloudFlare Origin SSL Certificate Authority
CloudFlare Origin SSL ECC Certificate Authority
What can I do to fix it?
I'm probably just not seeing something here, can anyone help me out? Thank you!
There are two CA certificates offered on the site you refer to:
The first one is the RSA certificate with the OU "CloudFlare Origin SSL Certificate Authority". The seconds one is the ECC certificate OU "CloudFlare Origin SSL ECC Certificate Authority".
Looks like you took ECC certificate while you should have taken the RSA certificate.

Can Root CA Certificate located in the middle of certificate path?

I made a program that connects to website(tls) and save certificate chain to files.
Sometimes certificate chain from a website is looking different from what I expected.
One of this certificate chain is issued from Sectigo(ex Comodo) CA.
I think "AddTrust External CA Root" should located in the last certificate of chain but is located in second certificate in its chain.(please look at below Certificate chain part )
$ openssl s_client -showcerts -connect adblockplus.org:443
CONNECTED(00000003)
depth=3 C = SE, O = AddTrust AB, OU = AddTrust External TTP Network, CN = AddTrust External CA Root
verify return:1
depth=2 C = US, ST = New Jersey, L = Jersey City, O = The USERTRUST Network, CN = USERTrust RSA Certification Authority
verify return:1
depth=1 C = GB, ST = Greater Manchester, L = Salford, O = Sectigo Limited, CN = Sectigo RSA Extended Validation Secure Server CA
verify return:1
depth=0 serialNumber = HRB 73508, jurisdictionC = DE, businessCategory = Private Organization, C = DE, postalCode = 50825, ST = Nordrhein-Westfalen, L = K\C3\B6ln, street = Lichtstra\C3\9Fe 25, O = Eyeo GmbH, OU = COMODO EV SSL, CN = www.adblockplus.org
verify return:1
---
Certificate chain
0 s:/serialNumber=HRB 73508/jurisdictionC=DE/businessCategory=Private Organization/C=DE/postalCode=50825/ST=Nordrhein-Westfalen/L=K\xC3\xB6ln/street=Lichtstra\xC3\x9Fe 25/O=Eyeo GmbH/OU=COMODO EV SSL/CN=www.adblockplus.org
i:/C=GB/ST=Greater Manchester/L=Salford/O=Sectigo Limited/CN=Sectigo RSA Extended Validation Secure Server CA
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
1 s:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root
i:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
2 s:/C=US/ST=New Jersey/L=Jersey City/O=The USERTRUST Network/CN=USERTrust RSA Certification Authority
i:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
3 s:/C=GB/ST=Greater Manchester/L=Salford/O=Sectigo Limited/CN=Sectigo RSA Extended Validation Secure Server CA
i:/C=US/ST=New Jersey/L=Jersey City/O=The USERTRUST Network/CN=USERTrust RSA Certification Authority
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
---
Server certificate
subject=/serialNumber=HRB 73508/jurisdictionC=DE/businessCategory=Private Organization/C=DE/postalCode=50825/ST=Nordrhein-Westfalen/L=K\xC3\xB6ln/street=Lichtstra\xC3\x9Fe 25/O=Eyeo GmbH/OU=COMODO EV SSL/CN=www.adblockplus.org
issuer=/C=GB/ST=Greater Manchester/L=Salford/O=Sectigo Limited/CN=Sectigo RSA Extended Validation Secure Server CA
my question is:
Is this case is normal?
Is the web server(adblockplus this time) making Certificate path ?
How to determine valid certificate path?
Any comments are welcome. thanks
A TLS-was-SSL server is supposed to send the certificate chain in the correct order in the handshake, but some don't, and most clients including OpenSSL will still handle it correctly, by matching up issuer=subject names, as long as the leaf (end-entity) cert is first. Note the trace of the validation process:
depth=3 C = SE, O = AddTrust AB, OU = AddTrust External TTP Network, CN = AddTrust External CA Root
verify return:1
depth=2 C = US, ST = New Jersey, L = Jersey City, O = The USERTRUST Network, CN = USERTrust RSA Certification Authority
verify return:1
depth=1 C = GB, ST = Greater Manchester, L = Salford, O = Sectigo Limited, CN = Sectigo RSA Extended Validation Secure Server CA
verify return:1
depth=0 serialNumber = HRB 73508, jurisdictionC = DE, businessCategory = Private Organization, C = DE, postalCode = 50825, ST = Nordrhein-Westfalen, L = K\C3\B6ln, street = Lichtstra\C3\9Fe 25, O = Eyeo GmbH, OU = COMODO EV SSL, CN = www.adblockplus.org
verify return:1
You can see that the certificates were used in the correct top-to-bottom order even though they weren't received in the correct bottom-to-top order.
This misbehavior is common enough TLS 1.3 was changed to officially permit it. Compare TLS 1.2 in RFC 5246 7.4.2:
certificate_list ... The sender's
certificate MUST come first in the list. Each following
certificate MUST directly certify the one preceding it. Because
certificate validation requires that root keys be distributed
independently, the self-signed certificate that specifies the root
certificate authority MAY be omitted from the chain, under the
assumption that the remote end must already possess it in order to
validate it in any case.
to TLS 1.3 in RFC 8446 4.4.2, emphasis added:
... The sender's certificate MUST come in the first
CertificateEntry in the list. Each following certificate SHOULD
directly certify the one immediately preceding it. Because
certificate validation requires that trust anchors be distributed
independently, a certificate that specifies a trust anchor MAY be
omitted from the chain, provided that supported peers are known to
possess any omitted certificates.
Note: Prior to TLS 1.3, "certificate_list" ordering required each
certificate to certify the one immediately preceding it; however,
some implementations allowed some flexibility. Servers sometimes
send both a current and deprecated intermediate for transitional
purposes, and others are simply configured incorrectly, but these
cases can nonetheless be validated properly. For maximum
compatibility, all implementations SHOULD be prepared to handle
potentially extraneous certificates and arbitrary orderings from any
TLS version, with the exception of the end-entity certificate which
MUST be first.
(And the same is true in the other direction for client certificates, but they are used only very rarely, while server certificates almost always are.)

openssl verify not working with GeoTrust Certificate

I have a newly purchased GeoTrust domain certificate and a matching CA file and would like to verify with openssl.
openssl verify -verbose -purpose any
-CAfile /full/path/sub.domain.com-geotrust.crt /full/path/sub.domain.com.crt
From this page: https://secure.marumoto.us/motowiki/tiki-index.php?page=Verify+a+Certificate+Chain
The issuer of each certificate in the chain should match the subject of the next certificate in the chain. For example the issuer of myserver.mydomain.com.cert should match the subject of myintermediate_ca.cert, and the issuer of myintermediate_ca.cert should match the subject of myroot_ca.cert. You can use the following command to view a certificate in .pem or base64 format.
From
openssl x509 -text -in sub.domain.crt and
openssl x509 -text -in sub.domain-geotrust.crt (CA root file)
sub.domain.com
Subject: OU=GT44865949,
OU=See www.geotrust.com/resources/cps (c)15,
OU=Domain Control Validated - QuickSSL(R),
CN=sub.domain.com
Issuer:
commonName = GeoTrust DV SSL CA - G4
organizationalUnitName = Domain Validated SSL
organizationName = GeoTrust Inc.
countryName = US
Intermediate:
Subject:
commonName = GeoTrust DV SSL CA - G4
organizationalUnitName = Domain Validated SSL
organizationName = GeoTrust Inc.
countryName = US
Issuer:
commonName = GeoTrust Global CA
organizationName = GeoTrust Inc.
countryName = US
Root:
Subject:
commonName = GeoTrust Global CA
organizationName = GeoTrust Inc.
countryName = US
Issuer:
organizationalUnitName = Equifax Secure Certificate Authority
organizationName = Equifax
countryName = US
It appears my Issuer and Subject fields are matching up properly but I am getting the following error with openssl:
error 20 at 0 depth lookup:unable to get local issuer certificate
/full/path/sub.domain.com.crt: /OU=GT44865949/OU=See www.geotrust.com/resources/cps (c)15/OU=Domain Control Validated - QuickSSL(R)/CN=sub.domain.com
error 20 at 0 depth lookup:unable to get local issuer certificate
I'd like to use this and a similar GeoTrust certificate at a different subdomain to do two-way SSL authentication at a restful web url but the certs won't verify with 'openssl verify' against the CA files issued with them. Any suggestions much appreciated.
As per discussion, it is a matter of allowing openssl to see the entire validation chain: with both GeoTrust CA intermediates and the root.
openssl should be run with CADir parameter containing all the 3 CAs in PEM format. The actual root for GeoTrust can either be extracted from your favourite browser, or here: filedropper.com/geotrustglobalca.
When you configure your actual server, just make sure that you send the intermediates on the Server Hello, some sites don't do that and break clients that do not have the intermediates cached.
Following on from RomanK's answer, you can get the GeoTrust Global CA from their root certificate store. They have a number of primary/universal/global certificates listed there, so make sure to get the right one for your intermediate certificate.
As per the chain display, the root certificate is not self signed . Its shows its issued by Equifax. Openssl will continue giving the error "local issuer certificate not found" till it gets a self signed root certificate. When it comes across a root self signed then it's able to verify the certificate chain as complete.

How to verify certificate chain with openssl

I am trying to verify a certificate file with OpenSSL. Can you explain me why s_client connection succeeds, but verify file with the same certificate chain fails? How can I verify the file?
Note I compiled OpenSSL 1.0.1k myself, it shouldn't be using any distro-specific config. And I provided the same CAfile to both commands.
$ openssl s_client -CAfile /etc/pki/tls/certs/ca-bundle.crt -connect www.google.com:443
WARNING: can't open config file: /usr/local/ssl/openssl.cnf
CONNECTED(00000003)
depth=3 C = US, O = Equifax, OU = Equifax Secure Certificate Authority
verify return:1
depth=2 C = US, O = GeoTrust Inc., CN = GeoTrust Global CA
verify return:1
depth=1 C = US, O = Google Inc, CN = Google Internet Authority G2
verify return:1
depth=0 C = US, ST = California, L = Mountain View, O = Google Inc, CN = www.google.com
verify return:1
---
Certificate chain
0 s:/C=US/ST=California/L=Mountain View/O=Google Inc/CN=www.google.com
i:/C=US/O=Google Inc/CN=Google Internet Authority G2
1 s:/C=US/O=Google Inc/CN=Google Internet Authority G2
i:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
2 s:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
i:/C=US/O=Equifax/OU=Equifax Secure Certificate Authority
---
...
Verify return code: 0 (ok)
---
If I run it with -showcerts argument, it outputs all three certificates sent from server. I concatenated them into file google.pem. But the chain can't be verified. See:
$ openssl verify -CAfile /etc/pki/tls/certs/ca-bundle.crt google.pem
WARNING: can't open config file: /usr/local/ssl/openssl.cnf
google.pem: C = US, ST = California, L = Mountain View, O = Google Inc, CN = www.google.com
error 20 at 0 depth lookup:unable to get local issuer certificate
Applying a patch suggested on https://stackoverflow.com/a/27606964/1823988 doesn't help.
I found it. openssl verify doesn't expect certificate file to contain its chain. Chain needs to be passed with -untrusted argument. It works with the same file, trust is still determined by finding a trusted root in -CAfile.
openssl verify -CAfile /etc/pki/tls/certs/ca-bundle.crt -untrusted google.pem google.pem