diff options
33 files changed, 1093 insertions, 71 deletions
diff --git a/.travis/install.sh b/.travis/install.sh index 18deb8e9..aacfc5a0 100755 --- a/.travis/install.sh +++ b/.travis/install.sh @@ -68,7 +68,7 @@ else fi # Retry `update` on failure, some of the servers aren't super reliable. - sudo apt-get -y update || sudo apt-get -y update + sudo apt-get -y update || sudo apt-get -y update || sudo apt-get -y update if [[ "${OPENSSL}" == "0.9.8" ]]; then sudo apt-get install -y --force-yes libssl-dev/lucid diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b35dc144..15e85415 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,12 @@ Changelog .. note:: This version is not yet released and is under active development. +* Deprecated support for Python 2.6. At the time there is no time table for + actually dropping support, however we strongly encourage all users to upgrade + their Python, as Python 2.6 no longer receives support from the Python core + team. +* Fixed compilation when using an OpenSSL which was compiled with the + ``no-comp`` (``OPENSSL_NO_COMP``) option. * Support :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER` serialization of public keys using the ``public_bytes`` method of :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKeyWithSerialization`, @@ -18,6 +24,9 @@ Changelog :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKeyWithSerialization`, and :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKeyWithSerialization`. +* Add support for parsing X.509 certificate signing requests (CSRs) with + :func:`~cryptography.x509.load_pem_x509_csr` and + :func:`~cryptography.x509.load_der_x509_csr`. 0.8.1 - 2015-03-20 ~~~~~~~~~~~~~~~~~~ diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst index ea6c95eb..5353b1d2 100644 --- a/docs/development/test-vectors.rst +++ b/docs/development/test-vectors.rst @@ -132,20 +132,25 @@ Custom X.509 Vectors a subject alternative name extension with the ``otherName`` general name. * ``san_registered_id.pem`` - An RSA 1024 bit certificate containing a 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. Custom X.509 Request Vectors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -* ``dsa_sha1.pem`` - Contains a certificate request using 1024-bit DSA - parameters and SHA1 generated using OpenSSL. -* ``rsa_md4.pem`` - Contains a certificate request using 2048 bit RSA and MD4 +* ``dsa_sha1.pem`` and ``dsa_sha1.der`` - Contain a certificate request using + 1024-bit DSA parameters and SHA1 generated using OpenSSL. +* ``rsa_md4.pem`` and ``rsa_md4.der`` - Contain a certificate request using + 2048 bit RSA and MD4 generated using OpenSSL. +* ``rsa_sha1.pem`` and ``rsa_sha1.der`` - Contain a certificate request using + 2048 bit RSA and SHA1 generated using OpenSSL. +* ``rsa_sha256.pem`` and ``rsa_sha256.der`` - Contain a certificate request + using 2048 bit RSA and SHA256 generated using OpenSSL. +* ``ec_sha256.pem`` and ``ec_sha256.der`` - Contain a certificate request + using EC (``secp384r1``) and SHA256 generated using OpenSSL. +* ``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. -* ``rsa_sha1.pem`` - Contains a certificate request using 2048 bit RSA and - SHA1 generated using OpenSSL. -* ``rsa_sha256.pem`` - Contains a certificate request using 2048 bit RSA and - SHA256 generated using OpenSSL. -* ``ec_sha256.pem`` - Contains a certificate request using EC (``secp384r1``) - and SHA256 generated using OpenSSL. Hashes ~~~~~~ diff --git a/docs/fernet.rst b/docs/fernet.rst index f1a4c748..eacbc2ae 100644 --- a/docs/fernet.rst +++ b/docs/fernet.rst @@ -92,8 +92,10 @@ has support for implementing key rotation via :class:`MultiFernet`. >>> f.decrypt(token) 'Secret message!' - Fernet performs all encryption options using the *first* key in the - ``list`` provided. Decryption supports using *any* of constituent keys. + MultiFernet performs all encryption options using the *first* key in the + ``list`` provided. MultiFernet attempts to decrypt tokens with each key in + turn. A :class:`cryptography.fernet.InvalidToken` exception is raised if + the correct key is not found in the ``list`` provided. Key rotation makes it easy to replace old keys. You can add your new key at the front of the list to start encrypting new messages, and remove old keys diff --git a/docs/hazmat/backends/interfaces.rst b/docs/hazmat/backends/interfaces.rst index 1af8d8f2..8866cf71 100644 --- a/docs/hazmat/backends/interfaces.rst +++ b/docs/hazmat/backends/interfaces.rst @@ -509,3 +509,12 @@ A specific ``backend`` may provide one or more of these interfaces. :param bytes data: DER formatted certificate data. :returns: An instance of :class:`~cryptography.x509.Certificate`. + + .. method:: load_pem_x509_csr(data) + + .. versionadded:: 0.9 + + :param bytes data: PEM formatted certificate signing request data. + + :returns: An instance of + :class:`~cryptography.x509.CertificateSigningRequest`. diff --git a/docs/hazmat/primitives/asymmetric/dsa.rst b/docs/hazmat/primitives/asymmetric/dsa.rst index 3c3567be..179bb8d1 100644 --- a/docs/hazmat/primitives/asymmetric/dsa.rst +++ b/docs/hazmat/primitives/asymmetric/dsa.rst @@ -438,4 +438,4 @@ Key interfaces .. _`DSA`: https://en.wikipedia.org/wiki/Digital_Signature_Algorithm .. _`public-key`: https://en.wikipedia.org/wiki/Public-key_cryptography .. _`FIPS 186-4`: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf -.. _`at least 2048`: http://www.ecrypt.eu.org/documents/D.SPA.20.pdf +.. _`at least 2048`: http://www.ecrypt.eu.org/ecrypt2/documents/D.SPA.20.pdf diff --git a/docs/hazmat/primitives/asymmetric/ec.rst b/docs/hazmat/primitives/asymmetric/ec.rst index 6c03d773..6f4afe7d 100644 --- a/docs/hazmat/primitives/asymmetric/ec.rst +++ b/docs/hazmat/primitives/asymmetric/ec.rst @@ -438,7 +438,7 @@ Key Interfaces .. _`FIPS 186-3`: http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf .. _`FIPS 186-4`: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf .. _`some concern`: https://crypto.stackexchange.com/questions/10263/should-we-trust-the-nist-recommended-ecc-parameters -.. _`less than 224 bits`: http://www.ecrypt.eu.org/documents/D.SPA.20.pdf +.. _`less than 224 bits`: http://www.ecrypt.eu.org/ecrypt2/documents/D.SPA.20.pdf .. _`64x lower computational cost than DH`: https://www.nsa.gov/business/programs/elliptic_curve.shtml .. _`minimize the number of security concerns for elliptic-curve cryptography`: http://cr.yp.to/ecdh/curve25519-20060209.pdf .. _`SafeCurves`: http://safecurves.cr.yp.to/ diff --git a/docs/hazmat/primitives/asymmetric/rsa.rst b/docs/hazmat/primitives/asymmetric/rsa.rst index e7033100..a5187749 100644 --- a/docs/hazmat/primitives/asymmetric/rsa.rst +++ b/docs/hazmat/primitives/asymmetric/rsa.rst @@ -683,7 +683,7 @@ Key interfaces .. _`public-key`: https://en.wikipedia.org/wiki/Public-key_cryptography .. _`specific mathematical properties`: https://en.wikipedia.org/wiki/RSA_(cryptosystem)#Key_generation .. _`use 65537`: http://www.daemonology.net/blog/2009-06-11-cryptographic-right-answers.html -.. _`at least 2048`: http://www.ecrypt.eu.org/documents/D.SPA.20.pdf +.. _`at least 2048`: http://www.ecrypt.eu.org/ecrypt2/documents/D.SPA.20.pdf .. _`OpenPGP`: https://en.wikipedia.org/wiki/Pretty_Good_Privacy .. _`Chinese Remainder Theorem`: https://en.wikipedia.org/wiki/RSA_%28cryptosystem%29#Using_the_Chinese_remainder_algorithm .. _`security proof`: http://eprint.iacr.org/2001/062.pdf diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt index 41728d2d..f7b73b38 100644 --- a/docs/spelling_wordlist.txt +++ b/docs/spelling_wordlist.txt @@ -22,6 +22,7 @@ deserialize deserialized Diffie Docstrings +Encodings fernet Fernet hazmat @@ -38,12 +39,14 @@ metadata naïve namespace namespaces +paddings pickleable plaintext preprocessor preprocessors pseudorandom pyOpenSSL +relicensed Schneier scrypt Serializers diff --git a/docs/x509.rst b/docs/x509.rst index 44d53a45..afc9620a 100644 --- a/docs/x509.rst +++ b/docs/x509.rst @@ -3,11 +3,57 @@ X.509 .. currentmodule:: cryptography.x509 +.. testsetup:: + + pem_req_data = b""" + -----BEGIN CERTIFICATE REQUEST----- + MIIC0zCCAbsCAQAwWTELMAkGA1UEBhMCVVMxETAPBgNVBAgMCElsbGlub2lzMRAw + DgYDVQQHDAdDaGljYWdvMREwDwYDVQQKDAhyNTA5IExMQzESMBAGA1UEAwwJaGVs + bG8uY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqhZx+Mo9VRd9 + vsnWWa6NBCws21rZ0+1B/JGgB4hDsZS7iDE4Bj5z4idheFRtl8bBbdjPknq7BfoF + 8v15Zq/Zv7i2xMSDL+LUrTBZezRd4bRTGqCm6YJ5EYkhqdcqeZleHCFImguHoq1J + Fh0+kObQrTHXw3ZP57a3o1IvyIUA3nNoCBL0QQhwBXaDXOojMKNR+bqB5ve8GS1y + Elr0AM/+cJsfaIahNQUgFKx3Eu3GeEOMKYOAG1lycgdQdmTUybLrT3U7vkClTseM + xHg1r5En7ALjONIhqRuq3rddYahrP8HXozb3zUy3cJ7P6IeaosuvNzvMXOX9P6HD + Ha9urDAJ1wIDAQABoDUwMwYJKoZIhvcNAQkOMSYwJDAiBgNVHREEGzAZggl3b3Js + ZC5jb22CDHdoYXRldmVyLmNvbTANBgkqhkiG9w0BAQUFAAOCAQEAS4Ro6h+z52SK + YSLCYARpnEu/rmh4jdqndt8naqcNb6uLx9mlKZ2W9on9XDjnSdQD9q+ZP5aZfESw + R0+rJhW9ZrNa/g1pt6M24ihclHYDAxYMWxT1z/TXXGM3TmZZ6gfYlNE1kkBuODHa + UYsR/1Ht1E1EsmmUimt2n+zQR2K8T9Coa+boaUW/GsTEuz1aaJAkj5ZvTDiIhRG4 + AOCqFZOLAQmCCNgJnnspD9hDz/Ons085LF5wnYjN4/Nsk5tS6AGs3xjZ3jPoOGGn + 82WQ9m4dBGoVDZXsobVTaN592JEYwN5iu72zRn7Einb4V4H5y3yD2dD4yWPlt4pk + 5wFkeYsZEA== + -----END CERTIFICATE REQUEST----- + """.strip() + + pem_data = b""" + -----BEGIN CERTIFICATE----- + MIIDfDCCAmSgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJVUzEf + MB0GA1UEChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEVMBMGA1UEAxMMVHJ1c3Qg + QW5jaG9yMB4XDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFowQDELMAkGA1UE + BhMCVVMxHzAdBgNVBAoTFlRlc3QgQ2VydGlmaWNhdGVzIDIwMTExEDAOBgNVBAMT + B0dvb2QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCQWJpHYo37 + Xfb7oJSPe+WvfTlzIG21WQ7MyMbGtK/m8mejCzR6c+f/pJhEH/OcDSMsXq8h5kXa + BGqWK+vSwD/Pzp5OYGptXmGPcthDtAwlrafkGOS4GqIJ8+k9XGKs+vQUXJKsOk47 + RuzD6PZupq4s16xaLVqYbUC26UcY08GpnoLNHJZS/EmXw1ZZ3d4YZjNlpIpWFNHn + UGmdiGKXUPX/9H0fVjIAaQwjnGAbpgyCumWgzIwPpX+ElFOUr3z7BoVnFKhIXze+ + VmQGSWxZxvWDUN90Ul0tLEpLgk3OVxUB4VUGuf15OJOpgo1xibINPmWt14Vda2N9 + yrNKloJGZNqLAgMBAAGjfDB6MB8GA1UdIwQYMBaAFOR9X9FclYYILAWuvnW2ZafZ + XahmMB0GA1UdDgQWBBRYAYQkG7wrUpRKPaUQchRR9a86yTAOBgNVHQ8BAf8EBAMC + AQYwFwYDVR0gBBAwDjAMBgpghkgBZQMCATABMA8GA1UdEwEB/wQFMAMBAf8wDQYJ + KoZIhvcNAQELBQADggEBADWHlxbmdTXNwBL/llwhQqwnazK7CC2WsXBBqgNPWj7m + tvQ+aLG8/50Qc2Sun7o2VnwF9D18UUe8Gj3uPUYH+oSI1vDdyKcjmMbKRU4rk0eo + 3UHNDXwqIVc9CQS9smyV+x1HCwL4TTrq+LXLKx/qVij0Yqk+UJfAtrg2jnYKXsCu + FMBQQnWCGrwa1g1TphRp/RmYHnMynYFmZrXtzFz+U9XEA7C+gPq4kqDI/iVfIT1s + 6lBtdB50lrDVwl2oYfAvW/6sC2se2QleZidUmrziVNP4oEeXINokU6T6p//HM1FG + QYw2jOvpKcKtWCSAnegEbgsGYzATKjmPJPJ0npHFqzM= + -----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`_. - Loading Certificates ~~~~~~~~~~~~~~~~~~~~ @@ -43,32 +89,6 @@ Loading Certificates :returns: An instance of :class:`~cryptography.x509.Certificate`. -.. testsetup:: - - pem_data = b""" - -----BEGIN CERTIFICATE----- - MIIDfDCCAmSgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJVUzEf - MB0GA1UEChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEVMBMGA1UEAxMMVHJ1c3Qg - QW5jaG9yMB4XDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFowQDELMAkGA1UE - BhMCVVMxHzAdBgNVBAoTFlRlc3QgQ2VydGlmaWNhdGVzIDIwMTExEDAOBgNVBAMT - B0dvb2QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCQWJpHYo37 - Xfb7oJSPe+WvfTlzIG21WQ7MyMbGtK/m8mejCzR6c+f/pJhEH/OcDSMsXq8h5kXa - BGqWK+vSwD/Pzp5OYGptXmGPcthDtAwlrafkGOS4GqIJ8+k9XGKs+vQUXJKsOk47 - RuzD6PZupq4s16xaLVqYbUC26UcY08GpnoLNHJZS/EmXw1ZZ3d4YZjNlpIpWFNHn - UGmdiGKXUPX/9H0fVjIAaQwjnGAbpgyCumWgzIwPpX+ElFOUr3z7BoVnFKhIXze+ - VmQGSWxZxvWDUN90Ul0tLEpLgk3OVxUB4VUGuf15OJOpgo1xibINPmWt14Vda2N9 - yrNKloJGZNqLAgMBAAGjfDB6MB8GA1UdIwQYMBaAFOR9X9FclYYILAWuvnW2ZafZ - XahmMB0GA1UdDgQWBBRYAYQkG7wrUpRKPaUQchRR9a86yTAOBgNVHQ8BAf8EBAMC - AQYwFwYDVR0gBBAwDjAMBgpghkgBZQMCATABMA8GA1UdEwEB/wQFMAMBAf8wDQYJ - KoZIhvcNAQELBQADggEBADWHlxbmdTXNwBL/llwhQqwnazK7CC2WsXBBqgNPWj7m - tvQ+aLG8/50Qc2Sun7o2VnwF9D18UUe8Gj3uPUYH+oSI1vDdyKcjmMbKRU4rk0eo - 3UHNDXwqIVc9CQS9smyV+x1HCwL4TTrq+LXLKx/qVij0Yqk+UJfAtrg2jnYKXsCu - FMBQQnWCGrwa1g1TphRp/RmYHnMynYFmZrXtzFz+U9XEA7C+gPq4kqDI/iVfIT1s - 6lBtdB50lrDVwl2oYfAvW/6sC2se2QleZidUmrziVNP4oEeXINokU6T6p//HM1FG - QYw2jOvpKcKtWCSAnegEbgsGYzATKjmPJPJ0npHFqzM= - -----END CERTIFICATE----- - """.strip() - .. doctest:: >>> from cryptography import x509 @@ -77,6 +97,52 @@ Loading Certificates >>> cert.serial 2 +Loading Certificate Signing Requests +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. function:: load_pem_x509_csr(data, backend) + + .. versionadded:: 0.9 + + Deserialize a certificate signing request (CSR) from PEM encoded data. PEM + requests are base64 decoded and have delimiters that look like + ``-----BEGIN CERTIFICATE REQUEST-----``. This format is also known as + PKCS#10. + + :param bytes data: The PEM encoded request data. + + :param backend: A backend supporting the + :class:`~cryptography.hazmat.backends.interfaces.X509Backend` + interface. + + :returns: An instance of + :class:`~cryptography.x509.CertificateSigningRequest`. + +.. function:: load_der_x509_csr(data, backend) + + .. versionadded:: 0.9 + + Deserialize a certificate signing request (CSR) from DER encoded data. DER + is a binary format and is not commonly used with CSRs. + + :param bytes data: The DER encoded request data. + + :param backend: A backend supporting the + :class:`~cryptography.hazmat.backends.interfaces.X509Backend` + interface. + + :returns: An instance of + :class:`~cryptography.x509.CertificateSigningRequest`. + +.. doctest:: + + >>> from cryptography import x509 + >>> from cryptography.hazmat.backends import default_backend + >>> from cryptography.hazmat.primitives import hashes + >>> csr = x509.load_pem_x509_csr(pem_req_data, default_backend()) + >>> isinstance(csr.signature_hash_algorithm, hashes.SHA1) + True + X.509 Certificate Object ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -205,6 +271,55 @@ X.509 Certificate Object :raises cryptography.x509.DuplicateExtension: If more than one extension of the same type is found within the certificate. + .. doctest:: + + >>> for ext in cert.extensions: + ... print(ext) + <Extension(oid=<ObjectIdentifier(oid=2.5.29.19, name=basicConstraints)>, critical=True, value=<BasicConstraints(ca=True, path_length=None)>)> + +X.509 CSR (Certificate Signing Request) Object +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. class:: CertificateSigningRequest + + .. versionadded:: 0.9 + + .. method:: public_key() + + :type: + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey` or + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey` or + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey` + + The public key associated with the request. + + .. doctest:: + + >>> from cryptography.hazmat.primitives.asymmetric import rsa + >>> public_key = csr.public_key() + >>> isinstance(public_key, rsa.RSAPublicKey) + True + + .. attribute:: subject + + :type: :class:`Name` + + The :class:`Name` of the subject. + + .. attribute:: signature_hash_algorithm + + :type: :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` + + Returns the + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` which + was used in signing this request. + + .. doctest:: + + >>> from cryptography.hazmat.primitives import hashes + >>> isinstance(csr.signature_hash_algorithm, hashes.SHA1) + True + .. class:: Name .. versionadded:: 0.8 @@ -292,6 +407,23 @@ X.509 Extensions An X.509 Extensions instance is an ordered list of extensions. The object is iterable to get every extension. + .. method:: get_extension_for_oid(oid) + + :param oid: An :class:`ObjectIdentifier` instance. + + :returns: An instance of the extension class. + + :raises cryptography.x509.ExtensionNotFound: If the certificate does + not have the extension requested. + + :raises cryptography.x509.UnsupportedExtension: If the certificate + contains an extension that is not supported. + + .. doctest:: + + >>> cert.extensions.get_extension_for_oid(x509.OID_BASIC_CONSTRAINTS) + <Extension(oid=<ObjectIdentifier(oid=2.5.29.19, name=basicConstraints)>, critical=True, value=<BasicConstraints(ca=True, path_length=None)>)> + .. class:: Extension .. versionadded:: 0.9 @@ -315,6 +447,98 @@ X.509 Extensions Returns an instance of the extension type corresponding to the OID. +.. class:: KeyUsage + + .. versionadded:: 0.9 + + The key usage extension defines the purpose of the key contained in the + certificate. The usage restriction might be employed when a key that could + be used for more than one operation is to be restricted. It corresponds to + :data:`OID_KEY_USAGE`. + + .. attribute:: digital_signature + + :type: bool + + This purpose is set to true when the subject public key is used for verifying + digital signatures, other than signatures on certificates + (``key_cert_sign``) and CRLs (``crl_sign``). + + .. attribute:: content_commitment + + :type: bool + + This purpose is set to true when the subject public key is used for verifying + digital signatures, other than signatures on certificates + (``key_cert_sign``) and CRLs (``crl_sign``). It is used to provide a + non-repudiation service that protects against the signing entity + falsely denying some action. In the case of later conflict, a + reliable third party may determine the authenticity of the signed + data. This was called ``non_repudiation`` in older revisions of the + X.509 specification. + + .. attribute:: key_encipherment + + :type: bool + + This purpose is set to true when the subject public key is used for + enciphering private or secret keys. + + .. attribute:: data_encipherment + + :type: bool + + This purpose is set to true when the subject public key is used for + directly enciphering raw user data without the use of an intermediate + symmetric cipher. + + .. attribute:: key_agreement + + :type: bool + + This purpose is set to true when the subject public key is used for key + agreement. For example, when a Diffie-Hellman key is to be used for + key management, then this purpose is set to true. + + .. attribute:: key_cert_sign + + :type: bool + + This purpose is set to true when the subject public key is used for + verifying signatures on public key certificates. If this purpose is set + to true then ``ca`` must be true in the :class:`BasicConstraints` + extension. + + .. attribute:: crl_sign + + :type: bool + + This purpose is set to true when the subject public key is used for + verifying signatures on certificate revocation lists. + + .. attribute:: encipher_only + + :type: bool + + When this purposes is set to true and the ``key_agreement`` purpose is + also set, the subject public key may be used only for enciphering data + while performing key agreement. + + :raises ValueError: This is raised if accessed when ``key_agreement`` + is false. + + .. attribute:: decipher_only + + :type: bool + + When this purposes is set to true and the ``key_agreement`` purpose is + also set, the subject public key may be used only for deciphering data + while performing key agreement. + + :raises ValueError: This is raised if accessed when ``key_agreement`` + is false. + + .. class:: BasicConstraints .. versionadded:: 0.9 @@ -343,6 +567,15 @@ X.509 Extensions subordinate CA, but the subordinate CA is not allowed to create subordinates with ``ca`` set to true. +.. class:: ExtendedKeyUsage + + .. versionadded:: 0.9 + + This extension indicates one or more purposes for which the certified + public key may be used, in addition to or in place of the basic + purposes indicated in the key usage extension. The object is + iterable to obtain the list of :ref:`extended key usage OIDs <eku_oids>`. + Object Identifiers ~~~~~~~~~~~~~~~~~~ @@ -501,6 +734,41 @@ Signature Algorithm OIDs Corresponds to the dotted string ``"2.16.840.1.101.3.4.3.2"``. This is a SHA256 digest signed by a DSA key. +.. _eku_oids: + +Extended Key Usage OIDs +~~~~~~~~~~~~~~~~~~~~~~~ + +.. data:: OID_SERVER_AUTH + + Corresponds to the dotted string ``"1.3.6.1.5.5.7.3.1"``. This is used to + denote that a certificate may be used for TLS web server authentication. + +.. data:: OID_CLIENT_AUTH + + Corresponds to the dotted string ``"1.3.6.1.5.5.7.3.2"``. This is used to + denote that a certificate may be used for TLS web client authentication. + +.. data:: OID_CODE_SIGNING + + Corresponds to the dotted string ``"1.3.6.1.5.5.7.3.3"``. This is used to + denote that a certificate may be used for code signing. + +.. data:: OID_EMAIL_PROTECTION + + Corresponds to the dotted string ``"1.3.6.1.5.5.7.3.4"``. This is used to + denote that a certificate may be used for email protection. + +.. data:: OID_TIME_STAMPING + + Corresponds to the dotted string ``"1.3.6.1.5.5.7.3.8"``. This is used to + denote that a certificate may be used for time stamping. + +.. data:: OID_OCSP_SIGNING + + 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. + .. _extension_oids: Extension OIDs @@ -511,6 +779,11 @@ Extension OIDs Corresponds to the dotted string ``"2.5.29.19"``. The identifier for the :class:`BasicConstraints` extension type. +.. data:: OID_KEY_USAGE + + Corresponds to the dotted string ``"2.5.29.15"``. The identifier for the + :class:`KeyUsage` extension type. + Exceptions ~~~~~~~~~~ @@ -546,6 +819,17 @@ Exceptions Returns the OID. +.. class:: ExtensionNotFound + + This is raised when calling :meth:`Extensions.get_extension_for_oid` with + an extension OID that is not present in the certificate. + + .. attribute:: oid + + :type: :class:`ObjectIdentifier` + + Returns the OID. + .. _`public key infrastructure`: https://en.wikipedia.org/wiki/Public_key_infrastructure .. _`TLS`: https://en.wikipedia.org/wiki/Transport_Layer_Security diff --git a/src/cryptography/__init__.py b/src/cryptography/__init__.py index 6da0b383..985ebd6f 100644 --- a/src/cryptography/__init__.py +++ b/src/cryptography/__init__.py @@ -4,6 +4,9 @@ from __future__ import absolute_import, division, print_function +import sys +import warnings + from cryptography.__about__ import ( __author__, __copyright__, __email__, __license__, __summary__, __title__, __uri__, __version__ @@ -14,3 +17,10 @@ __all__ = [ "__title__", "__summary__", "__uri__", "__version__", "__author__", "__email__", "__license__", "__copyright__", ] + +if sys.version_info[:2] == (2, 6): + warnings.warn( + "Python 2.6 is no longer supported by the Python core team, please " + "upgrade your Python.", + DeprecationWarning + ) diff --git a/src/cryptography/hazmat/backends/interfaces.py b/src/cryptography/hazmat/backends/interfaces.py index 79808909..5224f5c7 100644 --- a/src/cryptography/hazmat/backends/interfaces.py +++ b/src/cryptography/hazmat/backends/interfaces.py @@ -261,3 +261,15 @@ class X509Backend(object): """ Load an X.509 certificate from DER encoded data. """ + + @abc.abstractmethod + def load_der_x509_csr(self, data): + """ + Load an X.509 CSR from DER encoded data. + """ + + @abc.abstractmethod + def load_pem_x509_csr(self, data): + """ + Load an X.509 CSR from PEM encoded data. + """ diff --git a/src/cryptography/hazmat/backends/multibackend.py b/src/cryptography/hazmat/backends/multibackend.py index 6e378c19..784ab84d 100644 --- a/src/cryptography/hazmat/backends/multibackend.py +++ b/src/cryptography/hazmat/backends/multibackend.py @@ -324,3 +324,21 @@ class MultiBackend(object): "This backend does not support X.509.", _Reasons.UNSUPPORTED_X509 ) + + def load_der_x509_csr(self, data): + for b in self._filtered_backends(X509Backend): + return b.load_der_x509_csr(data) + + raise UnsupportedAlgorithm( + "This backend does not support X.509.", + _Reasons.UNSUPPORTED_X509 + ) + + def load_pem_x509_csr(self, data): + for b in self._filtered_backends(X509Backend): + return b.load_pem_x509_csr(data) + + raise UnsupportedAlgorithm( + "This backend does not support X.509.", + _Reasons.UNSUPPORTED_X509 + ) diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 60aa4531..665771a8 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -34,7 +34,9 @@ from cryptography.hazmat.backends.openssl.hmac import _HMACContext from cryptography.hazmat.backends.openssl.rsa import ( _RSAPrivateKey, _RSAPublicKey ) -from cryptography.hazmat.backends.openssl.x509 import _Certificate +from cryptography.hazmat.backends.openssl.x509 import ( + _Certificate, _CertificateSigningRequest +) from cryptography.hazmat.bindings.openssl.binding import Binding from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa @@ -475,20 +477,20 @@ class Backend(object): pointer. """ - type = evp_pkey.type + key_type = evp_pkey.type - if type == self._lib.EVP_PKEY_RSA: + if key_type == self._lib.EVP_PKEY_RSA: rsa_cdata = self._lib.EVP_PKEY_get1_RSA(evp_pkey) assert rsa_cdata != self._ffi.NULL rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) return _RSAPrivateKey(self, rsa_cdata) - elif type == self._lib.EVP_PKEY_DSA: + elif key_type == self._lib.EVP_PKEY_DSA: dsa_cdata = self._lib.EVP_PKEY_get1_DSA(evp_pkey) assert dsa_cdata != self._ffi.NULL dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) return _DSAPrivateKey(self, dsa_cdata) elif (self._lib.Cryptography_HAS_EC == 1 and - type == self._lib.EVP_PKEY_EC): + key_type == self._lib.EVP_PKEY_EC): ec_cdata = self._lib.EVP_PKEY_get1_EC_KEY(evp_pkey) assert ec_cdata != self._ffi.NULL ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free) @@ -502,20 +504,20 @@ class Backend(object): pointer. """ - type = evp_pkey.type + key_type = evp_pkey.type - if type == self._lib.EVP_PKEY_RSA: + if key_type == self._lib.EVP_PKEY_RSA: rsa_cdata = self._lib.EVP_PKEY_get1_RSA(evp_pkey) assert rsa_cdata != self._ffi.NULL rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) return _RSAPublicKey(self, rsa_cdata) - elif type == self._lib.EVP_PKEY_DSA: + elif key_type == self._lib.EVP_PKEY_DSA: dsa_cdata = self._lib.EVP_PKEY_get1_DSA(evp_pkey) assert dsa_cdata != self._ffi.NULL dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) return _DSAPublicKey(self, dsa_cdata) elif (self._lib.Cryptography_HAS_EC == 1 and - type == self._lib.EVP_PKEY_EC): + key_type == self._lib.EVP_PKEY_EC): ec_cdata = self._lib.EVP_PKEY_get1_EC_KEY(evp_pkey) assert ec_cdata != self._ffi.NULL ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free) @@ -669,7 +671,7 @@ class Backend(object): def dsa_parameters_supported(self, p, q, g): if self._lib.OPENSSL_VERSION_NUMBER < 0x1000000f: - return (utils.bit_length(p) <= 1024 and utils.bit_length(q) <= 160) + return utils.bit_length(p) <= 1024 and utils.bit_length(q) <= 160 else: return True @@ -820,6 +822,28 @@ class Backend(object): x509 = self._ffi.gc(x509, self._lib.X509_free) return _Certificate(self, x509) + def load_pem_x509_csr(self, data): + mem_bio = self._bytes_to_bio(data) + x509_req = self._lib.PEM_read_bio_X509_REQ( + mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL + ) + if x509_req == self._ffi.NULL: + self._consume_errors() + raise ValueError("Unable to load request") + + x509_req = self._ffi.gc(x509_req, self._lib.X509_REQ_free) + return _CertificateSigningRequest(self, x509_req) + + def load_der_x509_csr(self, data): + mem_bio = self._bytes_to_bio(data) + x509_req = self._lib.d2i_X509_REQ_bio(mem_bio.bio, self._ffi.NULL) + if x509_req == self._ffi.NULL: + self._consume_errors() + raise ValueError("Unable to load request") + + x509_req = self._ffi.gc(x509_req, self._lib.X509_REQ_free) + return _CertificateSigningRequest(self, x509_req) + def _load_key(self, openssl_read_func, convert_func, data, password): mem_bio = self._bytes_to_bio(data) @@ -1205,13 +1229,13 @@ class Backend(object): assert res == 1 return self._read_mem_bio(bio) - def _private_key_bytes_traditional_der(self, type, cdata): - if type == self._lib.EVP_PKEY_RSA: + def _private_key_bytes_traditional_der(self, key_type, cdata): + if key_type == self._lib.EVP_PKEY_RSA: write_bio = self._lib.i2d_RSAPrivateKey_bio elif (self._lib.Cryptography_HAS_EC == 1 and - type == self._lib.EVP_PKEY_EC): + key_type == self._lib.EVP_PKEY_EC): write_bio = self._lib.i2d_ECPrivateKey_bio - elif type == self._lib.EVP_PKEY_DSA: + elif key_type == self._lib.EVP_PKEY_DSA: write_bio = self._lib.i2d_DSAPrivateKey_bio bio = self._create_mem_bio() diff --git a/src/cryptography/hazmat/backends/openssl/utils.py b/src/cryptography/hazmat/backends/openssl/utils.py index 498c100d..001121f9 100644 --- a/src/cryptography/hazmat/backends/openssl/utils.py +++ b/src/cryptography/hazmat/backends/openssl/utils.py @@ -16,7 +16,7 @@ def _truncate_digest(digest, order_bits): if 8 * digest_len > order_bits: rshift = 8 - (order_bits & 0x7) - assert rshift > 0 and rshift < 8 + assert 0 < rshift < 8 mask = 0xFF >> rshift << rshift diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index 3502d122..6a7032ba 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -45,7 +45,7 @@ def _build_x509_name(backend, x509_name): assert res >= 0 assert buf[0] != backend._ffi.NULL buf = backend._ffi.gc( - buf, lambda buf: backend._lib.OPENSSL_free(buf[0]) + buf, lambda buffer: backend._lib.OPENSSL_free(buffer[0]) ) value = backend._ffi.buffer(buf[0], res)[:].decode('utf8') oid = _obj2txt(backend, obj) @@ -168,13 +168,16 @@ class _Certificate(object): raise x509.DuplicateExtension( "Duplicate {0} extension found".format(oid), oid ) - elif oid == x509.OID_BASIC_CONSTRAINTS and critical: + elif oid == x509.OID_BASIC_CONSTRAINTS: + value = self._build_basic_constraints(ext) + elif oid == x509.OID_KEY_USAGE and critical: # TODO: remove this obviously. warnings.warn( - "Extension support is not fully implemented. A basic " - "constraints extension with the critical flag was seen and" - " IGNORED." + "Extension support is not fully implemented. A key usage " + "extension with the critical flag was seen and IGNORED." ) + seen_oids.add(oid) + continue elif critical: raise x509.UnsupportedExtension( "{0} is not currently supported".format(oid), oid @@ -185,5 +188,60 @@ class _Certificate(object): continue seen_oids.add(oid) + extensions.append(x509.Extension(oid, critical, value)) return x509.Extensions(extensions) + + 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: + bn = self._backend._lib.ASN1_INTEGER_to_BN( + basic_constraints.pathlen, self._backend._ffi.NULL + ) + assert bn != self._backend._ffi.NULL + bn = self._backend._ffi.gc(bn, self._backend._lib.BN_free) + path_length = self._backend._bn_to_int(bn) + + return x509.BasicConstraints(ca, path_length) + + +@utils.register_interface(x509.CertificateSigningRequest) +class _CertificateSigningRequest(object): + def __init__(self, backend, x509_req): + self._backend = backend + self._x509_req = x509_req + + def public_key(self): + pkey = self._backend._lib.X509_REQ_get_pubkey(self._x509_req) + assert pkey != self._backend._ffi.NULL + pkey = self._backend._ffi.gc(pkey, self._backend._lib.EVP_PKEY_free) + return self._backend._evp_pkey_to_public_key(pkey) + + @property + 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) + + @property + def signature_hash_algorithm(self): + oid = _obj2txt(self._backend, self._x509_req.sig_alg.algorithm) + try: + return x509._SIG_OIDS_TO_HASH[oid] + except KeyError: + raise UnsupportedAlgorithm( + "Signature algorithm OID:{0} not recognized".format(oid) + ) diff --git a/src/cryptography/hazmat/bindings/openssl/asn1.py b/src/cryptography/hazmat/bindings/openssl/asn1.py index d8b8331e..45dfe758 100644 --- a/src/cryptography/hazmat/bindings/openssl/asn1.py +++ b/src/cryptography/hazmat/bindings/openssl/asn1.py @@ -40,6 +40,7 @@ struct asn1_string_st { typedef struct asn1_string_st ASN1_OCTET_STRING; typedef struct asn1_string_st ASN1_IA5STRING; +typedef ... ASN1_BIT_STRING; typedef ... ASN1_OBJECT; typedef ... ASN1_STRING; typedef ... ASN1_TYPE; @@ -115,9 +116,12 @@ int ASN1_ENUMERATED_set(ASN1_ENUMERATED *, long); ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **, const unsigned char **, long, const ASN1_ITEM *); +int ASN1_BIT_STRING_set_bit(ASN1_BIT_STRING *, int, int); """ MACROS = """ +/* This is not a macro, but is const on some versions of OpenSSL */ +int ASN1_BIT_STRING_get_bit(ASN1_BIT_STRING *, int); ASN1_TIME *M_ASN1_TIME_dup(void *); const ASN1_ITEM *ASN1_ITEM_ptr(ASN1_ITEM_EXP *); diff --git a/src/cryptography/hazmat/bindings/openssl/pem.py b/src/cryptography/hazmat/bindings/openssl/pem.py index 98c7648f..8ec3fefd 100644 --- a/src/cryptography/hazmat/bindings/openssl/pem.py +++ b/src/cryptography/hazmat/bindings/openssl/pem.py @@ -32,7 +32,9 @@ int i2d_PKCS8PrivateKey_bio(BIO *, EVP_PKEY *, const EVP_CIPHER *, int i2d_PKCS8PrivateKey_nid_bio(BIO *, EVP_PKEY *, int, char *, int, pem_password_cb *, void *); +int i2d_PKCS7_bio(BIO *, PKCS7 *); PKCS7 *d2i_PKCS7_bio(BIO *, PKCS7 **); + EVP_PKEY *d2i_PKCS8PrivateKey_bio(BIO *, EVP_PKEY **, pem_password_cb *, void *); @@ -45,6 +47,8 @@ X509_CRL *PEM_read_bio_X509_CRL(BIO *, X509_CRL **, pem_password_cb *, void *); int PEM_write_bio_X509_CRL(BIO *, X509_CRL *); PKCS7 *PEM_read_bio_PKCS7(BIO *, PKCS7 **, pem_password_cb *, void *); +int PEM_write_bio_PKCS7(BIO *, PKCS7 *); + DH *PEM_read_bio_DHparams(BIO *, DH **, pem_password_cb *, void *); DSA *PEM_read_bio_DSAPrivateKey(BIO *, DSA **, pem_password_cb *, void *); diff --git a/src/cryptography/hazmat/bindings/openssl/pkcs7.py b/src/cryptography/hazmat/bindings/openssl/pkcs7.py index 3196fa13..df82afef 100644 --- a/src/cryptography/hazmat/bindings/openssl/pkcs7.py +++ b/src/cryptography/hazmat/bindings/openssl/pkcs7.py @@ -13,10 +13,37 @@ typedef struct { ASN1_OBJECT *type; ...; } PKCS7; + +static const int PKCS7_BINARY; +static const int PKCS7_DETACHED; +static const int PKCS7_NOATTR; +static const int PKCS7_NOCERTS; +static const int PKCS7_NOCHAIN; +static const int PKCS7_NOINTERN; +static const int PKCS7_NOSIGS; +static const int PKCS7_NOSMIMECAP; +static const int PKCS7_NOVERIFY; +static const int PKCS7_STREAM; +static const int PKCS7_TEXT; """ FUNCTIONS = """ +PKCS7 *SMIME_read_PKCS7(BIO *, BIO **); +int SMIME_write_PKCS7(BIO *, PKCS7 *, BIO *, int); + void PKCS7_free(PKCS7 *); + +PKCS7 *PKCS7_sign(X509 *, EVP_PKEY *, Cryptography_STACK_OF_X509 *, + BIO *, int); +int PKCS7_verify(PKCS7 *, Cryptography_STACK_OF_X509 *, X509_STORE *, BIO *, + BIO *, int); +Cryptography_STACK_OF_X509 *PKCS7_get0_signers(PKCS7 *, + Cryptography_STACK_OF_X509 *, + int); + +PKCS7 *PKCS7_encrypt(Cryptography_STACK_OF_X509 *, BIO *, + const EVP_CIPHER *, int); +int PKCS7_decrypt(PKCS7 *, EVP_PKEY *, X509 *, BIO *, int); """ MACROS = """ @@ -26,7 +53,6 @@ int PKCS7_type_is_signedAndEnveloped(PKCS7 *); int PKCS7_type_is_data(PKCS7 *); """ -CUSTOMIZATIONS = """ -""" +CUSTOMIZATIONS = "" CONDITIONAL_NAMES = {} diff --git a/src/cryptography/hazmat/bindings/openssl/ssl.py b/src/cryptography/hazmat/bindings/openssl/ssl.py index bc4b2e79..d680c3a5 100644 --- a/src/cryptography/hazmat/bindings/openssl/ssl.py +++ b/src/cryptography/hazmat/bindings/openssl/ssl.py @@ -546,11 +546,7 @@ static const long Cryptography_HAS_ALPN = 0; #else static const long Cryptography_HAS_ALPN = 1; #endif -/* LibreSSL has removed support for compression, and with it the - * COMP_METHOD use in ssl.h. This is a hack to make the function types - * in this code match those in ssl.h. - */ -#ifdef LIBRESSL_VERSION_NUMBER +#if defined(OPENSSL_NO_COMP) || defined(LIBRESSL_VERSION_NUMBER) static const long Cryptography_HAS_COMPRESSION = 0; typedef void COMP_METHOD; #else diff --git a/src/cryptography/hazmat/bindings/openssl/x509.py b/src/cryptography/hazmat/bindings/openssl/x509.py index 949a936e..b5c9ee14 100644 --- a/src/cryptography/hazmat/bindings/openssl/x509.py +++ b/src/cryptography/hazmat/bindings/openssl/x509.py @@ -44,7 +44,10 @@ typedef struct { typedef ... X509_EXTENSIONS; -typedef ... X509_REQ; +typedef struct { + X509_ALGOR *sig_alg; + ...; +} X509_REQ; typedef struct { ASN1_INTEGER *serialNumber; @@ -165,6 +168,9 @@ void X509_REVOKED_free(X509_REVOKED *); int X509_REVOKED_set_serialNumber(X509_REVOKED *, ASN1_INTEGER *); +int X509_REVOKED_get_ext_count(X509_REVOKED *); +X509_EXTENSION *X509_REVOKED_get_ext(X509_REVOKED *, int); +int X509_REVOKED_add_ext(X509_REVOKED *, X509_EXTENSION*, int); int X509_REVOKED_add1_ext_i2d(X509_REVOKED *, int, void *, int, unsigned long); X509_CRL *d2i_X509_CRL_bio(BIO *, X509_CRL **); @@ -175,6 +181,9 @@ int i2d_X509_CRL_bio(BIO *, X509_CRL *); int X509_CRL_print(BIO *, X509_CRL *); int X509_CRL_set_issuer_name(X509_CRL *, X509_NAME *); int X509_CRL_sign(X509_CRL *, EVP_PKEY *, const EVP_MD *); +int X509_CRL_get_ext_count(X509_CRL *); +X509_EXTENSION *X509_CRL_get_ext(X509_CRL *, int); +int X509_CRL_add_ext(X509_CRL *, X509_EXTENSION *, int); int NETSCAPE_SPKI_verify(NETSCAPE_SPKI *, EVP_PKEY *); int NETSCAPE_SPKI_sign(NETSCAPE_SPKI *, EVP_PKEY *, const EVP_MD *); @@ -259,11 +268,22 @@ void sk_X509_EXTENSION_free(X509_EXTENSIONS *); int sk_X509_REVOKED_num(Cryptography_STACK_OF_X509_REVOKED *); X509_REVOKED *sk_X509_REVOKED_value(Cryptography_STACK_OF_X509_REVOKED *, int); +Cryptography_STACK_OF_X509_CRL *sk_X509_CRL_new_null(void); +void sk_X509_CRL_free(Cryptography_STACK_OF_X509_CRL *); +int sk_X509_CRL_num(Cryptography_STACK_OF_X509_CRL *); +int sk_X509_CRL_push(Cryptography_STACK_OF_X509_CRL *, X509_CRL *); +X509_CRL *sk_X509_CRL_value(Cryptography_STACK_OF_X509_CRL *, int); + int i2d_RSAPublicKey(RSA *, unsigned char **); int i2d_RSAPrivateKey(RSA *, unsigned char **); int i2d_DSAPublicKey(DSA *, unsigned char **); int i2d_DSAPrivateKey(DSA *, unsigned char **); +int X509_CRL_get_version(X509_CRL *); +ASN1_TIME *X509_CRL_get_lastUpdate(X509_CRL *); +ASN1_TIME *X509_CRL_get_nextUpdate(X509_CRL *); +X509_NAME *X509_CRL_get_issuer(X509_CRL *); + /* These aren't macros these arguments are all const X on openssl > 1.0.x */ int X509_CRL_set_lastUpdate(X509_CRL *, ASN1_TIME *); int X509_CRL_set_nextUpdate(X509_CRL *, ASN1_TIME *); diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py index 29602b3e..697d7d6e 100644 --- a/src/cryptography/x509.py +++ b/src/cryptography/x509.py @@ -42,8 +42,30 @@ _OID_NAMES = { "1.2.840.10040.4.3": "dsa-with-sha1", "2.16.840.1.101.3.4.3.1": "dsa-with-sha224", "2.16.840.1.101.3.4.3.2": "dsa-with-sha256", - "2.5.29.19": "basicConstraints", + "1.3.6.1.5.5.7.3.1": "serverAuth", + "1.3.6.1.5.5.7.3.2": "clientAuth", + "1.3.6.1.5.5.7.3.3": "codeSigning", + "1.3.6.1.5.5.7.3.4": "emailProtection", + "1.3.6.1.5.5.7.3.8": "timeStamping", + "1.3.6.1.5.5.7.3.9": "OCSPSigning", + "2.5.29.9": "subjectDirectoryAttributes", + "2.5.29.14": "subjectKeyIdentifier", "2.5.29.15": "keyUsage", + "2.5.29.17": "subjectAltName", + "2.5.29.18": "issuerAltName", + "2.5.29.19": "basicConstraints", + "2.5.29.30": "nameConstraints", + "2.5.29.31": "cRLDistributionPoints", + "2.5.29.32": "certificatePolicies", + "2.5.29.33": "policyMappings", + "2.5.29.35": "authorityKeyIdentifier", + "2.5.29.36": "policyConstraints", + "2.5.29.37": "extendedKeyUsage", + "2.5.29.46": "freshestCRL", + "2.5.29.54": "inhibitAnyPolicy", + "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", } @@ -60,6 +82,14 @@ def load_der_x509_certificate(data, backend): return backend.load_der_x509_certificate(data) +def load_pem_x509_csr(data, backend): + return backend.load_pem_x509_csr(data) + + +def load_der_x509_csr(data, backend): + return backend.load_der_x509_csr(data) + + class InvalidVersion(Exception): def __init__(self, msg, parsed_version): super(InvalidVersion, self).__init__(msg) @@ -78,6 +108,12 @@ class UnsupportedExtension(Exception): self.oid = oid +class ExtensionNotFound(Exception): + def __init__(self, msg, oid): + super(ExtensionNotFound, self).__init__(msg) + self.oid = oid + + class NameAttribute(object): def __init__(self, oid, value): if not isinstance(oid, ObjectIdentifier): @@ -155,14 +191,37 @@ class Name(object): return len(self._attributes) +OID_SUBJECT_DIRECTORY_ATTRIBUTES = ObjectIdentifier("2.5.29.9") +OID_SUBJECT_KEY_IDENTIFIER = ObjectIdentifier("2.5.29.14") OID_KEY_USAGE = ObjectIdentifier("2.5.29.15") +OID_SUBJECT_ALTERNATIVE_NAME = ObjectIdentifier("2.5.29.17") +OID_ISSUER_ALTERNATIVE_NAME = ObjectIdentifier("2.5.29.18") OID_BASIC_CONSTRAINTS = ObjectIdentifier("2.5.29.19") +OID_NAME_CONSTRAINTS = ObjectIdentifier("2.5.29.30") +OID_CRL_DISTRIBUTION_POINTS = ObjectIdentifier("2.5.29.31") +OID_CERTIFICATE_POLICIES = ObjectIdentifier("2.5.29.32") +OID_POLICY_MAPPINGS = ObjectIdentifier("2.5.29.33") +OID_AUTHORITY_KEY_IDENTIFIER = ObjectIdentifier("2.5.29.35") +OID_POLICY_CONSTRAINTS = ObjectIdentifier("2.5.29.36") +OID_EXTENDED_KEY_USAGE = ObjectIdentifier("2.5.29.37") +OID_FRESHEST_CRL = ObjectIdentifier("2.5.29.46") +OID_INHIBIT_ANY_POLICY = ObjectIdentifier("2.5.29.54") +OID_AUTHORITY_INFORMATION_ACCESS = ObjectIdentifier("1.3.6.1.5.5.7.1.1") +OID_SUBJECT_INFORMATION_ACCESS = ObjectIdentifier("1.3.6.1.5.5.7.1.11") +OID_OCSP_NO_CHECK = ObjectIdentifier("1.3.6.1.5.5.7.48.1.5") class Extensions(object): def __init__(self, extensions): self._extensions = extensions + def get_extension_for_oid(self, oid): + for ext in self: + if ext.oid == oid: + return ext + + raise ExtensionNotFound("No {0} extension was found".format(oid), oid) + def __iter__(self): return iter(self._extensions) @@ -193,6 +252,26 @@ class Extension(object): "value={0.value})>").format(self) +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" + ) + + self._usages = usages + + def __iter__(self): + return iter(self._usages) + + def __len__(self): + return len(self._usages) + + def __repr__(self): + return "<ExtendedKeyUsage({0})>".format(self._usages) + + class BasicConstraints(object): def __init__(self, ca, path_length): if not isinstance(ca, bool): @@ -220,6 +299,53 @@ class BasicConstraints(object): "path_length={0.path_length})>").format(self) +class KeyUsage(object): + def __init__(self, digital_signature, content_commitment, key_encipherment, + data_encipherment, key_agreement, key_cert_sign, crl_sign, + encipher_only, decipher_only): + if not key_agreement and (encipher_only or decipher_only): + raise ValueError( + "encipher_only and decipher_only can only be true when " + "key_agreement is true" + ) + + self._digital_signature = digital_signature + self._content_commitment = content_commitment + self._key_encipherment = key_encipherment + self._data_encipherment = data_encipherment + self._key_agreement = key_agreement + self._key_cert_sign = key_cert_sign + self._crl_sign = crl_sign + self._encipher_only = encipher_only + self._decipher_only = decipher_only + + digital_signature = utils.read_only_property("_digital_signature") + content_commitment = utils.read_only_property("_content_commitment") + key_encipherment = utils.read_only_property("_key_encipherment") + data_encipherment = utils.read_only_property("_data_encipherment") + key_agreement = utils.read_only_property("_key_agreement") + key_cert_sign = utils.read_only_property("_key_cert_sign") + crl_sign = utils.read_only_property("_crl_sign") + + @property + def encipher_only(self): + if not self.key_agreement: + raise ValueError( + "encipher_only is undefined unless key_agreement is true" + ) + else: + return self._encipher_only + + @property + def decipher_only(self): + if not self.key_agreement: + raise ValueError( + "decipher_only is undefined unless key_agreement is true" + ) + else: + return self._decipher_only + + OID_COMMON_NAME = ObjectIdentifier("2.5.4.3") OID_COUNTRY_NAME = ObjectIdentifier("2.5.4.6") OID_LOCALITY_NAME = ObjectIdentifier("2.5.4.7") @@ -266,6 +392,13 @@ _SIG_OIDS_TO_HASH = { OID_DSA_WITH_SHA256.dotted_string: hashes.SHA256() } +OID_SERVER_AUTH = ObjectIdentifier("1.3.6.1.5.5.7.3.1") +OID_CLIENT_AUTH = ObjectIdentifier("1.3.6.1.5.5.7.3.2") +OID_CODE_SIGNING = ObjectIdentifier("1.3.6.1.5.5.7.3.3") +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") + @six.add_metaclass(abc.ABCMeta) class Certificate(object): @@ -323,3 +456,25 @@ class Certificate(object): Returns a HashAlgorithm corresponding to the type of the digest signed in the certificate. """ + + +@six.add_metaclass(abc.ABCMeta) +class CertificateSigningRequest(object): + @abc.abstractmethod + def public_key(self): + """ + Returns the public key + """ + + @abc.abstractproperty + def subject(self): + """ + Returns the subject name object. + """ + + @abc.abstractproperty + def signature_hash_algorithm(self): + """ + Returns a HashAlgorithm corresponding to the type of the digest signed + in the certificate. + """ diff --git a/tests/hazmat/backends/test_multibackend.py b/tests/hazmat/backends/test_multibackend.py index 5a8891c4..5871e6c8 100644 --- a/tests/hazmat/backends/test_multibackend.py +++ b/tests/hazmat/backends/test_multibackend.py @@ -197,6 +197,12 @@ class DummyX509Backend(object): def load_der_x509_certificate(self, data): pass + def load_pem_x509_csr(self, data): + pass + + def load_der_x509_csr(self, data): + pass + class TestMultiBackend(object): def test_ciphers(self): @@ -472,9 +478,15 @@ class TestMultiBackend(object): backend.load_pem_x509_certificate(b"certdata") backend.load_der_x509_certificate(b"certdata") + backend.load_pem_x509_csr(b"reqdata") + backend.load_der_x509_csr(b"reqdata") backend = MultiBackend([]) with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_X509): backend.load_pem_x509_certificate(b"certdata") with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_X509): backend.load_der_x509_certificate(b"certdata") + with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_X509): + backend.load_pem_x509_csr(b"reqdata") + with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_X509): + backend.load_der_x509_csr(b"reqdata") diff --git a/tests/test_x509.py b/tests/test_x509.py index 2a472686..dc148d9d 100644 --- a/tests/test_x509.py +++ b/tests/test_x509.py @@ -340,6 +340,51 @@ class TestRSACertificate(object): with pytest.raises(UnsupportedAlgorithm): cert.signature_hash_algorithm + @pytest.mark.parametrize( + ("path", "loader_func"), + [ + [ + os.path.join("x509", "requests", "rsa_sha1.pem"), + x509.load_pem_x509_csr + ], + [ + os.path.join("x509", "requests", "rsa_sha1.der"), + x509.load_der_x509_csr + ], + ] + ) + def test_load_rsa_certificate_request(self, path, loader_func, backend): + request = _load_cert(path, loader_func, backend) + assert isinstance(request.signature_hash_algorithm, hashes.SHA1) + public_key = request.public_key() + assert isinstance(public_key, rsa.RSAPublicKey) + subject = request.subject + assert isinstance(subject, x509.Name) + assert list(subject) == [ + x509.NameAttribute(x509.OID_COUNTRY_NAME, 'US'), + x509.NameAttribute(x509.OID_STATE_OR_PROVINCE_NAME, 'Texas'), + x509.NameAttribute(x509.OID_LOCALITY_NAME, 'Austin'), + x509.NameAttribute(x509.OID_ORGANIZATION_NAME, 'PyCA'), + x509.NameAttribute(x509.OID_COMMON_NAME, 'cryptography.io'), + ] + + @pytest.mark.parametrize( + "loader_func", + [x509.load_pem_x509_csr, x509.load_der_x509_csr] + ) + def test_invalid_certificate_request(self, loader_func, backend): + with pytest.raises(ValueError): + loader_func(b"notacsr", backend) + + def test_unsupported_signature_hash_algorithm_request(self, backend): + request = _load_cert( + os.path.join("x509", "requests", "rsa_md4.pem"), + x509.load_pem_x509_csr, + backend + ) + with pytest.raises(UnsupportedAlgorithm): + request.signature_hash_algorithm + @pytest.mark.requires_backend_interface(interface=DSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) @@ -392,6 +437,34 @@ class TestDSACertificate(object): "822ff5d234e073b901cf5941f58e1f538e71d40d", 16 ) + @pytest.mark.parametrize( + ("path", "loader_func"), + [ + [ + os.path.join("x509", "requests", "dsa_sha1.pem"), + x509.load_pem_x509_csr + ], + [ + os.path.join("x509", "requests", "dsa_sha1.der"), + x509.load_der_x509_csr + ], + ] + ) + def test_load_dsa_request(self, path, loader_func, backend): + request = _load_cert(path, loader_func, backend) + assert isinstance(request.signature_hash_algorithm, hashes.SHA1) + public_key = request.public_key() + assert isinstance(public_key, dsa.DSAPublicKey) + subject = request.subject + assert isinstance(subject, x509.Name) + assert list(subject) == [ + x509.NameAttribute(x509.OID_COMMON_NAME, 'cryptography.io'), + x509.NameAttribute(x509.OID_ORGANIZATION_NAME, 'PyCA'), + x509.NameAttribute(x509.OID_COUNTRY_NAME, 'US'), + x509.NameAttribute(x509.OID_STATE_OR_PROVINCE_NAME, 'Texas'), + x509.NameAttribute(x509.OID_LOCALITY_NAME, 'Austin'), + ] + @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) @pytest.mark.requires_backend_interface(interface=X509Backend) @@ -428,6 +501,35 @@ class TestECDSACertificate(object): with pytest.raises(NotImplementedError): cert.public_key() + @pytest.mark.parametrize( + ("path", "loader_func"), + [ + [ + os.path.join("x509", "requests", "ec_sha256.pem"), + x509.load_pem_x509_csr + ], + [ + os.path.join("x509", "requests", "ec_sha256.der"), + x509.load_der_x509_csr + ], + ] + ) + def test_load_ecdsa_certificate_request(self, path, loader_func, backend): + _skip_curve_unsupported(backend, ec.SECP384R1()) + request = _load_cert(path, loader_func, backend) + assert isinstance(request.signature_hash_algorithm, hashes.SHA256) + public_key = request.public_key() + assert isinstance(public_key, ec.EllipticCurvePublicKey) + subject = request.subject + assert isinstance(subject, x509.Name) + assert list(subject) == [ + x509.NameAttribute(x509.OID_COMMON_NAME, 'cryptography.io'), + x509.NameAttribute(x509.OID_ORGANIZATION_NAME, 'PyCA'), + x509.NameAttribute(x509.OID_COUNTRY_NAME, 'US'), + x509.NameAttribute(x509.OID_STATE_OR_PROVINCE_NAME, 'Texas'), + x509.NameAttribute(x509.OID_LOCALITY_NAME, 'Austin'), + ] + class TestNameAttribute(object): def test_init_bad_oid(self): diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py index d8281526..c1512d5f 100644 --- a/tests/test_x509_ext.py +++ b/tests/test_x509_ext.py @@ -35,6 +35,103 @@ class TestExtension(object): ) +class TestKeyUsage(object): + def test_key_agreement_false_encipher_decipher_true(self): + with pytest.raises(ValueError): + x509.KeyUsage( + digital_signature=False, + content_commitment=False, + key_encipherment=False, + data_encipherment=False, + key_agreement=False, + key_cert_sign=False, + crl_sign=False, + encipher_only=True, + decipher_only=False + ) + + with pytest.raises(ValueError): + x509.KeyUsage( + digital_signature=False, + content_commitment=False, + key_encipherment=False, + data_encipherment=False, + key_agreement=False, + key_cert_sign=False, + crl_sign=False, + encipher_only=True, + decipher_only=True + ) + + with pytest.raises(ValueError): + x509.KeyUsage( + digital_signature=False, + content_commitment=False, + key_encipherment=False, + data_encipherment=False, + key_agreement=False, + key_cert_sign=False, + crl_sign=False, + encipher_only=False, + decipher_only=True + ) + + def test_properties_key_agreement_true(self): + ku = x509.KeyUsage( + digital_signature=True, + content_commitment=True, + key_encipherment=False, + data_encipherment=False, + key_agreement=False, + key_cert_sign=True, + crl_sign=False, + encipher_only=False, + decipher_only=False + ) + assert ku.digital_signature is True + assert ku.content_commitment is True + assert ku.key_encipherment is False + assert ku.data_encipherment is False + assert ku.key_agreement is False + assert ku.key_cert_sign is True + assert ku.crl_sign is False + + def test_key_agreement_true_properties(self): + ku = x509.KeyUsage( + digital_signature=False, + content_commitment=False, + key_encipherment=False, + data_encipherment=False, + key_agreement=True, + key_cert_sign=False, + crl_sign=False, + encipher_only=False, + decipher_only=True + ) + assert ku.key_agreement is True + assert ku.encipher_only is False + assert ku.decipher_only is True + + def test_key_agreement_false_properties(self): + ku = x509.KeyUsage( + digital_signature=False, + content_commitment=False, + key_encipherment=False, + data_encipherment=False, + key_agreement=False, + key_cert_sign=False, + crl_sign=False, + encipher_only=False, + decipher_only=False + ) + assert ku.key_agreement is False + with pytest.raises(ValueError): + ku.encipher_only + + with pytest.raises(ValueError): + ku.decipher_only + + class TestBasicConstraints(object): def test_ca_not_boolean(self): with pytest.raises(TypeError): @@ -62,6 +159,34 @@ class TestBasicConstraints(object): ) +class TestExtendedKeyUsage(object): + def test_not_all_oids(self): + with pytest.raises(TypeError): + x509.ExtendedKeyUsage(["notoid"]) + + def test_iter_len(self): + eku = x509.ExtendedKeyUsage([ + x509.ObjectIdentifier("1.3.6.1.5.5.7.3.1"), + x509.ObjectIdentifier("1.3.6.1.5.5.7.3.2"), + ]) + assert len(eku) == 2 + assert list(eku) == [ + x509.OID_SERVER_AUTH, + x509.OID_CLIENT_AUTH + ] + + def test_repr(self): + eku = x509.ExtendedKeyUsage([ + x509.ObjectIdentifier("1.3.6.1.5.5.7.3.1"), + x509.ObjectIdentifier("1.3.6.1.5.5.7.3.2"), + ]) + assert repr(eku) == ( + "<ExtendedKeyUsage([<ObjectIdentifier(oid=1.3.6.1.5.5.7.3.1, name=" + "serverAuth)>, <ObjectIdentifier(oid=1.3.6.1.5.5.7.3.2, name=clien" + "tAuth)>])>" + ) + + @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) class TestExtensions(object): @@ -74,6 +199,23 @@ class TestExtensions(object): ext = cert.extensions assert len(ext) == 0 assert list(ext) == [] + with pytest.raises(x509.ExtensionNotFound) as exc: + ext.get_extension_for_oid(x509.OID_BASIC_CONSTRAINTS) + + assert exc.value.oid == x509.OID_BASIC_CONSTRAINTS + + def test_one_extension(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "basic_constraints_not_critical.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + extensions = cert.extensions + ext = extensions.get_extension_for_oid(x509.OID_BASIC_CONSTRAINTS) + assert ext is not None + assert ext.value.ca is False def test_duplicate_extension(self, backend): cert = _load_cert( @@ -112,3 +254,94 @@ class TestExtensions(object): ) extensions = cert.extensions assert len(extensions) == 0 + + +@pytest.mark.requires_backend_interface(interface=RSABackend) +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestBasicConstraintsExtension(object): + def test_ca_true_pathlen_6(self, backend): + cert = _load_cert( + os.path.join( + "x509", "PKITS_data", "certs", "pathLenConstraint6CACert.crt" + ), + x509.load_der_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + x509.OID_BASIC_CONSTRAINTS + ) + assert ext is not None + assert ext.critical is True + assert ext.value.ca is True + assert ext.value.path_length == 6 + + def test_path_length_zero(self, backend): + cert = _load_cert( + os.path.join("x509", "custom", "bc_path_length_zero.pem"), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + x509.OID_BASIC_CONSTRAINTS + ) + assert ext is not None + assert ext.critical is True + assert ext.value.ca is True + assert ext.value.path_length == 0 + + def test_ca_true_no_pathlen(self, backend): + cert = _load_cert( + os.path.join("x509", "PKITS_data", "certs", "GoodCACert.crt"), + x509.load_der_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + x509.OID_BASIC_CONSTRAINTS + ) + assert ext is not None + assert ext.critical is True + assert ext.value.ca is True + assert ext.value.path_length is None + + def test_ca_false(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_BASIC_CONSTRAINTS + ) + assert ext is not None + assert ext.critical is True + assert ext.value.ca is False + assert ext.value.path_length is None + + def test_no_basic_constraints(self, backend): + cert = _load_cert( + os.path.join( + "x509", + "PKITS_data", + "certs", + "ValidCertificatePathTest1EE.crt" + ), + x509.load_der_x509_certificate, + backend + ) + with pytest.raises(x509.ExtensionNotFound): + cert.extensions.get_extension_for_oid(x509.OID_BASIC_CONSTRAINTS) + + def test_basic_constraint_not_critical(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "basic_constraints_not_critical.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + x509.OID_BASIC_CONSTRAINTS + ) + assert ext is not None + assert ext.critical is False + assert ext.value.ca is False diff --git a/vectors/cryptography_vectors/x509/custom/all_key_usages.pem b/vectors/cryptography_vectors/x509/custom/all_key_usages.pem new file mode 100644 index 00000000..e24caf28 --- /dev/null +++ b/vectors/cryptography_vectors/x509/custom/all_key_usages.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC6TCCAdGgAwIBAgITBmdJiX54UcRwde48tbHzferkszANBgkqhkiG9w0BAQUF +ADAmMRUwEwYDVQQDDAxjcnlwdG9ncmFwaHkxDTALBgNVBAoMBFB5Q0EwHhcNMTUw +NDAyMTgyMzIwWhcNMTYwNDAxMTgyMzIwWjAmMRUwEwYDVQQDDAxjcnlwdG9ncmFw +aHkxDTALBgNVBAoMBFB5Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQCtKAh5oo9zN6ATc8c7+kJNpi9uOOE1650X6H6F4XpDQGmg7uoOGpvZqi4BwkiJ +6tE6IR9qmfuksrSmVraBFGfXLKVknLBpB9aAAeBv7Kh7nrPfd39fbliwbW7NJIHH ++nG02FLPPMOdUKNyfTY2+kthkrjGCjYqOTEIUkFLgxk3/V2bmTSEiNGmi/1qQl9Y +pRJlaMYhDkS01Ox7/20uYI/S8EAXWQefV23szoesiiS6QvVncBRUeYCj+rQsr2+p +wXz1TWypLEukjo+C6SyjVEYUMUwYKg/0hBMQIpnAWuiNiiJArWf+l9a4O1SgsPG7 +nwWClir6jr33LBD5DF1cJCS3AgMBAAGjEDAOMAwGA1UdDwQFAwMH/4AwDQYJKoZI +hvcNAQEFBQADggEBAEJUuCiqMQYZowPi9OmyHGk7vAxh2MCKDQJDI1DhNdCPNoOl +nGSrNiFVRh6PAh3i+QSoh3pvbFvP0pCgasoaukqxKPK9pCKzBrwwsA7U7hvtJlIp +gOb5RG55mPDl5SxSJyHlOPHotG9ACeQOvbfqn3KM9Jn5aBir/laRKsSrM/daeeZ8 +4LQOb5pSNK41NKxeidm1AdNEMt33duYkhWZ63gviYvr6ri+3OOHhlFZeCI297TW9 +dHZpYMwi3hN7jYJLh5NFBNlnngG92lMcYfSBntjeCN2uPwO72utKMYb3kF/JxglX +dxeA+zWQjvhx3s2Zt8/N10JnnbKImPJdCA59X3M= +-----END CERTIFICATE----- diff --git a/vectors/cryptography_vectors/x509/requests/dsa_sha1.der b/vectors/cryptography_vectors/x509/requests/dsa_sha1.der Binary files differnew file mode 100644 index 00000000..35276d58 --- /dev/null +++ b/vectors/cryptography_vectors/x509/requests/dsa_sha1.der diff --git a/vectors/cryptography_vectors/x509/requests/ec_sha256.der b/vectors/cryptography_vectors/x509/requests/ec_sha256.der Binary files differnew file mode 100644 index 00000000..3a0cde2f --- /dev/null +++ b/vectors/cryptography_vectors/x509/requests/ec_sha256.der diff --git a/vectors/cryptography_vectors/x509/requests/rsa_md4.der b/vectors/cryptography_vectors/x509/requests/rsa_md4.der Binary files differnew file mode 100644 index 00000000..e9a3e953 --- /dev/null +++ b/vectors/cryptography_vectors/x509/requests/rsa_md4.der diff --git a/vectors/cryptography_vectors/x509/requests/rsa_sha1.der b/vectors/cryptography_vectors/x509/requests/rsa_sha1.der Binary files differnew file mode 100644 index 00000000..5bd63147 --- /dev/null +++ b/vectors/cryptography_vectors/x509/requests/rsa_sha1.der diff --git a/vectors/cryptography_vectors/x509/requests/rsa_sha256.der b/vectors/cryptography_vectors/x509/requests/rsa_sha256.der Binary files differnew file mode 100644 index 00000000..5c197754 --- /dev/null +++ b/vectors/cryptography_vectors/x509/requests/rsa_sha256.der diff --git a/vectors/cryptography_vectors/x509/requests/san_rsa_sha1.der b/vectors/cryptography_vectors/x509/requests/san_rsa_sha1.der Binary files differnew file mode 100644 index 00000000..c950e2e6 --- /dev/null +++ b/vectors/cryptography_vectors/x509/requests/san_rsa_sha1.der diff --git a/vectors/cryptography_vectors/x509/requests/san_rsa_sha1.pem b/vectors/cryptography_vectors/x509/requests/san_rsa_sha1.pem new file mode 100644 index 00000000..1db2bc1f --- /dev/null +++ b/vectors/cryptography_vectors/x509/requests/san_rsa_sha1.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIC4jCCAcoCAQAwWzELMAkGA1UEBhMCVVMxETAPBgNVBAgMCElsbGlub2lzMRAw +DgYDVQQHDAdDaGljYWdvMQ0wCwYDVQQKDARQeUNBMRgwFgYDVQQDDA9jcnlwdG9n +cmFwaHkuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqNTQULxLj +k/RirTqUfg/5PSUUQeBiNJd7aHIUfe/uXm+h+JV/wx+7pKV4VfLsog3Vc5NKwnt1 +5v2HUkrT4IfcU7bBKKBYENc8R+HqqcLDUtmW+XntuwJmLr/HX1kAT1XuaGorzTkf +SMVYlHlA7QagB8/jpxZATbmcHNPK4dUnlY+W70jO12hKtDYaIviHpCtIMNHLXso6 +xZS1tDr9a8DK2rFJ3OnPnoqPyhNkrUKt2tUC5aej2hZlewdZbKHax0xk+q4wTxT1 +qNQ9YiysHdnUdgzqXUJBIoqg/WKMxT2lUdF18nl5/DRQfJ2Ci49/T0AMnzt4PvJN +bxDf2uViMjAhAgMBAAGgQjBABgkqhkiG9w0BCQ4xMzAxMC8GA1UdEQQoMCaCD2Ny +eXB0b2dyYXBoeS5pb4ITc3ViLmNyeXB0b2dyYXBoeS5pbzANBgkqhkiG9w0BAQUF +AAOCAQEAavgmRwSFd8ASj5mQl03WdI+j+U2HIUhqiNU7taqM00FPcGdGs2nLApu3 +jH1MzZJ47pZD+Aqcb/8HD6MRYBgK8tH2pPdn7Z6cQZ1+cBBvOvXn771RPk+bQufs +J3lYe2eK6NZKY7a3nqCNCDK6p4sOnIF49GoXLABDO5/2iwCs7Zb1SOxw9YVoUQT8 +qzuO7DWO0ojKB7zUl9GEeKGiLvUZCi9cP7eA0Jf4ojrFeT6cwUr9g61h+bLLAOX0 +knAQVheFwSx2jeQk+J12ga8HCscst9Mx7IeZ+blADEXFALDXoVk8M+ZftvbaXABw +VUrJdCoVGtWDIk58Pvw71M+HqbQ3dg== +-----END CERTIFICATE REQUEST----- |