diff options
41 files changed, 888 insertions, 346 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 0bbbcde1..aad8d934 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,12 +8,16 @@ Changelog * Deprecated support for OpenSSL 0.9.8. Support will be removed in ``cryptography`` 1.4. -* Added support for the :class:`~cryptography.x509.PolicyConstraints` X.509 - extension. +* Added support for the :class:`~cryptography.x509.PolicyConstraints` + X.509 extension including both parsing and generation using + :class:`~cryptography.x509.CertificateBuilder` and + :class:`~cryptography.x509.CertificateSigningRequestBuilder`. * Added :attr:`~cryptography.x509.CertificateSigningRequest.is_signature_valid` to :class:`~cryptography.x509.CertificateSigningRequest`. * Fixed an intermittent ``AssertionError`` when performing an RSA decryption on an invalid ciphertext, ``ValueError`` is now correctly raised in all cases. +* Added + :meth:`~cryptography.x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier`. 1.2.3 - 2016-03-01 ~~~~~~~~~~~~~~~~~~ diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst index e09f0a0c..cc44492f 100644 --- a/docs/development/test-vectors.rst +++ b/docs/development/test-vectors.rst @@ -113,6 +113,9 @@ X.509 * ``department-of-state-root.pem`` - The intermediary CA for the Department of State, issued by the United States Federal Government's Common Policy CA. Notably has a ``critical`` policy constraints extensions. +* ``e-trust.ru.der`` - A certificate from a `Russian CA`_ signed using the GOST + cipher and containing numerous unusual encodings such as NUMERICSTRING in + the subject DN. Custom X.509 Vectors ~~~~~~~~~~~~~~~~~~~~ @@ -452,3 +455,4 @@ header format (substituting the correct information): .. _`root data`: https://hg.mozilla.org/projects/nss/file/25b2922cc564/security/nss/lib/ckfw/builtins/certdata.txt#l2053 .. _`asymmetric/public/PKCS1/dsa.pub.pem`: https://github.com/ruby/ruby/blob/4ccb387f3bc436a08fc6d72c4931994f5de95110/test/openssl/test_pkey_dsa.rb#L53 .. _`Mozilla bug`: https://bugzilla.mozilla.org/show_bug.cgi?id=233586 +.. _`Russian CA`: http://e-trust.gosuslugi.ru/MainCA diff --git a/docs/faq.rst b/docs/faq.rst index 10c8656b..3456ba97 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -14,5 +14,33 @@ to NaCl. If you prefer NaCl's design, we highly recommend `PyNaCl`_. +Compiling ``cryptography`` on OS X produces a ``fatal error: 'openssl/aes.h' file not found`` error +--------------------------------------------------------------------------------------------------- + +This happens because OS X 10.11 no longer includes a copy of OpenSSL. +``cryptography`` now provides wheels which include a statically linked copy of +OpenSSL. You're seeing this error because your copy of pip is too old to find +our wheel files. Upgrade your copy of pip with ``pip install -U pip`` and then +try install ``cryptography`` again. + +Starting ``cryptography`` using ``mod_wsgi`` produces an ``InternalError`` during a call in ``_register_osrandom_engine`` +------------------------------------------------------------------------------------------------------------------------- + +This happens because ``mod_wsgi`` uses sub-interpreters, which can cause a +problem during initialization of the OpenSSL backend. To resolve this set the +`WSGIApplicationGroup`_ to ``%{GLOBAL}`` in the ``mod_wsgi`` configuration. + +``cryptography`` raised an ``InternalError`` and I'm not sure what to do? +------------------------------------------------------------------------- + +Frequently ``InternalError`` is raised when there are errors on the OpenSSL +error stack that were placed there by other libraries that are also using +OpenSSL. Try removing the other libraries and see if the problem persists. +If you have no other libraries using OpenSSL in your process, or they do not +appear to be at fault, it's possible that this is a bug in ``cryptography``. +Please file an `issue`_ with instructions on how to reproduce it. + .. _`NaCl`: https://nacl.cr.yp.to/ .. _`PyNaCl`: https://pynacl.readthedocs.org +.. _`WSGIApplicationGroup`: https://modwsgi.readthedocs.org/en/develop/configuration-directives/WSGIApplicationGroup.html +.. _`issue`: https://github.com/pyca/cryptography/issues diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst index 67427ddb..399d693a 100644 --- a/docs/x509/reference.rst +++ b/docs/x509/reference.rst @@ -1541,6 +1541,13 @@ X.509 Extensions .. versionadded:: 1.0 + .. note:: + + This method should be used if the issuer certificate does not + contain a :class:`~cryptography.x509.SubjectKeyIdentifier`. + Otherwise, use + :meth:`~cryptography.x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier`. + Creates a new AuthorityKeyIdentifier instance using the public key provided to generate the appropriate digest. This should be the **issuer's public key**. The resulting object will contain @@ -1568,6 +1575,37 @@ X.509 Extensions >>> x509.AuthorityKeyIdentifier.from_issuer_public_key(issuer_cert.public_key()) <AuthorityKeyIdentifier(key_identifier='X\x01\x84$\x1b\xbc+R\x94J=\xa5\x10r\x14Q\xf5\xaf:\xc9', authority_cert_issuer=None, authority_cert_serial_number=None)> + .. classmethod:: from_issuer_subject_key_identifier(ski) + + .. versionadded:: 1.3 + + .. note:: + This method should be used if the issuer certificate contains a + :class:`~cryptography.x509.SubjectKeyIdentifier`. Otherwise, use + :meth:`~cryptography.x509.AuthorityKeyIdentifier.from_issuer_public_key`. + + Creates a new AuthorityKeyIdentifier instance using the + SubjectKeyIdentifier from the issuer certificate. The resulting object + will contain + :attr:`~cryptography.x509.AuthorityKeyIdentifier.key_identifier`, but + :attr:`~cryptography.x509.AuthorityKeyIdentifier.authority_cert_issuer` + and + :attr:`~cryptography.x509.AuthorityKeyIdentifier.authority_cert_serial_number` + will be None. + + :param ski: The + :class:`~cryptography.x509.SubjectKeyIdentifier` from the issuer + certificate. + + .. doctest:: + + >>> from cryptography import x509 + >>> from cryptography.hazmat.backends import default_backend + >>> issuer_cert = x509.load_pem_x509_certificate(pem_data, default_backend()) + >>> ski = issuer_cert.extensions.get_extension_for_class(x509.SubjectKeyIdentifier) + >>> x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(ski) + <AuthorityKeyIdentifier(key_identifier='X\x01\x84$\x1b\xbc+R\x94J=\xa5\x10r\x14Q\xf5\xaf:\xc9', authority_cert_issuer=None, authority_cert_serial_number=None)> + .. class:: SubjectKeyIdentifier(digest) .. versionadded:: 0.9 diff --git a/docs/x509/tutorial.rst b/docs/x509/tutorial.rst index 7252e43a..6941372f 100644 --- a/docs/x509/tutorial.rst +++ b/docs/x509/tutorial.rst @@ -82,3 +82,71 @@ a few details: ... f.write(csr.public_bytes(serialization.Encoding.PEM)) Now we can give our CSR to a CA, who will give a certificate to us in return. + +Creating a self-signed certificate +---------------------------------- + +While most of the time you want a certificate that has been *signed* by someone +else (i.e. a certificate authority), so that trust is established, sometimes +you want to create a self-signed certificate. Self-signed certificates are not +issued by a certificate authority, but instead they are signed by the private +key corresponding to the public key they embed. + +This means that other people don't trust these certificates, but it also means +they can be issued very easily. In general the only use case for a self-signed +certificate is local testing, where you don't need anyone else to trust your +certificate. + +Like generating a CSR, we start with creating a new private key: + +.. code-block:: pycon + + >>> # Generate our key + >>> key = rsa.generate_private_key( + ... public_exponent=65537, + ... key_size=2048, + ... backend=default_backend() + ... ) + >>> # Write our key to disk for safe keeping + >>> with open("path/to/store/key.pem", "wb") as f: + ... f.write(key.private_bytes( + ... encoding=serialization.Encoding.PEM, + ... format=serialization.PrivateFormat.TraditionalOpenSSL, + ... encryption_algorithm=serialization.BestAvailableEncryption(b"passphrase"), + ... )) + +Then we generate the certificate itself: + +.. code-block:: pycon + + >>> # Various details about who we are. For a self-signed certificate the + >>> # subject and issuer are always the same. + >>> subject = issuer = x509.Name([ + ... x509.NameAttribute(NameOID.COUNTRY_NAME, u"US"), + ... x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u"CA"), + ... x509.NameAttribute(NameOID.LOCALITY_NAME, u"San Francisco"), + ... x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"My Company"), + ... x509.NameAttribute(NameOID.COMMON_NAME, u"mysite.com"), + ... ]) + >>> cert = x509.CertificateBuilder().subject_name( + ... subject + ... ).issuer_name( + ... issuer + ... ).public_key( + ... private_key.public_key() + ... ).not_valid_before( + ... datetime.datetime.utcnow() + ... ).not_valid_after( + ... # Our certificate will be valid for 10 days + ... datetime.datetime.utcnow() + datetime.timedelta(days=10) + ... ).add_extension( + ... x509.SubjectAlternativeName([x509.DNSName(u"localhost")]), + ... critical=False, + ... # Sign our certificate with our private key + ... ).sign(private_key, hashes.SHA256(), default_backend()) + >>> # Write our certificate out to disk. + >>> with open("path/to/certificate.pem", "wb") as f: + ... f.write(cert.public_bytes(serialization.Encoding.PEM)) + +And now we have a private key and certificate that can be used for local +testing. diff --git a/src/_cffi_src/build_openssl.py b/src/_cffi_src/build_openssl.py index ba6e17b3..2ff28d75 100644 --- a/src/_cffi_src/build_openssl.py +++ b/src/_cffi_src/build_openssl.py @@ -42,21 +42,6 @@ _PRE_INCLUDE = """ #if defined(OPENSSL_SYS_WINDOWS) #include <windows.h> #endif -#ifdef __APPLE__ -#include <AvailabilityMacros.h> -#define __ORIG_DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER \ - DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER -#undef DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER -#define DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER -#endif -""" - -_POST_INCLUDE = """ -#ifdef __APPLE__ -#undef DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER -#define DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER \ - __ORIG_DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER -#endif """ @@ -70,7 +55,6 @@ ffi = build_ffi_for_binding( "bio", "cmac", "cms", - "conf", "crypto", "dh", "dsa", @@ -98,7 +82,6 @@ ffi = build_ffi_for_binding( "callbacks", ], pre_include=_PRE_INCLUDE, - post_include=_POST_INCLUDE, libraries=_get_openssl_libraries(sys.platform), extra_link_args=extra_link_args(compiler_type()), ) diff --git a/src/_cffi_src/openssl/aes.py b/src/_cffi_src/openssl/aes.py index 8a5d0471..438431b5 100644 --- a/src/_cffi_src/openssl/aes.py +++ b/src/_cffi_src/openssl/aes.py @@ -10,6 +10,7 @@ INCLUDES = """ TYPES = """ static const int Cryptography_HAS_AES_WRAP; +static const int Cryptography_HAS_AES_CTR128_ENCRYPT; struct aes_key_st { ...; @@ -50,5 +51,13 @@ int (*AES_wrap_key)(AES_KEY *, const unsigned char *, unsigned char *, int (*AES_unwrap_key)(AES_KEY *, const unsigned char *, unsigned char *, const unsigned char *, unsigned int) = NULL; #endif - +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) +static const int Cryptography_HAS_AES_CTR128_ENCRYPT = 0; +void (*AES_ctr128_encrypt)(const unsigned char *, unsigned char *, + const size_t, const AES_KEY *, + unsigned char[], unsigned char[], + unsigned int *) = NULL; +#else +static const int Cryptography_HAS_AES_CTR128_ENCRYPT = 1; +#endif """ diff --git a/src/_cffi_src/openssl/asn1.py b/src/_cffi_src/openssl/asn1.py index 30bd2451..084eec2c 100644 --- a/src/_cffi_src/openssl/asn1.py +++ b/src/_cffi_src/openssl/asn1.py @@ -24,6 +24,7 @@ struct asn1_string_st { typedef struct asn1_string_st ASN1_OCTET_STRING; typedef struct asn1_string_st ASN1_IA5STRING; typedef struct asn1_string_st ASN1_BIT_STRING; +typedef struct asn1_string_st ASN1_TIME; typedef ... ASN1_OBJECT; typedef struct asn1_string_st ASN1_STRING; typedef struct asn1_string_st ASN1_UTF8STRING; @@ -33,9 +34,6 @@ typedef ... ASN1_ENUMERATED; typedef ... ASN1_ITEM; typedef ... ASN1_VALUE; -typedef struct { - ...; -} ASN1_TIME; typedef ... ASN1_ITEM_EXP; typedef ... ASN1_UTCTIME; @@ -155,4 +153,10 @@ ASN1_TYPE *d2i_ASN1_TYPE(ASN1_TYPE **, const unsigned char **, long); """ CUSTOMIZATIONS = """ +/* This macro is removed in 1.1.0. We re-add it if required to support + pyOpenSSL versions older than whatever resolves + https://github.com/pyca/pyopenssl/issues/431 */ +#if !defined(M_ASN1_TIME_dup) +#define M_ASN1_TIME_dup(a) (ASN1_TIME *)ASN1_STRING_dup((const ASN1_STRING *)a) +#endif """ diff --git a/src/_cffi_src/openssl/bio.py b/src/_cffi_src/openssl/bio.py index 6439e63a..df9b1b48 100644 --- a/src/_cffi_src/openssl/bio.py +++ b/src/_cffi_src/openssl/bio.py @@ -68,8 +68,6 @@ static const int BIO_CTRL_WPENDING; static const int BIO_C_FILE_SEEK; static const int BIO_C_FILE_TELL; static const int BIO_TYPE_NONE; -static const int BIO_TYPE_PROXY_CLIENT; -static const int BIO_TYPE_PROXY_SERVER; static const int BIO_TYPE_NBIO_TEST; static const int BIO_TYPE_BER; static const int BIO_TYPE_BIO; @@ -113,7 +111,6 @@ long BIO_callback_ctrl( int, void (*)(struct bio_st *, int, const char *, int, long, long) ); -char *BIO_ptr_ctrl(BIO *, int, long); long BIO_int_ctrl(BIO *, int, long, int); size_t BIO_ctrl_pending(BIO *); size_t BIO_ctrl_wpending(BIO *); diff --git a/src/_cffi_src/openssl/conf.py b/src/_cffi_src/openssl/conf.py deleted file mode 100644 index c89ae5ca..00000000 --- a/src/_cffi_src/openssl/conf.py +++ /dev/null @@ -1,24 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import absolute_import, division, print_function - -INCLUDES = """ -#include <openssl/conf.h> -""" - -TYPES = """ -typedef ... CONF; -""" - -FUNCTIONS = """ -void OPENSSL_config(const char *); -void OPENSSL_no_config(void); -""" - -MACROS = """ -""" - -CUSTOMIZATIONS = """ -""" diff --git a/src/_cffi_src/openssl/crypto.py b/src/_cffi_src/openssl/crypto.py index 3c045410..9357815b 100644 --- a/src/_cffi_src/openssl/crypto.py +++ b/src/_cffi_src/openssl/crypto.py @@ -16,6 +16,11 @@ static const int SSLEAY_CFLAGS; static const int SSLEAY_PLATFORM; static const int SSLEAY_DIR; static const int SSLEAY_BUILT_ON; +static const int OPENSSL_VERSION; +static const int OPENSSL_CFLAGS; +static const int OPENSSL_BUILT_ON; +static const int OPENSSL_PLATFORM; +static const int OPENSSL_DIR; static const int CRYPTO_MEM_CHECK_ON; static const int CRYPTO_MEM_CHECK_OFF; static const int CRYPTO_MEM_CHECK_ENABLE; @@ -28,9 +33,6 @@ static const int CRYPTO_LOCK_SSL; """ FUNCTIONS = """ -unsigned long SSLeay(void); -const char *SSLeay_version(int); - void CRYPTO_free(void *); int CRYPTO_mem_ctrl(int); int CRYPTO_is_mem_check_on(void); @@ -38,8 +40,6 @@ void CRYPTO_mem_leaks(struct bio_st *); void CRYPTO_cleanup_all_ex_data(void); int CRYPTO_num_locks(void); void CRYPTO_set_locking_callback(void(*)(int, int, const char *, int)); -void CRYPTO_set_id_callback(unsigned long (*)(void)); -unsigned long (*CRYPTO_get_id_callback(void))(void); void (*CRYPTO_get_locking_callback(void))(int, int, const char *, int); void CRYPTO_lock(int, int, const char *, int); @@ -47,9 +47,38 @@ void OPENSSL_free(void *); """ MACROS = """ +/* SSLeay was removed in 1.1.0 */ +unsigned long SSLeay(void); +const char *SSLeay_version(int); +/* these functions were added to replace the SSLeay functions in 1.1.0 */ +unsigned long OpenSSL_version_num(void); +const char *OpenSSL_version(int); + void CRYPTO_add(int *, int, int); -void CRYPTO_malloc_init(void); """ CUSTOMIZATIONS = """ +/* In 1.1.0 SSLeay has finally been retired. We bidirectionally define the + values so you can use either one. This is so we can use the new function + names no matter what OpenSSL we're running on, but users on older pyOpenSSL + releases won't see issues if they're running OpenSSL 1.1.0 */ +#if !defined(SSLEAY_VERSION) +# define SSLeay OpenSSL_version_num +# define SSLeay_version OpenSSL_version +# define SSLEAY_VERSION_NUMBER OPENSSL_VERSION_NUMBER +# define SSLEAY_VERSION OPENSSL_VERSION +# define SSLEAY_CFLAGS OPENSSL_CFLAGS +# define SSLEAY_BUILT_ON OPENSSL_BUILT_ON +# define SSLEAY_PLATFORM OPENSSL_PLATFORM +# define SSLEAY_DIR OPENSSL_DIR +#endif +#if !defined(OPENSSL_VERSION) +# define OpenSSL_version_num SSLeay +# define OpenSSL_version SSLeay_version +# define OPENSSL_VERSION SSLEAY_VERSION +# define OPENSSL_CFLAGS SSLEAY_CFLAGS +# define OPENSSL_BUILT_ON SSLEAY_BUILT_ON +# define OPENSSL_PLATFORM SSLEAY_PLATFORM +# define OPENSSL_DIR SSLEAY_DIR +#endif """ diff --git a/src/_cffi_src/openssl/dh.py b/src/_cffi_src/openssl/dh.py index 8df66f8b..8055d0c8 100644 --- a/src/_cffi_src/openssl/dh.py +++ b/src/_cffi_src/openssl/dh.py @@ -29,7 +29,6 @@ FUNCTIONS = """ DH *DH_new(void); void DH_free(DH *); int DH_size(const DH *); -DH *DH_generate_parameters(int, int, void (*)(int, int, void *), void *); int DH_check(const DH *, int *); int DH_check_pub_key(const DH *, const BIGNUM *, int *); int DH_generate_key(DH *); diff --git a/src/_cffi_src/openssl/ec.py b/src/_cffi_src/openssl/ec.py index f5cbf968..91603096 100644 --- a/src/_cffi_src/openssl/ec.py +++ b/src/_cffi_src/openssl/ec.py @@ -76,8 +76,8 @@ int EC_KEY_get_flags(const EC_KEY *); void EC_KEY_set_flags(EC_KEY *, int); void EC_KEY_clear_flags(EC_KEY *, int); EC_KEY *EC_KEY_new_by_curve_name(int); -EC_KEY *EC_KEY_copy(EC_KEY *, const EC_KEY *); -EC_KEY *EC_KEY_dup(const EC_KEY *); +EC_KEY *EC_KEY_copy(EC_KEY *, EC_KEY *); +EC_KEY *EC_KEY_dup(EC_KEY *); int EC_KEY_up_ref(EC_KEY *); const EC_GROUP *EC_KEY_get0_group(const EC_KEY *); int EC_GROUP_get_order(const EC_GROUP *, BIGNUM *, BN_CTX *); @@ -90,19 +90,6 @@ unsigned int EC_KEY_get_enc_flags(const EC_KEY *); void EC_KEY_set_enc_flags(EC_KEY *eckey, unsigned int); point_conversion_form_t EC_KEY_get_conv_form(const EC_KEY *); void EC_KEY_set_conv_form(EC_KEY *, point_conversion_form_t); -void *EC_KEY_get_key_method_data( - EC_KEY *, - void *(*)(void *), - void (*)(void *), - void (*)(void *) -); -void EC_KEY_insert_key_method_data( - EC_KEY *, - void *, - void *(*)(void *), - void (*)(void *), - void (*)(void *) -); void EC_KEY_set_asn1_flag(EC_KEY *, int); int EC_KEY_precompute_mult(EC_KEY *, BN_CTX *); int EC_KEY_generate_key(EC_KEY *); @@ -237,11 +224,6 @@ unsigned int (*EC_KEY_get_enc_flags)(const EC_KEY *) = NULL; void (*EC_KEY_set_enc_flags)(EC_KEY *eckey, unsigned int) = NULL; point_conversion_form_t (*EC_KEY_get_conv_form)(const EC_KEY *) = NULL; void (*EC_KEY_set_conv_form)(EC_KEY *, point_conversion_form_t) = NULL; -void *(*EC_KEY_get_key_method_data)( - EC_KEY *, void *(*)(void *), void (*)(void *), void (*)(void *)) = NULL; -void (*EC_KEY_insert_key_method_data)( - EC_KEY *, void *, - void *(*)(void *), void (*)(void *), void (*)(void *)) = NULL; void (*EC_KEY_set_asn1_flag)(EC_KEY *, int) = NULL; int (*EC_KEY_precompute_mult)(EC_KEY *, BN_CTX *) = NULL; int (*EC_KEY_generate_key)(EC_KEY *) = NULL; diff --git a/src/_cffi_src/openssl/ecdh.py b/src/_cffi_src/openssl/ecdh.py index 3116c3b6..099f53cb 100644 --- a/src/_cffi_src/openssl/ecdh.py +++ b/src/_cffi_src/openssl/ecdh.py @@ -20,13 +20,6 @@ FUNCTIONS = """ MACROS = """ int ECDH_compute_key(void *, size_t, const EC_POINT *, EC_KEY *, void *(*)(const void *, size_t, void *, size_t *)); - -int ECDH_get_ex_new_index(long, void *, CRYPTO_EX_new *, CRYPTO_EX_dup *, - CRYPTO_EX_free *); - -int ECDH_set_ex_data(EC_KEY *, int, void *); - -void *ECDH_get_ex_data(EC_KEY *, int); """ CUSTOMIZATIONS = """ @@ -37,13 +30,6 @@ int (*ECDH_compute_key)(void *, size_t, const EC_POINT *, EC_KEY *, void *(*)(const void *, size_t, void *, size_t *)) = NULL; -int (*ECDH_get_ex_new_index)(long, void *, CRYPTO_EX_new *, CRYPTO_EX_dup *, - CRYPTO_EX_free *) = NULL; - -int (*ECDH_set_ex_data)(EC_KEY *, int, void *) = NULL; - -void *(*ECDH_get_ex_data)(EC_KEY *, int) = NULL; - #else static const long Cryptography_HAS_ECDH = 1; #endif diff --git a/src/_cffi_src/openssl/ecdsa.py b/src/_cffi_src/openssl/ecdsa.py index f231864b..f3e9fba0 100644 --- a/src/_cffi_src/openssl/ecdsa.py +++ b/src/_cffi_src/openssl/ecdsa.py @@ -13,10 +13,7 @@ INCLUDES = """ TYPES = """ static const int Cryptography_HAS_ECDSA; -typedef struct { - BIGNUM *r; - BIGNUM *s; -} ECDSA_SIG; +typedef ... ECDSA_SIG; typedef ... CRYPTO_EX_new; typedef ... CRYPTO_EX_dup; @@ -44,14 +41,6 @@ int ECDSA_verify(int, const unsigned char *, int, const unsigned char *, int, EC_KEY *); int ECDSA_size(const EC_KEY *); -const ECDSA_METHOD *ECDSA_OpenSSL(); -void ECDSA_set_default_method(const ECDSA_METHOD *); -const ECDSA_METHOD *ECDSA_get_default_method(); -int ECDSA_get_ex_new_index(long, void *, CRYPTO_EX_new *, - CRYPTO_EX_dup *, CRYPTO_EX_free *); -int ECDSA_set_method(EC_KEY *, const ECDSA_METHOD *); -int ECDSA_set_ex_data(EC_KEY *, int, void *); -void *ECDSA_get_ex_data(EC_KEY *, int); """ CUSTOMIZATIONS = """ @@ -83,14 +72,6 @@ int (*ECDSA_verify)(int, const unsigned char *, int, const unsigned char *, int, EC_KEY *) = NULL; int (*ECDSA_size)(const EC_KEY *) = NULL; -const ECDSA_METHOD* (*ECDSA_OpenSSL)() = NULL; -void (*ECDSA_set_default_method)(const ECDSA_METHOD *) = NULL; -const ECDSA_METHOD* (*ECDSA_get_default_method)() = NULL; -int (*ECDSA_set_method)(EC_KEY *, const ECDSA_METHOD *) = NULL; -int (*ECDSA_get_ex_new_index)(long, void *, CRYPTO_EX_new *, - CRYPTO_EX_dup *, CRYPTO_EX_free *) = NULL; -int (*ECDSA_set_ex_data)(EC_KEY *, int, void *) = NULL; -void* (*ECDSA_get_ex_data)(EC_KEY *, int) = NULL; #else static const long Cryptography_HAS_ECDSA = 1; #endif diff --git a/src/_cffi_src/openssl/engine.py b/src/_cffi_src/openssl/engine.py index 60c6f3e2..afdd54e4 100644 --- a/src/_cffi_src/openssl/engine.py +++ b/src/_cffi_src/openssl/engine.py @@ -14,18 +14,13 @@ static const long Cryptography_HAS_ENGINE_CRYPTODEV; typedef ... ENGINE; typedef ... RSA_METHOD; typedef ... DSA_METHOD; -typedef ... ECDH_METHOD; -typedef ... ECDSA_METHOD; typedef ... DH_METHOD; typedef struct { - void (*seed)(const void *, int); int (*bytes)(unsigned char *, int); - void (*cleanup)(); - void (*add)(const void *, int, double); int (*pseudorand)(unsigned char *, int); int (*status)(); + ...; } RAND_METHOD; -typedef ... STORE_METHOD; typedef int (*ENGINE_GEN_INT_FUNC_PTR)(ENGINE *); typedef ... *ENGINE_CTRL_FUNC_PTR; typedef ... *ENGINE_LOAD_KEY_PTR; @@ -37,11 +32,8 @@ typedef ... UI_METHOD; static const unsigned int ENGINE_METHOD_RSA; static const unsigned int ENGINE_METHOD_DSA; static const unsigned int ENGINE_METHOD_RAND; -static const unsigned int ENGINE_METHOD_ECDH; -static const unsigned int ENGINE_METHOD_ECDSA; static const unsigned int ENGINE_METHOD_CIPHERS; static const unsigned int ENGINE_METHOD_DIGESTS; -static const unsigned int ENGINE_METHOD_STORE; static const unsigned int ENGINE_METHOD_ALL; static const unsigned int ENGINE_METHOD_NONE; @@ -58,22 +50,16 @@ int ENGINE_remove(ENGINE *); ENGINE *ENGINE_by_id(const char *); int ENGINE_init(ENGINE *); int ENGINE_finish(ENGINE *); -void ENGINE_load_openssl(void); -void ENGINE_load_dynamic(void); void ENGINE_load_builtin_engines(void); void ENGINE_cleanup(void); ENGINE *ENGINE_get_default_RSA(void); ENGINE *ENGINE_get_default_DSA(void); -ENGINE *ENGINE_get_default_ECDH(void); -ENGINE *ENGINE_get_default_ECDSA(void); ENGINE *ENGINE_get_default_DH(void); ENGINE *ENGINE_get_default_RAND(void); ENGINE *ENGINE_get_cipher_engine(int); ENGINE *ENGINE_get_digest_engine(int); int ENGINE_set_default_RSA(ENGINE *); int ENGINE_set_default_DSA(ENGINE *); -int ENGINE_set_default_ECDH(ENGINE *); -int ENGINE_set_default_ECDSA(ENGINE *); int ENGINE_set_default_DH(ENGINE *); int ENGINE_set_default_RAND(ENGINE *); int ENGINE_set_default_ciphers(ENGINE *); @@ -88,21 +74,12 @@ void ENGINE_register_all_RSA(void); int ENGINE_register_DSA(ENGINE *); void ENGINE_unregister_DSA(ENGINE *); void ENGINE_register_all_DSA(void); -int ENGINE_register_ECDH(ENGINE *); -void ENGINE_unregister_ECDH(ENGINE *); -void ENGINE_register_all_ECDH(void); -int ENGINE_register_ECDSA(ENGINE *); -void ENGINE_unregister_ECDSA(ENGINE *); -void ENGINE_register_all_ECDSA(void); int ENGINE_register_DH(ENGINE *); void ENGINE_unregister_DH(ENGINE *); void ENGINE_register_all_DH(void); int ENGINE_register_RAND(ENGINE *); void ENGINE_unregister_RAND(ENGINE *); void ENGINE_register_all_RAND(void); -int ENGINE_register_STORE(ENGINE *); -void ENGINE_unregister_STORE(ENGINE *); -void ENGINE_register_all_STORE(void); int ENGINE_register_ciphers(ENGINE *); void ENGINE_unregister_ciphers(ENGINE *); void ENGINE_register_all_ciphers(void); @@ -123,11 +100,8 @@ int ENGINE_set_id(ENGINE *, const char *); int ENGINE_set_name(ENGINE *, const char *); int ENGINE_set_RSA(ENGINE *, const RSA_METHOD *); int ENGINE_set_DSA(ENGINE *, const DSA_METHOD *); -int ENGINE_set_ECDH(ENGINE *, const ECDH_METHOD *); -int ENGINE_set_ECDSA(ENGINE *, const ECDSA_METHOD *); int ENGINE_set_DH(ENGINE *, const DH_METHOD *); int ENGINE_set_RAND(ENGINE *, const RAND_METHOD *); -int ENGINE_set_STORE(ENGINE *, const STORE_METHOD *); int ENGINE_set_destroy_function(ENGINE *, ENGINE_GEN_INT_FUNC_PTR); int ENGINE_set_init_function(ENGINE *, ENGINE_GEN_INT_FUNC_PTR); int ENGINE_set_finish_function(ENGINE *, ENGINE_GEN_INT_FUNC_PTR); @@ -142,11 +116,8 @@ const char *ENGINE_get_id(const ENGINE *); const char *ENGINE_get_name(const ENGINE *); const RSA_METHOD *ENGINE_get_RSA(const ENGINE *); const DSA_METHOD *ENGINE_get_DSA(const ENGINE *); -const ECDH_METHOD *ENGINE_get_ECDH(const ENGINE *); -const ECDSA_METHOD *ENGINE_get_ECDSA(const ENGINE *); const DH_METHOD *ENGINE_get_DH(const ENGINE *); const RAND_METHOD *ENGINE_get_RAND(const ENGINE *); -const STORE_METHOD *ENGINE_get_STORE(const ENGINE *); const EVP_CIPHER *ENGINE_get_cipher(ENGINE *, int); const EVP_MD *ENGINE_get_digest(ENGINE *, int); @@ -158,6 +129,10 @@ void ENGINE_add_conf_module(void); """ MACROS = """ +/* these became macros in 1.1.0 */ +void ENGINE_load_openssl(void); +void ENGINE_load_dynamic(void); + void ENGINE_load_cryptodev(void); """ diff --git a/src/_cffi_src/openssl/err.py b/src/_cffi_src/openssl/err.py index 4ba90662..e31b1808 100644 --- a/src/_cffi_src/openssl/err.py +++ b/src/_cffi_src/openssl/err.py @@ -88,7 +88,6 @@ static const int ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM; static const int ASN1_R_UNKNOWN_OBJECT_TYPE; static const int ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE; static const int ASN1_R_UNKNOWN_TAG; -static const int ASN1_R_UNKOWN_FORMAT; static const int ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE; static const int ASN1_R_UNSUPPORTED_ENCRYPTION_ALGORITHM; static const int ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE; @@ -121,11 +120,6 @@ static const int EVP_F_EVP_PKEY2PKCS8_BROKEN; static const int EVP_F_EVP_PKEY_COPY_PARAMETERS; static const int EVP_F_EVP_PKEY_DECRYPT; static const int EVP_F_EVP_PKEY_ENCRYPT; -static const int EVP_F_EVP_PKEY_GET1_DH; -static const int EVP_F_EVP_PKEY_GET1_DSA; -static const int EVP_F_EVP_PKEY_GET1_ECDSA; -static const int EVP_F_EVP_PKEY_GET1_EC_KEY; -static const int EVP_F_EVP_PKEY_GET1_RSA; static const int EVP_F_EVP_PKEY_NEW; static const int EVP_F_EVP_RIJNDAEL; static const int EVP_F_EVP_SIGNFINAL; @@ -195,8 +189,6 @@ static const int PEM_F_PEM_READ; static const int PEM_F_PEM_READ_BIO; static const int PEM_F_PEM_READ_BIO_PRIVATEKEY; static const int PEM_F_PEM_READ_PRIVATEKEY; -static const int PEM_F_PEM_SEALFINAL; -static const int PEM_F_PEM_SEALINIT; static const int PEM_F_PEM_SIGNFINAL; static const int PEM_F_PEM_WRITE; static const int PEM_F_PEM_WRITE_BIO; @@ -236,8 +228,6 @@ static const int RSA_F_RSA_SIGN; """ FUNCTIONS = """ -void ERR_load_crypto_strings(void); -void ERR_load_SSL_strings(void); void ERR_free_strings(void); char *ERR_error_string(unsigned long, char *); void ERR_error_string_n(unsigned long, char *, size_t); diff --git a/src/_cffi_src/openssl/evp.py b/src/_cffi_src/openssl/evp.py index 1d37b814..5abc6451 100644 --- a/src/_cffi_src/openssl/evp.py +++ b/src/_cffi_src/openssl/evp.py @@ -10,16 +10,9 @@ INCLUDES = """ TYPES = """ typedef ... EVP_CIPHER; -typedef struct { - const EVP_CIPHER *cipher; - ENGINE *engine; - int encrypt; - ...; -} EVP_CIPHER_CTX; +typedef ... EVP_CIPHER_CTX; typedef ... EVP_MD; -typedef struct env_md_ctx_st { - ...; -} EVP_MD_CTX; +typedef struct { ...; } EVP_MD_CTX; typedef ... EVP_PKEY; typedef ... EVP_PKEY_CTX; @@ -56,18 +49,15 @@ int EVP_CipherUpdate(EVP_CIPHER_CTX *, unsigned char *, int *, const unsigned char *, int); int EVP_CipherFinal_ex(EVP_CIPHER_CTX *, unsigned char *, int *); int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *); -void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *); EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(void); void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *); int EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *, int); -EVP_MD_CTX *EVP_MD_CTX_create(void); int EVP_MD_CTX_copy_ex(EVP_MD_CTX *, const EVP_MD_CTX *); int EVP_DigestInit_ex(EVP_MD_CTX *, const EVP_MD *, ENGINE *); int EVP_DigestUpdate(EVP_MD_CTX *, const void *, size_t); int EVP_DigestFinal_ex(EVP_MD_CTX *, unsigned char *, unsigned int *); int EVP_MD_CTX_cleanup(EVP_MD_CTX *); -void EVP_MD_CTX_destroy(EVP_MD_CTX *); const EVP_MD *EVP_get_digestbyname(const char *); EVP_PKEY *EVP_PKEY_new(void); @@ -121,9 +111,18 @@ int EVP_PKEY_cmp(const EVP_PKEY *, const EVP_PKEY *); EVP_PKEY *EVP_PKCS82PKEY(PKCS8_PRIV_KEY_INFO *); int Cryptography_EVP_PKEY_id(const EVP_PKEY *); + +/* in 1.1.0 _create and _destroy were renamed to _new and _free. The following + two functions wrap both the old and new functions so we can call them + without worrying about what OpenSSL we're running against. */ +EVP_MD_CTX *Cryptography_EVP_MD_CTX_new(void); +void Cryptography_EVP_MD_CTX_free(EVP_MD_CTX *); """ MACROS = """ +/* became a macro in 1.1.0 */ +void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *); + void OpenSSL_add_all_algorithms(void); int EVP_PKEY_assign_RSA(EVP_PKEY *, RSA *); int EVP_PKEY_assign_DSA(EVP_PKEY *, DSA *); @@ -238,4 +237,18 @@ int Cryptography_EVP_PKEY_id(const EVP_PKEY *key) { return key->type; #endif } +EVP_MD_CTX *Cryptography_EVP_MD_CTX_new(void) { +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) + return EVP_MD_CTX_create(); +#else + return EVP_MD_CTX_new(); +#endif +} +void Cryptography_EVP_MD_CTX_free(EVP_MD_CTX *ctx) { +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) + EVP_MD_CTX_destroy(ctx); +#else + EVP_MD_CTX_free(ctx); +#endif +} """ diff --git a/src/_cffi_src/openssl/hmac.py b/src/_cffi_src/openssl/hmac.py index 7178e573..bcc8a861 100644 --- a/src/_cffi_src/openssl/hmac.py +++ b/src/_cffi_src/openssl/hmac.py @@ -9,18 +9,17 @@ INCLUDES = """ """ TYPES = """ -typedef struct { ...; } HMAC_CTX; +typedef ... HMAC_CTX; """ FUNCTIONS = """ -void HMAC_CTX_init(HMAC_CTX *); -void HMAC_CTX_cleanup(HMAC_CTX *); - int Cryptography_HMAC_Init_ex(HMAC_CTX *, const void *, int, const EVP_MD *, ENGINE *); int Cryptography_HMAC_Update(HMAC_CTX *, const unsigned char *, size_t); int Cryptography_HMAC_Final(HMAC_CTX *, unsigned char *, unsigned int *); int Cryptography_HMAC_CTX_copy(HMAC_CTX *, HMAC_CTX *); +HMAC_CTX *Cryptography_HMAC_CTX_new(void); +void Cryptography_HMAC_CTX_free(HMAC_CTX *ctx); """ MACROS = """ @@ -80,4 +79,28 @@ int Cryptography_HMAC_CTX_copy(HMAC_CTX *dst_ctx, HMAC_CTX *src_ctx) { return 0; #endif } + +HMAC_CTX *Cryptography_HMAC_CTX_new(void) { +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) + return HMAC_CTX_new(); +#else + /* This uses OPENSSL_zalloc in 1.1.0, which is malloc + memset */ + HMAC_CTX *ctx = (HMAC_CTX *)OPENSSL_malloc(sizeof(HMAC_CTX)); + memset(ctx, 0, sizeof(HMAC_CTX)); + return ctx; +#endif +} + + + +void Cryptography_HMAC_CTX_free(HMAC_CTX *ctx) { +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) + return HMAC_CTX_free(ctx); +#else + if (ctx != NULL) { + HMAC_CTX_cleanup(ctx); + OPENSSL_free(ctx); + } +#endif +} """ diff --git a/src/_cffi_src/openssl/rand.py b/src/_cffi_src/openssl/rand.py index 91e1a396..0a94d705 100644 --- a/src/_cffi_src/openssl/rand.py +++ b/src/_cffi_src/openssl/rand.py @@ -22,7 +22,6 @@ int RAND_load_file(const char *, long); int RAND_write_file(const char *); void RAND_cleanup(void); int RAND_bytes(unsigned char *, int); -int RAND_pseudo_bytes(unsigned char *, int); """ MACROS = """ @@ -32,7 +31,7 @@ int RAND_query_egd_bytes(const char *, unsigned char *, int); """ CUSTOMIZATIONS = """ -#if defined(LIBRESSL_VERSION_NUMBER) +#if defined(LIBRESSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER >= 0x10100000L static const long Cryptography_HAS_EGD = 0; int (*RAND_egd)(const char *) = NULL; int (*RAND_egd_bytes)(const char *, int) = NULL; diff --git a/src/_cffi_src/openssl/ssl.py b/src/_cffi_src/openssl/ssl.py index 98b396da..75b0f130 100644 --- a/src/_cffi_src/openssl/ssl.py +++ b/src/_cffi_src/openssl/ssl.py @@ -11,9 +11,8 @@ typedef STACK_OF(SSL_CIPHER) Cryptography_STACK_OF_SSL_CIPHER; """ TYPES = """ -/* - * Internally invented symbols to tell which versions of SSL/TLS are supported. -*/ +static const long Cryptography_HAS_SSL_ST; +static const long Cryptography_HAS_TLS_ST; static const long Cryptography_HAS_SSL2; static const long Cryptography_HAS_SSL3_METHOD; static const long Cryptography_HAS_TLSv1_1; @@ -126,6 +125,8 @@ static const long SSL_MODE_ENABLE_PARTIAL_WRITE; static const long SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER; static const long SSL_MODE_AUTO_RETRY; static const long SSL3_RANDOM_SIZE; +static const long TLS_ST_BEFORE; +static const long TLS_ST_OK; typedef ... SSL_METHOD; typedef ... SSL_CTX; @@ -162,9 +163,6 @@ typedef ... COMP_METHOD; """ FUNCTIONS = """ -void SSL_load_error_strings(void); -int SSL_library_init(void); - /* SSL */ const char *SSL_state_string_long(const SSL *); SSL_SESSION *SSL_get1_session(SSL *); @@ -253,20 +251,25 @@ char *SSL_CIPHER_get_version(const SSL_CIPHER *); size_t SSL_get_finished(const SSL *, void *, size_t); size_t SSL_get_peer_finished(const SSL *, void *, size_t); +Cryptography_STACK_OF_X509_NAME *SSL_load_client_CA_file(const char *); +""" -/* CRYPTO_EX_DATA */ +MACROS = """ +/* These became macros in 1.1.0 */ +int SSL_library_init(void); +void SSL_load_error_strings(void); + +/* these CRYPTO_EX_DATA functions became macros in 1.1.0 */ int SSL_get_ex_new_index(long, void *, CRYPTO_EX_new *, CRYPTO_EX_dup *, CRYPTO_EX_free *); int SSL_set_ex_data(SSL *, int, void *); - int SSL_CTX_get_ex_new_index(long, void *, CRYPTO_EX_new *, CRYPTO_EX_dup *, CRYPTO_EX_free *); int SSL_CTX_set_ex_data(SSL_CTX *, int, void *); -Cryptography_STACK_OF_X509_NAME *SSL_load_client_CA_file(const char *); -""" +SSL_SESSION *SSL_get_session(const SSL *); +const unsigned char *SSL_SESSION_get_id(const SSL_SESSION *, unsigned int *); -MACROS = """ /* not a macro, but older OpenSSLs don't pass the args as const */ char *SSL_CIPHER_description(const SSL_CIPHER *, char *, int); int SSL_SESSION_print(BIO *, const SSL_SESSION *); @@ -372,8 +375,6 @@ void (*SSL_CTX_get_info_callback(SSL_CTX *))(const SSL *, int, int); RHEL/CentOS 5 this can be moved back to FUNCTIONS. */ SSL_CTX *SSL_set_SSL_CTX(SSL *, SSL_CTX *); -const SSL_METHOD *Cryptography_SSL_CTX_get_method(const SSL_CTX *); - /* NPN APIs were introduced in OpenSSL 1.0.1. To continue to support earlier * versions some special handling of these is necessary. */ @@ -398,7 +399,7 @@ void SSL_get0_next_proto_negotiated(const SSL *, const unsigned char **, unsigned *); int sk_SSL_CIPHER_num(Cryptography_STACK_OF_SSL_CIPHER *); -SSL_CIPHER *sk_SSL_CIPHER_value(Cryptography_STACK_OF_SSL_CIPHER *, int); +const SSL_CIPHER *sk_SSL_CIPHER_value(Cryptography_STACK_OF_SSL_CIPHER *, int); /* ALPN APIs were introduced in OpenSSL 1.0.2. To continue to support earlier * versions some special handling of these is necessary. @@ -422,9 +423,91 @@ long SSL_get_server_tmp_key(SSL *, EVP_PKEY **); */ void SSL_CTX_set_cert_cb(SSL_CTX *, int (*)(SSL *, void *), void *); void SSL_set_cert_cb(SSL *, int (*)(SSL *, void *), void *); + +/* Added in 1.0.2 */ +const SSL_METHOD *SSL_CTX_get_ssl_method(SSL_CTX *); +/* Added in 1.0.1 */ +int SSL_SESSION_set1_id_context(SSL_SESSION *, const unsigned char *, + unsigned int); +/* Added in 1.1.0 for the great opaquing of structs */ +size_t SSL_SESSION_get_master_key(const SSL_SESSION *, unsigned char *, + size_t); +size_t SSL_get_client_random(const SSL *, unsigned char *, size_t); +size_t SSL_get_server_random(const SSL *, unsigned char *, size_t); """ CUSTOMIZATIONS = """ +/* Added in 1.0.1 but we need it in all versions now due to the great + opaquing. */ +#if OPENSSL_VERSION_NUMBER < 0x1000100fL +/* from ssl.h */ +#define SSL_F_SSL_SESSION_SET1_ID_CONTEXT 312 +#define SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG 273 +/* from ssl/ssl_sess.c */ +int SSL_SESSION_set1_id_context(SSL_SESSION *s, const unsigned char *sid_ctx, + unsigned int sid_ctx_len) +{ + if (sid_ctx_len > SSL_MAX_SID_CTX_LENGTH) { + SSLerr(SSL_F_SSL_SESSION_SET1_ID_CONTEXT, + SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG); + return 0; + } + s->sid_ctx_length = sid_ctx_len; + memcpy(s->sid_ctx, sid_ctx, sid_ctx_len); + + return 1; +} +#endif +/* Added in 1.0.2 but we need it in all versions now due to the great + opaquing. */ +#if OPENSSL_VERSION_NUMBER < 0x10002001L || defined(LIBRESSL_VERSION_NUMBER) +/* from ssl/ssl_lib.c */ +const SSL_METHOD *SSL_CTX_get_ssl_method(SSL_CTX *ctx) { + return ctx->method; +} +#endif +/* Added in 1.1.0 in the great opaquing, but we need to define it for older + OpenSSLs. Such is our burden. */ +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) +/* from ssl/ssl_lib.c */ +size_t SSL_get_client_random(const SSL *ssl, unsigned char *out, size_t outlen) +{ + if (outlen == 0) + return sizeof(ssl->s3->client_random); + if (outlen > sizeof(ssl->s3->client_random)) + outlen = sizeof(ssl->s3->client_random); + memcpy(out, ssl->s3->client_random, outlen); + return outlen; +} +/* Added in 1.1.0 as well */ +/* from ssl/ssl_lib.c */ +size_t SSL_get_server_random(const SSL *ssl, unsigned char *out, size_t outlen) +{ + if (outlen == 0) + return sizeof(ssl->s3->server_random); + if (outlen > sizeof(ssl->s3->server_random)) + outlen = sizeof(ssl->s3->server_random); + memcpy(out, ssl->s3->server_random, outlen); + return outlen; +} +/* Added in 1.1.0 as well */ +/* from ssl/ssl_lib.c */ +size_t SSL_SESSION_get_master_key(const SSL_SESSION *session, + unsigned char *out, size_t outlen) +{ + if (session->master_key_length < 0) { + /* Should never happen */ + return 0; + } + if (outlen == 0) + return session->master_key_length; + if (outlen > (size_t)session->master_key_length) + outlen = session->master_key_length; + memcpy(out, session->master_key, outlen); + return outlen; +} +#endif + /** Secure renegotiation is supported in OpenSSL >= 0.9.8m * But some Linux distributions have back ported some features. */ @@ -565,11 +648,6 @@ static const long Cryptography_HAS_NETBSD_D1_METH = 1; static const long Cryptography_HAS_NETBSD_D1_METH = 1; #endif -/* Workaround for #794 caused by cffi const** bug. */ -const SSL_METHOD *Cryptography_SSL_CTX_get_method(const SSL_CTX *ctx) { - return ctx->method; -} - /* Because OPENSSL defines macros that claim lack of support for things, rather * than macros that claim support for things, we need to do a version check in * addition to a definition check. NPN was added in 1.0.1: for any version @@ -655,4 +733,22 @@ static const long Cryptography_HAS_SSL_CTX_SET_CLIENT_CERT_ENGINE = 0; static const long Cryptography_HAS_SSL_CTX_SET_CLIENT_CERT_ENGINE = 1; #endif +/* in OpenSSL 1.1.0 the SSL_ST values were renamed to TLS_ST and several were + removed */ +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) +static const long Cryptography_HAS_SSL_ST = 1; +#else +static const long Cryptography_HAS_SSL_ST = 0; +static const long SSL_ST_BEFORE = 0; +static const long SSL_ST_OK = 0; +static const long SSL_ST_INIT = 0; +static const long SSL_ST_RENEGOTIATE = 0; +#endif +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) +static const long Cryptography_HAS_TLS_ST = 1; +#else +static const long Cryptography_HAS_TLS_ST = 0; +static const long TLS_ST_BEFORE = 0; +static const long TLS_ST_OK = 0; +#endif """ diff --git a/src/_cffi_src/openssl/x509.py b/src/_cffi_src/openssl/x509.py index c5eb600a..b0ff9844 100644 --- a/src/_cffi_src/openssl/x509.py +++ b/src/_cffi_src/openssl/x509.py @@ -36,6 +36,8 @@ typedef struct { ...; } X509_CINF; +/* TODO: opaque X509_EXTENSION. Cryptography no longer depends on it being + non-opaque but pyOpenSSL needs a release where it doesn't depend on this */ typedef struct { ASN1_OBJECT *object; ASN1_BOOLEAN critical; @@ -152,12 +154,6 @@ X509_EXTENSION *X509_EXTENSION_dup(X509_EXTENSION *); X509_EXTENSION *X509_get_ext(X509 *, int); int X509_get_ext_by_NID(X509 *, int, int); -/* CRYPTO_EX_DATA */ -int X509_get_ex_new_index(long, void *, CRYPTO_EX_new *, CRYPTO_EX_dup *, - CRYPTO_EX_free *); -int X509_set_ex_data(X509 *, int, void *); -void *X509_get_ex_data(X509 *, int); - int X509_EXTENSION_get_critical(X509_EXTENSION *); ASN1_OBJECT *X509_EXTENSION_get_object(X509_EXTENSION *); void X509_EXTENSION_free(X509_EXTENSION *); @@ -270,12 +266,22 @@ void PKCS8_PRIV_KEY_INFO_free(PKCS8_PRIV_KEY_INFO *); """ MACROS = """ +/* these CRYPTO_EX_DATA functions became macros in 1.1.0 */ +int X509_get_ex_new_index(long, void *, CRYPTO_EX_new *, CRYPTO_EX_dup *, + CRYPTO_EX_free *); +int X509_set_ex_data(X509 *, int, void *); +void *X509_get_ex_data(X509 *, int); + X509_REVOKED *Cryptography_X509_REVOKED_dup(X509_REVOKED *); int i2d_X509_CINF(X509_CINF *, unsigned char **); int i2d_X509_CRL_INFO(X509_CRL_INFO *, unsigned char **); int i2d_X509_REQ_INFO(X509_REQ_INFO *, unsigned char **); +/* new in 1.0.2 */ +int i2d_re_X509_tbs(X509 *, unsigned char **); +void X509_get0_signature(ASN1_BIT_STRING **, X509_ALGOR **, X509 *); + long X509_get_version(X509 *); ASN1_TIME *X509_get_notBefore(X509 *); @@ -347,9 +353,46 @@ ASN1_OBJECT *sk_ASN1_OBJECT_value(Cryptography_STACK_OF_ASN1_OBJECT *, int); void sk_ASN1_OBJECT_free(Cryptography_STACK_OF_ASN1_OBJECT *); Cryptography_STACK_OF_ASN1_OBJECT *sk_ASN1_OBJECT_new_null(void); int sk_ASN1_OBJECT_push(Cryptography_STACK_OF_ASN1_OBJECT *, ASN1_OBJECT *); + +/* these functions were added in 1.1.0 */ +ASN1_INTEGER *X509_REVOKED_get0_serialNumber(X509_REVOKED *); +ASN1_TIME *X509_REVOKED_get0_revocationDate(X509_REVOKED *); +void X509_CRL_get0_signature(ASN1_BIT_STRING **psig, X509_ALGOR **palg, + X509_CRL *crl); +int i2d_re_X509_REQ_tbs(X509_REQ *, unsigned char **); +int i2d_re_X509_CRL_tbs(X509_CRL *, unsigned char **); +void X509_REQ_get0_signature(ASN1_BIT_STRING **, X509_ALGOR **, X509_REQ *); """ CUSTOMIZATIONS = """ +/* Added in 1.0.2 beta but we need it in all versions now due to the great + opaquing. */ +#if OPENSSL_VERSION_NUMBER < 0x10002001L || defined(LIBRESSL_VERSION_NUMBER) +/* from x509/x_x509.c version 1.0.2 */ +void X509_get0_signature(ASN1_BIT_STRING **psig, X509_ALGOR **palg, + const X509 *x) +{ + if (psig) + *psig = x->signature; + if (palg) + *palg = x->sig_alg; +} +#endif +/* Added in 1.0.2 but we need it in all versions now due to the great + opaquing. */ +#if OPENSSL_VERSION_NUMBER < 0x10002003L || defined(LIBRESSL_VERSION_NUMBER) +/* from x509/x_x509.c */ +int i2d_re_X509_tbs(X509 *x, unsigned char **pp) +{ + /* in 1.0.2+ this function also sets x->cert_info->enc.modified = 1 + but older OpenSSLs don't have the enc ASN1_ENCODING member in the + X509 struct. Setting modified to 1 marks the encoding + (x->cert_info->enc.enc) as invalid, but since the entire struct isn't + present we don't care. */ + return i2d_X509_CINF(x->cert_info, pp); +} +#endif + /* OpenSSL 0.9.8e does not have this definition. */ #if OPENSSL_VERSION_NUMBER <= 0x0090805fL typedef STACK_OF(X509_EXTENSION) X509_EXTENSIONS; @@ -375,4 +418,43 @@ X509_REVOKED *Cryptography_X509_REVOKED_dup(X509_REVOKED *rev) { return ASN1_item_dup(ASN1_ITEM_rptr(X509_REVOKED), rev); } +/* Added in 1.1.0 but we need it in all versions now due to the great + opaquing. */ +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) +/* from x509/x509_req.c */ +void X509_REQ_get0_signature(ASN1_BIT_STRING **psig, X509_ALGOR **palg, + X509_REQ *req) +{ + if (psig != NULL) + *psig = req->signature; + if (palg != NULL) + *palg = req->sig_alg; +} +int i2d_re_X509_REQ_tbs(X509_REQ *req, unsigned char **pp) +{ + req->req_info->enc.modified = 1; + return i2d_X509_REQ_INFO(req->req_info, pp); +} +int i2d_re_X509_CRL_tbs(X509_CRL *crl, unsigned char **pp) { + crl->crl->enc.modified = 1; + return i2d_X509_CRL_INFO(crl->crl, pp); +} + +void X509_CRL_get0_signature(ASN1_BIT_STRING **psig, X509_ALGOR **palg, + X509_CRL *crl) +{ + if (psig != NULL) + *psig = crl->signature; + if (palg != NULL) + *palg = crl->sig_alg; +} +ASN1_TIME *X509_REVOKED_get0_revocationDate(X509_REVOKED *x) +{ + return x->revocationDate; +} +ASN1_INTEGER *X509_REVOKED_get0_serialNumber(X509_REVOKED *x) +{ + return x->serialNumber; +} +#endif """ diff --git a/src/_cffi_src/openssl/x509_vfy.py b/src/_cffi_src/openssl/x509_vfy.py index f8467a76..13287797 100644 --- a/src/_cffi_src/openssl/x509_vfy.py +++ b/src/_cffi_src/openssl/x509_vfy.py @@ -173,8 +173,6 @@ int X509_STORE_CTX_get_error(X509_STORE_CTX *); void X509_STORE_CTX_set_error(X509_STORE_CTX *, int); int X509_STORE_CTX_get_error_depth(X509_STORE_CTX *); X509 *X509_STORE_CTX_get_current_cert(X509_STORE_CTX *); -int X509_STORE_CTX_get_ex_new_index(long, void *, CRYPTO_EX_new *, - CRYPTO_EX_dup *, CRYPTO_EX_free *); int X509_STORE_CTX_set_ex_data(X509_STORE_CTX *, int, void *); void *X509_STORE_CTX_get_ex_data(X509_STORE_CTX *, int); @@ -194,6 +192,10 @@ int X509_VERIFY_PARAM_get_depth(const X509_VERIFY_PARAM *); """ MACROS = """ +/* this CRYPTO_EX_DATA function became a macro in 1.1.0 */ +int X509_STORE_CTX_get_ex_new_index(long, void *, CRYPTO_EX_new *, + CRYPTO_EX_dup *, CRYPTO_EX_free *); + /* X509_STORE_CTX */ void X509_STORE_CTX_set0_crls(X509_STORE_CTX *, Cryptography_STACK_OF_X509_CRL *); diff --git a/src/_cffi_src/openssl/x509name.py b/src/_cffi_src/openssl/x509name.py index 7b833d61..86d50bbd 100644 --- a/src/_cffi_src/openssl/x509name.py +++ b/src/_cffi_src/openssl/x509name.py @@ -16,10 +16,7 @@ typedef STACK_OF(X509_NAME_ENTRY) Cryptography_STACK_OF_X509_NAME_ENTRY; TYPES = """ typedef ... Cryptography_STACK_OF_X509_NAME_ENTRY; -typedef struct { - Cryptography_STACK_OF_X509_NAME_ENTRY *entries; - ...; -} X509_NAME; +typedef ... X509_NAME; typedef ... X509_NAME_ENTRY; typedef ... Cryptography_STACK_OF_X509_NAME; """ @@ -47,6 +44,10 @@ int X509_NAME_get_index_by_NID(X509_NAME *, int, int); int X509_NAME_cmp(const X509_NAME *, const X509_NAME *); char *X509_NAME_oneline(X509_NAME *, char *, int); X509_NAME *X509_NAME_dup(X509_NAME *); +X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_OBJ(X509_NAME_ENTRY **, + ASN1_OBJECT *, int, + const unsigned char *, int); +int X509_NAME_add_entry(X509_NAME *, X509_NAME_ENTRY *, int, int); """ MACROS = """ @@ -56,6 +57,9 @@ int sk_X509_NAME_push(Cryptography_STACK_OF_X509_NAME *, X509_NAME *); X509_NAME *sk_X509_NAME_value(Cryptography_STACK_OF_X509_NAME *, int); void sk_X509_NAME_free(Cryptography_STACK_OF_X509_NAME *); int sk_X509_NAME_ENTRY_num(Cryptography_STACK_OF_X509_NAME_ENTRY *); +Cryptography_STACK_OF_X509_NAME_ENTRY *sk_X509_NAME_ENTRY_new_null(void); +int sk_X509_NAME_ENTRY_push(Cryptography_STACK_OF_X509_NAME_ENTRY *, + X509_NAME_ENTRY *); X509_NAME_ENTRY *sk_X509_NAME_ENTRY_value( Cryptography_STACK_OF_X509_NAME_ENTRY *, int); Cryptography_STACK_OF_X509_NAME_ENTRY *sk_X509_NAME_ENTRY_dup( diff --git a/src/_cffi_src/openssl/x509v3.py b/src/_cffi_src/openssl/x509v3.py index 3612f1c2..d4a93f26 100644 --- a/src/_cffi_src/openssl/x509v3.py +++ b/src/_cffi_src/openssl/x509v3.py @@ -34,6 +34,7 @@ typedef ... Cryptography_STACK_OF_POLICYINFO; typedef ... Cryptography_STACK_OF_ASN1_INTEGER; typedef ... Cryptography_STACK_OF_GENERAL_SUBTREE; typedef ... EXTENDED_KEY_USAGE; +typedef ... CONF; typedef struct { X509 *issuer_cert; diff --git a/src/cryptography/hazmat/backends/multibackend.py b/src/cryptography/hazmat/backends/multibackend.py index 65f18531..48bc7d08 100644 --- a/src/cryptography/hazmat/backends/multibackend.py +++ b/src/cryptography/hazmat/backends/multibackend.py @@ -28,6 +28,13 @@ class MultiBackend(object): name = "multibackend" def __init__(self, backends): + if len(backends) == 0: + raise ValueError( + "Multibackend cannot be initialized with no backends. If you " + "are seeing this error when trying to use default_backend() " + "please try uninstalling and reinstalling cryptography." + ) + self._backends = backends def _filtered_backends(self, interface): diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 4a8fda99..5ce2489c 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -31,8 +31,7 @@ from cryptography.hazmat.backends.openssl.ec import ( from cryptography.hazmat.backends.openssl.encode_asn1 import ( _CRL_ENTRY_EXTENSION_ENCODE_HANDLERS, _CRL_EXTENSION_ENCODE_HANDLERS, _EXTENSION_ENCODE_HANDLERS, - _encode_asn1_int_gc, _encode_asn1_str_gc, _encode_name_gc, - _txt2obj_gc, + _encode_asn1_int_gc, _encode_asn1_str_gc, _encode_name_gc, _txt2obj_gc, ) from cryptography.hazmat.backends.openssl.hashes import _HashContext from cryptography.hazmat.backends.openssl.hmac import _HMACContext @@ -179,7 +178,7 @@ class Backend(object): Example: OpenSSL 1.0.1e 11 Feb 2013 """ return self._ffi.string( - self._lib.SSLeay_version(self._lib.SSLEAY_VERSION) + self._lib.OpenSSL_version(self._lib.OPENSSL_VERSION) ).decode("ascii") def create_hmac_ctx(self, key, algorithm): @@ -968,6 +967,31 @@ class Backend(object): def _create_x509_extensions(self, extensions, handlers, x509_obj, add_func, gc): for i, extension in enumerate(extensions): + x509_extension = self._create_x509_extension( + handlers, extension + ) + self.openssl_assert(x509_extension != self._ffi.NULL) + + if gc: + x509_extension = self._ffi.gc( + x509_extension, self._lib.X509_EXTENSION_free + ) + res = add_func(x509_obj, x509_extension, i) + self.openssl_assert(res >= 1) + + def _create_x509_extension(self, handlers, extension): + if isinstance(extension.value, x509.UnrecognizedExtension): + obj = _txt2obj_gc(self, extension.oid.dotted_string) + value = _encode_asn1_str_gc( + self, extension.value.value, len(extension.value.value) + ) + return self._lib.X509_EXTENSION_create_by_OBJ( + self._ffi.NULL, + obj, + 1 if extension.critical else 0, + value + ) + else: try: encode = handlers[extension.oid] except KeyError: @@ -975,21 +999,37 @@ class Backend(object): 'Extension not supported: {0}'.format(extension.oid) ) - pp, r = encode(self, extension.value) - obj = _txt2obj_gc(self, extension.oid.dotted_string) - x509_extension = self._lib.X509_EXTENSION_create_by_OBJ( - self._ffi.NULL, - obj, - 1 if extension.critical else 0, - _encode_asn1_str_gc(self, pp[0], r) + ext_struct = encode(self, extension.value) + nid = self._lib.OBJ_txt2nid( + extension.oid.dotted_string.encode("ascii") ) - self.openssl_assert(x509_extension != self._ffi.NULL) - if gc: - x509_extension = self._ffi.gc( - x509_extension, self._lib.X509_EXTENSION_free + backend.openssl_assert(nid != self._lib.NID_undef) + x509_extension = self._lib.X509V3_EXT_i2d( + nid, 1 if extension.critical else 0, ext_struct + ) + if ( + x509_extension == self._ffi.NULL and + extension.oid == x509.OID_CERTIFICATE_ISSUER + ): + # This path exists to support OpenSSL 0.9.8, which does not + # know how to encode a CERTIFICATE_ISSUER for CRLs. Once we + # drop 0.9.8 support we can remove this. + self._consume_errors() + pp = backend._ffi.new("unsigned char **") + r = self._lib.i2d_GENERAL_NAMES(ext_struct, pp) + backend.openssl_assert(r > 0) + pp = backend._ffi.gc( + pp, + lambda pointer: backend._lib.OPENSSL_free(pointer[0]) ) - res = add_func(x509_obj, x509_extension, i) - self.openssl_assert(res >= 1) + obj = _txt2obj_gc(self, extension.oid.dotted_string) + return self._lib.X509_EXTENSION_create_by_OBJ( + self._ffi.NULL, + obj, + 1 if extension.critical else 0, + _encode_asn1_str_gc(self, pp[0], r) + ) + return x509_extension def create_x509_revoked_certificate(self, builder): if not isinstance(builder, x509.RevokedCertificateBuilder): @@ -1003,11 +1043,14 @@ class Backend(object): x509_revoked, serial_number ) self.openssl_assert(res == 1) - res = self._lib.ASN1_TIME_set( - x509_revoked.revocationDate, + rev_date = self._lib.ASN1_TIME_set( + self._ffi.NULL, calendar.timegm(builder._revocation_date.timetuple()) ) - self.openssl_assert(res != self._ffi.NULL) + self.openssl_assert(rev_date != self._ffi.NULL) + rev_date = self._ffi.gc(rev_date, self._lib.ASN1_TIME_free) + res = self._lib.X509_REVOKED_set_revocationDate(x509_revoked, rev_date) + self.openssl_assert(res == 1) # add CRL entry extensions self._create_x509_extensions( extensions=builder._extensions, diff --git a/src/cryptography/hazmat/backends/openssl/decode_asn1.py b/src/cryptography/hazmat/backends/openssl/decode_asn1.py index 5f828c6b..26f56d12 100644 --- a/src/cryptography/hazmat/backends/openssl/decode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/decode_asn1.py @@ -198,7 +198,9 @@ class _X509ExtensionParser(object): backend.openssl_assert(ext != backend._ffi.NULL) crit = backend._lib.X509_EXTENSION_get_critical(ext) critical = crit == 1 - oid = x509.ObjectIdentifier(_obj2txt(backend, ext.object)) + oid = x509.ObjectIdentifier( + _obj2txt(backend, backend._lib.X509_EXTENSION_get_object(ext)) + ) if oid in seen_oids: raise x509.DuplicateExtension( "Duplicate {0} extension found".format(oid), oid @@ -652,9 +654,10 @@ def _decode_cert_issuer(backend, ext): """ data_ptr_ptr = backend._ffi.new("const unsigned char **") - data_ptr_ptr[0] = ext.value.data + value = backend._lib.X509_EXTENSION_get_data(ext) + data_ptr_ptr[0] = value.data gns = backend._lib.d2i_GENERAL_NAMES( - backend._ffi.NULL, data_ptr_ptr, ext.value.length + backend._ffi.NULL, data_ptr_ptr, value.length ) # Check the result of d2i_GENERAL_NAMES() is valid. Usually this is covered @@ -706,7 +709,11 @@ def _asn1_string_to_ascii(backend, asn1_string): def _asn1_string_to_utf8(backend, asn1_string): buf = backend._ffi.new("unsigned char **") res = backend._lib.ASN1_STRING_to_UTF8(buf, asn1_string) - backend.openssl_assert(res >= 0) + if res == -1: + raise ValueError( + "Unsupported ASN1 string type. Type: {0}".format(asn1_string.type) + ) + backend.openssl_assert(buf[0] != backend._ffi.NULL) buf = backend._ffi.gc( buf, lambda buffer: backend._lib.OPENSSL_free(buffer[0]) diff --git a/src/cryptography/hazmat/backends/openssl/encode_asn1.py b/src/cryptography/hazmat/backends/openssl/encode_asn1.py index 8cdf4c4b..b0e2e73e 100644 --- a/src/cryptography/hazmat/backends/openssl/encode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/encode_asn1.py @@ -74,21 +74,8 @@ def _encode_asn1_str_gc(backend, data, length): return s -def _encode_extension_to_der(backend, i2d_func, value): - pp = backend._ffi.new("unsigned char **") - r = i2d_func(value, pp) - backend.openssl_assert(r > 0) - pp = backend._ffi.gc( - pp, lambda pointer: backend._lib.OPENSSL_free(pointer[0]) - ) - return pp, r - - def _encode_inhibit_any_policy(backend, inhibit_any_policy): - asn1int = _encode_asn1_int_gc(backend, inhibit_any_policy.skip_certs) - return _encode_extension_to_der( - backend, backend._lib.i2d_ASN1_INTEGER, asn1int - ) + return _encode_asn1_int_gc(backend, inhibit_any_policy.skip_certs) def _encode_name(backend, attributes): @@ -97,17 +84,8 @@ def _encode_name(backend, attributes): """ subject = backend._lib.X509_NAME_new() for attribute in attributes: - value = attribute.value.encode('utf8') - obj = _txt2obj_gc(backend, attribute.oid.dotted_string) - if attribute.oid == NameOID.COUNTRY_NAME: - # Per RFC5280 Appendix A.1 countryName should be encoded as - # PrintableString, not UTF8String - type = backend._lib.MBSTRING_ASC - else: - type = backend._lib.MBSTRING_UTF8 - res = backend._lib.X509_NAME_add_entry_by_OBJ( - subject, obj, type, value, -1, -1, 0, - ) + name_entry = _encode_name_entry(backend, attribute) + res = backend._lib.X509_NAME_add_entry(subject, name_entry, -1, 0) backend.openssl_assert(res == 1) return subject @@ -118,11 +96,35 @@ def _encode_name_gc(backend, attributes): return subject -def _encode_crl_number(backend, crl_number): - asn1int = _encode_asn1_int_gc(backend, crl_number.crl_number) - return _encode_extension_to_der( - backend, backend._lib.i2d_ASN1_INTEGER, asn1int +def _encode_sk_name_entry(backend, attributes): + """ + The sk_X50_NAME_ENTRY created will not be gc'd. + """ + stack = backend._lib.sk_X509_NAME_ENTRY_new_null() + for attribute in attributes: + name_entry = _encode_name_entry(backend, attribute) + res = backend._lib.sk_X509_NAME_ENTRY_push(stack, name_entry) + backend.openssl_assert(res == 1) + return stack + + +def _encode_name_entry(backend, attribute): + value = attribute.value.encode('utf8') + obj = _txt2obj_gc(backend, attribute.oid.dotted_string) + if attribute.oid == NameOID.COUNTRY_NAME: + # Per RFC5280 Appendix A.1 countryName should be encoded as + # PrintableString, not UTF8String + type = backend._lib.MBSTRING_ASC + else: + type = backend._lib.MBSTRING_UTF8 + name_entry = backend._lib.X509_NAME_ENTRY_create_by_OBJ( + backend._ffi.NULL, obj, type, value, -1 ) + return name_entry + + +def _encode_crl_number(backend, crl_number): + return _encode_asn1_int_gc(backend, crl_number.crl_number) def _encode_crl_reason(backend, crl_reason): @@ -134,9 +136,7 @@ def _encode_crl_reason(backend, crl_reason): ) backend.openssl_assert(res == 1) - return _encode_extension_to_der( - backend, backend._lib.i2d_ASN1_ENUMERATED, asn1enum - ) + return asn1enum def _encode_invalidity_date(backend, invalidity_date): @@ -148,9 +148,7 @@ def _encode_invalidity_date(backend, invalidity_date): backend.openssl_assert(time != backend._ffi.NULL) time = backend._ffi.gc(time, backend._lib.ASN1_GENERALIZEDTIME_free) - return _encode_extension_to_der( - backend, backend._lib.i2d_ASN1_GENERALIZEDTIME, time - ) + return time def _encode_certificate_policies(backend, certificate_policies): @@ -200,9 +198,7 @@ def _encode_certificate_policies(backend, certificate_policies): pi.qualifiers = pqis - return _encode_extension_to_der( - backend, backend._lib.i2d_CERTIFICATEPOLICIES, cp - ) + return cp def _encode_notice_reference(backend, notice): @@ -243,10 +239,10 @@ def _txt2obj_gc(backend, name): def _encode_ocsp_nocheck(backend, ext): """ - The OCSP No Check extension is defined as a null ASN.1 value. Rather than - calling OpenSSL we can return a Python bytestring value in a list. + The OCSP No Check extension is defined as a null ASN.1 value embedded in + an ASN.1 string. """ - return [b"\x05\x00"], 2 + return _encode_asn1_str_gc(backend, b"\x05\x00", 2) def _encode_key_usage(backend, key_usage): @@ -278,9 +274,7 @@ def _encode_key_usage(backend, key_usage): res = set_bit(ku, 8, 0) backend.openssl_assert(res == 1) - return _encode_extension_to_der( - backend, backend._lib.i2d_ASN1_BIT_STRING, ku - ) + return ku def _encode_authority_key_identifier(backend, authority_keyid): @@ -304,9 +298,7 @@ def _encode_authority_key_identifier(backend, authority_keyid): backend, authority_keyid.authority_cert_serial_number ) - return _encode_extension_to_der( - backend, backend._lib.i2d_AUTHORITY_KEYID, akid - ) + return akid def _encode_basic_constraints(backend, basic_constraints): @@ -320,9 +312,7 @@ def _encode_basic_constraints(backend, basic_constraints): backend, basic_constraints.path_length ) - return _encode_extension_to_der( - backend, backend._lib.i2d_BASIC_CONSTRAINTS, constraints - ) + return constraints def _encode_authority_information_access(backend, authority_info_access): @@ -342,9 +332,7 @@ def _encode_authority_information_access(backend, authority_info_access): res = backend._lib.sk_ACCESS_DESCRIPTION_push(aia, ad) backend.openssl_assert(res >= 1) - return _encode_extension_to_der( - backend, backend._lib.i2d_AUTHORITY_INFO_ACCESS, aia - ) + return aia def _encode_general_names(backend, names): @@ -363,16 +351,11 @@ def _encode_alt_name(backend, san): general_names = backend._ffi.gc( general_names, backend._lib.GENERAL_NAMES_free ) - return _encode_extension_to_der( - backend, backend._lib.i2d_GENERAL_NAMES, general_names - ) + return general_names def _encode_subject_key_identifier(backend, ski): - asn1_str = _encode_asn1_str_gc(backend, ski.digest, len(ski.digest)) - return _encode_extension_to_der( - backend, backend._lib.i2d_ASN1_OCTET_STRING, asn1_str - ) + return _encode_asn1_str_gc(backend, ski.digest, len(ski.digest)) def _encode_general_name(backend, name): @@ -470,10 +453,7 @@ def _encode_extended_key_usage(backend, extended_key_usage): res = backend._lib.sk_ASN1_OBJECT_push(eku, obj) backend.openssl_assert(res >= 1) - eku_ptr = backend._ffi.cast("EXTENDED_KEY_USAGE *", eku) - return _encode_extension_to_der( - backend, backend._lib.i2d_EXTENDED_KEY_USAGE, eku_ptr - ) + return eku _CRLREASONFLAGS = { @@ -516,8 +496,7 @@ def _encode_crl_distribution_points(backend, crl_distribution_points): dpn = backend._lib.DIST_POINT_NAME_new() backend.openssl_assert(dpn != backend._ffi.NULL) dpn.type = _DISTPOINT_TYPE_RELATIVENAME - name = _encode_name_gc(backend, point.relative_name) - relativename = backend._lib.sk_X509_NAME_ENTRY_dup(name.entries) + relativename = _encode_sk_name_entry(backend, point.relative_name) backend.openssl_assert(relativename != backend._ffi.NULL) dpn.name.relativename = relativename dp.distpoint = dpn @@ -528,14 +507,12 @@ def _encode_crl_distribution_points(backend, crl_distribution_points): res = backend._lib.sk_DIST_POINT_push(cdp, dp) backend.openssl_assert(res >= 1) - return _encode_extension_to_der( - backend, backend._lib.i2d_CRL_DIST_POINTS, cdp - ) + return cdp def _encode_name_constraints(backend, name_constraints): nc = backend._lib.NAME_CONSTRAINTS_new() - assert nc != backend._ffi.NULL + backend.openssl_assert(nc != backend._ffi.NULL) nc = backend._ffi.gc(nc, backend._lib.NAME_CONSTRAINTS_free) permitted = _encode_general_subtree( backend, name_constraints.permitted_subtrees @@ -546,9 +523,24 @@ def _encode_name_constraints(backend, name_constraints): ) nc.excludedSubtrees = excluded - return _encode_extension_to_der( - backend, backend._lib.Cryptography_i2d_NAME_CONSTRAINTS, nc - ) + return nc + + +def _encode_policy_constraints(backend, policy_constraints): + pc = backend._lib.POLICY_CONSTRAINTS_new() + backend.openssl_assert(pc != backend._ffi.NULL) + pc = backend._ffi.gc(pc, backend._lib.POLICY_CONSTRAINTS_free) + if policy_constraints.require_explicit_policy is not None: + pc.requireExplicitPolicy = _encode_asn1_int( + backend, policy_constraints.require_explicit_policy + ) + + if policy_constraints.inhibit_policy_mapping is not None: + pc.inhibitPolicyMapping = _encode_asn1_int( + backend, policy_constraints.inhibit_policy_mapping + ) + + return pc def _encode_general_subtree(backend, subtrees): @@ -581,6 +573,7 @@ _EXTENSION_ENCODE_HANDLERS = { ExtensionOID.INHIBIT_ANY_POLICY: _encode_inhibit_any_policy, ExtensionOID.OCSP_NO_CHECK: _encode_ocsp_nocheck, ExtensionOID.NAME_CONSTRAINTS: _encode_name_constraints, + ExtensionOID.POLICY_CONSTRAINTS: _encode_policy_constraints, } _CRL_EXTENSION_ENCODE_HANDLERS = { diff --git a/src/cryptography/hazmat/backends/openssl/hashes.py b/src/cryptography/hazmat/backends/openssl/hashes.py index 02ce5f0d..2c8fce1a 100644 --- a/src/cryptography/hazmat/backends/openssl/hashes.py +++ b/src/cryptography/hazmat/backends/openssl/hashes.py @@ -18,9 +18,10 @@ class _HashContext(object): self._backend = backend if ctx is None: - ctx = self._backend._lib.EVP_MD_CTX_create() - ctx = self._backend._ffi.gc(ctx, - self._backend._lib.EVP_MD_CTX_destroy) + ctx = self._backend._lib.Cryptography_EVP_MD_CTX_new() + ctx = self._backend._ffi.gc( + ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free + ) evp_md = self._backend._lib.EVP_get_digestbyname( algorithm.name.encode("ascii")) if evp_md == self._backend._ffi.NULL: @@ -38,9 +39,9 @@ class _HashContext(object): algorithm = utils.read_only_property("_algorithm") def copy(self): - copied_ctx = self._backend._lib.EVP_MD_CTX_create() + copied_ctx = self._backend._lib.Cryptography_EVP_MD_CTX_new() copied_ctx = self._backend._ffi.gc( - copied_ctx, self._backend._lib.EVP_MD_CTX_destroy + copied_ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free ) res = self._backend._lib.EVP_MD_CTX_copy_ex(copied_ctx, self._ctx) self._backend.openssl_assert(res != 0) @@ -57,6 +58,4 @@ class _HashContext(object): res = self._backend._lib.EVP_DigestFinal_ex(self._ctx, buf, outlen) self._backend.openssl_assert(res != 0) self._backend.openssl_assert(outlen[0] == self.algorithm.digest_size) - res = self._backend._lib.EVP_MD_CTX_cleanup(self._ctx) - self._backend.openssl_assert(res == 1) return self._backend._ffi.buffer(buf)[:outlen[0]] diff --git a/src/cryptography/hazmat/backends/openssl/hmac.py b/src/cryptography/hazmat/backends/openssl/hmac.py index dcf2fbaf..ab1ad46f 100644 --- a/src/cryptography/hazmat/backends/openssl/hmac.py +++ b/src/cryptography/hazmat/backends/openssl/hmac.py @@ -20,10 +20,10 @@ class _HMACContext(object): self._backend = backend if ctx is None: - ctx = self._backend._ffi.new("HMAC_CTX *") - self._backend._lib.HMAC_CTX_init(ctx) + ctx = self._backend._lib.Cryptography_HMAC_CTX_new() + self._backend.openssl_assert(ctx != self._backend._ffi.NULL) ctx = self._backend._ffi.gc( - ctx, self._backend._lib.HMAC_CTX_cleanup + ctx, self._backend._lib.Cryptography_HMAC_CTX_free ) evp_md = self._backend._lib.EVP_get_digestbyname( algorithm.name.encode('ascii')) @@ -44,10 +44,10 @@ class _HMACContext(object): algorithm = utils.read_only_property("_algorithm") def copy(self): - copied_ctx = self._backend._ffi.new("HMAC_CTX *") - self._backend._lib.HMAC_CTX_init(copied_ctx) + copied_ctx = self._backend._lib.Cryptography_HMAC_CTX_new() + self._backend.openssl_assert(copied_ctx != self._backend._ffi.NULL) copied_ctx = self._backend._ffi.gc( - copied_ctx, self._backend._lib.HMAC_CTX_cleanup + copied_ctx, self._backend._lib.Cryptography_HMAC_CTX_free ) res = self._backend._lib.Cryptography_HMAC_CTX_copy( copied_ctx, self._ctx @@ -72,7 +72,6 @@ class _HMACContext(object): ) self._backend.openssl_assert(res != 0) self._backend.openssl_assert(outlen[0] == self.algorithm.digest_size) - self._backend._lib.HMAC_CTX_cleanup(self._ctx) return self._backend._ffi.buffer(buf)[:outlen[0]] def verify(self, signature): diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index c71f8d92..71a2fb78 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -97,7 +97,12 @@ class _Certificate(object): @property def signature_hash_algorithm(self): - oid = _obj2txt(self._backend, self._x509.sig_alg.algorithm) + alg = self._backend._ffi.new("X509_ALGOR **") + self._backend._lib.X509_get0_signature( + self._backend._ffi.NULL, alg, self._x509 + ) + self._backend.openssl_assert(alg[0] != self._backend._ffi.NULL) + oid = _obj2txt(self._backend, alg[0].algorithm) try: return x509._SIG_OIDS_TO_HASH[oid] except KeyError: @@ -111,13 +116,17 @@ class _Certificate(object): @property def signature(self): - return _asn1_string_to_bytes(self._backend, self._x509.signature) + sig = self._backend._ffi.new("ASN1_BIT_STRING **") + self._backend._lib.X509_get0_signature( + sig, self._backend._ffi.NULL, self._x509 + ) + self._backend.openssl_assert(sig[0] != self._backend._ffi.NULL) + return _asn1_string_to_bytes(self._backend, sig[0]) @property def tbs_certificate_bytes(self): pp = self._backend._ffi.new("unsigned char **") - # the X509_CINF struct holds the tbsCertificate data - res = self._backend._lib.i2d_X509_CINF(self._x509.cert_info, pp) + res = self._backend._lib.i2d_re_X509_tbs(self._x509, pp) self._backend.openssl_assert(res > 0) pp = self._backend._ffi.gc( pp, lambda pointer: self._backend._lib.OPENSSL_free(pointer[0]) @@ -153,14 +162,20 @@ class _RevokedCertificate(object): @property def serial_number(self): - asn1_int = self._x509_revoked.serialNumber + asn1_int = self._backend._lib.X509_REVOKED_get0_serialNumber( + self._x509_revoked + ) self._backend.openssl_assert(asn1_int != self._backend._ffi.NULL) return _asn1_integer_to_int(self._backend, asn1_int) @property def revocation_date(self): return _parse_asn1_time( - self._backend, self._x509_revoked.revocationDate) + self._backend, + self._backend._lib.X509_REVOKED_get0_revocationDate( + self._x509_revoked + ) + ) @property def extensions(self): @@ -198,7 +213,12 @@ class _CertificateRevocationList(object): @property def signature_hash_algorithm(self): - oid = _obj2txt(self._backend, self._x509_crl.sig_alg.algorithm) + alg = self._backend._ffi.new("X509_ALGOR **") + self._backend._lib.X509_CRL_get0_signature( + self._backend._ffi.NULL, alg, self._x509_crl + ) + self._backend.openssl_assert(alg[0] != self._backend._ffi.NULL) + oid = _obj2txt(self._backend, alg[0].algorithm) try: return x509._SIG_OIDS_TO_HASH[oid] except KeyError: @@ -226,13 +246,17 @@ class _CertificateRevocationList(object): @property def signature(self): - return _asn1_string_to_bytes(self._backend, self._x509_crl.signature) + sig = self._backend._ffi.new("ASN1_BIT_STRING **") + self._backend._lib.X509_CRL_get0_signature( + sig, self._backend._ffi.NULL, self._x509_crl + ) + self._backend.openssl_assert(sig[0] != self._backend._ffi.NULL) + return _asn1_string_to_bytes(self._backend, sig[0]) @property def tbs_certlist_bytes(self): pp = self._backend._ffi.new("unsigned char **") - # the X509_CRL_INFO struct holds the tbsCertList data - res = self._backend._lib.i2d_X509_CRL_INFO(self._x509_crl.crl, pp) + res = self._backend._lib.i2d_re_X509_CRL_tbs(self._x509_crl, pp) self._backend.openssl_assert(res > 0) pp = self._backend._ffi.gc( pp, lambda pointer: self._backend._lib.OPENSSL_free(pointer[0]) @@ -321,7 +345,12 @@ class _CertificateSigningRequest(object): @property def signature_hash_algorithm(self): - oid = _obj2txt(self._backend, self._x509_req.sig_alg.algorithm) + alg = self._backend._ffi.new("X509_ALGOR **") + self._backend._lib.X509_REQ_get0_signature( + self._backend._ffi.NULL, alg, self._x509_req + ) + self._backend.openssl_assert(alg[0] != self._backend._ffi.NULL) + oid = _obj2txt(self._backend, alg[0].algorithm) try: return x509._SIG_OIDS_TO_HASH[oid] except KeyError: @@ -351,8 +380,7 @@ class _CertificateSigningRequest(object): @property def tbs_certrequest_bytes(self): pp = self._backend._ffi.new("unsigned char **") - # the X509_REQ_INFO struct holds the CertificateRequestInfo data - res = self._backend._lib.i2d_X509_REQ_INFO(self._x509_req.req_info, pp) + res = self._backend._lib.i2d_re_X509_REQ_tbs(self._x509_req, pp) self._backend.openssl_assert(res > 0) pp = self._backend._ffi.gc( pp, lambda pointer: self._backend._lib.OPENSSL_free(pointer[0]) @@ -361,7 +389,12 @@ class _CertificateSigningRequest(object): @property def signature(self): - return _asn1_string_to_bytes(self._backend, self._x509_req.signature) + sig = self._backend._ffi.new("ASN1_BIT_STRING **") + self._backend._lib.X509_REQ_get0_signature( + sig, self._backend._ffi.NULL, self._x509_req + ) + self._backend.openssl_assert(sig[0] != self._backend._ffi.NULL) + return _asn1_string_to_bytes(self._backend, sig[0]) @property def is_signature_valid(self): diff --git a/src/cryptography/hazmat/bindings/openssl/_conditional.py b/src/cryptography/hazmat/bindings/openssl/_conditional.py index 206c2915..148534da 100644 --- a/src/cryptography/hazmat/bindings/openssl/_conditional.py +++ b/src/cryptography/hazmat/bindings/openssl/_conditional.py @@ -86,8 +86,6 @@ CONDITIONAL_NAMES = { "EC_KEY_get_enc_flags", "EC_KEY_set_enc_flags", "EC_KEY_set_conv_form", - "EC_KEY_get_key_method_data", - "EC_KEY_insert_key_method_data", "EC_KEY_set_asn1_flag", "EC_KEY_precompute_mult", "EC_KEY_generate_key", @@ -168,9 +166,6 @@ CONDITIONAL_NAMES = { ], "Cryptography_HAS_ECDH": [ "ECDH_compute_key", - "ECDH_get_ex_new_index", - "ECDH_set_ex_data", - "ECDH_get_ex_data", ], "Cryptography_HAS_ECDSA": [ "ECDSA_SIG_new", @@ -185,13 +180,6 @@ CONDITIONAL_NAMES = { "ECDSA_sign_ex", "ECDSA_verify", "ECDSA_size", - "ECDSA_OpenSSL", - "ECDSA_set_default_method", - "ECDSA_get_default_method", - "ECDSA_set_method", - "ECDSA_get_ex_new_index", - "ECDSA_set_ex_data", - "ECDSA_get_ex_data", ], "Cryptography_HAS_ENGINE_CRYPTODEV": [ "ENGINE_load_cryptodev" @@ -411,4 +399,17 @@ CONDITIONAL_NAMES = { "SSL_CTX_set_cert_cb", "SSL_set_cert_cb", ], + "Cryptography_HAS_AES_CTR128_ENCRYPT": [ + "AES_ctr128_encrypt", + ], + "Cryptography_HAS_SSL_ST": [ + "SSL_ST_BEFORE", + "SSL_ST_OK", + "SSL_ST_INIT", + "SSL_ST_RENEGOTIATE", + ], + "Cryptography_HAS_TLS_ST": [ + "TLS_ST_BEFORE", + "TLS_ST_OK", + ], } diff --git a/src/cryptography/hazmat/bindings/openssl/binding.py b/src/cryptography/hazmat/bindings/openssl/binding.py index b2215de3..5d7466f9 100644 --- a/src/cryptography/hazmat/bindings/openssl/binding.py +++ b/src/cryptography/hazmat/bindings/openssl/binding.py @@ -17,6 +17,9 @@ from cryptography.hazmat.bindings.openssl._conditional import CONDITIONAL_NAMES _OpenSSLError = collections.namedtuple("_OpenSSLError", ["code", "lib", "func", "reason"]) +_OpenSSLErrorWithText = collections.namedtuple( + "_OpenSSLErrorWithText", ["code", "lib", "func", "reason", "reason_text"] +) def _consume_errors(lib): @@ -31,17 +34,33 @@ def _consume_errors(lib): err_reason = lib.ERR_GET_REASON(code) errors.append(_OpenSSLError(code, err_lib, err_func, err_reason)) + return errors def _openssl_assert(lib, ok): if not ok: errors = _consume_errors(lib) + errors_with_text = [] + for err in errors: + err_text_reason = ffi.string( + lib.ERR_error_string(err.code, ffi.NULL) + ) + errors_with_text.append( + _OpenSSLErrorWithText( + err.code, err.lib, err.func, err.reason, err_text_reason + ) + ) + raise InternalError( - "Unknown OpenSSL error. Please file an issue at https://github.com" - "/pyca/cryptography/issues with information on how to reproduce " - "this. ({0!r})".format(errors), - errors + "Unknown OpenSSL error. This error is commonly encountered when " + "another library is not cleaning up the OpenSSL error stack. If " + "you are using cryptography with another library that uses " + "OpenSSL try disabling it before reporting a bug. Otherwise " + "please file an issue at https://github.com/pyca/cryptography/" + "issues with information on how to reproduce " + "this. ({0!r})".format(errors_with_text), + errors_with_text ) diff --git a/src/cryptography/x509/extensions.py b/src/cryptography/x509/extensions.py index 0aa67212..87d2de1c 100644 --- a/src/cryptography/x509/extensions.py +++ b/src/cryptography/x509/extensions.py @@ -191,6 +191,14 @@ class AuthorityKeyIdentifier(object): authority_cert_serial_number=None ) + @classmethod + def from_issuer_subject_key_identifier(cls, ski): + return cls( + key_identifier=ski.value.digest, + authority_cert_issuer=None, + authority_cert_serial_number=None + ) + def __repr__(self): return ( "<AuthorityKeyIdentifier(key_identifier={0.key_identifier!r}, " diff --git a/tests/hazmat/backends/test_multibackend.py b/tests/hazmat/backends/test_multibackend.py index 74835716..bf54d5ce 100644 --- a/tests/hazmat/backends/test_multibackend.py +++ b/tests/hazmat/backends/test_multibackend.py @@ -4,6 +4,8 @@ from __future__ import absolute_import, division, print_function +import pytest + from cryptography import utils from cryptography.exceptions import ( UnsupportedAlgorithm, _Reasons @@ -21,6 +23,10 @@ from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from ...utils import raises_unsupported_algorithm +class DummyBackend(object): + pass + + @utils.register_interface(CipherBackend) class DummyCipherBackend(object): def __init__(self, supported_ciphers): @@ -226,6 +232,10 @@ class DummyX509Backend(object): class TestMultiBackend(object): + def test_raises_error_with_empty_list(self): + with pytest.raises(ValueError): + MultiBackend([]) + def test_ciphers(self): backend = MultiBackend([ DummyHashBackend([]), @@ -310,7 +320,7 @@ class TestMultiBackend(object): backend.load_rsa_public_numbers("public_numbers") - backend = MultiBackend([]) + backend = MultiBackend([DummyBackend()]) with raises_unsupported_algorithm( _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM ): @@ -353,7 +363,7 @@ class TestMultiBackend(object): backend.load_dsa_public_numbers("numbers") backend.load_dsa_parameter_numbers("numbers") - backend = MultiBackend([]) + backend = MultiBackend([DummyBackend()]) with raises_unsupported_algorithm( _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM ): @@ -491,7 +501,7 @@ class TestMultiBackend(object): backend.load_pem_private_key(b"keydata", None) backend.load_pem_public_key(b"keydata") - backend = MultiBackend([]) + backend = MultiBackend([DummyBackend()]) with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_SERIALIZATION): backend.load_pem_private_key(b"keydata", None) with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_SERIALIZATION): @@ -503,7 +513,7 @@ class TestMultiBackend(object): backend.load_der_private_key(b"keydata", None) backend.load_der_public_key(b"keydata") - backend = MultiBackend([]) + backend = MultiBackend([DummyBackend()]) with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_SERIALIZATION): backend.load_der_private_key(b"keydata", None) with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_SERIALIZATION): @@ -523,7 +533,7 @@ class TestMultiBackend(object): backend.create_x509_crl(object(), b"privatekey", hashes.SHA1()) backend.create_x509_revoked_certificate(object()) - backend = MultiBackend([]) + backend = MultiBackend([DummyBackend()]) with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_X509): backend.load_pem_x509_certificate(b"certdata") with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_X509): diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py index 072f8be3..52bee7b3 100644 --- a/tests/hazmat/backends/test_openssl.py +++ b/tests/hazmat/backends/test_openssl.py @@ -31,6 +31,7 @@ from ..primitives.test_ec import _skip_curve_unsupported from ...doubles import ( DummyAsymmetricPadding, DummyCipherAlgorithm, DummyHashAlgorithm, DummyMode ) +from ...test_x509 import _load_cert from ...utils import load_vectors_from_file, raises_unsupported_algorithm @@ -656,3 +657,23 @@ class TestRSAPEMSerialization(object): serialization.PrivateFormat.PKCS8, serialization.BestAvailableEncryption(password) ) + + +class TestGOSTCertificate(object): + @pytest.mark.skipif( + backend._lib.OPENSSL_VERSION_NUMBER < 0x1000000f, + reason="Requires a newer OpenSSL. Must be >= 1.0.0" + ) + def test_numeric_string_x509_name_entry(self): + cert = _load_cert( + os.path.join("x509", "e-trust.ru.der"), + x509.load_der_x509_certificate, + backend + ) + with pytest.raises(ValueError) as exc: + cert.subject + + # We assert on the message in this case because if the certificate + # fails to load it will also raise a ValueError and this test could + # erroneously pass. + assert str(exc.value) == "Unsupported ASN1 string type. Type: 18" diff --git a/tests/hazmat/bindings/test_openssl.py b/tests/hazmat/bindings/test_openssl.py index 76a9218b..457799d3 100644 --- a/tests/hazmat/bindings/test_openssl.py +++ b/tests/hazmat/bindings/test_openssl.py @@ -6,7 +6,10 @@ from __future__ import absolute_import, division, print_function import pytest -from cryptography.hazmat.bindings.openssl.binding import Binding +from cryptography.exceptions import InternalError +from cryptography.hazmat.bindings.openssl.binding import ( + Binding, _OpenSSLErrorWithText, _openssl_assert +) class TestOpenSSL(object): @@ -149,3 +152,26 @@ class TestOpenSSL(object): else: with pytest.raises(AttributeError): b.lib.CMAC_Init + + def test_openssl_assert_error_on_stack(self): + b = Binding() + b.lib.ERR_put_error( + b.lib.ERR_LIB_EVP, + b.lib.EVP_F_EVP_ENCRYPTFINAL_EX, + b.lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH, + b"", + -1 + ) + with pytest.raises(InternalError) as exc_info: + _openssl_assert(b.lib, False) + + assert exc_info.value.err_code == [_OpenSSLErrorWithText( + code=101183626, + lib=b.lib.ERR_LIB_EVP, + func=b.lib.EVP_F_EVP_ENCRYPTFINAL_EX, + reason=b.lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH, + reason_text=( + b'error:0607F08A:digital envelope routines:EVP_EncryptFinal_' + b'ex:data not multiple of block length' + ) + )] diff --git a/tests/test_x509.py b/tests/test_x509.py index c042169c..aaeefae9 100644 --- a/tests/test_x509.py +++ b/tests/test_x509.py @@ -2225,6 +2225,54 @@ class TestCertificateBuilder(object): ) assert ext.value == x509.InhibitAnyPolicy(3) + @pytest.mark.parametrize( + "pc", + [ + x509.PolicyConstraints( + require_explicit_policy=None, + inhibit_policy_mapping=1 + ), + x509.PolicyConstraints( + require_explicit_policy=3, + inhibit_policy_mapping=1 + ), + x509.PolicyConstraints( + require_explicit_policy=0, + inhibit_policy_mapping=None + ), + ] + ) + @pytest.mark.requires_backend_interface(interface=RSABackend) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_policy_constraints(self, backend, pc): + issuer_private_key = RSA_KEY_2048.private_key(backend) + subject_private_key = RSA_KEY_2048.private_key(backend) + + not_valid_before = datetime.datetime(2002, 1, 1, 12, 1) + not_valid_after = datetime.datetime(2030, 12, 31, 8, 30) + + cert = x509.CertificateBuilder().subject_name( + x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')]) + ).issuer_name( + x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')]) + ).not_valid_before( + not_valid_before + ).not_valid_after( + not_valid_after + ).public_key( + subject_private_key.public_key() + ).serial_number( + 123 + ).add_extension( + pc, critical=False + ).sign(issuer_private_key, hashes.SHA256(), backend) + + ext = cert.extensions.get_extension_for_class( + x509.PolicyConstraints + ) + assert ext.critical is False + assert ext.value == pc + @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) def test_name_constraints(self, backend): @@ -2334,6 +2382,39 @@ class TestCertificateBuilder(object): ) assert basic_constraints.value.path_length is None + @pytest.mark.parametrize( + "unrecognized", [ + x509.UnrecognizedExtension( + x509.ObjectIdentifier("1.2.3.4.5"), + b"abcdef", + ) + ] + ) + @pytest.mark.requires_backend_interface(interface=RSABackend) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_unrecognized_extension(self, backend, unrecognized): + private_key = RSA_KEY_2048.private_key(backend) + + cert = x509.CertificateBuilder().subject_name( + x509.Name([x509.NameAttribute(x509.OID_COUNTRY_NAME, u'US')]) + ).issuer_name( + x509.Name([x509.NameAttribute(x509.OID_COUNTRY_NAME, u'US')]) + ).not_valid_before( + datetime.datetime(2002, 1, 1, 12, 1) + ).not_valid_after( + datetime.datetime(2030, 12, 31, 8, 30) + ).public_key( + private_key.public_key() + ).serial_number( + 123 + ).add_extension( + unrecognized, critical=False + ).sign(private_key, hashes.SHA256(), backend) + + ext = cert.extensions.get_extension_for_oid(unrecognized.oid) + + assert ext.value == unrecognized + @pytest.mark.requires_backend_interface(interface=X509Backend) class TestCertificateSigningRequestBuilder(object): diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py index d85b4bbc..28ddab87 100644 --- a/tests/test_x509_ext.py +++ b/tests/test_x509_ext.py @@ -2634,6 +2634,28 @@ class TestAuthorityKeyIdentifierExtension(object): ) assert ext.value == aki + def test_from_issuer_subject_key_identifier(self, backend): + issuer_cert = _load_cert( + os.path.join("x509", "rapidssl_sha256_ca_g3.pem"), + x509.load_pem_x509_certificate, + backend + ) + cert = _load_cert( + os.path.join("x509", "cryptography.io.pem"), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.AUTHORITY_KEY_IDENTIFIER + ) + ski = issuer_cert.extensions.get_extension_for_class( + x509.SubjectKeyIdentifier + ) + aki = x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier( + ski + ) + assert ext.value == aki + class TestNameConstraints(object): def test_ipaddress_wrong_type(self): diff --git a/vectors/cryptography_vectors/x509/e-trust.ru.der b/vectors/cryptography_vectors/x509/e-trust.ru.der Binary files differnew file mode 100644 index 00000000..72b581fe --- /dev/null +++ b/vectors/cryptography_vectors/x509/e-trust.ru.der |