#!/usr/bin/env python # Copyright 2019 The Chromium Authors # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """This script is called without any arguments to re-generate all of the *.pem files in the script's directory. The https://github.com/google/der-ascii tools must be in the PATH. These tests assume that the verification time will be 2017-03-09 00:00:00 GMT and verified with a max CRL age of 7 days. """ import datetime import subprocess import os from OpenSSL import crypto import base64 HEADER = "Generated by %s. Do not edit." % os.path.split(__file__)[1] NEXT_SERIAL = 0 # 2017-01-01 00:00 GMT CERT_DATE = datetime.datetime(2017, 1, 1, 0, 0) # 2018-01-01 00:00 GMT CERT_EXPIRE = CERT_DATE + datetime.timedelta(days=365) def DictUnion(a, b): return dict(a.items() + b.items()) def Der2Ascii(txt): p = subprocess.Popen(['der2ascii'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout_data, stderr_data = p.communicate(txt) if p.returncode: raise RuntimeError('der2ascii returned %i: %s' % (p.returncode, stderr_data)) return stdout_data def Ascii2Der(txt): p = subprocess.Popen(['ascii2der'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout_data, stderr_data = p.communicate(txt) if p.returncode: raise RuntimeError('ascii2der returned %i: %s' % (p.returncode, stderr_data)) return stdout_data def Ascii2OpensslDer(txt): der = Ascii2Der(txt) return 'DER:' + ''.join(['%02X' % ord(b) for b in der]) def CreateCert(name, signer, pkey=None, crl_dp=None, key_usage=None, is_ca=True, version=2): global NEXT_SERIAL if pkey is None: pkey = crypto.PKey() pkey.generate_key(crypto.TYPE_RSA, 1024) cert = crypto.X509() cert.set_version(version) cert.get_subject().CN = name cert.set_pubkey(pkey) cert.set_serial_number(NEXT_SERIAL) NEXT_SERIAL += 1 cert.set_notBefore(CERT_DATE.strftime('%Y%m%d%H%M%SZ')) cert.set_notAfter(CERT_EXPIRE.strftime('%Y%m%d%H%M%SZ')) if version == 2: if crl_dp: cert.add_extensions( [crypto.X509Extension('crlDistributionPoints', False, crl_dp)]) if key_usage: cert.add_extensions( [crypto.X509Extension('keyUsage', False, key_usage)]) if is_ca is not None: cert.add_extensions( [crypto.X509Extension('basicConstraints', True, 'CA:%s' % ('TRUE' if is_ca else 'FALSE'))]) if signer: cert.set_issuer(signer['cert'].get_subject()) cert.sign(signer['pkey'], 'sha256') else: cert.set_issuer(cert.get_subject()) cert.sign(pkey, 'sha256') result = dict(cert=cert, pkey=pkey) if not signer: signer = result result['signer'] = signer return result ROOT_CA = CreateCert('Test CA', None) # Multiple versions of the intermediate. All use the same name and private key. CA = CreateCert('Test Intermediate CA', ROOT_CA, key_usage='critical, keyCertSign, cRLSign') CA_NO_KEYUSAGE = CreateCert('Test Intermediate CA', ROOT_CA, pkey=CA['pkey'], key_usage=None) CA_KEYUSAGE_NOCRLSIGN = CreateCert('Test Intermediate CA', ROOT_CA, pkey=CA['pkey'], key_usage='critical, keyCertSign') # A different CA with a different name and key. OTHER_CA = CreateCert('Test Other Intermediate CA', ROOT_CA) # The target cert, with a simple crlDistributionPoints pointing to an arbitrary # URL, other crlDistributionPoints fields not set. LEAF = CreateCert('Test Cert', CA, crl_dp='URI:http://example.com/foo.crl', is_ca=False) # The target cert, with no basicConstraints. LEAF_NO_BASIC_CONSTRAINTS = CreateCert('Test Cert', CA, crl_dp='URI:http://example.com/foo.crl', is_ca=None) # The target cert, no crlDistributionPoints. LEAF_NO_CRLDP = CreateCert('Test Cert', CA, is_ca=False) # V1 target cert LEAF_V1 = CreateCert('Test Cert', CA, version=0, is_ca=None) # The target cert, crlDistributionPoints with crlIssuer and # crlDistributionPoints set. LEAF_CRLDP_CRLISSUER = CreateCert('Test Cert', CA, is_ca=False, # It doesn't seem like you can set crlIssuers through the one-line openssl # interface, so just do it manually. crl_dp=Ascii2OpensslDer(''' SEQUENCE { SEQUENCE { [0] { [0] { [6 PRIMITIVE] { "http://example.com/foo.crl" } } } [2] { [4] { SEQUENCE { SET { SEQUENCE { # commonName OBJECT_IDENTIFIER { 2.5.4.3 } UTF8String { "Test CRL Issuer CA" } } } } } } } } ''')) # Self-issued intermediate with a new key signed by the |CA| key. CA_NEW_BY_OLD = CreateCert('Test Intermediate CA', CA, key_usage='critical, keyCertSign, cRLSign', crl_dp='URI:http://example.com/foo.crl') # Target cert signed by |CA_NEW_BY_OLD|'s key. LEAF_BY_NEW = CreateCert( 'Test Cert', CA_NEW_BY_OLD, crl_dp='URI:http://example.com/foo.crl') def SignAsciiCRL(tbs_inner_txt, signer=CA): tbs_txt = 'SEQUENCE {\n%s\n}' % tbs_inner_txt tbs_der = Ascii2Der(tbs_txt) signature = crypto.sign(signer['pkey'], tbs_der, 'sha256') crl_text = ''' SEQUENCE { %s SEQUENCE { # sha256WithRSAEncryption OBJECT_IDENTIFIER { 1.2.840.113549.1.1.11 } NULL {} } BIT_STRING { `00%s` } } ''' % (tbs_txt, signature.encode('hex')) CRL = Ascii2Der(crl_text) return CRL def MakePemBlock(der, name): text = Der2Ascii(der).rstrip('\n') b64 = base64.b64encode(der) wrapped = '\n'.join(b64[pos:pos + 64] for pos in xrange(0, len(b64), 64)) return '%s\n-----BEGIN %s-----\n%s\n-----END %s-----' % ( text, name, wrapped, name) def WriteStringToFile(data, path): with open(path, "w") as f: f.write(data) def Store(fname, description, leaf, ca, crl_der, ca2=None): ca_cert_der = crypto.dump_certificate(crypto.FILETYPE_ASN1, ca['cert']) cert_der = crypto.dump_certificate(crypto.FILETYPE_ASN1, leaf['cert']) out = '\n\n'.join([ HEADER, description, MakePemBlock(crl_der, 'CRL'), MakePemBlock(ca_cert_der, 'CA CERTIFICATE'), MakePemBlock(cert_der, 'CERTIFICATE')]) if ca2: ca_cert_2_der = crypto.dump_certificate(crypto.FILETYPE_ASN1, ca2['cert']) out += '\n\n' + MakePemBlock(ca_cert_2_der, 'CA CERTIFICATE 2') open('%s.pem' % fname, 'w').write(out) crl_strings = { 'sha256WithRSAEncryption': ''' SEQUENCE { OBJECT_IDENTIFIER { 1.2.840.113549.1.1.11 } NULL {} } ''', 'sha384WithRSAEncryption': ''' SEQUENCE { OBJECT_IDENTIFIER { 1.2.840.113549.1.1.12 } NULL {} } ''', 'CA_name': ''' SEQUENCE { SET { SEQUENCE { # commonName OBJECT_IDENTIFIER { 2.5.4.3 } UTF8String { "Test Intermediate CA" } } } } ''', 'thisUpdate': 'UTCTime { "170302001122Z" }', 'nextUpdate': 'UTCTime { "170602001122Z" }', 'thisUpdateGeneralized': 'GeneralizedTime { "20170302001122Z" }', 'nextUpdateGeneralized': 'GeneralizedTime { "20170602001122Z" }', 'thisUpdate_too_old': 'UTCTime { "170301001122Z" }', 'thisUpdate_in_future': 'UTCTime { "170310001122Z" }', 'nextUpdate_too_old': 'UTCTime { "170308001122Z" }', 'leaf_revoked': ''' SEQUENCE { SEQUENCE { INTEGER { %i } UTCTime { "170201001122Z" } # no crlEntryExtensions } SEQUENCE { INTEGER { %i } UTCTime { "170201001122Z" } # no crlEntryExtensions } SEQUENCE { INTEGER { %i } UTCTime { "170201001122Z" } # no crlEntryExtensions } } ''' % (LEAF['cert'].get_serial_number() + 100, LEAF['cert'].get_serial_number(), LEAF['cert'].get_serial_number() + 101), 'leaf_revoked_fake_extension': ''' SEQUENCE { SEQUENCE { INTEGER { %i } UTCTime { "170201001122Z" } # no crlEntryExtensions } SEQUENCE { INTEGER { %i } UTCTime { "170201001122Z" } SEQUENCE { SEQUENCE { OBJECT_IDENTIFIER { 1.2.3.4 } OCTET_STRING { `5678` } } } } SEQUENCE { INTEGER { %i } UTCTime { "170201001122Z" } # no crlEntryExtensions } } ''' % (LEAF['cert'].get_serial_number() + 100, LEAF['cert'].get_serial_number(), LEAF['cert'].get_serial_number() + 101), 'leaf_revoked_before_fake_critical_extension': ''' SEQUENCE { SEQUENCE { INTEGER { %i } UTCTime { "170201001122Z" } # leaf revocation entry has no crlEntryExtensions } SEQUENCE { INTEGER { %i } UTCTime { "170201001122Z" } # next revocation entry has a critical crlEntryExtension SEQUENCE { SEQUENCE { OBJECT_IDENTIFIER { 1.2.3.4 } BOOLEAN { `ff` } OCTET_STRING { `5678` } } } } } ''' % (LEAF['cert'].get_serial_number(), LEAF['cert'].get_serial_number() + 101), 'leaf_revoked_generalizedtime': ''' SEQUENCE { SEQUENCE { INTEGER { %i } GeneralizedTime { "20170201001122Z" } # no crlEntryExtensions } SEQUENCE { INTEGER { %i } GeneralizedTime { "20170201001122Z" } # no crlEntryExtensions } SEQUENCE { INTEGER { %i } GeneralizedTime { "20170201001122Z" } # no crlEntryExtensions } } ''' % (LEAF['cert'].get_serial_number() + 100, LEAF['cert'].get_serial_number(), LEAF['cert'].get_serial_number() + 101), 'fake_extension': ''' SEQUENCE { OBJECT_IDENTIFIER { 1.2.3.4 } OCTET_STRING { `5678` } } ''', 'fake_critical_extension': ''' SEQUENCE { OBJECT_IDENTIFIER { 1.2.3.4 } BOOLEAN { `ff` } OCTET_STRING { `5678` } } ''', # An issuingDistributionPoint with multiple fullName values, one of which # matches the URI in |LEAF|'s crlDistributionPoints extension. 'issuingDistributionPoint': ''' SEQUENCE { OBJECT_IDENTIFIER { 2.5.29.28 } BOOLEAN { `ff` } OCTET_STRING { SEQUENCE { [0] { [0] { [1 PRIMITIVE] { "foo@example.com" } [6 PRIMITIVE] { "http://zexample.com/foo.crl" } [6 PRIMITIVE] { "http://example.com/foo.crl" } [6 PRIMITIVE] { "http://aexample.com/foo.crl" } } } } } } ''', 'issuingDistributionPoint_wrong_uri': ''' SEQUENCE { OBJECT_IDENTIFIER { 2.5.29.28 } BOOLEAN { `ff` } OCTET_STRING { SEQUENCE { [0] { [0] { [6 PRIMITIVE] { "http://example.com/FOO.CRL" } } } } } } ''', 'issuingDistributionPoint_with_indirectCRL': ''' SEQUENCE { OBJECT_IDENTIFIER { 2.5.29.28 } BOOLEAN { `ff` } OCTET_STRING { SEQUENCE { [0] { [0] { [6 PRIMITIVE] { "http://example.com/foo.crl" } } } [4 PRIMITIVE] { `ff` } } } } ''', 'issuingDistributionPoint_with_onlyContainsUserCerts': ''' SEQUENCE { OBJECT_IDENTIFIER { 2.5.29.28 } BOOLEAN { `ff` } OCTET_STRING { SEQUENCE { [1 PRIMITIVE] { `ff` } } } } ''', 'issuingDistributionPoint_with_uri_and_onlyContainsUserCerts': ''' SEQUENCE { OBJECT_IDENTIFIER { 2.5.29.28 } BOOLEAN { `ff` } OCTET_STRING { SEQUENCE { [0] { [0] { [6 PRIMITIVE] { "http://example.com/foo.crl" } } } [1 PRIMITIVE] { `ff` } } } } ''', 'issuingDistributionPoint_with_uri_and_onlyContainsCACerts': ''' SEQUENCE { OBJECT_IDENTIFIER { 2.5.29.28 } BOOLEAN { `ff` } OCTET_STRING { SEQUENCE { [0] { [0] { [6 PRIMITIVE] { "http://example.com/foo.crl" } } } [2 PRIMITIVE] { `ff` } } } } ''', 'issuingDistributionPoint_with_onlyContainsCACerts': ''' SEQUENCE { OBJECT_IDENTIFIER { 2.5.29.28 } BOOLEAN { `ff` } OCTET_STRING { SEQUENCE { [2 PRIMITIVE] { `ff` } } } } ''', } Store( 'good', 'Leaf covered by CRLs and not revoked', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s # no revoked certs list # no crlExtensions ''' % crl_strings)) Store( 'good_issuer_name_normalization', 'Good, non-revoked, but issuer name in CRL requires case folding', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s SEQUENCE { SET { SEQUENCE { # commonName OBJECT_IDENTIFIER { 2.5.4.3 } # Name that requires case folding and type conversion. PrintableString { "tEST iNTERMEDIATE ca" } } } } %(thisUpdate)s %(nextUpdate)s # no revoked certs list # no crlExtensions ''' % crl_strings)) Store( 'good_issuer_no_keyusage', 'Leaf covered by CRLs and not revoked, issuer has no keyUsage extension', LEAF, CA_NO_KEYUSAGE, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s # no revoked certs list # no crlExtensions ''' % crl_strings, signer=CA_NO_KEYUSAGE)) Store( 'good_no_nextupdate', 'Leaf covered by CRLs and not revoked, optional nextUpdate field is absent', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s # no nextUpdate # no revoked certs list # no crlExtensions ''' % crl_strings)) Store( 'good_fake_extension', 'Leaf covered by CRLs and not revoked, CRL has an irrelevant non-critical ' 'extension', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s # no revoked certs list [0] { SEQUENCE { %(fake_extension)s } } ''' % crl_strings)) Store( 'good_fake_extension_no_nextupdate', 'Leaf covered by CRLs and not revoked, CRL has an irrelevant non-critical ' 'extension', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s # no nextUpdate # no revoked certs list [0] { SEQUENCE { %(fake_extension)s } } ''' % crl_strings)) Store( 'good_generalizedtime', 'Leaf covered by CRLs and not revoked, dates encoded as GeneralizedTime', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdateGeneralized)s %(nextUpdateGeneralized)s # no revoked certs list # no crlExtensions ''' % crl_strings)) Store( 'good_no_version', 'Leaf covered by CRLs and not revoked, CRL is V1', LEAF, CA, SignAsciiCRL(''' # no version %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s # no revoked certs list # no crlExtensions ''' % crl_strings)) Store( 'good_idp_contains_uri', 'Leaf covered by CRLs and not revoked, CRL has IDP with URI matching ' 'cert DP', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s # no revoked certs list [0] { SEQUENCE { %(issuingDistributionPoint)s } } ''' % crl_strings)) Store( 'good_idp_onlycontainsusercerts', 'Leaf covered by CRLs and not revoked, CRL has IDP with ' 'onlyContainsUserCerts', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s # no revoked certs list [0] { SEQUENCE { %(issuingDistributionPoint_with_onlyContainsUserCerts)s } } ''' % crl_strings)) Store( 'good_idp_onlycontainsusercerts_no_basic_constraints', 'Leaf covered by CRLs and not revoked, CRL has IDP with ' 'onlyContainsUserCerts, leaf has no basicConstraints', LEAF_NO_BASIC_CONSTRAINTS, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s # no revoked certs list [0] { SEQUENCE { %(issuingDistributionPoint_with_onlyContainsUserCerts)s } } ''' % crl_strings)) Store( 'good_idp_onlycontainscacerts', 'CA_NEW_BY_OLD covered by CRLs and not revoked, CRL has IDP with ' 'onlyContainsCaCerts', CA_NEW_BY_OLD, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s # no revoked certs list [0] { SEQUENCE { %(issuingDistributionPoint_with_onlyContainsCACerts)s } } ''' % crl_strings)) Store( 'good_idp_uri_and_onlycontainsusercerts', 'Leaf covered by CRLs and not revoked, CRL has IDP with URI and ' 'onlyContainsUserCerts', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s # no revoked certs list [0] { SEQUENCE { %(issuingDistributionPoint_with_uri_and_onlyContainsUserCerts)s } } ''' % crl_strings)) Store( 'good_idp_uri_and_onlycontainscacerts', 'CA_NEW_BY_OLD covered by CRLs and not revoked, CRL has IDP with URI and ' 'onlyContainsCACerts', CA_NEW_BY_OLD, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s # no revoked certs list [0] { SEQUENCE { %(issuingDistributionPoint_with_uri_and_onlyContainsCACerts)s } } ''' % crl_strings)) Store( 'good_no_crldp', 'Leaf covered by CRLs and not revoked and has no crlDistributionPoints.\n' 'This tests the case where CheckCRL is called with a synthesized ' 'distributionPoint.', LEAF_NO_CRLDP, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s # no revoked certs list # no crlExtensions ''' % crl_strings)) Store( 'good_key_rollover', "Leaf issued by CA's new key but CRL is signed by old key", LEAF_BY_NEW, CA_NEW_BY_OLD, ca2=CA, crl_der=SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s # no revoked certs list # no crlExtensions ''' % crl_strings)) Store( 'revoked', 'Leaf is revoked', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s %(leaf_revoked)s # no crlExtensions ''' % crl_strings)) Store( 'revoked_no_nextupdate', 'Leaf is revoked, optional nextUpdate field is absent', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s # no nextUpdate %(leaf_revoked)s # no crlExtensions ''' % crl_strings)) Store( 'revoked_fake_crlentryextension', 'Leaf is revoked, has non-critical crlEntryExtension', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s %(leaf_revoked_fake_extension)s # no crlExtensions ''' % crl_strings)) Store( 'revoked_generalized_revocationdate', 'Leaf is revoked, revocationDate is encoded as GeneralizedTime', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s %(leaf_revoked_generalizedtime)s # no crlExtensions ''' % crl_strings)) Store( 'revoked_key_rollover', "Leaf issued by CA's new key but CRL is signed by old key", LEAF_BY_NEW, CA_NEW_BY_OLD, ca2=CA, crl_der=SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s SEQUENCE { SEQUENCE { INTEGER { %(LEAF_SERIAL)i } UTCTime { "170201001122Z" } # no crlEntryExtensions } } # no crlExtensions ''' % DictUnion(crl_strings, {'LEAF_SERIAL':LEAF_BY_NEW['cert'].get_serial_number()}))) Store( 'bad_crldp_has_crlissuer', 'Leaf covered by CRLs and not revoked, leaf has crlDistributionPoints ' 'with a crlIssuer', LEAF_CRLDP_CRLISSUER, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s # no revoked certs list # no crlExtensions ''' % crl_strings)) Store( 'bad_fake_critical_extension', 'Leaf covered by CRLs and not revoked, but CRL has an unhandled critical ' 'extension', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s # no nextUpdate # no revoked certs list [0] { SEQUENCE { %(fake_critical_extension)s } } ''' % crl_strings)) Store( 'bad_fake_critical_crlentryextension', 'Leaf is revoked, but a later entry has a critical crlEntryExtension', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s %(leaf_revoked_before_fake_critical_extension)s # no crlExtensions ''' % crl_strings)) Store( 'bad_signature', 'No revoked certs, but CRL signed by a different key', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s # no revoked certs list # no crlExtensions ''' % crl_strings, signer=OTHER_CA)) Store( 'bad_thisupdate_in_future', 'Leaf covered by CRLs and not revoked, but thisUpdate is in the future', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate_in_future)s %(nextUpdate)s # no revoked certs list # no crlExtensions ''' % crl_strings)) Store( 'bad_thisupdate_too_old', 'Leaf covered by CRLs and not revoked, but thisUpdate time is more than ' '7 days before verification time', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate_too_old)s %(nextUpdate)s # no revoked certs list # no crlExtensions ''' % crl_strings)) Store( 'bad_nextupdate_too_old', 'Leaf covered by CRLs and not revoked, but nextUpdate time is before ' 'verification time', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate_too_old)s # no revoked certs list # no crlExtensions ''' % crl_strings)) Store( 'bad_wrong_issuer', 'issuer name in CRL is different', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s SEQUENCE { SET { SEQUENCE { # commonName OBJECT_IDENTIFIER { 2.5.4.3 } PrintableString { "Test Unrelated CA" } } } } %(thisUpdate)s %(nextUpdate)s # no revoked certs list # no crlExtensions ''' % crl_strings)) Store( 'bad_key_rollover_signature', "Leaf issued by CA's new key which is signed by old key, but CRL isn't " "signed by either", LEAF_BY_NEW, CA_NEW_BY_OLD, ca2=CA, crl_der=SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s # no revoked certs list # no crlExtensions ''' % crl_strings, signer=OTHER_CA)) Store( 'bad_idp_contains_wrong_uri', 'Leaf not covered by CRL (IDP with different URI)', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s # no revoked certs list [0] { SEQUENCE { %(issuingDistributionPoint_wrong_uri)s } } ''' % crl_strings)) Store( 'bad_idp_indirectcrl', 'CRL IDP name matches, but has indirectCRL flag set', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s # no revoked certs list [0] { SEQUENCE { %(issuingDistributionPoint_with_indirectCRL)s } } ''' % crl_strings)) Store( 'bad_idp_onlycontainscacerts', 'Leaf not covered by CRLs because IDP has onlyContainsCACerts', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s # no revoked certs list [0] { SEQUENCE { %(issuingDistributionPoint_with_onlyContainsCACerts)s } } ''' % crl_strings)) Store( 'bad_idp_onlycontainscacerts_no_basic_constraints', 'Leaf not covered by CRLs because IDP has onlyContainsCACerts, ' 'leaf has no basicConstraints', LEAF_NO_BASIC_CONSTRAINTS, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s # no revoked certs list [0] { SEQUENCE { %(issuingDistributionPoint_with_onlyContainsCACerts)s } } ''' % crl_strings)) Store( 'bad_idp_onlycontainsusercerts', 'CA_NEW_BY_OLD not covered by CRLs because IDP has ' 'onlyContainsUserCerts', CA_NEW_BY_OLD, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s # no revoked certs list [0] { SEQUENCE { %(issuingDistributionPoint_with_onlyContainsUserCerts)s } } ''' % crl_strings)) Store( 'bad_idp_uri_and_onlycontainsusercerts', 'CA_NEW_BY_OLD not covered by CRLs because IDP has ' 'onlyContainsUserCerts (and URI, but the URI matches)', CA_NEW_BY_OLD, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s # no revoked certs list [0] { SEQUENCE { %(issuingDistributionPoint_with_uri_and_onlyContainsUserCerts)s } } ''' % crl_strings)) Store( 'bad_idp_uri_and_onlycontainscacerts', 'Leaf not covered by CRLs because IDP has ' 'onlyContainsCACerts (and URI, but the URI matches)', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s # no revoked certs list [0] { SEQUENCE { %(issuingDistributionPoint_with_uri_and_onlyContainsCACerts)s } } ''' % crl_strings)) Store( 'invalid_mismatched_signature_algorithm', 'Leaf covered by CRLs and not revoked, but signatureAlgorithm in ' 'CertificateList does not match the one in TBSCertList.', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha384WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s # no revoked certs list # no crlExtensions ''' % crl_strings)) Store( 'invalid_revoked_empty_sequence', 'revokedCertificates is an empty sequence (should be omitted)', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s SEQUENCE { # no revoked certs. revokedCertificates should be omitted in this case. } # no crlExtensions ''' % crl_strings)) Store( 'invalid_v1_with_extension', 'CRL is V1 and has crlExtensions', LEAF, CA, SignAsciiCRL(''' # no version %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s # no nextUpdate # no revoked certs list [0] { SEQUENCE { %(fake_extension)s } } ''' % crl_strings)) Store( 'invalid_v1_with_crlentryextension', 'Leaf is revoked, has non-critical crlEntryExtension, but CRL is V1', LEAF, CA, SignAsciiCRL(''' # no version %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s %(leaf_revoked_fake_extension)s # no crlExtensions ''' % crl_strings)) Store( 'invalid_v1_explicit', 'CRL has explicit V1 version', LEAF, CA, SignAsciiCRL(''' INTEGER { 0 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s # no revoked certs list # no crlExtensions ''' % crl_strings)) Store( 'invalid_v3', 'CRL has invalid V3 version', LEAF, CA, SignAsciiCRL(''' INTEGER { 2 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s # no revoked certs list # no crlExtensions ''' % crl_strings)) Store( 'invalid_issuer_keyusage_no_crlsign', 'Leaf covered by CRLs and not revoked, issuer has keyUsage extension ' 'without the cRLSign bit set', LEAF, CA_KEYUSAGE_NOCRLSIGN, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s # no revoked certs list # no crlExtensions ''' % crl_strings, signer=CA_KEYUSAGE_NOCRLSIGN)) Store( 'invalid_key_rollover_issuer_keyusage_no_crlsign', "Leaf issued by CA's new key but CRL is signed by old key, and the old " "key cert has keyUsage extension without the cRLSign bit set", LEAF_BY_NEW, CA_NEW_BY_OLD, ca2=CA_KEYUSAGE_NOCRLSIGN, crl_der=SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s # no revoked certs list # no crlExtensions ''' % crl_strings, signer=CA_KEYUSAGE_NOCRLSIGN)) Store( 'invalid_garbage_version', 'CRL version is garbage', LEAF, CA, SignAsciiCRL(''' OCTET_STRING { `01` } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s # no revoked certs list # no crlExtensions ''' % crl_strings)) Store( 'invalid_garbage_tbs_signature_algorithm', 'CRL tbs signature algorithm is garbage', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } INTEGER { 1 } %(CA_name)s %(thisUpdate)s %(nextUpdate)s # no revoked certs list # no crlExtensions ''' % crl_strings)) Store( 'invalid_garbage_issuer_name', 'CRL issuer is garbage', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s INTEGER { 1 } %(thisUpdate)s # no revoked certs list # no crlExtensions ''' % crl_strings)) Store( 'invalid_garbage_thisupdate', 'CRL thisUpdate is garbage', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s INTEGER { 1 } %(thisUpdate)s # no revoked certs list # no crlExtensions ''' % crl_strings)) Store( 'invalid_garbage_after_thisupdate', 'CRL garbage after thisupdate', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s # garbage: INTEGER { 1 } ''' % crl_strings)) Store( 'invalid_garbage_after_nextupdate', 'CRL garbage after nextUpdate', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s # garbage: INTEGER { 1 } ''' % crl_strings)) Store( 'invalid_garbage_after_revokedcerts', 'CRL garbage after revokedCertificates', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s # no nextUpdate %(leaf_revoked)s # no crlExtensions # garbage: nextUpdate doesn't go here: %(nextUpdate)s ''' % crl_strings)) Store( 'invalid_garbage_after_extensions', 'CRL garbage after extensions', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s # no revoked certs list [0] { SEQUENCE { %(fake_extension)s } } # Garbage: revoked certs sequence doesn't go here: %(leaf_revoked)s ''' % crl_strings)) Store( 'invalid_garbage_tbscertlist', 'CRL garbage tbsCertList', LEAF, CA, Ascii2Der(''' SEQUENCE { OCTET_STRING { `5678` } SEQUENCE { # sha256WithRSAEncryption OBJECT_IDENTIFIER { 1.2.840.113549.1.1.11 } NULL {} } # Actual signatureValue doesn't matter, shouldn't get to verifying signature. BIT_STRING { `001a` } } ''')) Store( 'invalid_garbage_signaturealgorithm', 'CRL garbage signatureAlgorithm', LEAF, CA, Ascii2Der(''' SEQUENCE { SEQUENCE { INTEGER { 1 } # tbsCertList contents doesn't matter, parsing shouldn't get this far. } OCTET_STRING { `5678` } # Actual signatureValue doesn't matter, shouldn't get to verifying signature. BIT_STRING { `001a` } } ''')) Store( 'invalid_garbage_signaturevalue', 'CRL garbage signatureValue', LEAF, CA, Ascii2Der(''' SEQUENCE { SEQUENCE { INTEGER { 1 } # tbsCertList contents doesn't matter, parsing shouldn't get this far. } SEQUENCE { # sha256WithRSAEncryption OBJECT_IDENTIFIER { 1.2.840.113549.1.1.11 } NULL {} } # Actual signatureValue contents don't matter, should be BIT_STRING rather # than OCTET_STRING. OCTET_STRING { `001a` } } ''')) Store( 'invalid_garbage_after_signaturevalue', 'CRL garbage after signatureValue', LEAF, CA, Ascii2Der(''' SEQUENCE { SEQUENCE { INTEGER { 1 } # tbsCertList contents doesn't matter, parsing shouldn't get this far. } SEQUENCE { # sha256WithRSAEncryption OBJECT_IDENTIFIER { 1.2.840.113549.1.1.11 } NULL {} } # Actual signatureValue doesn't matter, shouldn't get to verifying signature. BIT_STRING { `001a` } SEQUENCE {} } ''')) Store( 'invalid_garbage_revoked_serial_number', 'Leaf is revoked but a following crlentry is garbage', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s SEQUENCE { SEQUENCE { INTEGER { %(LEAF_SERIAL)i } UTCTime { "170201001122Z" } # no crlEntryExtensions } SEQUENCE { OCTET_STRING { `7F`} UTCTime { "170201001122Z" } # no crlEntryExtensions } } # no crlExtensions ''' % (DictUnion(crl_strings, {'LEAF_SERIAL':LEAF['cert'].get_serial_number()})))) Store( 'invalid_garbage_revocationdate', 'Leaf is revoked but a following crlentry is garbage', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s SEQUENCE { SEQUENCE { INTEGER { %(LEAF_SERIAL)i } UTCTime { "170201001122Z" } # no crlEntryExtensions } SEQUENCE { INTEGER { 100001 } OCTET_STRING { "170201001122Z" } # no crlEntryExtensions } } # no crlExtensions ''' % (DictUnion(crl_strings, {'LEAF_SERIAL':LEAF['cert'].get_serial_number()})))) Store( 'invalid_garbage_after_revocationdate', 'Leaf is revoked but a following crlentry is garbage', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s SEQUENCE { SEQUENCE { INTEGER { %(LEAF_SERIAL)i } UTCTime { "170201001122Z" } # no crlEntryExtensions } SEQUENCE { INTEGER { 100001 } UTCTime { "170201001122Z" } INTEGER { 01 } } } # no crlExtensions ''' % (DictUnion(crl_strings, {'LEAF_SERIAL':LEAF['cert'].get_serial_number()})))) Store( 'invalid_garbage_after_crlentryextensions', 'Leaf is revoked but a following crlentry is garbage', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s SEQUENCE { SEQUENCE { INTEGER { %(LEAF_SERIAL)i } UTCTime { "170201001122Z" } # no crlEntryExtensions } SEQUENCE { INTEGER { 100001 } UTCTime { "170201001122Z" } SEQUENCE { SEQUENCE { OBJECT_IDENTIFIER { 1.2.3.4 } OCTET_STRING { `5678` } } } INTEGER { 01 } } } # no crlExtensions ''' % (DictUnion(crl_strings, {'LEAF_SERIAL':LEAF['cert'].get_serial_number()})))) Store( 'invalid_garbage_crlentry', 'Leaf is revoked but a following crlentry is garbage', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s SEQUENCE { SEQUENCE { INTEGER { %(LEAF_SERIAL)i } UTCTime { "170201001122Z" } # no crlEntryExtensions } INTEGER { 01 } } # no crlExtensions ''' % (DictUnion(crl_strings, {'LEAF_SERIAL':LEAF['cert'].get_serial_number()})))) Store( 'invalid_idp_dpname_choice_extra_data', 'IssuingDistributionPoint extension distributionPoint is invalid', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s # no revoked certs list [0] { SEQUENCE { SEQUENCE { OBJECT_IDENTIFIER { 2.5.29.28 } BOOLEAN { `ff` } OCTET_STRING { SEQUENCE { [0] { [0] { [6 PRIMITIVE] { "http://example.com/foo.crl" } } [1] { SET { SEQUENCE { # countryName OBJECT_IDENTIFIER { 2.5.4.6 } PrintableString { "US" } } } } } } } } } } ''' % crl_strings)) Store( 'invalid_idp_empty_sequence', 'IssuingDistributionPoint extension is invalid', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s # no revoked certs list [0] { SEQUENCE { SEQUENCE { OBJECT_IDENTIFIER { 2.5.29.28 } BOOLEAN { `ff` } OCTET_STRING { SEQUENCE { } } } } } ''' % crl_strings)) Store( 'invalid_idp_onlycontains_user_and_ca_certs', 'IssuingDistributionPoint extension is invalid, cannot specify more than ' 'one of onlyContainsUserCerts and onlyContainsCACerts', LEAF, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s # no revoked certs list [0] { SEQUENCE { SEQUENCE { OBJECT_IDENTIFIER { 2.5.29.28 } BOOLEAN { `ff` } OCTET_STRING { SEQUENCE { [1 PRIMITIVE] { `ff` } [2 PRIMITIVE] { `ff` } } } } } } ''' % crl_strings)) Store( 'invalid_idp_onlycontainsusercerts_v1_leaf', 'v1 leaf is covered by CRL with onlyContainsUserCerts, which is invalid', LEAF_V1, CA, SignAsciiCRL(''' INTEGER { 1 } %(sha256WithRSAEncryption)s %(CA_name)s %(thisUpdate)s %(nextUpdate)s # no revoked certs list [0] { SEQUENCE { %(issuingDistributionPoint_with_onlyContainsUserCerts)s } } ''' % crl_strings))