outer AlgorithmIdentifer parameters are not verified against tbsCertificate
Description of problem:
I think GnuTLS might not be conforming with RFC5280 section 4.1.1.2.
This field MUST contain the same algorithm identifier as the signature field in the sequence tbsCertificate (Section 4.1.2.3).
GnuTLS does not consider the parameters of the signatureAlgorithm
to be part of the AlgorithmIdentifier
, and therefore the outer signatureAlgorithm
can be different from the tbsCertificate
signatureAlgorithm
. This behavior does not match the behaviour of OpenSSL and NSS who do consider the parameters part of the identifier.
I think that this isn't a security vulnerability on it's own (although, I am not a cryptographer), because most (do any?) algorithms don't specify any parameters. However, you can modify and add new objects to signed certificates and they will still verify.
That really feels like it might have significant consequences, even though I don't have the crypto skills to analyze it.
Version of gnutls used:
3.6.6
Distributor of gnutls (e.g., Ubuntu, Fedora, RHEL)
Built from source
How reproducible:
I modified this certificate to change the outer signatureAlgorithm
to have a 1 byte BIT STRING object (rather than the RFC-required NULL object).
I could make the object larger because the signature starts with an empty byte I can truncate (maybe there are certificates with more room).
Steps to Reproduce:
- Download the attached pem certificate.
- Observe that the file is different from the original.
- Notice that gnutls still verifies the certificate.
OpenSSL does not consider it valid.
Actual results:
$ certtool --verify-allow-broken --verify --infile AlgorithmIdentifer.parameters.pem
Loaded system trust (299 CAs available)
Subject: CN=RapidSSL CA,O=GeoTrust\, Inc.,C=US
Issuer: CN=GeoTrust Global CA,O=GeoTrust Inc.,C=US
Checked against: CN=GeoTrust Global CA,O=GeoTrust Inc.,C=US
Signature algorithm: RSA-SHA1
Output: Verified. The certificate is trusted.
Chain verification output: Verified. The certificate is trusted.
Expected results:
$ openssl verify AlgorithmIdentifer.parameters.pem
C = US, O = "GeoTrust, Inc.", CN = RapidSSL CA
error 7 at 0 depth lookup: certificate signature failure
error AlgorithmIdentifer.parameters.pem: verification failed
If you look at the diff between the two certificates, you can see the changes I made:
--- /dev/fd/63 2019-02-05 14:13:31.409400948 -0800
+++ /dev/fd/62 2019-02-05 14:13:31.409400948 -0800
@@ -1,4 +1,4 @@
- 0:d=0 hl=4 l= 981 cons: SEQUENCE
+ 0:d=0 hl=4 l= 982 cons: SEQUENCE
4:d=1 hl=4 l= 701 cons: SEQUENCE
8:d=2 hl=2 l= 3 cons: cont [ 0 ]
10:d=3 hl=2 l= 1 prim: INTEGER :02
@@ -62,7 +62,7 @@
655:d=4 hl=2 l= 52 cons: SEQUENCE
657:d=5 hl=2 l= 8 prim: OBJECT :Authority Information Access
667:d=5 hl=2 l= 40 prim: OCTET STRING [HEX DUMP]:3026302406082B060105050730018618687474703A2F2F6F6373702E67656F74727573742E636F6D
- 709:d=1 hl=2 l= 13 cons: SEQUENCE
+ 709:d=1 hl=2 l= 14 cons: SEQUENCE
711:d=2 hl=2 l= 9 prim: OBJECT :sha1WithRSAEncryption
- 722:d=2 hl=2 l= 0 prim: NULL
- 724:d=1 hl=4 l= 257 prim: BIT STRING
+ 722:d=2 hl=2 l= 1 prim: OCTET STRING :A
+ 725:d=1 hl=4 l= 257 prim: BIT STRING
Notice I just added an OCTET STRING where the parameters are supposed to be (in fact, the RFC says it SHALL be NULL, so this is non-conforming)