After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 681299 - GTlsDatabaseGnutls fails to validate certain Verisign certificates
GTlsDatabaseGnutls fails to validate certain Verisign certificates
Status: RESOLVED FIXED
Product: glib
Classification: Platform
Component: network
unspecified
Other Linux
: Normal normal
: ---
Assigned To: gtkdev
gtkdev
Depends on:
Blocks:
 
 
Reported: 2012-08-06 13:32 UTC by Marc Deslauriers
Modified: 2012-08-11 04:21 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
reproducer (2.46 KB, text/x-python)
2012-08-06 13:32 UTC, Marc Deslauriers
  Details
gnutls: Try to find root certificates locally if not anchored (4.01 KB, patch)
2012-08-08 05:38 UTC, Stef Walter
none Details | Review
The debian/ubuntu /etc/ssl/certs/ca-certificates.crt file (124.77 KB, application/x-gzip)
2012-08-08 07:18 UTC, Michael Vogt
  Details
Simple testcase using gio (551 bytes, text/x-python)
2012-08-08 07:44 UTC, Michael Vogt
  Details
gnutls: Try to find root certificates locally if not anchored (16.94 KB, patch)
2012-08-08 10:26 UTC, Stef Walter
accepted-commit_now Details | Review
tests: Fix typo (1.03 KB, patch)
2012-08-11 04:19 UTC, Stef Walter
committed Details | Review

Description Marc Deslauriers 2012-08-06 13:32:02 UTC
Created attachment 220440 [details]
reproducer

Verisign shipped G1 PCA Roots with md2 signatures on them. At some point, they resigned those same roots using SHA1.

See discussion here:
https://groups.google.com/forum/?fromgroups#!msg/mozilla.dev.security.policy/I6bUbW3WkBU/lRxqGv6vYHYJ

In Ubuntu, the Verisign md2 certs do not ship in the system CA certs bundle, as the sha1 certs are being shipped instead. SSL libraries are supposed to verify certs with the sha1 G1 PCA Root just fine, even if the web site sends the md2 G1 PCA Root as part of the cert bundle.

You can test this by using the following command:

gnutls-cli --x509cafile /etc/ssl/certs/ca-certificates.crt --print-cert -p 443 secure-test.streamline-esolutions.com

In older versions of libsoup, such as 2.36.1, this worked fine. Since libsoup 2.37.1, this is no longer working correctly. It seems glib-networking gtlsfiledatabase-gnutls.c:g_tls_file_database_gnutls_lookup_assertion() is attempting to validate the whole DER, which wouldn't properly accept the sha1 cert for validation.

Attached is a reproducer. It will first attempt to validate the web site cert using the old md2 Root, and then will attempt with the sha1 Root. Both should succeed. With libsoup > 2.37, the sha1 Root fails verification.
Comment 1 Michael Vogt 2012-08-07 07:05:01 UTC
The root of the problem appears to be glib-networking in its tls/gtlsdatabase-gnutls.c:g_tls_database_gnutls_verify_chain():

This first runs build_certificate_chain() which will try to find the "anchor" certificate from the chain that the server sends. In the case of this bug the anchor is the md2 cert which is no longer distributed on the systems ca cert bundle. Then gnutls_x509_crt_list_verify() is called with a empty "anchors" list and that fails with a GNUTLS_CERT_SIGNER_NOT_FOUND error.

What gnutls-cli is doing is that it passes the list of all trusted certificates from the systems CA certs bundle to gnutls_x509_crt_list_verify(). That works because there is a trusted issuer (the sha-1 cert) available on the system even though the "wrong" (md2 signed but as its a root one it does not really matter as its just self-signed) one was send out from the server as part of the chain.
Comment 2 Dan Winship 2012-08-07 11:15:14 UTC
so... I guess g_tls_file_database_gnutls_lookup_assertion() should look up the certificate by its public key rather than by the DER of the whole cert? Or should we actually "canonicalize" the GTlsCertificate's issuer property when we create it?
Comment 3 Stef Walter 2012-08-07 11:30:06 UTC
Well for starters 'secure-test.streamline-esolutions.com' is technically misconfigured. A site shouldn't be sending out the root certificate. If it didn't send the root cert then glib-networking would just work.

Here's what the site is sending: 

[stef@stef-rawhide ~]$ openssl s_client -connect secure-test.streamline-esolutions.com:443 
CONNECTED(00000003)
depth=2 C = US, O = "VeriSign, Inc.", OU = Class 3 Public Primary Certification Authority
verify return:1
depth=1 C = US, O = "VeriSign, Inc.", OU = VeriSign Trust Network, OU = Terms of use at https://www.verisign.com/rpa (c)10, CN = VeriSign Class 3 Secure Server CA - G3
verify return:1
depth=0 C = GB, ST = Lothian, L = Edinburgh, O = The Royal Bank of Scotland Group Plc, OU = Business Standard, CN = secure-test.streamline-esolutions.com
verify return:1
---
Certificate chain
 0 s:/C=GB/ST=Lothian/L=Edinburgh/O=The Royal Bank of Scotland Group Plc/OU=Business Standard/CN=secure-test.streamline-esolutions.com
   i:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=Terms of use at https://www.verisign.com/rpa (c)10/CN=VeriSign Class 3 Secure Server CA - G3
 1 s:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=Terms of use at https://www.verisign.com/rpa (c)10/CN=VeriSign Class 3 Secure Server CA - G3
   i:/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority
 2 s:/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority
   i:/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority

But obviously we need to support this case. To do that it seems that we need to build multiple certificate chains according to the relevant RFC, weight them and pass them in turn to gnutls.

Dan, I don't think it's possible to pick the 'right' issuer without checking the signature, which is done at the gnutls_x509_crt_list_verify() step.

BTW, Marc, the reason we can't just pass all the anchors to gnutls_x509_crt_list_verify() is because for the PKCS#11 backend we don't have a definitive list of all the anchors (and/or it would be prohibitive to load them all).
Comment 4 Stef Walter 2012-08-07 11:33:10 UTC
Hmmm, tangentially this also exposes a flaw it GTlsDatabase. the lookup_certificate_issuer() vfunc should really be lookup_certificate_issuers() (or more like lookup_possible_certificate_issuers() actually).
Comment 5 Dan Winship 2012-08-07 13:57:26 UTC
(In reply to comment #3)
> Dan, I don't think it's possible to pick the 'right' issuer without checking
> the signature, which is done at the gnutls_x509_crt_list_verify() step.

There is no "right" issuer though; the signature verification only depends on the public key of the issuer, which is the same in both certificates. So if we have the md2 cert in our db, then we can verify against that, and if we have the sha1 cert in our db, then we can verify against that; as you said, if the server hadn't sent us the "bad" issuer cert in the first place, then everything would have worked.

All we need to do is notice at some point in the process that the "CN=VeriSign Class 3 Secure Server CA - G3" in the server's signing chain can be considered equivalent (for this purpose) to the "CN=VeriSign Class 3 Secure Server CA - G3" certificate in our db, even though they are not g_tls_certificate_is_same().
Comment 6 Stef Walter 2012-08-08 04:34:58 UTC
(In reply to comment #5)
> (In reply to comment #3)
> > Dan, I don't think it's possible to pick the 'right' issuer without checking
> > the signature, which is done at the gnutls_x509_crt_list_verify() step.
> 
> There is no "right" issuer though; the signature verification only depends on
> the public key of the issuer, which is the same in both certificates. 

Right. Hence the quote marks. I should have been more clear. 

> All we need to do is notice at some point in the process that the "CN=VeriSign
> Class 3 Secure Server CA - G3" in the server's signing chain can be considered
> equivalent (for this purpose) to the "CN=VeriSign Class 3 Secure Server CA -
> G3" certificate in our db, even though they are not
> g_tls_certificate_is_same().

It's tough to lookup certificates by public key in a database (especially for PKCS#11). So you end up looking for certificates based on subject, and then choosing which one is 'better'. 

If we're going for simple fix (ie: fix this one case) then we can just detect the case where the root certificate is not anchored and see if we can find one with the same issuer that is anchored.

However eventually we will need to move toward building multiple certification paths, sorting them and trying them out. This is in order to deal with stuff like cross certificates. RFC 4158 details this. Not all of RFC 4158 (and RFC 5280) is actually implementable in all cases, but they have very helpful guidelines and algorithms for this sort of thing.
Comment 7 Stef Walter 2012-08-08 05:37:22 UTC
Marc or Michael, could you attach the ubuntu system certs bundle so we can test this correctly?
Comment 8 Stef Walter 2012-08-08 05:38:24 UTC
Created attachment 220636 [details] [review]
gnutls: Try to find root certificates locally if not anchored

Possible fix. Not yet completely tested, waiting for certificate bundle.
Comment 9 Michael Vogt 2012-08-08 07:18:24 UTC
Created attachment 220640 [details]
The debian/ubuntu /etc/ssl/certs/ca-certificates.crt file
Comment 10 Michael Vogt 2012-08-08 07:44:13 UTC
Created attachment 220643 [details]
Simple testcase using gio

Hey Stef, thanks a lot for the patch. 

It looks great to me, maybe the comment after is_self_signed could reference this bug just to ensure that the full discussion around it can be easily found? But I guess this is not needed as the git log will reference it already.

I tested the change locally here and it works fine for my attached minimal testcase and also for a real world testcase (pointing epiphany to secure-test.streamline-esolutions.com).
Comment 11 Stef Walter 2012-08-08 10:26:10 UTC
Created attachment 220658 [details] [review]
gnutls: Try to find root certificates locally if not anchored

Now with a test.
Comment 12 Dan Winship 2012-08-10 20:15:30 UTC
Comment on attachment 220658 [details] [review]
gnutls: Try to find root certificates locally if not anchored

Makes sense to me

>+   * verify this chain as valid, since the issuer fierds and signatures should chain up
                                                       ^ typo
Comment 13 Stef Walter 2012-08-10 21:12:40 UTC
Attachment 220658 [details] pushed as acec8a8 - gnutls: Try to find root certificates locally if not anchored
Comment 14 Stef Walter 2012-08-10 21:14:15 UTC
(In reply to comment #12)
> >+   * verify this chain as valid, since the issuer fierds and signatures should chain up
>                                                        ^ typo

Was tired and missed this :S  Worth another commit?
Comment 15 Dan Winship 2012-08-10 21:20:43 UTC
(In reply to comment #14)
> >                                                        ^ typo
> 
> Was tired and missed this :S  Worth another commit?

yes. otherwise it will annoy me later :)
Comment 16 Stef Walter 2012-08-11 04:19:33 UTC
Created attachment 220917 [details] [review]
tests: Fix typo
Comment 17 Stef Walter 2012-08-11 04:21:23 UTC
Comment on attachment 220917 [details] [review]
tests: Fix typo

Attachment 220917 [details] pushed as cfa28b3 - tests: Fix typo