[openssl-dev] [openssl.org #2634] Cross-signed certs rejected by OpenSSL because root cert not base of chain

Matt Caswell matt at openssl.org
Wed Feb 25 13:18:23 UTC 2015



On 24/02/15 21:28, nagle at sitetruth.com via RT wrote:
> This is an old bug from 2011, generated originally by someone who put a
> self-signed cert in their cert chain.  Until now, it's been ignored.
> It's become a big problem now that Verisign cross-signed one of their
> major root certs (VeriSign Class 3 Public Primary Certification
> Authority - G5). Their root cert is thus no longer the base of a
> chain, and is rejected by OpenSSL. This bug now comes up if you use
> Mozilla's root cert store with Python. It's affecting some major
> web sites and systems which use OpenSSL are struggling to deal
> with this defect.

Your description of this issue isn't quite right I think. There are
actually two different certificates for "VeriSign Class 3 Public Primary
Certification Authority - G5" - an old one and a new one. I've attached
them both. If you look at each certificate you will notice that the
modulus/SubjectKeyIdentifier/Subject are the same in both. In other
words the private/public keys are the same and the certificate is issued
to the same Subject. However the issuers are different. For the old one:

Issuer: C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification
Authority

and the new one:

Issuer: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006
VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public
Primary Certification Authority - G5

For the new one, the issuer is the same as the subject - this is as self
signed certificate and is a true root in its own right. Its not the case
that suddenly the "root cert is no longer the base of the chain".
Because both certificates have the same subject and have the same keys -
both can be used to form valid certificate chains. The difference is
that before, normally, there would only ever be one way to make a chain.
Now, with CAs issuing certs like this, there is more than one way.

OpenSSL only supports one way of making a chain (its only ever needed
one way). The algorithm works something like this:

Take the certificate provided by the remote peer. Try and build as long
a chain as possible from the untrusted certificates provided by that
remote peer.

If we can build a full chain (all the way back to a self-signed root)
from untrusted certificates, look to see if we have the same root in our
trust store. If so, replace the untrusted root, with our trusted root.
We have a complete (and trusted) chain.

If we can't build a full chain from the peer provided certs, see if we
can add certs from our trust store. Keep adding them until we get to a
root. If we successfully end up with a trusted root then we have a
complete (and trusted) chain.

Anything else means we don't have a trusted chain.

Where servers provide all the certs up to and including the cert in
verisign-old.pem, then OpenSSL will will try to complete that chain by
looking in its trust store for the issuer of that cert, i.e.

Issuer: C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification
Authority

If it doesn't find it then it has failed to build the chain and stops.

However there is an alternative chain that could be built, i.e. if we
modified the behaviour so that OpenSSL starts knocking off certs off the
top of the chain provided by the peer, we could look to see if we have
an alternative cert for that issuer in our store. If we find one then we
have found an alternative chain.

I have today pushed to the master branch in git a series of commits that
do just that. See commits:
da084a5ec6
15dba5be6a
25690b7f5f
fa7b01115b

You may also wish to look at RT tickets 3621 and 3637 which are relevant
here.

This is not a bug as such in OpenSSL but an addition to the existing
verify algorithm. As such this won't be backported to released versions
(which only receive bug fixes). It will however be in OpenSSL 1.1.0.


> The problem can be reproduced with the OpenSSL command line client,
> but only on some platforms. See the comments in the Python bug report:
> 
> "I have determined that s_client is buggy. It will always load the
> system certs *if and only if* you also pass it a valid custom CA cert
> (which is the reverse of what's expected)."
> 
> "Antione closed this, as a not python error, as
> if you do not pass a valid certificate to openssl s_client
> it will not read the system certificates, which is clearly
> utterly surprising and nuts."
> 
> So three different development teams now agree it's an OpenSSL bug.

This is a completely separate issue and *is* a bug in s_client. I have
just pulled together a fix for this which is going through review at the
moment. This will be applied to master, 1.0.2 and 1.0.1.

I will close RT 2634, as I think it is largely addressed by the latest
commits in master.

Matt


-------------- next part --------------
A non-text attachment was scrubbed...
Name: verisign-new.pem
Type: application/x-x509-ca-cert
Size: 1758 bytes
Desc: not available
URL: <http://mta.openssl.org/pipermail/openssl-dev/attachments/20150225/f7fd5dbe/attachment.crt>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: verisign-old.pem
Type: application/x-x509-ca-cert
Size: 1716 bytes
Desc: not available
URL: <http://mta.openssl.org/pipermail/openssl-dev/attachments/20150225/f7fd5dbe/attachment-0001.crt>


More information about the openssl-dev mailing list