diff options
23 files changed, 1166 insertions, 34 deletions
diff --git a/.travis.yml b/.travis.yml index 71efd8ff..c7413ea9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -120,3 +120,5 @@ notifications: - "irc.freenode.org#cryptography-dev" use_notice: true skip_join: true + webhooks: + - https://buildtimetrend.herokuapp.com/travis diff --git a/docs/development/custom-vectors/secp256k1.rst b/docs/development/custom-vectors/secp256k1.rst new file mode 100644 index 00000000..b19bf4e4 --- /dev/null +++ b/docs/development/custom-vectors/secp256k1.rst @@ -0,0 +1,32 @@ +SECP256K1 vector creation +========================= + +This page documents the code that was used to generate the SECP256K1 elliptic +curve test vectors as well as code used to verify them against another +implementation. + + +Creation +-------- + +The vectors are generated using a `pure Python ecdsa`_ implementation. The test +messages and combinations of algorithms are derived from the NIST vector data. + +.. literalinclude:: /development/custom-vectors/secp256k1/generate_secp256k1.py + +Download link: :download:`generate_secp256k1.py +</development/custom-vectors/secp256k1/generate_secp256k1.py>` + + +Verification +------------ + +``cryptography`` was modified to support the SECP256K1 curve. Then +the following python script was run to generate the vector files. + +.. literalinclude:: /development/custom-vectors/secp256k1/verify_secp256k1.py + +Download link: :download:`verify_secp256k1.py +</development/custom-vectors/secp256k1/verify_secp256k1.py>` + +.. _`pure Python ecdsa`: https://pypi.python.org/pypi/ecdsa diff --git a/docs/development/custom-vectors/secp256k1/generate_secp256k1.py b/docs/development/custom-vectors/secp256k1/generate_secp256k1.py new file mode 100644 index 00000000..502a3ff6 --- /dev/null +++ b/docs/development/custom-vectors/secp256k1/generate_secp256k1.py @@ -0,0 +1,89 @@ +from __future__ import absolute_import, print_function + +import hashlib +import os +from binascii import hexlify +from collections import defaultdict + +from ecdsa import SECP256k1, SigningKey +from ecdsa.util import sigdecode_der, sigencode_der + +from cryptography_vectors import open_vector_file + +from tests.utils import ( + load_fips_ecdsa_signing_vectors, load_vectors_from_file +) + +HASHLIB_HASH_TYPES = { + "SHA-1": hashlib.sha1, + "SHA-224": hashlib.sha224, + "SHA-256": hashlib.sha256, + "SHA-384": hashlib.sha384, + "SHA-512": hashlib.sha512, +} + + +class TruncatedHash(object): + def __init__(self, hasher): + self.hasher = hasher + + def __call__(self, data): + self.hasher.update(data) + return self + + def digest(self): + return self.hasher.digest()[:256 // 8] + + +def build_vectors(fips_vectors): + vectors = defaultdict(list) + for vector in fips_vectors: + vectors[vector['digest_algorithm']].append(vector['message']) + + for digest_algorithm, messages in vectors.items(): + if digest_algorithm not in HASHLIB_HASH_TYPES: + continue + + yield "" + yield "[K-256,{0}]".format(digest_algorithm) + yield "" + + for message in messages: + # Make a hash context + hash_func = TruncatedHash(HASHLIB_HASH_TYPES[digest_algorithm]()) + + # Sign the message using warner/ecdsa + secret_key = SigningKey.generate(curve=SECP256k1) + public_key = secret_key.get_verifying_key() + signature = secret_key.sign(message, hashfunc=hash_func, + sigencode=sigencode_der) + + r, s = sigdecode_der(signature, None) + + yield "Msg = {0}".format(hexlify(message)) + yield "d = {0:x}".format(secret_key.privkey.secret_multiplier) + yield "Qx = {0:x}".format(public_key.pubkey.point.x()) + yield "Qy = {0:x}".format(public_key.pubkey.point.y()) + yield "R = {0:x}".format(r) + yield "S = {0:x}".format(s) + yield "" + + +def write_file(lines, dest): + for line in lines: + print(line) + print(line, file=dest) + +source_path = os.path.join("asymmetric", "ECDSA", "FIPS_186-3", "SigGen.txt") +dest_path = os.path.join("asymmetric", "ECDSA", "SECP256K1", "SigGen.txt") + +fips_vectors = load_vectors_from_file( + source_path, + load_fips_ecdsa_signing_vectors +) + +with open_vector_file(dest_path, "w") as dest_file: + write_file( + build_vectors(fips_vectors), + dest_file + ) diff --git a/docs/development/custom-vectors/secp256k1/verify_secp256k1.py b/docs/development/custom-vectors/secp256k1/verify_secp256k1.py new file mode 100644 index 00000000..3d2c25b9 --- /dev/null +++ b/docs/development/custom-vectors/secp256k1/verify_secp256k1.py @@ -0,0 +1,59 @@ +from __future__ import absolute_import, print_function + +import os + +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.asymmetric import ec +from cryptography.hazmat.primitives.asymmetric.utils import ( + encode_rfc6979_signature +) + +from tests.utils import ( + load_fips_ecdsa_signing_vectors, load_vectors_from_file +) + +CRYPTOGRAPHY_HASH_TYPES = { + "SHA-1": hashes.SHA1, + "SHA-224": hashes.SHA224, + "SHA-256": hashes.SHA256, + "SHA-384": hashes.SHA384, + "SHA-512": hashes.SHA512, +} + + +def verify_one_vector(vector): + digest_algorithm = vector['digest_algorithm'] + message = vector['message'] + x = vector['x'] + y = vector['y'] + signature = encode_rfc6979_signature(vector['r'], vector['s']) + + numbers = ec.EllipticCurvePublicNumbers( + x, y, + ec.SECP256K1() + ) + + key = numbers.public_key(default_backend()) + + verifier = key.verifier( + signature, + ec.ECDSA(CRYPTOGRAPHY_HASH_TYPES[digest_algorithm]()) + ) + verifier.update(message) + return verifier.verify() + + +def verify_vectors(vectors): + for vector in vectors: + assert verify_one_vector(vector) + + +vector_path = os.path.join("asymmetric", "ECDSA", "SECP256K1", "SigGen.txt") + +secp256k1_vectors = load_vectors_from_file( + vector_path, + load_fips_ecdsa_signing_vectors +) + +verify_vectors(secp256k1_vectors) diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst index 622a9d70..41531f7b 100644 --- a/docs/development/test-vectors.rst +++ b/docs/development/test-vectors.rst @@ -37,9 +37,14 @@ Asymmetric ciphers Ruby test suite. -Custom Asymmetric Vectors +Custom asymmetric vectors ~~~~~~~~~~~~~~~~~~~~~~~~~ +.. toctree:: + :maxdepth: 1 + + custom-vectors/secp256k1 + * ``asymmetric/PEM_Serialization/ec_private_key.pem`` and ``asymmetric/DER_Serialization/ec_private_key.der`` - Contains an Elliptic Curve key generated by OpenSSL from the curve ``secp256r1``. @@ -78,6 +83,7 @@ Custom Asymmetric Vectors ``asymmetric/public/PKCS1/rsa.pub.der`` are PKCS1 conversions of the public key from ``asymmetric/PKCS8/unenc-rsa-pkcs8.pem`` using PEM and DER encoding. + Key exchange ~~~~~~~~~~~~ @@ -140,6 +146,8 @@ Custom X.509 Vectors subject alternative name extension with the ``registeredID`` general name. * ``all_key_usages.pem`` - An RSA 2048 bit self-signed certificate containing a key usage extension with all nine purposes set to true. +* ``extended_key_usage.pem`` - An RSA 2048 bit self-signed certificate + containing an extended key usage extension with eight usages. * ``san_idna_names.pem`` - An RSA 2048 bit self-signed certificate containing a subject alternative name extension with ``rfc822Name``, ``dNSName``, and ``uniformResourceIdentifier`` general names with IDNA (:rfc:`5895`) encoding. @@ -154,6 +162,23 @@ Custom X.509 Vectors subject alternative name extension with an ``iPAddress`` value. * ``san_dirname.pem`` - An RSA 2048 bit self-signed certificate containing a subject alternative name extension with a ``directoryName`` value. +* ``inhibit_any_policy_5.pem`` - An RSA 2048 bit self-signed certificate + containing an inhibit any policy extension with the value 5. +* ``inhibit_any_policy_negative.pem`` - An RSA 2048 bit self-signed certificate + containing an inhibit any policy extension with the value -1. +* ``authority_key_identifier.pem`` - An RSA 2048 bit self-signed certificate + containing an authority key identifier extension with key identifier, + authority certificate issuer, and authority certificate serial number fields. +* ``authority_key_identifier_no_keyid.pem`` - An RSA 2048 bit self-signed + certificate containing an authority key identifier extension with authority + certificate issuer and authority certificate serial number fields. +* ``aia_ocsp_ca_issuers.pem`` - An RSA 2048 bit self-signed certificate + containing an authority information access extension with two OCSP and one + CA issuers entry. +* ``aia_ocsp.pem`` - An RSA 2048 bit self-signed certificate + containing an authority information access extension with an OCSP entry. +* ``aia_ca_issuers.pem`` - An RSA 2048 bit self-signed certificate + containing an authority information access extension with a CA issuers entry. Custom X.509 Request Vectors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt index b7c4c6c2..badb500c 100644 --- a/docs/spelling_wordlist.txt +++ b/docs/spelling_wordlist.txt @@ -40,6 +40,7 @@ multi naïve namespace namespaces +online paddings pickleable plaintext diff --git a/docs/x509.rst b/docs/x509.rst index 5f36a921..f4ea2a52 100644 --- a/docs/x509.rst +++ b/docs/x509.rst @@ -50,6 +50,42 @@ X.509 -----END CERTIFICATE----- """.strip() + cryptography_cert_pem = b""" + -----BEGIN CERTIFICATE----- + MIIFvTCCBKWgAwIBAgICPyAwDQYJKoZIhvcNAQELBQAwRzELMAkGA1UEBhMCVVMx + FjAUBgNVBAoTDUdlb1RydXN0IEluYy4xIDAeBgNVBAMTF1JhcGlkU1NMIFNIQTI1 + NiBDQSAtIEczMB4XDTE0MTAxNTEyMDkzMloXDTE4MTExNjAxMTUwM1owgZcxEzAR + BgNVBAsTCkdUNDg3NDI5NjUxMTAvBgNVBAsTKFNlZSB3d3cucmFwaWRzc2wuY29t + L3Jlc291cmNlcy9jcHMgKGMpMTQxLzAtBgNVBAsTJkRvbWFpbiBDb250cm9sIFZh + bGlkYXRlZCAtIFJhcGlkU1NMKFIpMRwwGgYDVQQDExN3d3cuY3J5cHRvZ3JhcGh5 + LmlvMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAom/FebKJIot7Sp3s + itG1sicpe3thCssjI+g1JDAS7I3GLVNmbms1DOdIIqwf01gZkzzXBN2+9sOnyRaR + PPfCe1jTr3dk2y6rPE559vPa1nZQkhlzlhMhlPyjaT+S7g4Tio4qV2sCBZU01DZJ + CaksfohN+5BNVWoJzTbOcrHOEJ+M8B484KlBCiSxqf9cyNQKru4W3bHaCVNVJ8eu + 6i6KyhzLa0L7yK3LXwwXVs583C0/vwFhccGWsFODqD/9xHUzsBIshE8HKjdjDi7Y + 3BFQzVUQFjBB50NSZfAA/jcdt1blxJouc7z9T8Oklh+V5DDBowgAsrT4b6Z2Fq6/ + r7D1GqivLK/ypUQmxq2WXWAUBb/Q6xHgxASxI4Br+CByIUQJsm8L2jzc7k+mF4hW + ltAIUkbo8fGiVnat0505YJgxWEDKOLc4Gda6d/7GVd5AvKrz242bUqeaWo6e4MTx + diku2Ma3rhdcr044Qvfh9hGyjqNjvhWY/I+VRWgihU7JrYvgwFdJqsQ5eiKT4OHi + gsejvWwkZzDtiQ+aQTrzM1FsY2swJBJsLSX4ofohlVRlIJCn/ME+XErj553431Lu + YQ5SzMd3nXzN78Vj6qzTfMUUY72UoT1/AcFiUMobgIqrrmwuNxfrkbVE2b6Bga74 + FsJX63prvrJ41kuHK/16RQBM7fcCAwEAAaOCAWAwggFcMB8GA1UdIwQYMBaAFMOc + 8/zTRgg0u85Gf6B8W/PiCMtZMFcGCCsGAQUFBwEBBEswSTAfBggrBgEFBQcwAYYT + aHR0cDovL2d2LnN5bWNkLmNvbTAmBggrBgEFBQcwAoYaaHR0cDovL2d2LnN5bWNi + LmNvbS9ndi5jcnQwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMB + BggrBgEFBQcDAjAvBgNVHREEKDAmghN3d3cuY3J5cHRvZ3JhcGh5Lmlvgg9jcnlw + dG9ncmFwaHkuaW8wKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL2d2LnN5bWNiLmNv + bS9ndi5jcmwwDAYDVR0TAQH/BAIwADBFBgNVHSAEPjA8MDoGCmCGSAGG+EUBBzYw + LDAqBggrBgEFBQcCARYeaHR0cHM6Ly93d3cucmFwaWRzc2wuY29tL2xlZ2FsMA0G + CSqGSIb3DQEBCwUAA4IBAQAzIYO2jx7h17FBT74tJ2zbV9OKqGb7QF8y3wUtP4xc + dH80vprI/Cfji8s86kr77aAvAqjDjaVjHn7UzebhSUivvRPmfzRgyWBacomnXTSt + Xlt2dp2nDQuwGyK2vB7dMfKnQAkxwq1sYUXznB8i0IhhCAoXp01QGPKq51YoIlnF + 7DRMk6iEaL1SJbkIrLsCQyZFDf0xtfW9DqXugMMLoxeCsBhZJQzNyS2ryirrv9LH + aK3+6IZjrcyy9bkpz/gzJucyhU+75c4My/mnRCrtItRbCQuiI5pd5poDowm+HH9i + GVI9+0lAFwxOUnOnwsoI40iOoxjLMGB+CgFLKCGUcWxP + -----END CERTIFICATE----- + """.strip() + X.509 is an ITU-T standard for a `public key infrastructure`_. X.509v3 is defined in :rfc:`5280` (which obsoletes :rfc:`2459` and :rfc:`3280`). X.509 certificates are commonly used in protocols like `TLS`_. @@ -281,6 +317,7 @@ X.509 Certificate Object >>> for ext in cert.extensions: ... print(ext) + <Extension(oid=<ObjectIdentifier(oid=2.5.29.35, name=authorityKeyIdentifier)>, critical=False, value=<AuthorityKeyIdentifier(key_identifier='\xe4}_\xd1\\\x95\x86\x08,\x05\xae\xbeu\xb6e\xa7\xd9]\xa8f', authority_cert_issuer=None, authority_cert_serial_number=None)>)> <Extension(oid=<ObjectIdentifier(oid=2.5.29.14, name=subjectKeyIdentifier)>, critical=False, value=<SubjectKeyIdentifier(digest='X\x01\x84$\x1b\xbc+R\x94J=\xa5\x10r\x14Q\xf5\xaf:\xc9')>)> <Extension(oid=<ObjectIdentifier(oid=2.5.29.15, name=keyUsage)>, critical=True, value=<KeyUsage(digital_signature=False, content_commitment=False, key_encipherment=False, data_encipherment=False, key_agreement=False, key_cert_sign=True, crl_sign=True, encipher_only=None, decipher_only=None)>)> <Extension(oid=<ObjectIdentifier(oid=2.5.29.19, name=basicConstraints)>, critical=True, value=<BasicConstraints(ca=True, path_length=None)>)> @@ -646,10 +683,10 @@ X.509 Extensions certificate. This attribute only has meaning if ``ca`` is true. If ``ca`` is true then a path length of None means there's no restriction on the number of subordinate CAs in the certificate chain. - If it is zero or greater then that number defines the maximum length. - For example, a ``path_length`` of 1 means the certificate can sign a - subordinate CA, but the subordinate CA is not allowed to create - subordinates with ``ca`` set to true. + If it is zero or greater then it defines the maximum length for a + subordinate CA's certificate chain. For example, a ``path_length`` of 1 + means the certificate can sign a subordinate CA, but the subordinate CA + is not allowed to create subordinates with ``ca`` set to true. .. class:: ExtendedKeyUsage @@ -718,6 +755,48 @@ X.509 Extensions :returns: A list of values extracted from the matched general names. + .. doctest:: + + >>> from cryptography import x509 + >>> from cryptography.hazmat.backends import default_backend + >>> from cryptography.hazmat.primitives import hashes + >>> cert = x509.load_pem_x509_certificate(cryptography_cert_pem, default_backend()) + >>> # Get the subjectAltName extension from the certificate + >>> ext = cert.extensions.get_extension_for_oid(x509.OID_SUBJECT_ALTERNATIVE_NAME) + >>> # Get the dNSName entries from the SAN extension + >>> ext.value.get_values_for_type(x509.DNSName) + [u'www.cryptography.io', u'cryptography.io'] + + +.. class:: AuthorityInformationAccess + + .. versionadded:: 0.9 + + The authority information access extension indicates how to access + information and services for the issuer of the certificate in which + the extension appears. Information and services may include online + validation services (such as OCSP) and issuer data. It is an iterable, + containing one or more :class:`AccessDescription` instances. + + +.. class:: AccessDescription + + .. attribute:: access_method + + :type: :class:`ObjectIdentifier` + + The access method defines what the ``access_location`` means. It must + be either :data:`OID_OCSP` or :data:`OID_CA_ISSUERS`. If it is + :data:`OID_OCSP` the access location will be where to obtain OCSP + information for the certificate. If it is :data:`OID_CA_ISSUERS` the + access location will provide additional information about the issuing + certificate. + + .. attribute:: access_location + + :type: :class:`GeneralName` + + Where to access the information defined by the access method. Object Identifiers ~~~~~~~~~~~~~~~~~~ @@ -911,6 +990,19 @@ Extended Key Usage OIDs Corresponds to the dotted string ``"1.3.6.1.5.5.7.3.9"``. This is used to denote that a certificate may be used for signing OCSP responses. +Authority Information Access OIDs +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. data:: OID_OCSP + + Corresponds to the dotted string ``"1.3.6.1.5.5.7.48.1"``. Used as the + identifier for OCSP data in :class:`AccessDescription` objects. + +.. data:: OID_CA_ISSUERS + + Corresponds to the dotted string ``"1.3.6.1.5.5.7.48.2"``. Used as the + identifier for CA issuer data in :class:`AccessDescription` objects. + .. _extension_oids: Extension OIDs diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index 7f633c76..42ca138d 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -15,6 +15,7 @@ from __future__ import absolute_import, division, print_function import datetime import ipaddress +from email.utils import parseaddr import idna @@ -107,6 +108,27 @@ def _build_general_name(backend, gn): return x509.DirectoryName( _build_x509_name(backend, gn.d.directoryName) ) + elif gn.type == backend._lib.GEN_EMAIL: + data = backend._ffi.buffer( + gn.d.rfc822Name.data, gn.d.rfc822Name.length + )[:].decode("ascii") + name, address = parseaddr(data) + parts = address.split(u"@") + if name or len(parts) > 2 or not address: + # parseaddr has found a name (e.g. Name <email>) or the split + # has found more than 2 parts (which means more than one @ sign) + # or the entire value is an empty string. + raise ValueError("Invalid rfc822name value") + elif len(parts) == 1: + # Single label email name. This is valid for local delivery. No + # IDNA decoding can be done since there is no domain component. + return x509.RFC822Name(address) + else: + # A normal email of the form user@domain.com. Let's attempt to + # decode the domain component and return the entire address. + return x509.RFC822Name( + parts[0] + u"@" + idna.decode(parts[1]) + ) else: # otherName, x400Address or ediPartyName raise x509.UnsupportedGeneralNameType( @@ -245,6 +267,12 @@ class _Certificate(object): value = self._build_key_usage(ext) elif oid == x509.OID_SUBJECT_ALTERNATIVE_NAME: value = self._build_subject_alt_name(ext) + elif oid == x509.OID_EXTENDED_KEY_USAGE: + value = self._build_extended_key_usage(ext) + elif oid == x509.OID_AUTHORITY_KEY_IDENTIFIER: + value = self._build_authority_key_identifier(ext) + elif oid == x509.OID_AUTHORITY_INFORMATION_ACCESS: + value = self._build_authority_information_access(ext) elif critical: raise x509.UnsupportedExtension( "{0} is not currently supported".format(oid), oid @@ -297,6 +325,66 @@ class _Certificate(object): self._backend._ffi.buffer(asn1_string.data, asn1_string.length)[:] ) + 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 + ) + 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 = [] + + num = self._backend._lib.sk_GENERAL_NAME_num(akid.issuer) + for i in range(num): + gn = self._backend._lib.sk_GENERAL_NAME_value(akid.issuer, i) + assert gn != self._backend._ffi.NULL + value = _build_general_name(self._backend, gn) + + authority_cert_issuer.append(value) + + if akid.serial != self._backend._ffi.NULL: + bn = self._backend._lib.ASN1_INTEGER_to_BN( + akid.serial, self._backend._ffi.NULL + ) + assert bn != self._backend._ffi.NULL + bn = self._backend._ffi.gc(bn, self._backend._lib.BN_free) + authority_cert_serial_number = self._backend._bn_to_int(bn) + + return x509.AuthorityKeyIdentifier( + key_identifier, authority_cert_issuer, authority_cert_serial_number + ) + + 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 @@ -344,6 +432,24 @@ class _Certificate(object): return x509.SubjectAlternativeName(general_names) + 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) + + return x509.ExtendedKeyUsage(ekus) + @utils.register_interface(x509.CertificateSigningRequest) class _CertificateSigningRequest(object): diff --git a/src/cryptography/hazmat/bindings/openssl/ssl.py b/src/cryptography/hazmat/bindings/openssl/ssl.py index b182180f..6493e867 100644 --- a/src/cryptography/hazmat/bindings/openssl/ssl.py +++ b/src/cryptography/hazmat/bindings/openssl/ssl.py @@ -211,6 +211,9 @@ int SSL_CTX_use_certificate_chain_file(SSL_CTX *, const char *); int SSL_CTX_use_PrivateKey(SSL_CTX *, EVP_PKEY *); int SSL_CTX_use_PrivateKey_file(SSL_CTX *, const char *, int); int SSL_CTX_check_private_key(const SSL_CTX *); +void SSL_CTX_set_cert_verify_callback(SSL_CTX *, + int (*)(X509_STORE_CTX *,void *), + void *); void SSL_CTX_set_cert_store(SSL_CTX *, X509_STORE *); X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *); @@ -322,6 +325,7 @@ void SSL_CTX_set_tlsext_servername_callback( is fraught with peril thanks to OS distributions we check some constants to determine if they are supported or not */ long SSL_set_tlsext_status_ocsp_resp(SSL *, unsigned char *, int); +long SSL_get_tlsext_status_ocsp_resp(SSL *, const unsigned char **); long SSL_CTX_set_tlsext_status_cb(SSL_CTX *, int(*)(SSL *, void *)); long SSL_session_reused(SSL *); @@ -431,6 +435,7 @@ static const long Cryptography_HAS_STATUS_REQ_OCSP_RESP = 1; #else static const long Cryptography_HAS_STATUS_REQ_OCSP_RESP = 0; long (*SSL_set_tlsext_status_ocsp_resp)(SSL *, unsigned char *, int) = NULL; +long (*SSL_get_tlsext_status_ocsp_resp)(SSL *, const unsigned char **) = NULL; #endif #ifdef SSL_MODE_RELEASE_BUFFERS @@ -617,6 +622,7 @@ CONDITIONAL_NAMES = { "Cryptography_HAS_STATUS_REQ_OCSP_RESP": [ "SSL_set_tlsext_status_ocsp_resp", + "SSL_get_tlsext_status_ocsp_resp", ], "Cryptography_HAS_RELEASE_BUFFERS": [ diff --git a/src/cryptography/hazmat/bindings/openssl/x509.py b/src/cryptography/hazmat/bindings/openssl/x509.py index a1fb7ffb..fa6a16b3 100644 --- a/src/cryptography/hazmat/bindings/openssl/x509.py +++ b/src/cryptography/hazmat/bindings/openssl/x509.py @@ -303,6 +303,11 @@ EC_KEY *d2i_EC_PUBKEY_bio(BIO *, EC_KEY **); int i2d_EC_PUBKEY_bio(BIO *, EC_KEY *); EC_KEY *d2i_ECPrivateKey_bio(BIO *, EC_KEY **); int i2d_ECPrivateKey_bio(BIO *, EC_KEY *); + +// declared in safestack +int sk_ASN1_OBJECT_num(Cryptography_STACK_OF_ASN1_OBJECT *); +ASN1_OBJECT *sk_ASN1_OBJECT_value(Cryptography_STACK_OF_ASN1_OBJECT *, int); +void sk_ASN1_OBJECT_free(Cryptography_STACK_OF_ASN1_OBJECT *); """ CUSTOMIZATIONS = """ diff --git a/src/cryptography/hazmat/bindings/openssl/x509v3.py b/src/cryptography/hazmat/bindings/openssl/x509v3.py index 28dd7f32..c2b6860f 100644 --- a/src/cryptography/hazmat/bindings/openssl/x509v3.py +++ b/src/cryptography/hazmat/bindings/openssl/x509v3.py @@ -19,9 +19,12 @@ typedef LHASH_OF(CONF_VALUE) Cryptography_LHASH_OF_CONF_VALUE; #else typedef LHASH Cryptography_LHASH_OF_CONF_VALUE; #endif +typedef STACK_OF(ACCESS_DESCRIPTION) Cryptography_STACK_OF_ACCESS_DESCRIPTION; """ TYPES = """ +typedef ... Cryptography_STACK_OF_ACCESS_DESCRIPTION; + typedef struct { X509 *issuer_cert; X509 *subject_cert; @@ -92,6 +95,11 @@ typedef struct { ASN1_INTEGER *serial; } AUTHORITY_KEYID; +typedef struct { + ASN1_OBJECT *method; + GENERAL_NAME *location; +} ACCESS_DESCRIPTION; + typedef ... Cryptography_LHASH_OF_CONF_VALUE; """ @@ -109,11 +117,20 @@ MACROS = """ /* This is a macro defined by a call to DECLARE_ASN1_FUNCTIONS in the x509v3.h header. */ void BASIC_CONSTRAINTS_free(BASIC_CONSTRAINTS *); +/* This is a macro defined by a call to DECLARE_ASN1_FUNCTIONS in the + x509v3.h header. */ +void AUTHORITY_KEYID_free(AUTHORITY_KEYID *); void *X509V3_set_ctx_nodb(X509V3_CTX *); int sk_GENERAL_NAME_num(struct stack_st_GENERAL_NAME *); int sk_GENERAL_NAME_push(struct stack_st_GENERAL_NAME *, GENERAL_NAME *); GENERAL_NAME *sk_GENERAL_NAME_value(struct stack_st_GENERAL_NAME *, int); +int sk_ACCESS_DESCRIPTION_num(Cryptography_STACK_OF_ACCESS_DESCRIPTION *); +ACCESS_DESCRIPTION *sk_ACCESS_DESCRIPTION_value( + Cryptography_STACK_OF_ACCESS_DESCRIPTION *, int +); +void sk_ACCESS_DESCRIPTION_free(Cryptography_STACK_OF_ACCESS_DESCRIPTION *); + X509_EXTENSION *X509V3_EXT_conf_nid(Cryptography_LHASH_OF_CONF_VALUE *, X509V3_CTX *, int, char *); diff --git a/src/cryptography/hazmat/primitives/kdf/hkdf.py b/src/cryptography/hazmat/primitives/kdf/hkdf.py index 65b7091a..f738bbdc 100644 --- a/src/cryptography/hazmat/primitives/kdf/hkdf.py +++ b/src/cryptography/hazmat/primitives/kdf/hkdf.py @@ -26,7 +26,7 @@ class HKDF(object): self._algorithm = algorithm - if not isinstance(salt, bytes) and salt is not None: + if not (salt is None or isinstance(salt, bytes)): raise TypeError("salt must be bytes.") if salt is None: @@ -77,7 +77,7 @@ class HKDFExpand(object): self._length = length - if not isinstance(info, bytes) and info is not None: + if not (info is None or isinstance(info, bytes)): raise TypeError("info must be bytes.") if info is None: diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py index b22ac8be..0d87cd51 100644 --- a/src/cryptography/x509.py +++ b/src/cryptography/x509.py @@ -67,6 +67,8 @@ _OID_NAMES = { "1.3.6.1.5.5.7.1.1": "authorityInfoAccess", "1.3.6.1.5.5.7.1.11": "subjectInfoAccess", "1.3.6.1.5.5.7.48.1.5": "OCSPNoCheck", + "1.3.6.1.5.5.7.48.1": "OCSP", + "1.3.6.1.5.5.7.48.2": "caIssuers", } @@ -277,11 +279,10 @@ class Extension(object): class ExtendedKeyUsage(object): def __init__(self, usages): - for oid in usages: - if not isinstance(oid, ObjectIdentifier): - raise TypeError( - "Every item in the usages list must be an ObjectIdentifier" - ) + if not all(isinstance(x, ObjectIdentifier) for x in usages): + raise TypeError( + "Every item in the usages list must be an ObjectIdentifier" + ) self._usages = usages @@ -294,6 +295,15 @@ class ExtendedKeyUsage(object): def __repr__(self): return "<ExtendedKeyUsage({0})>".format(self._usages) + def __eq__(self, other): + if not isinstance(other, ExtendedKeyUsage): + return NotImplemented + + return self._usages == other._usages + + def __ne__(self, other): + return not self == other + class BasicConstraints(object): def __init__(self, ca, path_length): @@ -386,6 +396,70 @@ class KeyUsage(object): self, encipher_only, decipher_only) +class AuthorityInformationAccess(object): + def __init__(self, descriptions): + if not all(isinstance(x, AccessDescription) for x in descriptions): + raise TypeError( + "Every item in the descriptions list must be an " + "AccessDescription" + ) + + self._descriptions = descriptions + + def __iter__(self): + return iter(self._descriptions) + + def __len__(self): + return len(self._descriptions) + + def __repr__(self): + return "<AuthorityInformationAccess({0})>".format(self._descriptions) + + def __eq__(self, other): + if not isinstance(other, AuthorityInformationAccess): + return NotImplemented + + return self._descriptions == other._descriptions + + def __ne__(self, other): + return not self == other + + +class AccessDescription(object): + def __init__(self, access_method, access_location): + if not (access_method == OID_OCSP or access_method == OID_CA_ISSUERS): + raise ValueError( + "access_method must be OID_OCSP or OID_CA_ISSUERS" + ) + + if not isinstance(access_location, GeneralName): + raise TypeError("access_location must be a GeneralName") + + self._access_method = access_method + self._access_location = access_location + + def __repr__(self): + return ( + "<AccessDescription(access_method={0.access_method}, access_locati" + "on={0.access_location})>".format(self) + ) + + def __eq__(self, other): + if not isinstance(other, AccessDescription): + return NotImplemented + + return ( + self.access_method == other.access_method and + self.access_location == other.access_location + ) + + def __ne__(self, other): + return not self == other + + access_method = utils.read_only_property("_access_method") + access_location = utils.read_only_property("_access_location") + + class SubjectKeyIdentifier(object): def __init__(self, digest): self._digest = digest @@ -592,8 +666,13 @@ class AuthorityKeyIdentifier(object): "must both be present or both None" ) - if not isinstance(authority_cert_issuer, Name): - raise TypeError("authority_cert_issuer must be a Name") + if not all( + isinstance(x, GeneralName) for x in authority_cert_issuer + ): + raise TypeError( + "authority_cert_issuer must be a list of GeneralName " + "objects" + ) if not isinstance(authority_cert_serial_number, six.integer_types): raise TypeError( @@ -672,6 +751,9 @@ OID_EMAIL_PROTECTION = ObjectIdentifier("1.3.6.1.5.5.7.3.4") OID_TIME_STAMPING = ObjectIdentifier("1.3.6.1.5.5.7.3.8") OID_OCSP_SIGNING = ObjectIdentifier("1.3.6.1.5.5.7.3.9") +OID_CA_ISSUERS = ObjectIdentifier("1.3.6.1.5.5.7.48.2") +OID_OCSP = ObjectIdentifier("1.3.6.1.5.5.7.48.1") + @six.add_metaclass(abc.ABCMeta) class Certificate(object): diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py index d38fe573..8a227953 100644 --- a/tests/test_x509_ext.py +++ b/tests/test_x509_ext.py @@ -221,29 +221,33 @@ class TestSubjectKeyIdentifier(object): class TestAuthorityKeyIdentifier(object): - def test_authority_cert_issuer_not_name(self): + def test_authority_cert_issuer_not_generalname(self): with pytest.raises(TypeError): - x509.AuthorityKeyIdentifier(b"identifier", "notname", 3) + x509.AuthorityKeyIdentifier(b"identifier", ["notname"], 3) def test_authority_cert_serial_number_not_integer(self): - name = x509.Name([ - x509.NameAttribute(x509.ObjectIdentifier('oid'), 'value1'), - x509.NameAttribute(x509.ObjectIdentifier('oid2'), 'value2'), - ]) + dirname = x509.DirectoryName( + x509.Name([ + x509.NameAttribute(x509.ObjectIdentifier('oid'), 'value1'), + x509.NameAttribute(x509.ObjectIdentifier('oid2'), 'value2'), + ]) + ) with pytest.raises(TypeError): - x509.AuthorityKeyIdentifier(b"identifier", name, "notanint") + x509.AuthorityKeyIdentifier(b"identifier", [dirname], "notanint") def test_authority_issuer_none_serial_not_none(self): with pytest.raises(ValueError): x509.AuthorityKeyIdentifier(b"identifier", None, 3) def test_authority_issuer_not_none_serial_none(self): - name = x509.Name([ - x509.NameAttribute(x509.ObjectIdentifier('oid'), 'value1'), - x509.NameAttribute(x509.ObjectIdentifier('oid2'), 'value2'), - ]) + dirname = x509.DirectoryName( + x509.Name([ + x509.NameAttribute(x509.ObjectIdentifier('oid'), 'value1'), + x509.NameAttribute(x509.ObjectIdentifier('oid2'), 'value2'), + ]) + ) with pytest.raises(ValueError): - x509.AuthorityKeyIdentifier(b"identifier", name, None) + x509.AuthorityKeyIdentifier(b"identifier", [dirname], None) def test_authority_cert_serial_and_issuer_none(self): aki = x509.AuthorityKeyIdentifier(b"id", None, None) @@ -252,22 +256,24 @@ class TestAuthorityKeyIdentifier(object): assert aki.authority_cert_serial_number is None def test_repr(self): - name = x509.Name([x509.NameAttribute(x509.OID_COMMON_NAME, 'myCN')]) - aki = x509.AuthorityKeyIdentifier(b"digest", name, 1234) + dirname = x509.DirectoryName( + x509.Name([x509.NameAttribute(x509.OID_COMMON_NAME, 'myCN')]) + ) + aki = x509.AuthorityKeyIdentifier(b"digest", [dirname], 1234) if six.PY3: assert repr(aki) == ( "<AuthorityKeyIdentifier(key_identifier=b'digest', authority_" - "cert_issuer=<Name([<NameAttribute(oid=<ObjectIdentifier(oid=" - "2.5.4.3, name=commonName)>, value='myCN')>])>, authority_cer" - "t_serial_number=1234)>" + "cert_issuer=[<DirectoryName(value=<Name([<NameAttribute(oid=" + "<ObjectIdentifier(oid=2.5.4.3, name=commonName)>, value='myC" + "N')>])>)>], authority_cert_serial_number=1234)>" ) else: assert repr(aki) == ( "<AuthorityKeyIdentifier(key_identifier='digest', authority_ce" - "rt_issuer=<Name([<NameAttribute(oid=<ObjectIdentifier(oid=2.5" - ".4.3, name=commonName)>, value='myCN')>])>, authority_cert_se" - "rial_number=1234)>" + "rt_issuer=[<DirectoryName(value=<Name([<NameAttribute(oid=<Ob" + "jectIdentifier(oid=2.5.4.3, name=commonName)>, value='myCN')>" + "])>)>], authority_cert_serial_number=1234)>" ) @@ -325,6 +331,21 @@ class TestExtendedKeyUsage(object): "tAuth)>])>" ) + def test_eq(self): + eku = x509.ExtendedKeyUsage([ + x509.ObjectIdentifier("1.3.6"), x509.ObjectIdentifier("1.3.7") + ]) + eku2 = x509.ExtendedKeyUsage([ + x509.ObjectIdentifier("1.3.6"), x509.ObjectIdentifier("1.3.7") + ]) + assert eku == eku2 + + def test_ne(self): + eku = x509.ExtendedKeyUsage([x509.ObjectIdentifier("1.3.6")]) + eku2 = x509.ExtendedKeyUsage([x509.ObjectIdentifier("1.3.6.1")]) + assert eku != eku2 + assert eku != object() + @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) @@ -856,3 +877,444 @@ class TestRSASubjectAlternativeNameExtension(object): x509.NameAttribute(x509.OID_STATE_OR_PROVINCE_NAME, 'Texas'), ]) ] == dirname + + def test_rfc822name(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "san_rfc822_idna.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + x509.OID_SUBJECT_ALTERNATIVE_NAME + ) + assert ext is not None + assert ext.critical is False + + san = ext.value + + rfc822name = san.get_values_for_type(x509.RFC822Name) + assert [u"email@em\xe5\xefl.com"] == rfc822name + + def test_unicode_rfc822_name_dns_name_uri(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "san_idna_names.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + x509.OID_SUBJECT_ALTERNATIVE_NAME + ) + assert ext is not None + rfc822_name = ext.value.get_values_for_type(x509.RFC822Name) + dns_name = ext.value.get_values_for_type(x509.DNSName) + uri = ext.value.get_values_for_type(x509.UniformResourceIdentifier) + assert rfc822_name == [u"email@\u043f\u044b\u043a\u0430.cryptography"] + assert dns_name == [u"\u043f\u044b\u043a\u0430.cryptography"] + assert uri == [u"https://www.\u043f\u044b\u043a\u0430.cryptography"] + + def test_rfc822name_dnsname_ipaddress_directoryname_uri(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "san_email_dns_ip_dirname_uri.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + x509.OID_SUBJECT_ALTERNATIVE_NAME + ) + assert ext is not None + assert ext.critical is False + + san = ext.value + + rfc822_name = san.get_values_for_type(x509.RFC822Name) + uri = san.get_values_for_type(x509.UniformResourceIdentifier) + dns = san.get_values_for_type(x509.DNSName) + ip = san.get_values_for_type(x509.IPAddress) + dirname = san.get_values_for_type(x509.DirectoryName) + assert [u"user@cryptography.io"] == rfc822_name + assert [u"https://cryptography.io"] == uri + assert [u"cryptography.io"] == dns + assert [ + x509.Name([ + x509.NameAttribute(x509.OID_COMMON_NAME, 'dirCN'), + x509.NameAttribute( + x509.OID_ORGANIZATION_NAME, 'Cryptographic Authority' + ), + ]) + ] == dirname + assert [ + ipaddress.ip_address(u"127.0.0.1"), + ipaddress.ip_address(u"ff::") + ] == ip + + def test_invalid_rfc822name(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "san_rfc822_names.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + with pytest.raises(ValueError) as exc: + cert.extensions + + assert 'Invalid rfc822name value' in str(exc.value) + + +@pytest.mark.requires_backend_interface(interface=RSABackend) +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestExtendedKeyUsageExtension(object): + def test_eku(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "extended_key_usage.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + x509.OID_EXTENDED_KEY_USAGE + ) + assert ext is not None + assert ext.critical is False + + assert [ + x509.ObjectIdentifier("1.3.6.1.5.5.7.3.1"), + x509.ObjectIdentifier("1.3.6.1.5.5.7.3.2"), + x509.ObjectIdentifier("1.3.6.1.5.5.7.3.3"), + x509.ObjectIdentifier("1.3.6.1.5.5.7.3.4"), + x509.ObjectIdentifier("1.3.6.1.5.5.7.3.9"), + x509.ObjectIdentifier("1.3.6.1.5.5.7.3.8"), + x509.ObjectIdentifier("2.5.29.37.0"), + x509.ObjectIdentifier("2.16.840.1.113730.4.1"), + ] == list(ext.value) + + +class TestAccessDescription(object): + def test_invalid_access_method(self): + with pytest.raises(ValueError): + x509.AccessDescription("notanoid", x509.DNSName(u"test")) + + def test_invalid_access_location(self): + with pytest.raises(TypeError): + x509.AccessDescription(x509.OID_CA_ISSUERS, "invalid") + + def test_repr(self): + ad = x509.AccessDescription( + x509.OID_OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ) + assert repr(ad) == ( + "<AccessDescription(access_method=<ObjectIdentifier(oid=1.3.6.1.5." + "5.7.48.1, name=OCSP)>, access_location=<UniformResourceIdentifier" + "(value=http://ocsp.domain.com)>)>" + ) + + def test_eq(self): + ad = x509.AccessDescription( + x509.OID_OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ) + ad2 = x509.AccessDescription( + x509.OID_OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ) + assert ad == ad2 + + def test_ne(self): + ad = x509.AccessDescription( + x509.OID_OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ) + ad2 = x509.AccessDescription( + x509.OID_CA_ISSUERS, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ) + ad3 = x509.AccessDescription( + x509.OID_OCSP, + x509.UniformResourceIdentifier(u"http://notthesame") + ) + assert ad != ad2 + assert ad != ad3 + assert ad != object() + + +class TestAuthorityInformationAccess(object): + def test_invalid_descriptions(self): + with pytest.raises(TypeError): + x509.AuthorityInformationAccess(["notanAccessDescription"]) + + def test_iter_len(self): + aia = x509.AuthorityInformationAccess([ + x509.AccessDescription( + x509.OID_OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ), + x509.AccessDescription( + x509.OID_CA_ISSUERS, + x509.UniformResourceIdentifier(u"http://domain.com/ca.crt") + ) + ]) + assert len(aia) == 2 + assert list(aia) == [ + x509.AccessDescription( + x509.OID_OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ), + x509.AccessDescription( + x509.OID_CA_ISSUERS, + x509.UniformResourceIdentifier(u"http://domain.com/ca.crt") + ) + ] + + def test_repr(self): + aia = x509.AuthorityInformationAccess([ + x509.AccessDescription( + x509.OID_OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ), + x509.AccessDescription( + x509.OID_CA_ISSUERS, + x509.UniformResourceIdentifier(u"http://domain.com/ca.crt") + ) + ]) + assert repr(aia) == ( + "<AuthorityInformationAccess([<AccessDescription(access_method=<Ob" + "jectIdentifier(oid=1.3.6.1.5.5.7.48.1, name=OCSP)>, access_locati" + "on=<UniformResourceIdentifier(value=http://ocsp.domain.com)>)>, <" + "AccessDescription(access_method=<ObjectIdentifier(oid=1.3.6.1.5.5" + ".7.48.2, name=caIssuers)>, access_location=<UniformResourceIdenti" + "fier(value=http://domain.com/ca.crt)>)>])>" + ) + + def test_eq(self): + aia = x509.AuthorityInformationAccess([ + x509.AccessDescription( + x509.OID_OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ), + x509.AccessDescription( + x509.OID_CA_ISSUERS, + x509.UniformResourceIdentifier(u"http://domain.com/ca.crt") + ) + ]) + aia2 = x509.AuthorityInformationAccess([ + x509.AccessDescription( + x509.OID_OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ), + x509.AccessDescription( + x509.OID_CA_ISSUERS, + x509.UniformResourceIdentifier(u"http://domain.com/ca.crt") + ) + ]) + assert aia == aia2 + + def test_ne(self): + aia = x509.AuthorityInformationAccess([ + x509.AccessDescription( + x509.OID_OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ), + x509.AccessDescription( + x509.OID_CA_ISSUERS, + x509.UniformResourceIdentifier(u"http://domain.com/ca.crt") + ) + ]) + aia2 = x509.AuthorityInformationAccess([ + x509.AccessDescription( + x509.OID_OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ), + ]) + + assert aia != aia2 + assert aia != object() + + +@pytest.mark.requires_backend_interface(interface=RSABackend) +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestAuthorityInformationAccessExtension(object): + def test_aia_ocsp_ca_issuers(self, backend): + cert = _load_cert( + os.path.join("x509", "cryptography.io.pem"), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + x509.OID_AUTHORITY_INFORMATION_ACCESS + ) + assert ext is not None + assert ext.critical is False + + assert ext.value == x509.AuthorityInformationAccess([ + x509.AccessDescription( + x509.OID_OCSP, + x509.UniformResourceIdentifier(u"http://gv.symcd.com") + ), + x509.AccessDescription( + x509.OID_CA_ISSUERS, + x509.UniformResourceIdentifier(u"http://gv.symcb.com/gv.crt") + ), + ]) + + def test_aia_multiple_ocsp_ca_issuers(self, backend): + cert = _load_cert( + os.path.join("x509", "custom", "aia_ocsp_ca_issuers.pem"), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + x509.OID_AUTHORITY_INFORMATION_ACCESS + ) + assert ext is not None + assert ext.critical is False + + assert ext.value == x509.AuthorityInformationAccess([ + x509.AccessDescription( + x509.OID_OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ), + x509.AccessDescription( + x509.OID_OCSP, + x509.UniformResourceIdentifier(u"http://ocsp2.domain.com") + ), + x509.AccessDescription( + x509.OID_CA_ISSUERS, + x509.DirectoryName(x509.Name([ + x509.NameAttribute(x509.OID_COMMON_NAME, "myCN"), + x509.NameAttribute(x509.OID_ORGANIZATION_NAME, "some Org"), + ])) + ), + ]) + + def test_aia_ocsp_only(self, backend): + cert = _load_cert( + os.path.join("x509", "custom", "aia_ocsp.pem"), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + x509.OID_AUTHORITY_INFORMATION_ACCESS + ) + assert ext is not None + assert ext.critical is False + + assert ext.value == x509.AuthorityInformationAccess([ + x509.AccessDescription( + x509.OID_OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ), + ]) + + def test_aia_ca_issuers_only(self, backend): + cert = _load_cert( + os.path.join("x509", "custom", "aia_ca_issuers.pem"), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + x509.OID_AUTHORITY_INFORMATION_ACCESS + ) + assert ext is not None + assert ext.critical is False + + assert ext.value == x509.AuthorityInformationAccess([ + x509.AccessDescription( + x509.OID_CA_ISSUERS, + x509.DirectoryName(x509.Name([ + x509.NameAttribute(x509.OID_COMMON_NAME, "myCN"), + x509.NameAttribute(x509.OID_ORGANIZATION_NAME, "some Org"), + ])) + ), + ]) + + +@pytest.mark.requires_backend_interface(interface=RSABackend) +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestAuthorityKeyIdentifierExtension(object): + def test_aki_keyid(self, backend): + cert = _load_cert( + os.path.join( + "x509", "cryptography.io.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + x509.OID_AUTHORITY_KEY_IDENTIFIER + ) + assert ext is not None + assert ext.critical is False + + assert ext.value.key_identifier == ( + b"\xc3\x9c\xf3\xfc\xd3F\x084\xbb\xceF\x7f\xa0|[\xf3\xe2\x08\xcbY" + ) + assert ext.value.authority_cert_issuer is None + assert ext.value.authority_cert_serial_number is None + + def test_aki_all_fields(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "authority_key_identifier.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + x509.OID_AUTHORITY_KEY_IDENTIFIER + ) + assert ext is not None + assert ext.critical is False + + assert ext.value.key_identifier == ( + b"9E>\xca=b\x1d\xea\x86I\xf6Z\xab@\xb7\xa4p\x98\xf1\xec" + ) + assert ext.value.authority_cert_issuer == [ + x509.DirectoryName( + x509.Name([ + x509.NameAttribute( + x509.OID_ORGANIZATION_NAME, u"PyCA" + ), + x509.NameAttribute( + x509.OID_COMMON_NAME, u"cryptography.io" + ) + ]) + ) + ] + assert ext.value.authority_cert_serial_number == 3 + + def test_aki_no_keyid(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "authority_key_identifier_no_keyid.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + x509.OID_AUTHORITY_KEY_IDENTIFIER + ) + assert ext is not None + assert ext.critical is False + + assert ext.value.key_identifier is None + assert ext.value.authority_cert_issuer == [ + x509.DirectoryName( + x509.Name([ + x509.NameAttribute( + x509.OID_ORGANIZATION_NAME, u"PyCA" + ), + x509.NameAttribute( + x509.OID_COMMON_NAME, u"cryptography.io" + ) + ]) + ) + ] + assert ext.value.authority_cert_serial_number == 3 diff --git a/tests/utils.py b/tests/utils.py index 4c74ca7c..ab922c94 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -498,6 +498,7 @@ _ECDSA_CURVE_NAMES = { "K-163": "sect163k1", "K-233": "sect233k1", + "K-256": "secp256k1", "K-283": "sect283k1", "K-409": "sect409k1", "K-571": "sect571k1", diff --git a/vectors/cryptography_vectors/x509/custom/aia_ca_issuers.pem b/vectors/cryptography_vectors/x509/custom/aia_ca_issuers.pem new file mode 100644 index 00000000..8e7d6233 --- /dev/null +++ b/vectors/cryptography_vectors/x509/custom/aia_ca_issuers.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDIzCCAgugAwIBAgITBmpzihaCgW4OeroV/vOMmWeoVTANBgkqhkiG9w0BAQUF +ADApMQ0wCwYDVQQKDARQeUNBMRgwFgYDVQQDDA9jcnlwdG9ncmFwaHkuaW8wHhcN +MTUwNTA0MTYwMTM1WhcNMTYwNTAzMTYwMTM1WjApMQ0wCwYDVQQKDARQeUNBMRgw +FgYDVQQDDA9jcnlwdG9ncmFwaHkuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDCadi1UZioxdnPajqlRZHeKsSxvXXhgrWvlt91P3gV0dBThRFhJsLO +hjNLz6PO6KeRbjz9GhTA2hdkxtIpXrjvTv9dEJ1/k0xebsHWgFC43aTlgekw0U4c +MwMe5NGeeg1tfzbJwldIN+cKvabc08ADlkmM6DMnUArkzA2yii0DErRFMSIGrkDr +6E9puord3h6Mh8Jfnc3TDAq8Qo1DI2XM7oFSWNfecQ9KbIC5wzzT+7Shoyz7QmCk +/XhRzt8Xcfc3yAXIwazvLf8bYP1auaSG11a5E+w6onj91h8UHKKOXu+rdq5YYPZ+ +qUYpxA7ZJ/VAGadMulYbXaO8Syi39HTpAgMBAAGjRDBCMEAGCCsGAQUFBwEBBDQw +MjAwBggrBgEFBQcwAqQkMCIxDTALBgNVBAMMBG15Q04xETAPBgNVBAoMCHNvbWUg +T3JnMA0GCSqGSIb3DQEBBQUAA4IBAQA77ax7iuD6Ood7lCfqGkUAHnZCTRBTaIBf +Ob8fDYdXWe7nr3dAq+M14GNMIvBURixL8xnb+AameJdGzzxEIkmzYpJmeVM+UCHJ +oOO2Q2JuHOvULOxQjrYdwBsb9jgiwWGuAfFA2nV+zO1/zjQ0meOL7p98ulaDbZKi +JMMNtKA2P3XnSeKXBN0HSKUk0DCpIeEpMNx3KOpzx1QtVkXUDeAXb8R+CPWHkKAp +9v5lV/Q2UG39/Mb1QdlNksoVkti0/wIXFUQy2z1ZwfP2Ty/gloZqYVaXcD3qFHea +XtzbzmYSHqRUVug3+yg1n6qBDl6YblHwr9EwtPAreMzk6FEjjwVE +-----END CERTIFICATE----- diff --git a/vectors/cryptography_vectors/x509/custom/aia_ocsp.pem b/vectors/cryptography_vectors/x509/custom/aia_ocsp.pem new file mode 100644 index 00000000..9bdb5d1a --- /dev/null +++ b/vectors/cryptography_vectors/x509/custom/aia_ocsp.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDFTCCAf2gAwIBAgITBmpzjEDbt6vFUmUSgFfQY90MnjANBgkqhkiG9w0BAQUF +ADApMQ0wCwYDVQQKDARQeUNBMRgwFgYDVQQDDA9jcnlwdG9ncmFwaHkuaW8wHhcN +MTUwNTA0MTYwMjA0WhcNMTYwNTAzMTYwMjA0WjApMQ0wCwYDVQQKDARQeUNBMRgw +FgYDVQQDDA9jcnlwdG9ncmFwaHkuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDCadi1UZioxdnPajqlRZHeKsSxvXXhgrWvlt91P3gV0dBThRFhJsLO +hjNLz6PO6KeRbjz9GhTA2hdkxtIpXrjvTv9dEJ1/k0xebsHWgFC43aTlgekw0U4c +MwMe5NGeeg1tfzbJwldIN+cKvabc08ADlkmM6DMnUArkzA2yii0DErRFMSIGrkDr +6E9puord3h6Mh8Jfnc3TDAq8Qo1DI2XM7oFSWNfecQ9KbIC5wzzT+7Shoyz7QmCk +/XhRzt8Xcfc3yAXIwazvLf8bYP1auaSG11a5E+w6onj91h8UHKKOXu+rdq5YYPZ+ +qUYpxA7ZJ/VAGadMulYbXaO8Syi39HTpAgMBAAGjNjA0MDIGCCsGAQUFBwEBBCYw +JDAiBggrBgEFBQcwAYYWaHR0cDovL29jc3AuZG9tYWluLmNvbTANBgkqhkiG9w0B +AQUFAAOCAQEAN3+EuDWKytFLzHO21aZHCQOSZhXLf+Vv9epdI9mgLUkZ712ntkjY +obJVQ5YK9viAutiRArTyEHRT2YMPYV7gaBof5bxKmrSflUNKmPMd9U6zDU2BDuRe +mLOo9S0wIh0Qfm1mhD27waKy/HhjZ3nkeORICmej3GWIK8mo+fL0LiDKTeoZdQ4B +ENWj+xMOcaOlhBeq9NBNawPR/YihAID/m/em5kvq4dMoVpASNPpK/gTQb7wGHSh9 +59TUBUyS6ilmYrku4y+kdDG4uommrgGkqbX/xixug623GnGvGQKvPeZ0CoyKTzgQ +6145cQvWl04a7TQqqgCCFQexn3O+kvJVJA== +-----END CERTIFICATE----- diff --git a/vectors/cryptography_vectors/x509/custom/aia_ocsp_ca_issuers.pem b/vectors/cryptography_vectors/x509/custom/aia_ocsp_ca_issuers.pem new file mode 100644 index 00000000..1a2b5a23 --- /dev/null +++ b/vectors/cryptography_vectors/x509/custom/aia_ocsp_ca_issuers.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDbzCCAlegAwIBAgITBmpzhaASIzPUgqgz8AKBt68y2zANBgkqhkiG9w0BAQUF +ADApMQ0wCwYDVQQKDARQeUNBMRgwFgYDVQQDDA9jcnlwdG9ncmFwaHkuaW8wHhcN +MTUwNTA0MTYwMDM1WhcNMTYwNTAzMTYwMDM1WjApMQ0wCwYDVQQKDARQeUNBMRgw +FgYDVQQDDA9jcnlwdG9ncmFwaHkuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDCadi1UZioxdnPajqlRZHeKsSxvXXhgrWvlt91P3gV0dBThRFhJsLO +hjNLz6PO6KeRbjz9GhTA2hdkxtIpXrjvTv9dEJ1/k0xebsHWgFC43aTlgekw0U4c +MwMe5NGeeg1tfzbJwldIN+cKvabc08ADlkmM6DMnUArkzA2yii0DErRFMSIGrkDr +6E9puord3h6Mh8Jfnc3TDAq8Qo1DI2XM7oFSWNfecQ9KbIC5wzzT+7Shoyz7QmCk +/XhRzt8Xcfc3yAXIwazvLf8bYP1auaSG11a5E+w6onj91h8UHKKOXu+rdq5YYPZ+ +qUYpxA7ZJ/VAGadMulYbXaO8Syi39HTpAgMBAAGjgY8wgYwwgYkGCCsGAQUFBwEB +BH0wezAiBggrBgEFBQcwAYYWaHR0cDovL29jc3AuZG9tYWluLmNvbTAjBggrBgEF +BQcwAYYXaHR0cDovL29jc3AyLmRvbWFpbi5jb20wMAYIKwYBBQUHMAKkJDAiMQ0w +CwYDVQQDDARteUNOMREwDwYDVQQKDAhzb21lIE9yZzANBgkqhkiG9w0BAQUFAAOC +AQEAG6t7q/a5SzRhXSjl29eK+psDadkm4tS1LC2aVuNexO2ZggK/0n3wkCa7M0jZ +90DRTWeClBekhx5U0jDNAbzOlb64pnwAxoj+Vw3O5Jn6LoF2il5kpQMcvLII1bh9 +V6iXgEDRZxlAPoVkSMN4bGUKLRmKK0MGWTniw/2eSPOr6wqbzgXytPrPjOVP1XYF +njasNI/LdXZBxe7AmlNziYMMBt1fII0c6W3PXgTHmGbHAocz+rbWI0ENax8YmKKd +k99fYtY2675va+a9CVXR2Cr3B86OwltAqvW6iVZP0qF+A+QqrAaZOghCwATu/6Ho +8OrvFjYaK5wyyBzvUbAs9L7mqg== +-----END CERTIFICATE----- diff --git a/vectors/cryptography_vectors/x509/custom/authority_key_identifier.pem b/vectors/cryptography_vectors/x509/custom/authority_key_identifier.pem new file mode 100644 index 00000000..cbe9169f --- /dev/null +++ b/vectors/cryptography_vectors/x509/custom/authority_key_identifier.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDIjCCAgqgAwIBAgIBAzANBgkqhkiG9w0BAQUFADApMQ0wCwYDVQQKDARQeUNB +MRgwFgYDVQQDDA9jcnlwdG9ncmFwaHkuaW8wHhcNMTUwNTAzMDk0OTU2WhcNMTYw +NTAyMDk0OTU2WjApMQ0wCwYDVQQKDARQeUNBMRgwFgYDVQQDDA9jcnlwdG9ncmFw +aHkuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCadi1UZioxdnP +ajqlRZHeKsSxvXXhgrWvlt91P3gV0dBThRFhJsLOhjNLz6PO6KeRbjz9GhTA2hdk +xtIpXrjvTv9dEJ1/k0xebsHWgFC43aTlgekw0U4cMwMe5NGeeg1tfzbJwldIN+cK +vabc08ADlkmM6DMnUArkzA2yii0DErRFMSIGrkDr6E9puord3h6Mh8Jfnc3TDAq8 +Qo1DI2XM7oFSWNfecQ9KbIC5wzzT+7Shoyz7QmCk/XhRzt8Xcfc3yAXIwazvLf8b +YP1auaSG11a5E+w6onj91h8UHKKOXu+rdq5YYPZ+qUYpxA7ZJ/VAGadMulYbXaO8 +Syi39HTpAgMBAAGjVTBTMFEGA1UdIwRKMEiAFDlFPso9Yh3qhkn2WqtAt6RwmPHs +oS2kKzApMQ0wCwYDVQQKDARQeUNBMRgwFgYDVQQDDA9jcnlwdG9ncmFwaHkuaW+C +AQMwDQYJKoZIhvcNAQEFBQADggEBAFbZYy6aZJUK/f7nJx2Rs/ht6hMbM32/RoXZ +JGbYapNVqVu/vymcfc/se3FHS5OVmPsnRlo/FIKDn/r5DGl73Sn/FvDJiLJZFucT +msyYuHZ+ZRYWzWmN2fcB3cfxj0s3qps6f5OoCOqoINOSe4HRGlw4X9keZSD+3xAt +vHNwQdlPC7zWbPdrzLT+FqR0e/O81vFJJS6drHJWqPcR3NQVtZw+UF7A/HKwbfeL +Nu2zj6165hzOi9HUxa2/mPr/eLUUV1sTzXp2+TFjt3rVCjW1XnpMLdwNBHzjpyAB +dTOX3iw0+BPy3s2jtnCW1PLpc74kvSTaBwhg74sq39EXfIKax00= +-----END CERTIFICATE----- diff --git a/vectors/cryptography_vectors/x509/custom/authority_key_identifier_no_keyid.pem b/vectors/cryptography_vectors/x509/custom/authority_key_identifier_no_keyid.pem new file mode 100644 index 00000000..fffcc653 --- /dev/null +++ b/vectors/cryptography_vectors/x509/custom/authority_key_identifier_no_keyid.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDDDCCAfSgAwIBAgIBAzANBgkqhkiG9w0BAQUFADApMQ0wCwYDVQQKDARQeUNB +MRgwFgYDVQQDDA9jcnlwdG9ncmFwaHkuaW8wHhcNMTUwNTAzMTAxNTU2WhcNMTYw +NTAyMTAxNTU2WjApMQ0wCwYDVQQKDARQeUNBMRgwFgYDVQQDDA9jcnlwdG9ncmFw +aHkuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCadi1UZioxdnP +ajqlRZHeKsSxvXXhgrWvlt91P3gV0dBThRFhJsLOhjNLz6PO6KeRbjz9GhTA2hdk +xtIpXrjvTv9dEJ1/k0xebsHWgFC43aTlgekw0U4cMwMe5NGeeg1tfzbJwldIN+cK +vabc08ADlkmM6DMnUArkzA2yii0DErRFMSIGrkDr6E9puord3h6Mh8Jfnc3TDAq8 +Qo1DI2XM7oFSWNfecQ9KbIC5wzzT+7Shoyz7QmCk/XhRzt8Xcfc3yAXIwazvLf8b +YP1auaSG11a5E+w6onj91h8UHKKOXu+rdq5YYPZ+qUYpxA7ZJ/VAGadMulYbXaO8 +Syi39HTpAgMBAAGjPzA9MDsGA1UdIwQ0MDKhLaQrMCkxDTALBgNVBAoMBFB5Q0Ex +GDAWBgNVBAMMD2NyeXB0b2dyYXBoeS5pb4IBAzANBgkqhkiG9w0BAQUFAAOCAQEA +AViX0VIVQW2xyf0lfLiuFhrpdgX9i49StZvs+n/qH5yvWxfqRJAyVT1pk2Xs0Goj +ul7vYMfIGU0nIr8eLMlAH9j6lkllAd/oO1BDONZ1kH6PMdkOdvgz5gmhMQx6MFr6 +zMzzQ+JOAnXKFFUEycOiRJyh3VXiTY1M1IG1kWY+LoqB72S7y9c25yFoHqUNi2Xf +rbuaR7gNS/4z7XvLJkbNbVS2+y69gQGL+8vk5AG7MiZ1mzUQ44r/zy6HNDBb55kK +H+YTYavijRApH5hccJBXyoIM0x9ZtKdcrV0h+J2KOFGEyHp3FXViFEB2IZUpJNA/ +aduVbH8gZy5Y+cHzenwzBg== +-----END CERTIFICATE----- diff --git a/vectors/cryptography_vectors/x509/custom/extended_key_usage.pem b/vectors/cryptography_vectors/x509/custom/extended_key_usage.pem new file mode 100644 index 00000000..e17c87e0 --- /dev/null +++ b/vectors/cryptography_vectors/x509/custom/extended_key_usage.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDOTCCAiGgAwIBAgITBmouGmlz8B0jbn/oy5Zm347WAjANBgkqhkiG9w0BAQUF +ADApMQ0wCwYDVQQKDARQeUNBMRgwFgYDVQQDDA9jcnlwdG9ncmFwaHkuaW8wHhcN +MTUwNTAxMjIyMzM1WhcNMTYwNDMwMjIyMzM1WjApMQ0wCwYDVQQKDARQeUNBMRgw +FgYDVQQDDA9jcnlwdG9ncmFwaHkuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDCadi1UZioxdnPajqlRZHeKsSxvXXhgrWvlt91P3gV0dBThRFhJsLO +hjNLz6PO6KeRbjz9GhTA2hdkxtIpXrjvTv9dEJ1/k0xebsHWgFC43aTlgekw0U4c +MwMe5NGeeg1tfzbJwldIN+cKvabc08ADlkmM6DMnUArkzA2yii0DErRFMSIGrkDr +6E9puord3h6Mh8Jfnc3TDAq8Qo1DI2XM7oFSWNfecQ9KbIC5wzzT+7Shoyz7QmCk +/XhRzt8Xcfc3yAXIwazvLf8bYP1auaSG11a5E+w6onj91h8UHKKOXu+rdq5YYPZ+ +qUYpxA7ZJ/VAGadMulYbXaO8Syi39HTpAgMBAAGjWjBYMFYGA1UdJQRPME0GCCsG +AQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCQYI +KwYBBQUHAwgGBFUdJQAGCWCGSAGG+EIEATANBgkqhkiG9w0BAQUFAAOCAQEAZEnO +bpVLLVFVihyp3wX8JiPgeHAiAexs2KuVD2yVYhzSLm3f1k580mK1VDtW0Cn3GEiQ +qZax/KHN7WmZXdqNHQ3qJp86QXR7BATD1hgUOW1H62jRaH82OKl0o/LxeLKKJyt8 +YehtxE0If+HL0dDL1KdNgEggcG4iVG5QS5PJNZ/2j2ZqjT+PTy96++L8BhdEfrAT +PNpWyAB31Tyx3P4iQOT7WOgbXCp7/a2piSRaaqcWHioQ6OtAujEJ8Yu22IuwwyNZ +gZNEB57kX0L3t9dg1ojVGHtaUql8aWf+OiFBjzZH+YcgNDyqAJWhy3d7T4f6VC+S +kHrqKK+Nv7i6s/qH5Q== +-----END CERTIFICATE----- diff --git a/vectors/cryptography_vectors/x509/custom/inhibit_any_policy_5.pem b/vectors/cryptography_vectors/x509/custom/inhibit_any_policy_5.pem new file mode 100644 index 00000000..681770cf --- /dev/null +++ b/vectors/cryptography_vectors/x509/custom/inhibit_any_policy_5.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC8DCCAdigAwIBAgITBmot4z1/TiVQVVjARir3nGQGETANBgkqhkiG9w0BAQUF +ADApMQ0wCwYDVQQKDARQeUNBMRgwFgYDVQQDDA9jcnlwdG9ncmFwaHkuaW8wHhcN +MTUwNTAxMjIxMTIyWhcNMTYwNDMwMjIxMTIyWjApMQ0wCwYDVQQKDARQeUNBMRgw +FgYDVQQDDA9jcnlwdG9ncmFwaHkuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQCZcYt4uuICKbglCg0qlreb8P52FjWhdrJ7GNbZBDw5iwsKoLb191YI +6cXRk+FMtMJJ7aqjoXxpHDsad2iDsMRtj9ZjUMRxZTJyZVvmYCm4FP4bP1GE+W48 +N3hiUq8hv3UX4nAzLMIniXfQANYpHDZxh0EkX3vQaCEi5abwbzb0Ra7sUWNAPUVF +Ag3IyNkYqXm1lveWkogkXnBgr8RH7dN59hGHYbKU0aRpmHBB82NyJUkDCl47ybNJ +xaRS9M/QOMg2FCXgQGJzDcLvafIeEqcoy6jq9NwzydafHeYc6QY5P7pl7AqwEYeL +AYC3i0eTtRCP64ChL4eA9VKREiwesKS5AgMBAAGjETAPMA0GA1UdNgEB/wQDAgEF +MA0GCSqGSIb3DQEBBQUAA4IBAQCYMu1zYjS7pDmJE+RJtIHxzUNrfBs9mV58H9PN +UgUvttCWdD+6U9v5mOJS5HVl9wiR8Slf9lz9KuTJkT0K5qmcn0PZpo/eJZd7yDYK +hRfQ8xQapA/zK4u1S/kfflXmvvwvCaAn3fEfqOrylPrtCQBFwLZDo88a1Fmjmjti +ipwxCkGMrwRaWQtIzEB1T0lCEGSfNtI4pcNM84RrlW+WYUBjsNm4X3kPnLLl8BY3 +xcUPQgBZpFdLDcOLrd0XeTRpMenzAZ/ksYEpvDlnlk54Pfe+I8dXF9oe9LhFUfjx +rbvJIJgRkQeJl9hwqQyqgnpaIZHA5opoMkjeYxihsR5pQ+ag +-----END CERTIFICATE----- diff --git a/vectors/cryptography_vectors/x509/custom/inhibit_any_policy_negative.pem b/vectors/cryptography_vectors/x509/custom/inhibit_any_policy_negative.pem new file mode 100644 index 00000000..3d610e6e --- /dev/null +++ b/vectors/cryptography_vectors/x509/custom/inhibit_any_policy_negative.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC8DCCAdigAwIBAgITBmot7URN56N4n8y2DDs8wRpz6zANBgkqhkiG9w0BAQUF +ADApMQ0wCwYDVQQKDARQeUNBMRgwFgYDVQQDDA9jcnlwdG9ncmFwaHkuaW8wHhcN +MTUwNTAxMjIxMzM1WhcNMTYwNDMwMjIxMzM1WjApMQ0wCwYDVQQKDARQeUNBMRgw +FgYDVQQDDA9jcnlwdG9ncmFwaHkuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDCadi1UZioxdnPajqlRZHeKsSxvXXhgrWvlt91P3gV0dBThRFhJsLO +hjNLz6PO6KeRbjz9GhTA2hdkxtIpXrjvTv9dEJ1/k0xebsHWgFC43aTlgekw0U4c +MwMe5NGeeg1tfzbJwldIN+cKvabc08ADlkmM6DMnUArkzA2yii0DErRFMSIGrkDr +6E9puord3h6Mh8Jfnc3TDAq8Qo1DI2XM7oFSWNfecQ9KbIC5wzzT+7Shoyz7QmCk +/XhRzt8Xcfc3yAXIwazvLf8bYP1auaSG11a5E+w6onj91h8UHKKOXu+rdq5YYPZ+ +qUYpxA7ZJ/VAGadMulYbXaO8Syi39HTpAgMBAAGjETAPMA0GA1UdNgEB/wQDAgH/ +MA0GCSqGSIb3DQEBBQUAA4IBAQBbFY9BzxtBqovxCIhxhaiSemoAbIPJx/j8i0fn +YYzcL8CDWO1tjb3m2w4tFRtdx16xFPfvN30FWWD0925uNK0CPxcPsisLB4a6mLBU +1Epy9/0Zwfw+lF73lpCBeJ5PGw/yqNyV6fLWzJN1q1q9KJfdAMqm+4YZHEjM9s5q +h+SsDrtDghLR97xyEwLzI4wkByFSOlk/f80Y56V9uftihbpDkNp8ujVMfFqpchzo +kQ20U/wwhmkAP1iEfacCY8eGngJ5DQEkEN5pbOvZGj2ZFAExfFlF58CpBH+Hy9+I +NeelamzVj+GvcPzICMkU31ESyjajSJ6Ta4yssn8FH8B0hp/z +-----END CERTIFICATE----- |