diff options
author | Alex Gaynor <alex.gaynor@gmail.com> | 2015-05-18 18:26:08 -0400 |
---|---|---|
committer | Alex Gaynor <alex.gaynor@gmail.com> | 2015-05-18 18:26:08 -0400 |
commit | af89bb64b59f8352c6f9f2d48fbd6f98e7f18213 (patch) | |
tree | 13a7cdbfad66503fd891b10b4eecf0d64ae4df0e | |
parent | 63d95d0973970c01dbfa8432055bc7e13acc1049 (diff) | |
parent | f85201830f737f2591622624a03df52bcb1c0f7e (diff) | |
download | cryptography-af89bb64b59f8352c6f9f2d48fbd6f98e7f18213.tar.gz cryptography-af89bb64b59f8352c6f9f2d48fbd6f98e7f18213.tar.bz2 cryptography-af89bb64b59f8352c6f9f2d48fbd6f98e7f18213.zip |
Merge branch 'master' into macstadium-travis
-rwxr-xr-x | .travis/install.sh | 2 | ||||
-rw-r--r-- | AUTHORS.rst | 1 | ||||
-rw-r--r-- | docs/development/test-vectors.rst | 13 | ||||
-rw-r--r-- | docs/x509.rst | 23 | ||||
-rw-r--r-- | src/cryptography/hazmat/backends/openssl/x509.py | 636 | ||||
-rw-r--r-- | src/cryptography/x509.py | 42 | ||||
-rw-r--r-- | tests/test_x509.py | 58 | ||||
-rw-r--r-- | tests/test_x509_ext.py | 33 | ||||
-rw-r--r-- | vectors/cryptography_vectors/x509/requests/basic_constraints.pem | 64 | ||||
-rw-r--r-- | vectors/cryptography_vectors/x509/requests/two_basic_constraints.pem | 66 | ||||
-rw-r--r-- | vectors/cryptography_vectors/x509/requests/unsupported_extension.pem | 64 | ||||
-rw-r--r-- | vectors/cryptography_vectors/x509/requests/unsupported_extension_critical.pem | 64 |
12 files changed, 765 insertions, 301 deletions
diff --git a/.travis/install.sh b/.travis/install.sh index f5873288..1baae5ba 100755 --- a/.travis/install.sh +++ b/.travis/install.sh @@ -4,7 +4,7 @@ set -e set -x if [[ "$(uname -s)" == 'Darwin' ]]; then - brew update + brew update || brew update if [[ "${OPENSSL}" != "0.9.8" ]]; then brew upgrade openssl diff --git a/AUTHORS.rst b/AUTHORS.rst index 6e92a84f..430e30ea 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -22,3 +22,4 @@ PGP key fingerprints are enclosed in parentheses. * Gregory Haynes <greg@greghaynes.net> (6FB6 44BF 9FD0 EBA2 1CE9 471F B08F 42F9 0DC6 599F) * Chelsea Winfree <chelsea.winfree@gmail.com> * Steven Buss <steven.buss@gmail.com> (1FB9 2EC1 CF93 DFD6 B47F F583 B1A5 6C22 290D A4C3) +* Andre Caron <andre.l.caron@gmail.com> diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst index 6f61a7ee..4c0063b5 100644 --- a/docs/development/test-vectors.rst +++ b/docs/development/test-vectors.rst @@ -217,6 +217,19 @@ Custom X.509 Request Vectors * ``san_rsa_sha1.pem`` and ``san_rsa_sha1.der`` - Contain a certificate request using RSA and SHA1 with a subject alternative name extension generated using OpenSSL. +* ``two_basic_constraints.pem`` - A certificate signing request + for a RSA 2048 bit key containing two basic constraints extensions. +* ``unsupported_extension.pem`` - A certificate signing request + for an RSA 2048 bit key containing containing an unsupported + extension type. The OID was encoded as "1.2.3.4" with an + ``extnValue`` of "value". +* ``unsupported_extension_critical.pem`` - A certificate signing + request for an RSA 2048 bit key containing containing an unsupported + extension type marked critical. The OID was encoded as "1.2.3.4" + with an ``extnValue`` of "value". +* ``basic_constraints.pem`` - A certificate signing request for a RSA + 2048 bit key containing a basic constraints extension marked as + critical. Hashes ~~~~~~ diff --git a/docs/x509.rst b/docs/x509.rst index ff43be01..3f1af86c 100644 --- a/docs/x509.rst +++ b/docs/x509.rst @@ -509,8 +509,9 @@ General Name Classes .. attribute:: value - :type: :class:`~ipaddress.IPv4Address` or - :class:`~ipaddress.IPv6Address`. + :type: :class:`~ipaddress.IPv4Address`, + :class:`~ipaddress.IPv6Address`, :class:`~ipaddress.IPv4Network`, + or :class:`~ipaddress.IPv6Network`. .. class:: RegisteredID @@ -698,6 +699,19 @@ X.509 Extensions purposes indicated in the key usage extension. The object is iterable to obtain the list of :ref:`extended key usage OIDs <eku_oids>`. +.. class:: OCSPNoCheck + + .. versionadded:: 0.10 + + This presence of this extension indicates that an OCSP client can trust a + responder for the lifetime of the responder's certificate. CAs issuing + such a certificate should realize that a compromise of the responder's key + is as serious as the compromise of a CA key used to sign CRLs, at least for + the validity period of this certificate. CA's may choose to issue this type + of certificate with a very short lifetime and renew it frequently. This + extension is only relevant when the certificate is an authorized OCSP + responder. + .. class:: AuthorityKeyIdentifier .. versionadded:: 0.9 @@ -1234,6 +1248,11 @@ Extension OIDs Corresponds to the dotted string ``"1.3.6.1.5.5.7.1.1"``. The identifier for the :class:`AuthorityInformationAccess` extension type. +.. data:: OID_OCSP_NO_CHECK + + Corresponds to the dotted string ``"1.3.6.1.5.5.7.48.1.5"``. The identifier + for the :class:`OCSPNoCheck` extension type. + Exceptions ~~~~~~~~~~ diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index 07e54baa..6db6fc9c 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -56,7 +56,7 @@ def _asn1_string_to_utf8(backend, asn1_string): return backend._ffi.buffer(buf[0], res)[:].decode('utf8') -def _build_x509_name_entry(backend, x509_name_entry): +def _decode_x509_name_entry(backend, x509_name_entry): obj = backend._lib.X509_NAME_ENTRY_get_object(x509_name_entry) assert obj != backend._ffi.NULL data = backend._lib.X509_NAME_ENTRY_get_data(x509_name_entry) @@ -67,28 +67,28 @@ def _build_x509_name_entry(backend, x509_name_entry): return x509.NameAttribute(x509.ObjectIdentifier(oid), value) -def _build_x509_name(backend, x509_name): +def _decode_x509_name(backend, x509_name): count = backend._lib.X509_NAME_entry_count(x509_name) attributes = [] for x in range(count): entry = backend._lib.X509_NAME_get_entry(x509_name, x) - attributes.append(_build_x509_name_entry(backend, entry)) + attributes.append(_decode_x509_name_entry(backend, entry)) return x509.Name(attributes) -def _build_general_names(backend, gns): +def _decode_general_names(backend, gns): num = backend._lib.sk_GENERAL_NAME_num(gns) names = [] for i in range(num): gn = backend._lib.sk_GENERAL_NAME_value(gns, i) assert gn != backend._ffi.NULL - names.append(_build_general_name(backend, gn)) + names.append(_decode_general_name(backend, gn)) return names -def _build_general_name(backend, gn): +def _decode_general_name(backend, gn): if gn.type == backend._lib.GEN_DNS: data = backend._ffi.buffer(gn.d.dNSName.data, gn.d.dNSName.length)[:] return x509.DNSName(idna.decode(data)) @@ -129,7 +129,7 @@ def _build_general_name(backend, gn): ) elif gn.type == backend._lib.GEN_DIRNAME: return x509.DirectoryName( - _build_x509_name(backend, gn.d.directoryName) + _decode_x509_name(backend, gn.d.directoryName) ) elif gn.type == backend._lib.GEN_EMAIL: data = backend._ffi.buffer( @@ -244,13 +244,13 @@ class _Certificate(object): def issuer(self): issuer = self._backend._lib.X509_get_issuer_name(self._x509) assert issuer != self._backend._ffi.NULL - return _build_x509_name(self._backend, issuer) + return _decode_x509_name(self._backend, issuer) @property def subject(self): subject = self._backend._lib.X509_get_subject_name(self._x509) assert subject != self._backend._ffi.NULL - return _build_x509_name(self._backend, subject) + return _decode_x509_name(self._backend, subject) @property def signature_hash_algorithm(self): @@ -278,23 +278,25 @@ class _Certificate(object): "Duplicate {0} extension found".format(oid), oid ) elif oid == x509.OID_BASIC_CONSTRAINTS: - value = self._build_basic_constraints(ext) + value = _decode_basic_constraints(self._backend, ext) elif oid == x509.OID_SUBJECT_KEY_IDENTIFIER: - value = self._build_subject_key_identifier(ext) + value = _decode_subject_key_identifier(self._backend, ext) elif oid == x509.OID_KEY_USAGE: - value = self._build_key_usage(ext) + value = _decode_key_usage(self._backend, ext) elif oid == x509.OID_SUBJECT_ALTERNATIVE_NAME: - value = self._build_subject_alt_name(ext) + value = _decode_subject_alt_name(self._backend, ext) elif oid == x509.OID_EXTENDED_KEY_USAGE: - value = self._build_extended_key_usage(ext) + value = _decode_extended_key_usage(self._backend, ext) elif oid == x509.OID_AUTHORITY_KEY_IDENTIFIER: - value = self._build_authority_key_identifier(ext) + value = _decode_authority_key_identifier(self._backend, ext) elif oid == x509.OID_AUTHORITY_INFORMATION_ACCESS: - value = self._build_authority_information_access(ext) + value = _decode_authority_information_access( + self._backend, ext + ) elif oid == x509.OID_CERTIFICATE_POLICIES: - value = self._build_certificate_policies(ext) + value = _decode_certificate_policies(self._backend, ext) elif oid == x509.OID_CRL_DISTRIBUTION_POINTS: - value = self._build_crl_distribution_points(ext) + value = _decode_crl_distribution_points(self._backend, ext) elif critical: raise x509.UnsupportedExtension( "{0} is not currently supported".format(oid), oid @@ -309,311 +311,323 @@ class _Certificate(object): return x509.Extensions(extensions) - def _build_certificate_policies(self, ext): - cp = self._backend._ffi.cast( - "Cryptography_STACK_OF_POLICYINFO *", - self._backend._lib.X509V3_EXT_d2i(ext) - ) - assert cp != self._backend._ffi.NULL - cp = self._backend._ffi.gc(cp, self._backend._lib.sk_POLICYINFO_free) - num = self._backend._lib.sk_POLICYINFO_num(cp) - certificate_policies = [] - for i in range(num): - qualifiers = None - pi = self._backend._lib.sk_POLICYINFO_value(cp, i) - oid = x509.ObjectIdentifier(_obj2txt(self._backend, pi.policyid)) - if pi.qualifiers != self._backend._ffi.NULL: - qnum = self._backend._lib.sk_POLICYQUALINFO_num(pi.qualifiers) - qualifiers = [] - for j in range(qnum): - pqi = self._backend._lib.sk_POLICYQUALINFO_value( - pi.qualifiers, j - ) - pqualid = x509.ObjectIdentifier( - _obj2txt(self._backend, pqi.pqualid) - ) - if pqualid == x509.OID_CPS_QUALIFIER: - cpsuri = self._backend._ffi.buffer( - pqi.d.cpsuri.data, pqi.d.cpsuri.length - )[:].decode('ascii') - qualifiers.append(cpsuri) - elif pqualid == x509.OID_CPS_USER_NOTICE: - user_notice = self._build_user_notice(pqi.d.usernotice) - qualifiers.append(user_notice) - - certificate_policies.append( - x509.PolicyInformation(oid, qualifiers) - ) - - return x509.CertificatePolicies(certificate_policies) - def _build_user_notice(self, un): - explicit_text = None - notice_reference = None - - if un.exptext != self._backend._ffi.NULL: - explicit_text = _asn1_string_to_utf8(self._backend, un.exptext) - - if un.noticeref != self._backend._ffi.NULL: - organization = _asn1_string_to_utf8( - self._backend, un.noticeref.organization - ) - - num = self._backend._lib.sk_ASN1_INTEGER_num( - un.noticeref.noticenos - ) - notice_numbers = [] - for i in range(num): - asn1_int = self._backend._lib.sk_ASN1_INTEGER_value( - un.noticeref.noticenos, i +def _decode_certificate_policies(backend, ext): + cp = backend._ffi.cast( + "Cryptography_STACK_OF_POLICYINFO *", + backend._lib.X509V3_EXT_d2i(ext) + ) + assert cp != backend._ffi.NULL + cp = backend._ffi.gc(cp, backend._lib.sk_POLICYINFO_free) + num = backend._lib.sk_POLICYINFO_num(cp) + certificate_policies = [] + for i in range(num): + qualifiers = None + pi = backend._lib.sk_POLICYINFO_value(cp, i) + oid = x509.ObjectIdentifier(_obj2txt(backend, pi.policyid)) + if pi.qualifiers != backend._ffi.NULL: + qnum = backend._lib.sk_POLICYQUALINFO_num(pi.qualifiers) + qualifiers = [] + for j in range(qnum): + pqi = backend._lib.sk_POLICYQUALINFO_value( + pi.qualifiers, j ) - notice_num = _asn1_integer_to_int( - self._backend, asn1_int + pqualid = x509.ObjectIdentifier( + _obj2txt(backend, pqi.pqualid) ) - notice_numbers.append(notice_num) + if pqualid == x509.OID_CPS_QUALIFIER: + cpsuri = backend._ffi.buffer( + pqi.d.cpsuri.data, pqi.d.cpsuri.length + )[:].decode('ascii') + qualifiers.append(cpsuri) + elif pqualid == x509.OID_CPS_USER_NOTICE: + user_notice = _decode_user_notice( + backend, pqi.d.usernotice + ) + qualifiers.append(user_notice) - notice_reference = x509.NoticeReference( - organization, notice_numbers - ) + certificate_policies.append( + x509.PolicyInformation(oid, qualifiers) + ) - return x509.UserNotice(notice_reference, explicit_text) + return x509.CertificatePolicies(certificate_policies) - def _build_basic_constraints(self, ext): - bc_st = self._backend._lib.X509V3_EXT_d2i(ext) - assert bc_st != self._backend._ffi.NULL - basic_constraints = self._backend._ffi.cast( - "BASIC_CONSTRAINTS *", bc_st - ) - basic_constraints = self._backend._ffi.gc( - basic_constraints, self._backend._lib.BASIC_CONSTRAINTS_free - ) - # The byte representation of an ASN.1 boolean true is \xff. OpenSSL - # chooses to just map this to its ordinal value, so true is 255 and - # false is 0. - ca = basic_constraints.ca == 255 - if basic_constraints.pathlen == self._backend._ffi.NULL: - path_length = None - else: - path_length = _asn1_integer_to_int( - self._backend, basic_constraints.pathlen - ) - return x509.BasicConstraints(ca, path_length) +def _decode_user_notice(backend, un): + explicit_text = None + notice_reference = None - def _build_subject_key_identifier(self, ext): - asn1_string = self._backend._lib.X509V3_EXT_d2i(ext) - assert asn1_string != self._backend._ffi.NULL - asn1_string = self._backend._ffi.cast( - "ASN1_OCTET_STRING *", asn1_string - ) - asn1_string = self._backend._ffi.gc( - asn1_string, self._backend._lib.ASN1_OCTET_STRING_free - ) - return x509.SubjectKeyIdentifier( - self._backend._ffi.buffer(asn1_string.data, asn1_string.length)[:] + if un.exptext != backend._ffi.NULL: + explicit_text = _asn1_string_to_utf8(backend, un.exptext) + + if un.noticeref != backend._ffi.NULL: + organization = _asn1_string_to_utf8( + backend, un.noticeref.organization ) - def _build_authority_key_identifier(self, ext): - akid = self._backend._lib.X509V3_EXT_d2i(ext) - assert akid != self._backend._ffi.NULL - akid = self._backend._ffi.cast("AUTHORITY_KEYID *", akid) - akid = self._backend._ffi.gc( - akid, self._backend._lib.AUTHORITY_KEYID_free + num = backend._lib.sk_ASN1_INTEGER_num( + un.noticeref.noticenos ) - key_identifier = None - authority_cert_issuer = None - authority_cert_serial_number = None - - if akid.keyid != self._backend._ffi.NULL: - key_identifier = self._backend._ffi.buffer( - akid.keyid.data, akid.keyid.length - )[:] - - if akid.issuer != self._backend._ffi.NULL: - authority_cert_issuer = _build_general_names( - self._backend, akid.issuer + notice_numbers = [] + for i in range(num): + asn1_int = backend._lib.sk_ASN1_INTEGER_value( + un.noticeref.noticenos, i ) - - if akid.serial != self._backend._ffi.NULL: - authority_cert_serial_number = _asn1_integer_to_int( - self._backend, akid.serial + notice_num = _asn1_integer_to_int( + backend, asn1_int ) + notice_numbers.append(notice_num) - return x509.AuthorityKeyIdentifier( - key_identifier, authority_cert_issuer, authority_cert_serial_number + notice_reference = x509.NoticeReference( + organization, notice_numbers ) - def _build_authority_information_access(self, ext): - aia = self._backend._lib.X509V3_EXT_d2i(ext) - assert aia != self._backend._ffi.NULL - aia = self._backend._ffi.cast( - "Cryptography_STACK_OF_ACCESS_DESCRIPTION *", aia - ) - aia = self._backend._ffi.gc( - aia, self._backend._lib.sk_ACCESS_DESCRIPTION_free - ) - num = self._backend._lib.sk_ACCESS_DESCRIPTION_num(aia) - access_descriptions = [] - for i in range(num): - ad = self._backend._lib.sk_ACCESS_DESCRIPTION_value(aia, i) - assert ad.method != self._backend._ffi.NULL - oid = x509.ObjectIdentifier(_obj2txt(self._backend, ad.method)) - assert ad.location != self._backend._ffi.NULL - gn = _build_general_name(self._backend, ad.location) - access_descriptions.append(x509.AccessDescription(oid, gn)) - - return x509.AuthorityInformationAccess(access_descriptions) - - def _build_key_usage(self, ext): - bit_string = self._backend._lib.X509V3_EXT_d2i(ext) - assert bit_string != self._backend._ffi.NULL - bit_string = self._backend._ffi.cast("ASN1_BIT_STRING *", bit_string) - bit_string = self._backend._ffi.gc( - bit_string, self._backend._lib.ASN1_BIT_STRING_free + return x509.UserNotice(notice_reference, explicit_text) + + +def _decode_basic_constraints(backend, ext): + bc_st = backend._lib.X509V3_EXT_d2i(ext) + assert bc_st != backend._ffi.NULL + basic_constraints = backend._ffi.cast( + "BASIC_CONSTRAINTS *", bc_st + ) + basic_constraints = backend._ffi.gc( + basic_constraints, backend._lib.BASIC_CONSTRAINTS_free + ) + # The byte representation of an ASN.1 boolean true is \xff. OpenSSL + # chooses to just map this to its ordinal value, so true is 255 and + # false is 0. + ca = basic_constraints.ca == 255 + if basic_constraints.pathlen == backend._ffi.NULL: + path_length = None + else: + path_length = _asn1_integer_to_int( + backend, basic_constraints.pathlen ) - get_bit = self._backend._lib.ASN1_BIT_STRING_get_bit - digital_signature = get_bit(bit_string, 0) == 1 - content_commitment = get_bit(bit_string, 1) == 1 - key_encipherment = get_bit(bit_string, 2) == 1 - data_encipherment = get_bit(bit_string, 3) == 1 - key_agreement = get_bit(bit_string, 4) == 1 - key_cert_sign = get_bit(bit_string, 5) == 1 - crl_sign = get_bit(bit_string, 6) == 1 - encipher_only = get_bit(bit_string, 7) == 1 - decipher_only = get_bit(bit_string, 8) == 1 - return x509.KeyUsage( - digital_signature, - content_commitment, - key_encipherment, - data_encipherment, - key_agreement, - key_cert_sign, - crl_sign, - encipher_only, - decipher_only + + return x509.BasicConstraints(ca, path_length) + + +def _decode_subject_key_identifier(backend, ext): + asn1_string = backend._lib.X509V3_EXT_d2i(ext) + assert asn1_string != backend._ffi.NULL + asn1_string = backend._ffi.cast( + "ASN1_OCTET_STRING *", asn1_string + ) + asn1_string = backend._ffi.gc( + asn1_string, backend._lib.ASN1_OCTET_STRING_free + ) + return x509.SubjectKeyIdentifier( + backend._ffi.buffer(asn1_string.data, asn1_string.length)[:] + ) + + +def _decode_authority_key_identifier(backend, ext): + akid = backend._lib.X509V3_EXT_d2i(ext) + assert akid != backend._ffi.NULL + akid = backend._ffi.cast("AUTHORITY_KEYID *", akid) + akid = backend._ffi.gc( + akid, backend._lib.AUTHORITY_KEYID_free + ) + key_identifier = None + authority_cert_issuer = None + authority_cert_serial_number = None + + if akid.keyid != backend._ffi.NULL: + key_identifier = backend._ffi.buffer( + akid.keyid.data, akid.keyid.length + )[:] + + if akid.issuer != backend._ffi.NULL: + authority_cert_issuer = _decode_general_names( + backend, akid.issuer ) - def _build_subject_alt_name(self, ext): - gns = self._backend._ffi.cast( - "GENERAL_NAMES *", self._backend._lib.X509V3_EXT_d2i(ext) + if akid.serial != backend._ffi.NULL: + authority_cert_serial_number = _asn1_integer_to_int( + backend, akid.serial ) - assert gns != self._backend._ffi.NULL - gns = self._backend._ffi.gc(gns, self._backend._lib.GENERAL_NAMES_free) - general_names = _build_general_names(self._backend, gns) - return x509.SubjectAlternativeName(general_names) + return x509.AuthorityKeyIdentifier( + key_identifier, authority_cert_issuer, authority_cert_serial_number + ) - def _build_extended_key_usage(self, ext): - sk = self._backend._ffi.cast( - "Cryptography_STACK_OF_ASN1_OBJECT *", - self._backend._lib.X509V3_EXT_d2i(ext) - ) - assert sk != self._backend._ffi.NULL - sk = self._backend._ffi.gc(sk, self._backend._lib.sk_ASN1_OBJECT_free) - num = self._backend._lib.sk_ASN1_OBJECT_num(sk) - ekus = [] - for i in range(num): - obj = self._backend._lib.sk_ASN1_OBJECT_value(sk, i) - assert obj != self._backend._ffi.NULL - oid = x509.ObjectIdentifier(_obj2txt(self._backend, obj)) - ekus.append(oid) +def _decode_authority_information_access(backend, ext): + aia = backend._lib.X509V3_EXT_d2i(ext) + assert aia != backend._ffi.NULL + aia = backend._ffi.cast( + "Cryptography_STACK_OF_ACCESS_DESCRIPTION *", aia + ) + aia = backend._ffi.gc( + aia, backend._lib.sk_ACCESS_DESCRIPTION_free + ) + num = backend._lib.sk_ACCESS_DESCRIPTION_num(aia) + access_descriptions = [] + for i in range(num): + ad = backend._lib.sk_ACCESS_DESCRIPTION_value(aia, i) + assert ad.method != backend._ffi.NULL + oid = x509.ObjectIdentifier(_obj2txt(backend, ad.method)) + assert ad.location != backend._ffi.NULL + gn = _decode_general_name(backend, ad.location) + access_descriptions.append(x509.AccessDescription(oid, gn)) + + return x509.AuthorityInformationAccess(access_descriptions) + + +def _decode_key_usage(backend, ext): + bit_string = backend._lib.X509V3_EXT_d2i(ext) + assert bit_string != backend._ffi.NULL + bit_string = backend._ffi.cast("ASN1_BIT_STRING *", bit_string) + bit_string = backend._ffi.gc( + bit_string, backend._lib.ASN1_BIT_STRING_free + ) + get_bit = backend._lib.ASN1_BIT_STRING_get_bit + digital_signature = get_bit(bit_string, 0) == 1 + content_commitment = get_bit(bit_string, 1) == 1 + key_encipherment = get_bit(bit_string, 2) == 1 + data_encipherment = get_bit(bit_string, 3) == 1 + key_agreement = get_bit(bit_string, 4) == 1 + key_cert_sign = get_bit(bit_string, 5) == 1 + crl_sign = get_bit(bit_string, 6) == 1 + encipher_only = get_bit(bit_string, 7) == 1 + decipher_only = get_bit(bit_string, 8) == 1 + return x509.KeyUsage( + digital_signature, + content_commitment, + key_encipherment, + data_encipherment, + key_agreement, + key_cert_sign, + crl_sign, + encipher_only, + decipher_only + ) - return x509.ExtendedKeyUsage(ekus) - def _build_crl_distribution_points(self, ext): - cdps = self._backend._ffi.cast( - "Cryptography_STACK_OF_DIST_POINT *", - self._backend._lib.X509V3_EXT_d2i(ext) - ) - assert cdps != self._backend._ffi.NULL - cdps = self._backend._ffi.gc( - cdps, self._backend._lib.sk_DIST_POINT_free) - num = self._backend._lib.sk_DIST_POINT_num(cdps) +def _decode_subject_alt_name(backend, ext): + gns = backend._ffi.cast( + "GENERAL_NAMES *", backend._lib.X509V3_EXT_d2i(ext) + ) + assert gns != backend._ffi.NULL + gns = backend._ffi.gc(gns, backend._lib.GENERAL_NAMES_free) + general_names = _decode_general_names(backend, gns) - dist_points = [] - for i in range(num): - full_name = None - relative_name = None - crl_issuer = None - reasons = None - cdp = self._backend._lib.sk_DIST_POINT_value(cdps, i) - if cdp.reasons != self._backend._ffi.NULL: - # We will check each bit from RFC 5280 - # ReasonFlags ::= BIT STRING { - # unused (0), - # keyCompromise (1), - # cACompromise (2), - # affiliationChanged (3), - # superseded (4), - # cessationOfOperation (5), - # certificateHold (6), - # privilegeWithdrawn (7), - # aACompromise (8) } - reasons = [] - get_bit = self._backend._lib.ASN1_BIT_STRING_get_bit - if get_bit(cdp.reasons, 1): - reasons.append(x509.ReasonFlags.key_compromise) - - if get_bit(cdp.reasons, 2): - reasons.append(x509.ReasonFlags.ca_compromise) - - if get_bit(cdp.reasons, 3): - reasons.append(x509.ReasonFlags.affiliation_changed) - - if get_bit(cdp.reasons, 4): - reasons.append(x509.ReasonFlags.superseded) - - if get_bit(cdp.reasons, 5): - reasons.append(x509.ReasonFlags.cessation_of_operation) - - if get_bit(cdp.reasons, 6): - reasons.append(x509.ReasonFlags.certificate_hold) - - if get_bit(cdp.reasons, 7): - reasons.append(x509.ReasonFlags.privilege_withdrawn) - - if get_bit(cdp.reasons, 8): - reasons.append(x509.ReasonFlags.aa_compromise) - - reasons = frozenset(reasons) - - if cdp.CRLissuer != self._backend._ffi.NULL: - crl_issuer = _build_general_names(self._backend, cdp.CRLissuer) - - # Certificates may have a crl_issuer/reasons and no distribution - # point so make sure it's not null. - if cdp.distpoint != self._backend._ffi.NULL: - # Type 0 is fullName, there is no #define for it in the code. - if cdp.distpoint.type == 0: - full_name = _build_general_names( - self._backend, cdp.distpoint.name.fullname - ) - # OpenSSL code doesn't test for a specific type for - # relativename, everything that isn't fullname is considered - # relativename. - else: - rns = cdp.distpoint.name.relativename - rnum = self._backend._lib.sk_X509_NAME_ENTRY_num(rns) - attributes = [] - for i in range(rnum): - rn = self._backend._lib.sk_X509_NAME_ENTRY_value( - rns, i - ) - assert rn != self._backend._ffi.NULL - attributes.append( - _build_x509_name_entry(self._backend, rn) - ) - - relative_name = x509.Name(attributes) - - dist_points.append( - x509.DistributionPoint( - full_name, relative_name, reasons, crl_issuer + return x509.SubjectAlternativeName(general_names) + + +def _decode_extended_key_usage(backend, ext): + sk = backend._ffi.cast( + "Cryptography_STACK_OF_ASN1_OBJECT *", + backend._lib.X509V3_EXT_d2i(ext) + ) + assert sk != backend._ffi.NULL + sk = backend._ffi.gc(sk, backend._lib.sk_ASN1_OBJECT_free) + num = backend._lib.sk_ASN1_OBJECT_num(sk) + ekus = [] + + for i in range(num): + obj = backend._lib.sk_ASN1_OBJECT_value(sk, i) + assert obj != backend._ffi.NULL + oid = x509.ObjectIdentifier(_obj2txt(backend, obj)) + ekus.append(oid) + + return x509.ExtendedKeyUsage(ekus) + + +def _decode_crl_distribution_points(backend, ext): + cdps = backend._ffi.cast( + "Cryptography_STACK_OF_DIST_POINT *", + backend._lib.X509V3_EXT_d2i(ext) + ) + assert cdps != backend._ffi.NULL + cdps = backend._ffi.gc( + cdps, backend._lib.sk_DIST_POINT_free) + num = backend._lib.sk_DIST_POINT_num(cdps) + + dist_points = [] + for i in range(num): + full_name = None + relative_name = None + crl_issuer = None + reasons = None + cdp = backend._lib.sk_DIST_POINT_value(cdps, i) + if cdp.reasons != backend._ffi.NULL: + # We will check each bit from RFC 5280 + # ReasonFlags ::= BIT STRING { + # unused (0), + # keyCompromise (1), + # cACompromise (2), + # affiliationChanged (3), + # superseded (4), + # cessationOfOperation (5), + # certificateHold (6), + # privilegeWithdrawn (7), + # aACompromise (8) } + reasons = [] + get_bit = backend._lib.ASN1_BIT_STRING_get_bit + if get_bit(cdp.reasons, 1): + reasons.append(x509.ReasonFlags.key_compromise) + + if get_bit(cdp.reasons, 2): + reasons.append(x509.ReasonFlags.ca_compromise) + + if get_bit(cdp.reasons, 3): + reasons.append(x509.ReasonFlags.affiliation_changed) + + if get_bit(cdp.reasons, 4): + reasons.append(x509.ReasonFlags.superseded) + + if get_bit(cdp.reasons, 5): + reasons.append(x509.ReasonFlags.cessation_of_operation) + + if get_bit(cdp.reasons, 6): + reasons.append(x509.ReasonFlags.certificate_hold) + + if get_bit(cdp.reasons, 7): + reasons.append(x509.ReasonFlags.privilege_withdrawn) + + if get_bit(cdp.reasons, 8): + reasons.append(x509.ReasonFlags.aa_compromise) + + reasons = frozenset(reasons) + + if cdp.CRLissuer != backend._ffi.NULL: + crl_issuer = _decode_general_names(backend, cdp.CRLissuer) + + # Certificates may have a crl_issuer/reasons and no distribution + # point so make sure it's not null. + if cdp.distpoint != backend._ffi.NULL: + # Type 0 is fullName, there is no #define for it in the code. + if cdp.distpoint.type == 0: + full_name = _decode_general_names( + backend, cdp.distpoint.name.fullname ) + # OpenSSL code doesn't test for a specific type for + # relativename, everything that isn't fullname is considered + # relativename. + else: + rns = cdp.distpoint.name.relativename + rnum = backend._lib.sk_X509_NAME_ENTRY_num(rns) + attributes = [] + for i in range(rnum): + rn = backend._lib.sk_X509_NAME_ENTRY_value( + rns, i + ) + assert rn != backend._ffi.NULL + attributes.append( + _decode_x509_name_entry(backend, rn) + ) + + relative_name = x509.Name(attributes) + + dist_points.append( + x509.DistributionPoint( + full_name, relative_name, reasons, crl_issuer ) + ) - return x509.CRLDistributionPoints(dist_points) + return x509.CRLDistributionPoints(dist_points) @utils.register_interface(x509.CertificateSigningRequest) @@ -632,7 +646,7 @@ class _CertificateSigningRequest(object): def subject(self): subject = self._backend._lib.X509_REQ_get_subject_name(self._x509_req) assert subject != self._backend._ffi.NULL - return _build_x509_name(self._backend, subject) + return _decode_x509_name(self._backend, subject) @property def signature_hash_algorithm(self): @@ -643,3 +657,35 @@ class _CertificateSigningRequest(object): raise UnsupportedAlgorithm( "Signature algorithm OID:{0} not recognized".format(oid) ) + + @property + def extensions(self): + extensions = [] + seen_oids = set() + x509_exts = self._backend._lib.X509_REQ_get_extensions(self._x509_req) + extcount = self._backend._lib.sk_X509_EXTENSION_num(x509_exts) + for i in range(0, extcount): + ext = self._backend._lib.sk_X509_EXTENSION_value(x509_exts, i) + assert ext != self._backend._ffi.NULL + crit = self._backend._lib.X509_EXTENSION_get_critical(ext) + critical = crit == 1 + oid = x509.ObjectIdentifier(_obj2txt(self._backend, ext.object)) + if oid in seen_oids: + raise x509.DuplicateExtension( + "Duplicate {0} extension found".format(oid), oid + ) + elif oid == x509.OID_BASIC_CONSTRAINTS: + value = _decode_basic_constraints(self._backend, ext) + elif critical: + raise x509.UnsupportedExtension( + "{0} is not currently supported".format(oid), oid + ) + else: + # Unsupported non-critical extension, silently skipping for now + seen_oids.add(oid) + continue + + seen_oids.add(oid) + extensions.append(x509.Extension(oid, critical, value)) + + return x509.Extensions(extensions) diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py index 71ba9042..7ac06622 100644 --- a/src/cryptography/x509.py +++ b/src/cryptography/x509.py @@ -278,6 +278,19 @@ class Extension(object): return ("<Extension(oid={0.oid}, critical={0.critical}, " "value={0.value})>").format(self) + def __eq__(self, other): + if not isinstance(other, Extension): + return NotImplemented + + return ( + self.oid == other.oid and + self.critical == other.critical and + self.value == other.value + ) + + def __ne__(self, other): + return not self == other + class ExtendedKeyUsage(object): def __init__(self, usages): @@ -307,6 +320,10 @@ class ExtendedKeyUsage(object): return not self == other +class OCSPNoCheck(object): + pass + + class BasicConstraints(object): def __init__(self, ca, path_length): if not isinstance(ca, bool): @@ -896,11 +913,18 @@ class RegisteredID(object): class IPAddress(object): def __init__(self, value): if not isinstance( - value, (ipaddress.IPv4Address, ipaddress.IPv6Address) + value, + ( + ipaddress.IPv4Address, + ipaddress.IPv6Address, + ipaddress.IPv4Network, + ipaddress.IPv6Network + ) ): raise TypeError( - "value must be an instance of ipaddress.IPv4Address or " - "ipaddress.IPv6Address" + "value must be an instance of ipaddress.IPv4Address, " + "ipaddress.IPv6Address, ipaddress.IPv4Network, or " + "ipaddress.IPv6Network" ) self._value = value @@ -1125,6 +1149,12 @@ class Certificate(object): in the certificate. """ + @abc.abstractproperty + def extensions(self): + """ + Returns an Extensions object. + """ + @abc.abstractmethod def __eq__(self, other): """ @@ -1158,3 +1188,9 @@ class CertificateSigningRequest(object): Returns a HashAlgorithm corresponding to the type of the digest signed in the certificate. """ + + @abc.abstractproperty + def extensions(self): + """ + Returns the extensions in the signing request. + """ diff --git a/tests/test_x509.py b/tests/test_x509.py index 8561f1f4..47c1c647 100644 --- a/tests/test_x509.py +++ b/tests/test_x509.py @@ -395,6 +395,9 @@ class TestRSACertificate(object): x509.NameAttribute(x509.OID_ORGANIZATION_NAME, 'PyCA'), x509.NameAttribute(x509.OID_COMMON_NAME, 'cryptography.io'), ] + extensions = request.extensions + assert isinstance(extensions, x509.Extensions) + assert list(extensions) == [] @pytest.mark.parametrize( "loader_func", @@ -413,6 +416,61 @@ class TestRSACertificate(object): with pytest.raises(UnsupportedAlgorithm): request.signature_hash_algorithm + def test_duplicate_extension(self, backend): + request = _load_cert( + os.path.join( + "x509", "requests", "two_basic_constraints.pem" + ), + x509.load_pem_x509_csr, + backend + ) + with pytest.raises(x509.DuplicateExtension) as exc: + request.extensions + + assert exc.value.oid == x509.OID_BASIC_CONSTRAINTS + + def test_unsupported_critical_extension(self, backend): + request = _load_cert( + os.path.join( + "x509", "requests", "unsupported_extension_critical.pem" + ), + x509.load_pem_x509_csr, + backend + ) + with pytest.raises(x509.UnsupportedExtension) as exc: + request.extensions + + assert exc.value.oid == x509.ObjectIdentifier('1.2.3.4') + + def test_unsupported_extension(self, backend): + request = _load_cert( + os.path.join( + "x509", "requests", "unsupported_extension.pem" + ), + x509.load_pem_x509_csr, + backend + ) + extensions = request.extensions + assert len(extensions) == 0 + + def test_request_basic_constraints(self, backend): + request = _load_cert( + os.path.join( + "x509", "requests", "basic_constraints.pem" + ), + x509.load_pem_x509_csr, + backend + ) + extensions = request.extensions + assert isinstance(extensions, x509.Extensions) + assert list(extensions) == [ + x509.Extension( + x509.OID_BASIC_CONSTRAINTS, + True, + x509.BasicConstraints(True, 1), + ), + ] + @pytest.mark.requires_backend_interface(interface=DSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py index 72f2f9e4..d3488a9f 100644 --- a/tests/test_x509_ext.py +++ b/tests/test_x509_ext.py @@ -38,6 +38,33 @@ class TestExtension(object): "_length=None)>)>" ) + def test_eq(self): + ext1 = x509.Extension( + x509.ObjectIdentifier('1.2.3.4'), False, 'value' + ) + ext2 = x509.Extension( + x509.ObjectIdentifier('1.2.3.4'), False, 'value' + ) + assert ext1 == ext2 + + def test_ne(self): + ext1 = x509.Extension( + x509.ObjectIdentifier('1.2.3.4'), False, 'value' + ) + ext2 = x509.Extension( + x509.ObjectIdentifier('1.2.3.5'), False, 'value' + ) + ext3 = x509.Extension( + x509.ObjectIdentifier('1.2.3.4'), True, 'value' + ) + ext4 = x509.Extension( + x509.ObjectIdentifier('1.2.3.4'), False, 'value4' + ) + assert ext1 != ext2 + assert ext1 != ext3 + assert ext1 != ext4 + assert ext1 != object() + class TestNoticeReference(object): def test_notice_numbers_not_all_int(self): @@ -1094,6 +1121,12 @@ class TestIPAddress(object): gn2 = x509.IPAddress(ipaddress.IPv6Address(u"ff::")) assert repr(gn2) == "<IPAddress(value=ff::)>" + gn3 = x509.IPAddress(ipaddress.IPv4Network(u"192.168.0.0/24")) + assert repr(gn3) == "<IPAddress(value=192.168.0.0/24)>" + + gn4 = x509.IPAddress(ipaddress.IPv6Network(u"ff::/96")) + assert repr(gn4) == "<IPAddress(value=ff::/96)>" + def test_eq(self): gn = x509.IPAddress(ipaddress.IPv4Address(u"127.0.0.1")) gn2 = x509.IPAddress(ipaddress.IPv4Address(u"127.0.0.1")) diff --git a/vectors/cryptography_vectors/x509/requests/basic_constraints.pem b/vectors/cryptography_vectors/x509/requests/basic_constraints.pem new file mode 100644 index 00000000..7169cda7 --- /dev/null +++ b/vectors/cryptography_vectors/x509/requests/basic_constraints.pem @@ -0,0 +1,64 @@ +Certificate Request: + Data: + Version: 2 (0x2) + Subject: C=US, ST=Texas, L=Austin, O=PyCA, CN=cryptography.io + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (2048 bit) + Modulus (2048 bit): + 00:a4:1a:ae:63:a2:ad:23:0a:b7:a2:f0:0e:50:fd: + 96:e1:02:96:05:07:72:c8:96:a7:d6:a9:f6:19:fd: + 61:98:9a:ca:98:5c:41:69:0c:f2:f8:27:f2:c4:7d: + fe:6d:08:9e:f7:99:2c:f7:ad:45:97:97:c3:eb:4c: + d7:03:e1:32:27:77:be:73:74:3b:62:1f:66:c7:83: + 3c:44:45:76:a8:f1:34:00:84:fd:43:f8:2e:95:00: + 2f:34:f5:c9:d6:67:44:e1:65:42:42:c1:53:5f:7c: + 47:b2:65:a6:d5:ad:c8:9a:13:0b:58:c4:b9:42:c7: + 4d:76:c0:99:57:9d:b0:33:ec:f8:dd:a3:61:86:1f: + df:bd:d8:56:ae:0d:bf:41:c8:b1:69:8a:2a:df:cf: + 2a:05:25:8a:34:6c:32:7e:8c:73:fa:41:1a:57:90: + 3d:5f:89:e1:b4:c6:bf:96:50:b7:62:fc:f7:20:13: + 6d:25:cc:b0:4f:3d:4b:85:d5:31:4a:a2:33:f9:f5: + 1f:e9:c1:e8:03:29:b3:df:65:51:80:27:2b:3e:d3: + 83:b2:fa:80:1b:03:43:56:07:26:f0:e9:58:64:bb: + dc:7e:fd:c1:88:e1:10:54:4e:a3:f6:67:6c:c9:54: + 3d:9c:8d:62:43:be:31:77:d4:c3:ee:39:3c:b0:eb: + e5:ab + Exponent: 65537 (0x10001) + Attributes: + Requested Extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:1 + Signature Algorithm: sha1WithRSAEncryption + 0a:8a:70:98:1c:68:65:04:bb:6b:0c:93:90:03:e8:94:21:08: + 1d:af:e6:59:2a:27:b1:f7:80:c3:aa:0a:dd:8b:07:67:7e:cf: + ac:99:c7:c9:70:d8:f2:13:32:25:b9:03:7d:b7:37:da:f4:d6: + 43:00:be:80:fd:7d:6d:05:f7:a0:e8:3e:69:8a:b7:44:46:3c: + 58:87:28:72:1e:eb:31:50:26:25:39:0e:57:85:b5:28:a2:6a: + 0d:f5:88:70:f4:bc:81:d6:87:4e:f2:ca:64:1b:86:d5:04:2d: + 1e:d6:32:00:23:04:8b:b0:9a:a9:8c:5b:60:2d:9e:ea:57:7a: + d2:e3:b4:f0:f4:0c:08:54:af:91:e3:b4:61:51:91:7e:60:4f: + 0a:6e:db:65:38:1a:4f:35:07:e7:08:0d:0a:39:3e:7b:4a:bf: + 03:f6:6e:5b:f4:47:95:53:22:21:b9:91:db:0e:76:f1:0f:6f: + 82:a5:0f:b7:65:cf:19:12:9e:67:4e:5f:c1:b2:a7:02:d7:e4: + 6a:55:de:35:52:32:4d:45:ab:b3:fc:82:3d:6d:65:9c:be:6c: + 81:9a:10:9a:22:f8:75:de:9c:f4:61:de:6c:82:3a:5f:51:f4: + 7b:b7:14:68:0b:ac:2b:16:76:46:5e:3c:bb:03:dd:dc:12:17: + 70:06:4b:3c +-----BEGIN CERTIFICATE REQUEST----- +MIICwTCCAakCAQIwVzELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVRleGFzMQ8wDQYD +VQQHDAZBdXN0aW4xDTALBgNVBAoMBFB5Q0ExGDAWBgNVBAMMD2NyeXB0b2dyYXBo +eS5pbzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKQarmOirSMKt6Lw +DlD9luEClgUHcsiWp9ap9hn9YZiayphcQWkM8vgn8sR9/m0InveZLPetRZeXw+tM +1wPhMid3vnN0O2IfZseDPERFdqjxNACE/UP4LpUALzT1ydZnROFlQkLBU198R7Jl +ptWtyJoTC1jEuULHTXbAmVedsDPs+N2jYYYf373YVq4Nv0HIsWmKKt/PKgUlijRs +Mn6Mc/pBGleQPV+J4bTGv5ZQt2L89yATbSXMsE89S4XVMUqiM/n1H+nB6AMps99l +UYAnKz7Tg7L6gBsDQ1YHJvDpWGS73H79wYjhEFROo/ZnbMlUPZyNYkO+MXfUw+45 +PLDr5asCAwEAAaAlMCMGCSqGSIb3DQEJDjEWMBQwEgYDVR0TAQH/BAgwBgEB/wIB +ATANBgkqhkiG9w0BAQUFAAOCAQEACopwmBxoZQS7awyTkAPolCEIHa/mWSonsfeA +w6oK3YsHZ37PrJnHyXDY8hMyJbkDfbc32vTWQwC+gP19bQX3oOg+aYq3REY8WIco +ch7rMVAmJTkOV4W1KKJqDfWIcPS8gdaHTvLKZBuG1QQtHtYyACMEi7CaqYxbYC2e +6ld60uO08PQMCFSvkeO0YVGRfmBPCm7bZTgaTzUH5wgNCjk+e0q/A/ZuW/RHlVMi +IbmR2w528Q9vgqUPt2XPGRKeZ05fwbKnAtfkalXeNVIyTUWrs/yCPW1lnL5sgZoQ +miL4dd6c9GHebII6X1H0e7cUaAusKxZ2Rl48uwPd3BIXcAZLPA== +-----END CERTIFICATE REQUEST----- diff --git a/vectors/cryptography_vectors/x509/requests/two_basic_constraints.pem b/vectors/cryptography_vectors/x509/requests/two_basic_constraints.pem new file mode 100644 index 00000000..da23c06e --- /dev/null +++ b/vectors/cryptography_vectors/x509/requests/two_basic_constraints.pem @@ -0,0 +1,66 @@ +Certificate Request: + Data: + Version: 2 (0x2) + Subject: C=US, ST=Texas, L=Austin, O=PyCA, CN=cryptography.io + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (2048 bit) + Modulus (2048 bit): + 00:cc:72:54:2d:83:be:73:f5:9a:60:3f:b8:bd:78: + 7d:f4:3d:6e:31:38:a9:26:72:86:19:14:87:0d:f4: + 68:97:19:2f:d7:7c:80:45:ad:38:27:59:db:57:76: + a5:f3:b1:5e:34:5f:43:63:e5:24:0a:0f:c6:ab:39: + 69:d1:1a:87:68:8c:98:02:3a:08:1c:25:d7:65:30: + c3:b6:a9:fa:df:ca:9d:4b:4c:b3:00:a7:fa:ea:de: + ad:99:d2:67:5f:c4:15:0d:b3:70:4d:b2:0a:a7:dd: + 35:67:35:b9:4f:a8:b2:f6:a6:22:26:b6:ae:e8:ed: + 2d:e7:82:7e:a5:f2:2c:05:d5:03:5a:2e:1e:d0:62: + 79:04:55:4b:b3:99:94:8b:9f:6a:5e:ee:6e:b3:d4: + f0:d4:9a:82:ce:e3:f4:81:5c:b2:db:24:85:b8:e4: + 1c:6f:a8:3d:4e:91:27:6a:fe:48:29:f2:09:40:9e: + a1:e2:34:41:18:29:ce:f5:24:11:d9:22:2f:6f:94: + cf:22:4e:ba:f2:38:90:00:70:d5:86:d4:6d:c2:ce: + 6c:32:74:75:df:f1:1f:c9:a0:be:43:2b:84:34:db: + 34:2f:d3:15:8f:ff:85:62:40:79:d3:3c:04:a2:b8: + 43:34:ae:c2:3e:1d:ad:c0:4b:28:34:c2:6d:7e:e2: + 9f:75 + Exponent: 65537 (0x10001) + Attributes: + Requested Extensions: + X509v3 Basic Constraints: critical + CA:FALSE + X509v3 Basic Constraints: critical + CA:FALSE + Signature Algorithm: sha1WithRSAEncryption + b8:00:de:3c:28:bf:56:9a:a7:8f:50:a3:86:a3:02:91:8b:97: + 1c:b8:73:81:c2:fd:85:d7:6f:ba:b1:c3:18:8a:17:d9:66:cd: + b9:9a:9c:1f:c8:0b:88:33:b7:4e:97:b2:60:43:ea:13:57:13: + 17:7c:23:7d:22:6e:65:b0:0a:bc:dc:12:ec:b3:85:2f:1b:c9: + ef:9c:19:f3:15:fd:78:89:a6:d1:2d:b8:bf:b6:17:b8:dc:b5: + 7a:e6:2a:4d:2c:da:01:10:31:96:12:13:49:08:1b:d9:ba:97: + 54:e4:21:b8:50:92:9d:1f:30:f0:a2:de:99:8e:da:0e:1f:84: + d4:22:2a:f6:d4:3b:43:81:25:ca:2a:e2:17:f6:ef:2f:db:df: + 67:dc:0f:1b:36:ac:46:b4:39:3b:d6:17:1a:12:fb:5f:1d:28: + db:9f:66:38:64:b7:43:ab:84:49:11:3b:ae:f1:30:cf:79:7e: + a6:52:ff:91:cb:9c:53:09:44:89:83:cf:04:7b:3c:12:7b:8f: + 56:e7:48:9a:e5:2a:f3:1f:93:ec:07:5f:1d:f1:6d:59:ed:5e: + f6:6a:be:63:60:02:f4:65:34:fb:dc:0a:1b:b3:99:b5:4b:4f: + 66:55:35:d3:79:85:48:7e:ca:0e:06:0f:92:00:27:93:79:ce: + f7:2f:ad:2b +-----BEGIN CERTIFICATE REQUEST----- +MIICyTCCAbECAQIwVzELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVRleGFzMQ8wDQYD +VQQHDAZBdXN0aW4xDTALBgNVBAoMBFB5Q0ExGDAWBgNVBAMMD2NyeXB0b2dyYXBo +eS5pbzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMxyVC2DvnP1mmA/ +uL14ffQ9bjE4qSZyhhkUhw30aJcZL9d8gEWtOCdZ21d2pfOxXjRfQ2PlJAoPxqs5 +adEah2iMmAI6CBwl12Uww7ap+t/KnUtMswCn+urerZnSZ1/EFQ2zcE2yCqfdNWc1 +uU+osvamIia2rujtLeeCfqXyLAXVA1ouHtBieQRVS7OZlIufal7ubrPU8NSags7j +9IFcstskhbjkHG+oPU6RJ2r+SCnyCUCeoeI0QRgpzvUkEdkiL2+UzyJOuvI4kABw +1YbUbcLObDJ0dd/xH8mgvkMrhDTbNC/TFY//hWJAedM8BKK4QzSuwj4drcBLKDTC +bX7in3UCAwEAAaAtMCsGCSqGSIb3DQEJDjEeMBwwDAYDVR0TAQH/BAIwADAMBgNV +HRMBAf8EAjAAMA0GCSqGSIb3DQEBBQUAA4IBAQC4AN48KL9WmqePUKOGowKRi5cc +uHOBwv2F12+6scMYihfZZs25mpwfyAuIM7dOl7JgQ+oTVxMXfCN9Im5lsAq83BLs +s4UvG8nvnBnzFf14iabRLbi/the43LV65ipNLNoBEDGWEhNJCBvZupdU5CG4UJKd +HzDwot6ZjtoOH4TUIir21DtDgSXKKuIX9u8v299n3A8bNqxGtDk71hcaEvtfHSjb +n2Y4ZLdDq4RJETuu8TDPeX6mUv+Ry5xTCUSJg88EezwSe49W50ia5SrzH5PsB18d +8W1Z7V72ar5jYAL0ZTT73Aobs5m1S09mVTXTeYVIfsoOBg+SACeTec73L60r +-----END CERTIFICATE REQUEST----- diff --git a/vectors/cryptography_vectors/x509/requests/unsupported_extension.pem b/vectors/cryptography_vectors/x509/requests/unsupported_extension.pem new file mode 100644 index 00000000..d96097c3 --- /dev/null +++ b/vectors/cryptography_vectors/x509/requests/unsupported_extension.pem @@ -0,0 +1,64 @@ +Certificate Request: + Data: + Version: 2 (0x2) + Subject: C=US, ST=Texas, L=Austin, O=PyCA, CN=cryptography.io + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (2048 bit) + Modulus (2048 bit): + 00:b6:64:25:bd:fc:ba:bf:7b:ee:da:a6:25:79:75: + 59:59:cb:bc:da:eb:22:66:97:93:4d:f0:67:39:45: + 01:5c:58:0a:17:88:e4:05:14:c8:3f:33:39:5f:a0: + ca:fc:dd:28:3e:b1:d1:0d:87:c1:65:22:21:d3:4a: + 5c:f0:b6:4f:49:83:90:b1:88:47:b5:7f:7e:4f:34: + ae:51:a5:ee:fb:92:68:2d:0f:83:86:cb:8e:e7:1d: + ba:f4:6a:f2:ab:81:aa:fc:a4:05:fd:fd:07:88:59: + 6a:b7:c7:f5:df:92:e6:fd:ec:e7:a7:6f:ac:02:95: + b7:3f:01:39:82:8e:94:84:18:cf:07:1b:25:5e:94: + 56:ec:2e:b7:37:71:ba:09:d2:ef:a3:46:ec:38:34: + 1d:0f:f8:d1:1f:4f:11:bd:03:9e:c9:46:65:f7:6d: + 80:2d:32:5e:44:6f:e3:21:ec:c2:76:32:62:c2:9e: + 47:03:27:8b:ba:49:01:2b:61:1f:6d:7b:3c:05:11: + 84:bd:a8:bd:44:e2:30:1e:c2:19:fc:9c:60:79:29: + b9:62:92:97:94:d2:f7:30:84:b6:51:af:f1:9a:61: + 80:2e:f8:94:22:f7:73:32:20:79:b1:bf:ea:2d:20: + 20:48:51:3d:f1:51:03:b1:02:90:74:46:cf:3b:4e: + f8:4b + Exponent: 65537 (0x10001) + Attributes: + Requested Extensions: + 1.2.3.4: + value + Signature Algorithm: sha1WithRSAEncryption + 16:5f:86:90:13:fd:63:e6:c9:ca:74:68:b4:6e:e6:c5:c3:46: + c1:26:bc:64:2b:fc:ef:be:ab:eb:8b:a9:de:8d:4e:a8:f9:f0: + 3e:b0:0b:8c:e4:f8:0b:28:5b:13:0c:46:f8:3b:55:cb:cc:cb: + ed:6a:4f:16:3a:4b:e9:65:2d:3c:1a:a5:1f:a8:07:ab:22:ee: + 91:60:f1:06:76:0c:6e:8f:7b:25:36:4b:d6:60:04:77:e6:35: + 10:4f:eb:fc:2a:c3:71:e5:cb:9f:94:bd:6c:44:08:79:fb:b2: + a0:f5:f2:c0:79:b0:c4:22:ec:81:29:b3:97:e5:2f:1f:47:c5: + 1a:3f:be:50:c8:f4:29:9a:94:1d:19:a9:e2:d6:06:ca:07:43: + 6c:f1:e4:7e:fb:b8:70:0c:5b:41:c4:10:84:29:39:49:17:09: + d1:21:89:d7:c8:e5:6c:48:66:98:ac:8b:33:ab:da:1f:51:a9: + 2f:4c:39:6d:48:d9:7b:34:7f:b5:1e:9e:b8:87:8b:21:13:41: + d4:53:64:c1:16:e0:a8:c1:6f:dc:be:8f:67:ad:e6:30:79:af: + bf:7e:ff:64:99:50:d8:4c:58:66:9c:da:d1:53:06:2e:d3:82: + e3:2d:b3:65:71:6e:6a:67:cf:e1:96:4f:f7:ac:0b:2e:6e:28: + a4:df:f5:e6 +-----BEGIN CERTIFICATE REQUEST----- +MIICuzCCAaMCAQIwVzELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVRleGFzMQ8wDQYD +VQQHDAZBdXN0aW4xDTALBgNVBAoMBFB5Q0ExGDAWBgNVBAMMD2NyeXB0b2dyYXBo +eS5pbzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALZkJb38ur977tqm +JXl1WVnLvNrrImaXk03wZzlFAVxYCheI5AUUyD8zOV+gyvzdKD6x0Q2HwWUiIdNK +XPC2T0mDkLGIR7V/fk80rlGl7vuSaC0Pg4bLjucduvRq8quBqvykBf39B4hZarfH +9d+S5v3s56dvrAKVtz8BOYKOlIQYzwcbJV6UVuwutzdxugnS76NG7Dg0HQ/40R9P +Eb0DnslGZfdtgC0yXkRv4yHswnYyYsKeRwMni7pJASthH217PAURhL2ovUTiMB7C +GfycYHkpuWKSl5TS9zCEtlGv8ZphgC74lCL3czIgebG/6i0gIEhRPfFRA7ECkHRG +zztO+EsCAwEAAaAfMB0GCSqGSIb3DQEJDjEQMA4wDAYDKgMEBAV2YWx1ZTANBgkq +hkiG9w0BAQUFAAOCAQEAFl+GkBP9Y+bJynRotG7mxcNGwSa8ZCv8776r64up3o1O +qPnwPrALjOT4CyhbEwxG+DtVy8zL7WpPFjpL6WUtPBqlH6gHqyLukWDxBnYMbo97 +JTZL1mAEd+Y1EE/r/CrDceXLn5S9bEQIefuyoPXywHmwxCLsgSmzl+UvH0fFGj++ +UMj0KZqUHRmp4tYGygdDbPHkfvu4cAxbQcQQhCk5SRcJ0SGJ18jlbEhmmKyLM6va +H1GpL0w5bUjZezR/tR6euIeLIRNB1FNkwRbgqMFv3L6PZ63mMHmvv37/ZJlQ2ExY +Zpza0VMGLtOC4y2zZXFuamfP4ZZP96wLLm4opN/15g== +-----END CERTIFICATE REQUEST----- diff --git a/vectors/cryptography_vectors/x509/requests/unsupported_extension_critical.pem b/vectors/cryptography_vectors/x509/requests/unsupported_extension_critical.pem new file mode 100644 index 00000000..2ae17d8e --- /dev/null +++ b/vectors/cryptography_vectors/x509/requests/unsupported_extension_critical.pem @@ -0,0 +1,64 @@ +Certificate Request: + Data: + Version: 2 (0x2) + Subject: C=US, ST=Texas, L=Austin, O=PyCA, CN=cryptography.io + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (2048 bit) + Modulus (2048 bit): + 00:ce:ed:18:2c:b8:63:f6:65:50:1e:ec:7e:7b:86: + 56:25:3e:3d:5d:86:6e:9a:d1:56:b0:79:b7:85:c9: + 14:23:4d:ff:10:c7:68:f2:00:b6:57:39:a6:5d:3f: + ed:50:67:cd:bd:da:fb:68:a9:0f:79:a9:0e:79:23: + 62:d0:d1:27:96:f2:d6:36:b9:6d:4e:d6:4e:0f:32: + 88:9b:0b:90:98:31:00:fa:2e:ca:ac:82:e3:c3:60: + 1c:8e:f1:be:0d:1e:bc:b6:f7:a7:9b:60:aa:4b:9a: + a5:04:b5:a0:a8:29:0b:21:af:2c:40:26:87:75:85: + 3c:00:38:4d:a4:f9:25:8e:d5:d7:11:b4:dd:3c:27: + 11:0c:1c:1c:86:63:35:66:d6:47:73:6c:bd:00:03: + 2b:4a:d0:90:db:8c:e8:b4:8d:2a:ff:90:8f:0b:c8: + 32:ed:b3:23:7f:ce:01:74:26:f6:84:e6:53:54:44: + 45:e8:53:20:54:ec:00:6d:60:13:2b:bb:da:fe:19: + 82:db:a6:6c:72:fb:be:26:d2:9d:03:fd:7f:72:94: + 06:4e:25:d3:17:12:c5:2b:d6:a5:e1:29:3c:7b:d7: + da:da:89:bf:a9:09:41:ab:73:fb:8d:8b:3f:83:4b: + f1:bb:2b:5f:c6:a9:03:e6:c9:0a:fc:0a:f4:82:e1: + 4b:97 + Exponent: 65537 (0x10001) + Attributes: + Requested Extensions: + 1.2.3.4: critical + value + Signature Algorithm: sha1WithRSAEncryption + 2c:70:0f:a6:d0:0d:70:24:a8:94:ad:4b:1d:50:46:19:7c:c0: + a8:fb:01:84:3b:3b:7e:b0:6f:6b:d9:86:81:a3:d4:03:e9:d7: + 0c:f6:ff:c6:43:00:88:59:7b:bc:8f:6d:3d:46:4d:a1:0b:40: + ba:7e:13:4e:4f:1d:02:35:e4:5b:30:a0:a8:fc:4d:49:a5:1b: + 11:19:57:25:58:57:03:09:55:56:cb:50:94:54:f9:15:a3:de: + ab:96:0d:b8:98:9d:0f:c7:16:e1:d6:0b:3b:7a:a2:53:07:d2: + 3c:f7:89:62:66:a4:34:39:c9:03:35:2b:a5:27:69:94:7d:56: + dc:72:8c:bc:3a:33:15:86:f8:c3:19:bb:c2:1d:51:3e:a9:1c: + 5c:8b:7a:63:18:1b:78:57:f4:14:be:39:90:38:d1:b6:8d:e1: + 45:63:1e:e1:32:54:3e:52:e9:5d:4d:d5:3c:65:b1:21:e3:00: + 88:f4:28:f7:34:f4:ac:08:54:59:4d:7b:b5:f4:84:d0:66:df: + 98:10:a3:38:bd:2c:e2:fa:87:7c:3f:c8:36:e6:a5:e1:b9:00: + 7d:c0:3a:40:69:b2:df:f9:c0:af:9f:e3:c6:48:a6:b6:69:0f: + e2:9e:36:dd:e8:ee:02:a1:10:1e:78:e6:c6:c3:b4:12:21:2d: + 70:4c:c0:b4 +-----BEGIN CERTIFICATE REQUEST----- +MIICvjCCAaYCAQIwVzELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVRleGFzMQ8wDQYD +VQQHDAZBdXN0aW4xDTALBgNVBAoMBFB5Q0ExGDAWBgNVBAMMD2NyeXB0b2dyYXBo +eS5pbzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM7tGCy4Y/ZlUB7s +fnuGViU+PV2GbprRVrB5t4XJFCNN/xDHaPIAtlc5pl0/7VBnzb3a+2ipD3mpDnkj +YtDRJ5by1ja5bU7WTg8yiJsLkJgxAPouyqyC48NgHI7xvg0evLb3p5tgqkuapQS1 +oKgpCyGvLEAmh3WFPAA4TaT5JY7V1xG03TwnEQwcHIZjNWbWR3NsvQADK0rQkNuM +6LSNKv+QjwvIMu2zI3/OAXQm9oTmU1RERehTIFTsAG1gEyu72v4ZgtumbHL7vibS +nQP9f3KUBk4l0xcSxSvWpeEpPHvX2tqJv6kJQatz+42LP4NL8bsrX8apA+bJCvwK +9ILhS5cCAwEAAaAiMCAGCSqGSIb3DQEJDjETMBEwDwYDKgMEAQH/BAV2YWx1ZTAN +BgkqhkiG9w0BAQUFAAOCAQEALHAPptANcCSolK1LHVBGGXzAqPsBhDs7frBva9mG +gaPUA+nXDPb/xkMAiFl7vI9tPUZNoQtAun4TTk8dAjXkWzCgqPxNSaUbERlXJVhX +AwlVVstQlFT5FaPeq5YNuJidD8cW4dYLO3qiUwfSPPeJYmakNDnJAzUrpSdplH1W +3HKMvDozFYb4wxm7wh1RPqkcXIt6YxgbeFf0FL45kDjRto3hRWMe4TJUPlLpXU3V +PGWxIeMAiPQo9zT0rAhUWU17tfSE0GbfmBCjOL0s4vqHfD/INual4bkAfcA6QGmy +3/nAr5/jxkimtmkP4p423ejuAqEQHnjmxsO0EiEtcEzAtA== +-----END CERTIFICATE REQUEST----- |