From 33b02802cde52194c760a93b46b5b5d9c301470f Mon Sep 17 00:00:00 2001 From: Martin Nilsson <nilsson@opera.com> Date: Sat, 26 Apr 2014 21:46:15 +0200 Subject: [PATCH] Move the certificate extension parsing into the TBSCertificate object. Not really a great API, but we need to start somewhere. --- lib/modules/Standards.pmod/X509.pmod | 174 ++++++++++++++++++++------- 1 file changed, 129 insertions(+), 45 deletions(-) diff --git a/lib/modules/Standards.pmod/X509.pmod b/lib/modules/Standards.pmod/X509.pmod index a6e2150209..75b4700ea3 100644 --- a/lib/modules/Standards.pmod/X509.pmod +++ b/lib/modules/Standards.pmod/X509.pmod @@ -796,6 +796,15 @@ class TBSCertificate a[i][0]->type_name == "SEQUENCE") { raw_extensions = a[i][0]; i++; + +#define EXT(X) if(!parse_##X(internal_extensions[ \ + .PKCS.Identifiers.ce_ids.##X])) { \ + werror("TBSCertificate: Failed to parse extension %O.\n", #X); } + EXT(basicConstraints); + EXT(authorityKeyIdentifier); + EXT(subjectKeyIdentifier); + EXT(keyUsage); +#undef EXT } } internal_der = asn1->get_der(); @@ -804,6 +813,102 @@ class TBSCertificate /* Too many fields */ return 0; } + + // + // --- Extension code + // + + //! Set if the certificate contains a valid basicConstraints + //! extension. RFC3280 4.2.1.10. + int(0..1) ext_basicConstraints; + + //! If set, the certificate may be used as a CA certificate, i.e. + //! sign other certificates. + int(0..1) ext_basicConstraints_cA; + + //! The maximum number of intermediate certificates that may follow + //! this certificate in a certificate chain. @exp{-1@} in case no + //! limit is imposed. + int ext_basicConstraints_pathLenConstraint = -1; + + protected int(0..1) parse_basicConstraints(Object o) + { + // FIXME: This extension must be critical if certificate contains + // public keys use usage is to validate signatures on + // certificates. + + if( !o || o->type_name!="SEQUENCE" ) + return 0; + Sequence s = [object(Sequence)]o; + if( sizeof(s)<1 || sizeof(s)>2 || s[0]->type_name!="BOOLEAN" ) + return 0; + if( sizeof(s)==2 ) + { + if( s[1]->type_name!="INTEGER" || s[0]->value==0 || s[1]->value<0 ) + return 0; + ext_basicConstraints_pathLenConstraint = s[1]->value; + // FIXME: pathLenConstraint is not permitted if keyCertSign + // isn't set in key usage. + } + ext_basicConstraints = 1; + ext_basicConstraints_cA = s[0]->value; + return 1; + } + + //! Set if the certificate contains a valid authorityKeyIdentifier + //! extension. RFC3280 4.2.1.1. + int(0..1) ext_authorityKeyIdentifier; + + protected int(0..1) parse_authorityKeyIdentifier(Object o) + { + if( !o ) return 1; + if( o->type_name!="SEQUENCE" ) + return 0; + + // FIXME: Actually parse this. + ext_authorityKeyIdentifier = 1; + return 1; + } + + //! Set to the value of the SubjectKeyIdentifier if the certificate + //! contains the subjectKeyIdentifier extension. RFC3280 4.2.1.2. + string ext_subjectKeyIdentifier; + + protected int(0..1) parse_subjectKeyIdentifier(Object o) + { + if( !o ) return 1; + if( o->type_name!="OCTET STRING" ) + return 0; + ext_subjectKeyIdentifier = o->value; + return 1; + } + + //! Set to the value of the KeyUsage if the certificate + //! contains the keyUsage extension. RFC3280 4.2.1.3. + int ext_keyUsage; + + protected int(0..1) parse_keyUsage(Object o) + { + if( !o ) return 1; + if( o->type_name!="BIT STRING" ) + return 0; +#if 0 + int bits, pos; + foreach(o->value;; int char) + for(int i; i<8; i++) + { + int bit = !!(char & 0x80); + bits |= (bit << pos); + pos++; + char <<= 1; + } +#endif + int bits = o->value[0]; + ext_keyUsage = bits; + return 1; + } + + } //! Creates the ASN.1 TBSCertificate sequence (see RFC2459 section @@ -1083,58 +1188,46 @@ TBSCertificate verify_ca_certificate(string|TBSCertificate tbs) multiset crit = tbs->critical + (<>); int self_signed = (tbs->issuer->get_der() == tbs->subject->get_der()); - Object lookup(Identifier id) - { - crit[id] = 0; - return tbs->extensions[id]; - }; - - // FIXME: Move extension parsing into tbs. - // id-ce-basicConstraints is required for certificates with public - // key used to validate certificate signatures. RFC 3280, 4.2.1.10. - Object c = lookup(.PKCS.Identifiers.ce_ids.basicConstraints); - if( !c || c->type_name!="SEQUENCE" || sizeof(c)<1 || sizeof(c)>2 || - c[0]->type_name!="BOOLEAN" || - !c[0]->value ) + // key used to validate certificate signatures. + crit[.PKCS.Identifiers.ce_ids.basicConstraints]=0; + if( tbs->ext_basicConstraints ) { - DBG("verify ca: Bad or missing id-ce-basicConstraints.\n"); - return 0; + if( !tbs->ext_basicConstraints_cA ) + { + DBG("vertify ca: id-ce-basicContraints-cA is false.\n"); + return 0; + } } - Sequence s = [object(Sequence)]c; - if( sizeof(s)==2 && s[1]->type_name!="INTEGER" ) + else { - DBG("verify ca: id-ce-basicConstraints has incorrect pathLenConstraint.\n"); + DBG("verify ca: Bad or missing id-ce-basicConstraints.\n"); return 0; } // id-ce-authorityKeyIdentifier is required by RFC 5759, unless self // signed. Defined in RFC 3280 4.2.1.1, but there only as // recommended. - if( !lookup(.PKCS.Identifiers.ce_ids.authorityKeyIdentifier) && !self_signed ) + crit[.PKCS.Identifiers.ce_ids.authorityKeyIdentifier]=0; + if( !tbs->ext_authorityKeyIdentifier && !self_signed ) { DBG("verify ca: Missing id-ce-authorityKeyIdentifier.\n"); return 0; } - // id-ce-keyUsage is required. RFC 3280 4.2.1.3 - c = lookup(.PKCS.Identifiers.ce_ids.keyUsage); - if( !c || c->type_name!="BIT STRING" ) - { - DBG("verify ca: Missing id-ce-keyUsage.\n"); - return 0; - } - keyUsage usage = c->value[0]; // Arguably API violation. - if( !( usage & keyCertSign ) ) // RFC 5759 + // id-ce-keyUsage is required. + crit[.PKCS.Identifiers.ce_ids.keyUsage]=0; + if( !(tbs->ext_keyUsage & keyCertSign) ) { DBG("verify ca: id-ce-keyUsage doesn't allow keyCertSign.\n"); return 0; } // FIXME: RFC 5759 also requires CRLSign set. - if( usage & (~(keyCertSign | cRLSign | digitalSignature | nonRepudiation)&255) ) + if( tbs->ext_keyUsage & + (~(keyCertSign | cRLSign | digitalSignature | nonRepudiation)&255) ) { DBG("verify ca: illegal CA uses in id-ce-keyUsage.\n"); - return 0; + return 0; } // FIXME: In addition RFC 5759 requires policyMappings, @@ -1350,31 +1443,22 @@ mapping verify_certificate_chain(array(string) cert_chain, if(idx != len-1) // Not the leaf { - Object o = tbs->extensions[ Identifiers.ce_ids.basicConstraints ]; - // id-ce-basicConstraints is required for certificates with - // public key used to validate certificate signatures. RFC 3280, - // 4.2.1.10. - if( !o || o->type_name!="SEQUENCE" ) - ERROR(CERT_INVALID); - Sequence s = [object(Sequence)]o; - if( sizeof(o)<1 || sizeof(o)>2 || - s[0]->type_name!="BOOLEAN" ) + // public key used to validate certificate signatures. + + if( !tbs->ext_basicConstraints ) ERROR(CERT_INVALID); - if( !s[0]->value ) + if( !tbs->ext_basicConstraints_cA ) ERROR(CERT_UNAUTHORIZED_CA); - if( sizeof(s)==2 ) + if( tbs->ext_basicConstraints_pathLenConstraint!=-1 ) { - if( s[1]->type_name!="INTEGER" || s[1]->value<0 ) - ERROR(CERT_INVALID); - // pathLenConstraint is the maximum number of intermediate // certificates. len-1-idx is the number of following // certificates. Subtract one more to not count the leaf // certificate. - if( len-1-idx-1 > s[1]->value ) + if( len-1-idx-1 > tbs->ext_basicConstraints_pathLenConstraint ) { // The error was later in the chain though, so maybe a // different error should be sent. -- GitLab