aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.rst20
-rw-r--r--docs/development/test-vectors.rst2
-rw-r--r--docs/installation.rst25
-rw-r--r--docs/x509/reference.rst19
-rw-r--r--src/_cffi_src/build_openssl.py15
-rw-r--r--src/_cffi_src/openssl/asn1.py2
-rw-r--r--src/_cffi_src/openssl/err.py1
-rw-r--r--src/_cffi_src/openssl/x509.py2
-rw-r--r--src/_cffi_src/openssl/x509v3.py32
-rw-r--r--src/cryptography/hazmat/backends/openssl/backend.py267
-rw-r--r--src/cryptography/hazmat/backends/openssl/rsa.py5
-rw-r--r--src/cryptography/hazmat/backends/openssl/x509.py152
-rw-r--r--src/cryptography/x509.py4
-rw-r--r--tests/hazmat/backends/test_openssl.py27
-rw-r--r--tests/hazmat/bindings/test_openssl.py30
-rw-r--r--tests/test_utils.py5
-rw-r--r--tests/test_x509.py127
-rw-r--r--tests/test_x509_ext.py15
-rw-r--r--tests/utils.py11
-rw-r--r--vectors/cryptography_vectors/x509/custom/cp_invalid.pem16
20 files changed, 516 insertions, 261 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 85f84477..4506a466 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -24,8 +24,26 @@ Changelog
and :class:`~cryptography.hazmat.primitives.kdf.concatkdf.ConcatKDFHMAC`.
* Raise a ``TypeError`` when passing objects that are not text as the value to
:class:`~cryptography.x509.NameAttribute`.
+* Add support for :class:`~cryptography.x509.OtherName` as a general name
+ type.
+* Added new X.509 extension support in :class:`~cryptography.x509.Certificate`
+ The following new extensions are now supported:
+
+ * :class:`~cryptography.x509.OCSPNoCheck`
+ * :class:`~cryptography.x509.InhibitAnyPolicy`
+ * :class:`~cryptography.x509.IssuerAlternativeName`
+ * :class:`~cryptography.x509.NameConstraints`
+
+* Extension support was added to
+ :class:`~cryptography.x509.CertificateSigningRequest`.
* Add support for creating certificate signing requests with
- :class:`~cryptography.x509.CertificateSigningRequestBuilder`.
+ :class:`~cryptography.x509.CertificateSigningRequestBuilder`. This includes
+ support for the following extensions:
+
+ * :class:`~cryptography.x509.BasicConstraints`
+ * :class:`~cryptography.x509.ExtendedKeyUsage`
+ * :class:`~cryptography.x509.KeyUsage`
+ * :class:`~cryptography.x509.SubjectAlternativeName`
0.9.3 - 2015-07-09
~~~~~~~~~~~~~~~~~~
diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst
index ea44a46c..d400e662 100644
--- a/docs/development/test-vectors.rst
+++ b/docs/development/test-vectors.rst
@@ -233,6 +233,8 @@ Custom X.509 Vectors
* ``cp_user_notice_no_explicit_text.pem`` - An RSA 2048 bit self-signed
certificate containing a certificate policies extension with a user notice
with no explicit text.
+* ``cp_invalid.pem`` - An RSA 2048 bit self-signed certificate containing a
+ certificate policies extension with invalid data.
* ``ian_uri.pem`` - An RSA 2048 bit certificate containing an issuer
alternative name extension with a ``URI`` general name.
* ``ocsp_nocheck.pem`` - An RSA 2048 bit self-signed certificate containing
diff --git a/docs/installation.rst b/docs/installation.rst
index 96e1e8de..becab6b0 100644
--- a/docs/installation.rst
+++ b/docs/installation.rst
@@ -45,28 +45,18 @@ dependencies are included. Just run
$ pip install cryptography
If you prefer to compile it yourself you'll need to have OpenSSL installed.
-There are `pre-compiled binaries`_ available. If your installation is in an
-unusual location set the ``LIB`` and ``INCLUDE`` environment variables to
-include the corresponding locations.For example:
+You can compile OpenSSL yourself as well or use the binaries we build for our
+release infrastructure (`32-bit`_ and `64-bit`_). Wherever you place your copy
+of OpenSSL you'll need to set the ``LIB`` and ``INCLUDE`` environment variables
+to include the proper locations. For example:
.. code-block:: console
C:\> \path\to\vcvarsall.bat x86_amd64
- C:\> set LIB=C:\OpenSSL\lib\VC\static;C:\OpenSSL\lib;%LIB%
- C:\> set INCLUDE=C:\OpenSSL\include;%INCLUDE%
+ C:\> set LIB=C:\OpenSSL-win64\lib;%LIB%
+ C:\> set INCLUDE=C:\OpenSSL-win64\include;%INCLUDE%
C:\> pip install cryptography
-You can also choose to build statically or dynamically using the
-``PYCA_WINDOWS_LINK_TYPE`` variable. Allowed values are ``static`` (default)
-and ``dynamic``.
-
-.. code-block:: console
-
- C:\> \path\to\vcvarsall.bat x86_amd64
- C:\> set LIB=C:\OpenSSL\lib\VC\static;C:\OpenSSL\lib;%LIB%
- C:\> set INCLUDE=C:\OpenSSL\include;%INCLUDE%
- C:\> set PYCA_WINDOWS_LINK_TYPE=dynamic
- C:\> pip install cryptography
Building cryptography on Linux
------------------------------
@@ -186,6 +176,7 @@ information, consult `Greg Wilson's blog post`_ on the subject.
.. _`Homebrew`: http://brew.sh
.. _`MacPorts`: http://www.macports.org
-.. _`pre-compiled binaries`: https://www.openssl.org/related/binaries.html
+.. _`32-bit`: https://jenkins.cryptography.io/job/openssl-win32-release/
+.. _`64-bit`: https://jenkins.cryptography.io/job/openssl-win64-release/
.. _`bug in conda`: https://github.com/conda/conda-recipes/issues/110
.. _`Greg Wilson's blog post`: http://software-carpentry.org/blog/2014/04/mr-biczo-was-right.html
diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst
index 5e58886f..799126b9 100644
--- a/docs/x509/reference.rst
+++ b/docs/x509/reference.rst
@@ -565,6 +565,25 @@ X.509 CSR (Certificate Signing Request) Object
>>> isinstance(csr.signature_hash_algorithm, hashes.SHA1)
True
+ .. attribute:: extensions
+
+ :type: :class:`Extensions`
+
+ The extensions encoded in the certificate signing request.
+
+ :raises cryptography.x509.DuplicateExtension: If more than one
+ extension of the same type is found within the certificate signing request.
+
+ :raises cryptography.x509.UnsupportedExtension: If the certificate signing request
+ contains an extension that is not supported.
+
+ :raises cryptography.x509.UnsupportedGeneralNameType: If an extension
+ contains a general name that is not supported.
+
+ :raises UnicodeError: If an extension contains IDNA encoding that is
+ invalid or not compliant with IDNA 2008.
+
+
.. method:: public_bytes(encoding)
.. versionadded:: 1.0
diff --git a/src/_cffi_src/build_openssl.py b/src/_cffi_src/build_openssl.py
index dac3e4d8..6a5bf2da 100644
--- a/src/_cffi_src/build_openssl.py
+++ b/src/_cffi_src/build_openssl.py
@@ -4,7 +4,6 @@
from __future__ import absolute_import, division, print_function
-import os
import sys
from _cffi_src.utils import build_ffi_for_binding, extra_link_args
@@ -19,20 +18,8 @@ def _get_openssl_libraries(platform):
# (http://marc.info/?l=openssl-users&m=135361825921871)
return ["ssl", "crypto"]
else:
- link_type = os.environ.get("PYCA_WINDOWS_LINK_TYPE", "static")
- return _get_openssl_windows_libraries(link_type)
-
-
-def _get_openssl_windows_libraries(link_type):
- if link_type == "dynamic":
- return ["libeay32", "ssleay32", "advapi32"]
- elif link_type == "static" or link_type == "":
- return ["libeay32mt", "ssleay32mt", "advapi32",
+ return ["libeay32", "ssleay32", "advapi32",
"crypt32", "gdi32", "user32", "ws2_32"]
- else:
- raise ValueError(
- "PYCA_WINDOWS_LINK_TYPE must be 'static' or 'dynamic'"
- )
_OSX_PRE_INCLUDE = """
diff --git a/src/_cffi_src/openssl/asn1.py b/src/_cffi_src/openssl/asn1.py
index 5f8ca697..96eff7d3 100644
--- a/src/_cffi_src/openssl/asn1.py
+++ b/src/_cffi_src/openssl/asn1.py
@@ -125,7 +125,9 @@ int ASN1_BIT_STRING_set_bit(ASN1_BIT_STRING *, int, int);
"""
MACROS = """
+ASN1_BIT_STRING *ASN1_BIT_STRING_new(void);
void ASN1_BIT_STRING_free(ASN1_BIT_STRING *);
+int i2d_ASN1_BIT_STRING(ASN1_BIT_STRING *, unsigned char **);
/* 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 *);
diff --git a/src/_cffi_src/openssl/err.py b/src/_cffi_src/openssl/err.py
index eebf19ba..73ce4e3c 100644
--- a/src/_cffi_src/openssl/err.py
+++ b/src/_cffi_src/openssl/err.py
@@ -230,6 +230,7 @@ static const int RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY;
static const int RSA_R_BLOCK_TYPE_IS_NOT_01;
static const int RSA_R_BLOCK_TYPE_IS_NOT_02;
static const int RSA_R_PKCS_DECODING_ERROR;
+static const int RSA_F_RSA_SIGN;
"""
FUNCTIONS = """
diff --git a/src/_cffi_src/openssl/x509.py b/src/_cffi_src/openssl/x509.py
index 6bd117b0..bdcc1719 100644
--- a/src/_cffi_src/openssl/x509.py
+++ b/src/_cffi_src/openssl/x509.py
@@ -325,6 +325,8 @@ int i2o_ECPublicKey(EC_KEY *, unsigned char **);
int sk_ASN1_OBJECT_num(Cryptography_STACK_OF_ASN1_OBJECT *);
ASN1_OBJECT *sk_ASN1_OBJECT_value(Cryptography_STACK_OF_ASN1_OBJECT *, int);
void sk_ASN1_OBJECT_free(Cryptography_STACK_OF_ASN1_OBJECT *);
+Cryptography_STACK_OF_ASN1_OBJECT *sk_ASN1_OBJECT_new_null(void);
+int sk_ASN1_OBJECT_push(Cryptography_STACK_OF_ASN1_OBJECT *, ASN1_OBJECT *);
"""
CUSTOMIZATIONS = """
diff --git a/src/_cffi_src/openssl/x509v3.py b/src/_cffi_src/openssl/x509v3.py
index 8e42b65d..a61ad321 100644
--- a/src/_cffi_src/openssl/x509v3.py
+++ b/src/_cffi_src/openssl/x509v3.py
@@ -33,6 +33,7 @@ typedef ... Cryptography_STACK_OF_POLICYQUALINFO;
typedef ... Cryptography_STACK_OF_POLICYINFO;
typedef ... Cryptography_STACK_OF_ASN1_INTEGER;
typedef ... Cryptography_STACK_OF_GENERAL_SUBTREE;
+typedef ... EXTENDED_KEY_USAGE;
typedef struct {
X509 *issuer_cert;
@@ -200,6 +201,8 @@ void *X509V3_set_ctx_nodb(X509V3_CTX *);
int i2d_GENERAL_NAMES(GENERAL_NAMES *, unsigned char **);
+int i2d_EXTENDED_KEY_USAGE(EXTENDED_KEY_USAGE *, unsigned char **);
+
int sk_GENERAL_NAME_num(struct stack_st_GENERAL_NAME *);
int sk_GENERAL_NAME_push(struct stack_st_GENERAL_NAME *, GENERAL_NAME *);
GENERAL_NAME *sk_GENERAL_NAME_value(struct stack_st_GENERAL_NAME *, int);
@@ -220,19 +223,42 @@ X509_EXTENSION *X509V3_EXT_conf_nid(Cryptography_LHASH_OF_CONF_VALUE *,
const X509V3_EXT_METHOD *X509V3_EXT_get(X509_EXTENSION *);
const X509V3_EXT_METHOD *X509V3_EXT_get_nid(int);
+Cryptography_STACK_OF_DIST_POINT *sk_DIST_POINT_new_null(void);
void sk_DIST_POINT_free(Cryptography_STACK_OF_DIST_POINT *);
int sk_DIST_POINT_num(Cryptography_STACK_OF_DIST_POINT *);
DIST_POINT *sk_DIST_POINT_value(Cryptography_STACK_OF_DIST_POINT *, int);
+int sk_DIST_POINT_push(Cryptography_STACK_OF_DIST_POINT *, DIST_POINT *);
void sk_POLICYINFO_free(Cryptography_STACK_OF_POLICYINFO *);
int sk_POLICYINFO_num(Cryptography_STACK_OF_POLICYINFO *);
POLICYINFO *sk_POLICYINFO_value(Cryptography_STACK_OF_POLICYINFO *, int);
+int sk_POLICYINFO_push(Cryptography_STACK_OF_POLICYINFO *, POLICYINFO *);
+Cryptography_STACK_OF_POLICYINFO *sk_POLICYINFO_new_null(void);
+
+POLICYINFO *POLICYINFO_new(void);
+void POLICYINFO_free(POLICYINFO *);
+
+POLICYQUALINFO *POLICYQUALINFO_new(void);
+void POLICYQUALINFO_free(POLICYQUALINFO *);
+
+NOTICEREF *NOTICEREF_new(void);
+void NOTICEREF_free(NOTICEREF *);
+
+USERNOTICE *USERNOTICE_new(void);
+void USERNOTICE_free(USERNOTICE *);
+
+int i2d_CERTIFICATEPOLICIES(Cryptography_STACK_OF_POLICYINFO *,
+ unsigned char **);
void sk_POLICYQUALINFO_free(Cryptography_STACK_OF_POLICYQUALINFO *);
int sk_POLICYQUALINFO_num(Cryptography_STACK_OF_POLICYQUALINFO *);
POLICYQUALINFO *sk_POLICYQUALINFO_value(Cryptography_STACK_OF_POLICYQUALINFO *,
int);
+int sk_POLICYQUALINFO_push(Cryptography_STACK_OF_POLICYQUALINFO *,
+ POLICYQUALINFO *);
+Cryptography_STACK_OF_POLICYQUALINFO *sk_POLICYQUALINFO_new_null(void);
+Cryptography_STACK_OF_GENERAL_SUBTREE *sk_GENERAL_SUBTREE_new_null(void);
void sk_GENERAL_SUBTREE_free(Cryptography_STACK_OF_GENERAL_SUBTREE *);
int sk_GENERAL_SUBTREE_num(Cryptography_STACK_OF_GENERAL_SUBTREE *);
GENERAL_SUBTREE *sk_GENERAL_SUBTREE_value(
@@ -244,8 +270,14 @@ int sk_GENERAL_SUBTREE_push(Cryptography_STACK_OF_GENERAL_SUBTREE *,
void sk_ASN1_INTEGER_free(Cryptography_STACK_OF_ASN1_INTEGER *);
int sk_ASN1_INTEGER_num(Cryptography_STACK_OF_ASN1_INTEGER *);
ASN1_INTEGER *sk_ASN1_INTEGER_value(Cryptography_STACK_OF_ASN1_INTEGER *, int);
+int sk_ASN1_INTEGER_push(Cryptography_STACK_OF_ASN1_INTEGER *, ASN1_INTEGER *);
X509_EXTENSION *X509V3_EXT_i2d(int, int, void *);
+
+DIST_POINT *DIST_POINT_new(void);
+void DIST_POINT_free(DIST_POINT *);
+
+int i2d_CRL_DIST_POINTS(Cryptography_STACK_OF_DIST_POINT *, unsigned char **);
"""
CUSTOMIZATIONS = """
diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py
index c190f591..0176de21 100644
--- a/src/cryptography/hazmat/backends/openssl/backend.py
+++ b/src/cryptography/hazmat/backends/openssl/backend.py
@@ -108,7 +108,7 @@ def _encode_name(backend, attributes):
subject = backend._lib.X509_NAME_new()
for attribute in attributes:
value = attribute.value.encode('utf8')
- obj = _txt2obj(backend, attribute.oid.dotted_string)
+ obj = _txt2obj_gc(backend, attribute.oid.dotted_string)
res = backend._lib.X509_NAME_add_entry_by_OBJ(
subject,
obj,
@@ -134,10 +134,53 @@ def _txt2obj(backend, name):
name = name.encode('ascii')
obj = backend._lib.OBJ_txt2obj(name, 1)
assert obj != backend._ffi.NULL
+ return obj
+
+
+def _txt2obj_gc(backend, name):
+ obj = _txt2obj(backend, name)
obj = backend._ffi.gc(obj, backend._lib.ASN1_OBJECT_free)
return obj
+def _encode_key_usage(backend, key_usage):
+ set_bit = backend._lib.ASN1_BIT_STRING_set_bit
+ ku = backend._lib.ASN1_BIT_STRING_new()
+ ku = backend._ffi.gc(ku, backend._lib.ASN1_BIT_STRING_free)
+ res = set_bit(ku, 0, key_usage.digital_signature)
+ assert res == 1
+ res = set_bit(ku, 1, key_usage.content_commitment)
+ assert res == 1
+ res = set_bit(ku, 2, key_usage.key_encipherment)
+ assert res == 1
+ res = set_bit(ku, 3, key_usage.data_encipherment)
+ assert res == 1
+ res = set_bit(ku, 4, key_usage.key_agreement)
+ assert res == 1
+ res = set_bit(ku, 5, key_usage.key_cert_sign)
+ assert res == 1
+ res = set_bit(ku, 6, key_usage.crl_sign)
+ assert res == 1
+ if key_usage.key_agreement:
+ res = set_bit(ku, 7, key_usage.encipher_only)
+ assert res == 1
+ res = set_bit(ku, 8, key_usage.decipher_only)
+ assert res == 1
+ else:
+ res = set_bit(ku, 7, 0)
+ assert res == 1
+ res = set_bit(ku, 8, 0)
+ assert res == 1
+
+ pp = backend._ffi.new('unsigned char **')
+ r = backend._lib.i2d_ASN1_BIT_STRING(ku, pp)
+ assert r > 0
+ pp = backend._ffi.gc(
+ pp, lambda pointer: backend._lib.OPENSSL_free(pointer[0])
+ )
+ return pp, r
+
+
def _encode_basic_constraints(backend, basic_constraints):
constraints = backend._lib.BASIC_CONSTRAINTS_new()
constraints = backend._ffi.gc(
@@ -167,94 +210,118 @@ def _encode_subject_alt_name(backend, san):
)
for alt_name in san:
- if isinstance(alt_name, x509.DNSName):
- gn = backend._lib.GENERAL_NAME_new()
- assert gn != backend._ffi.NULL
- gn.type = backend._lib.GEN_DNS
+ gn = _encode_general_name(backend, alt_name)
+ res = backend._lib.sk_GENERAL_NAME_push(general_names, gn)
+ assert res != 0
- ia5 = backend._lib.ASN1_IA5STRING_new()
- assert ia5 != backend._ffi.NULL
+ pp = backend._ffi.new("unsigned char **")
+ r = backend._lib.i2d_GENERAL_NAMES(general_names, pp)
+ assert r > 0
+ pp = backend._ffi.gc(
+ pp, lambda pointer: backend._lib.OPENSSL_free(pointer[0])
+ )
+ return pp, r
- if alt_name.value.startswith(u"*."):
- value = b"*." + idna.encode(alt_name.value[2:])
- else:
- value = idna.encode(alt_name.value)
- res = backend._lib.ASN1_STRING_set(ia5, value, len(value))
- assert res == 1
- gn.d.dNSName = ia5
- elif isinstance(alt_name, x509.RegisteredID):
- gn = backend._lib.GENERAL_NAME_new()
- assert gn != backend._ffi.NULL
- gn.type = backend._lib.GEN_RID
- obj = backend._lib.OBJ_txt2obj(
- alt_name.value.dotted_string.encode('ascii'), 1
- )
- assert obj != backend._ffi.NULL
- gn.d.registeredID = obj
- elif isinstance(alt_name, x509.DirectoryName):
- gn = backend._lib.GENERAL_NAME_new()
- assert gn != backend._ffi.NULL
- name = _encode_name(backend, alt_name.value)
- gn.type = backend._lib.GEN_DIRNAME
- gn.d.directoryName = name
- elif isinstance(alt_name, x509.IPAddress):
- gn = backend._lib.GENERAL_NAME_new()
- assert gn != backend._ffi.NULL
- ipaddr = _encode_asn1_str(
- backend, alt_name.value.packed, len(alt_name.value.packed)
- )
- gn.type = backend._lib.GEN_IPADD
- gn.d.iPAddress = ipaddr
- elif isinstance(alt_name, x509.OtherName):
- gn = backend._lib.GENERAL_NAME_new()
- assert gn != backend._ffi.NULL
- other_name = backend._lib.OTHERNAME_new()
- assert other_name != backend._ffi.NULL
-
- type_id = backend._lib.OBJ_txt2obj(
- alt_name.type_id.dotted_string.encode('ascii'), 1
- )
- assert type_id != backend._ffi.NULL
- data = backend._ffi.new("unsigned char[]", alt_name.value)
- data_ptr_ptr = backend._ffi.new("unsigned char **")
- data_ptr_ptr[0] = data
- value = backend._lib.d2i_ASN1_TYPE(
- backend._ffi.NULL, data_ptr_ptr, len(alt_name.value)
- )
- if value == backend._ffi.NULL:
- backend._consume_errors()
- raise ValueError("Invalid ASN.1 data")
- other_name.type_id = type_id
- other_name.value = value
- gn.type = backend._lib.GEN_OTHERNAME
- gn.d.otherName = other_name
- elif isinstance(alt_name, x509.RFC822Name):
- gn = backend._lib.GENERAL_NAME_new()
- assert gn != backend._ffi.NULL
- asn1_str = _encode_asn1_str(
- backend, alt_name._encoded, len(alt_name._encoded)
- )
- gn.type = backend._lib.GEN_EMAIL
- gn.d.rfc822Name = asn1_str
- elif isinstance(alt_name, x509.UniformResourceIdentifier):
- gn = backend._lib.GENERAL_NAME_new()
- assert gn != backend._ffi.NULL
- asn1_str = _encode_asn1_str(
- backend, alt_name._encoded, len(alt_name._encoded)
- )
- gn.type = backend._lib.GEN_URI
- gn.d.uniformResourceIdentifier = asn1_str
+def _encode_general_name(backend, name):
+ if isinstance(name, x509.DNSName):
+ gn = backend._lib.GENERAL_NAME_new()
+ assert gn != backend._ffi.NULL
+ gn.type = backend._lib.GEN_DNS
+
+ ia5 = backend._lib.ASN1_IA5STRING_new()
+ assert ia5 != backend._ffi.NULL
+
+ if name.value.startswith(u"*."):
+ value = b"*." + idna.encode(name.value[2:])
else:
- raise ValueError(
- "{0} is an unknown GeneralName type".format(alt_name)
- )
+ value = idna.encode(name.value)
- res = backend._lib.sk_GENERAL_NAME_push(general_names, gn)
- assert res != 0
+ res = backend._lib.ASN1_STRING_set(ia5, value, len(value))
+ assert res == 1
+ gn.d.dNSName = ia5
+ elif isinstance(name, x509.RegisteredID):
+ gn = backend._lib.GENERAL_NAME_new()
+ assert gn != backend._ffi.NULL
+ gn.type = backend._lib.GEN_RID
+ obj = backend._lib.OBJ_txt2obj(
+ name.value.dotted_string.encode('ascii'), 1
+ )
+ assert obj != backend._ffi.NULL
+ gn.d.registeredID = obj
+ elif isinstance(name, x509.DirectoryName):
+ gn = backend._lib.GENERAL_NAME_new()
+ assert gn != backend._ffi.NULL
+ dir_name = _encode_name(backend, name.value)
+ gn.type = backend._lib.GEN_DIRNAME
+ gn.d.directoryName = dir_name
+ elif isinstance(name, x509.IPAddress):
+ gn = backend._lib.GENERAL_NAME_new()
+ assert gn != backend._ffi.NULL
+ ipaddr = _encode_asn1_str(
+ backend, name.value.packed, len(name.value.packed)
+ )
+ gn.type = backend._lib.GEN_IPADD
+ gn.d.iPAddress = ipaddr
+ elif isinstance(name, x509.OtherName):
+ gn = backend._lib.GENERAL_NAME_new()
+ assert gn != backend._ffi.NULL
+ other_name = backend._lib.OTHERNAME_new()
+ assert other_name != backend._ffi.NULL
+
+ type_id = backend._lib.OBJ_txt2obj(
+ name.type_id.dotted_string.encode('ascii'), 1
+ )
+ assert type_id != backend._ffi.NULL
+ data = backend._ffi.new("unsigned char[]", name.value)
+ data_ptr_ptr = backend._ffi.new("unsigned char **")
+ data_ptr_ptr[0] = data
+ value = backend._lib.d2i_ASN1_TYPE(
+ backend._ffi.NULL, data_ptr_ptr, len(name.value)
+ )
+ if value == backend._ffi.NULL:
+ backend._consume_errors()
+ raise ValueError("Invalid ASN.1 data")
+ other_name.type_id = type_id
+ other_name.value = value
+ gn.type = backend._lib.GEN_OTHERNAME
+ gn.d.otherName = other_name
+ elif isinstance(name, x509.RFC822Name):
+ gn = backend._lib.GENERAL_NAME_new()
+ assert gn != backend._ffi.NULL
+ asn1_str = _encode_asn1_str(
+ backend, name._encoded, len(name._encoded)
+ )
+ gn.type = backend._lib.GEN_EMAIL
+ gn.d.rfc822Name = asn1_str
+ elif isinstance(name, x509.UniformResourceIdentifier):
+ gn = backend._lib.GENERAL_NAME_new()
+ assert gn != backend._ffi.NULL
+ asn1_str = _encode_asn1_str(
+ backend, name._encoded, len(name._encoded)
+ )
+ gn.type = backend._lib.GEN_URI
+ gn.d.uniformResourceIdentifier = asn1_str
+ else:
+ raise ValueError(
+ "{0} is an unknown GeneralName type".format(name)
+ )
- pp = backend._ffi.new("unsigned char **")
- r = backend._lib.i2d_GENERAL_NAMES(general_names, pp)
+ return gn
+
+
+def _encode_extended_key_usage(backend, extended_key_usage):
+ eku = backend._lib.sk_ASN1_OBJECT_new_null()
+ eku = backend._ffi.gc(eku, backend._lib.sk_ASN1_OBJECT_free)
+ for oid in extended_key_usage:
+ obj = _txt2obj(backend, oid.dotted_string)
+ res = backend._lib.sk_ASN1_OBJECT_push(eku, obj)
+ assert res >= 1
+
+ pp = backend._ffi.new('unsigned char **')
+ r = backend._lib.i2d_EXTENDED_KEY_USAGE(
+ backend._ffi.cast("EXTENDED_KEY_USAGE *", eku), pp
+ )
assert r > 0
pp = backend._ffi.gc(
pp, lambda pointer: backend._lib.OPENSSL_free(pointer[0])
@@ -971,10 +1038,14 @@ class Backend(object):
pp, r = _encode_basic_constraints(self, extension.value)
elif isinstance(extension.value, x509.SubjectAlternativeName):
pp, r = _encode_subject_alt_name(self, extension.value)
+ elif isinstance(extension.value, x509.KeyUsage):
+ pp, r = _encode_key_usage(self, extension.value)
+ elif isinstance(extension.value, x509.ExtendedKeyUsage):
+ pp, r = _encode_extended_key_usage(self, extension.value)
else:
raise NotImplementedError('Extension not yet supported.')
- obj = _txt2obj(self, extension.oid.dotted_string)
+ obj = _txt2obj_gc(self, extension.oid.dotted_string)
extension = self._lib.X509_EXTENSION_create_by_OBJ(
self._ffi.NULL,
obj,
@@ -983,7 +1054,7 @@ class Backend(object):
)
assert extension != self._ffi.NULL
res = self._lib.sk_X509_EXTENSION_push(extensions, extension)
- assert res == 1
+ assert res >= 1
res = self._lib.X509_REQ_add_extensions(x509_req, extensions)
assert res == 1
@@ -991,7 +1062,11 @@ class Backend(object):
res = self._lib.X509_REQ_sign(
x509_req, private_key._evp_pkey, evp_md
)
- assert res > 0
+ if res == 0:
+ errors = self._consume_errors()
+ assert errors[0][1] == self._lib.ERR_LIB_RSA
+ assert errors[0][3] == self._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY
+ raise ValueError("Digest too big for RSA key")
return _CertificateSigningRequest(self, x509_req)
@@ -1609,13 +1684,15 @@ class Backend(object):
if format is serialization.PrivateFormat.PKCS8:
write_bio = self._lib.PEM_write_bio_PKCS8PrivateKey
key = evp_pkey
- elif format is serialization.PrivateFormat.TraditionalOpenSSL:
+ else:
+ assert format is serialization.PrivateFormat.TraditionalOpenSSL
if evp_pkey.type == self._lib.EVP_PKEY_RSA:
write_bio = self._lib.PEM_write_bio_RSAPrivateKey
elif evp_pkey.type == self._lib.EVP_PKEY_DSA:
write_bio = self._lib.PEM_write_bio_DSAPrivateKey
- elif (self._lib.Cryptography_HAS_EC == 1 and
- evp_pkey.type == self._lib.EVP_PKEY_EC):
+ else:
+ assert self._lib.Cryptography_HAS_EC == 1
+ assert evp_pkey.type == self._lib.EVP_PKEY_EC
write_bio = self._lib.PEM_write_bio_ECPrivateKey
key = cdata
@@ -1632,7 +1709,8 @@ class Backend(object):
return self._private_key_bytes_traditional_der(
evp_pkey.type, cdata
)
- elif format is serialization.PrivateFormat.PKCS8:
+ else:
+ assert format is serialization.PrivateFormat.PKCS8
write_bio = self._lib.i2d_PKCS8PrivateKey_bio
key = evp_pkey
else:
@@ -1657,7 +1735,8 @@ class Backend(object):
elif (self._lib.Cryptography_HAS_EC == 1 and
key_type == self._lib.EVP_PKEY_EC):
write_bio = self._lib.i2d_ECPrivateKey_bio
- elif key_type == self._lib.EVP_PKEY_DSA:
+ else:
+ assert key_type == self._lib.EVP_PKEY_DSA
write_bio = self._lib.i2d_DSAPrivateKey_bio
bio = self._create_mem_bio()
@@ -1672,7 +1751,8 @@ class Backend(object):
if format is serialization.PublicFormat.SubjectPublicKeyInfo:
if encoding is serialization.Encoding.PEM:
write_bio = self._lib.PEM_write_bio_PUBKEY
- elif encoding is serialization.Encoding.DER:
+ else:
+ assert encoding is serialization.Encoding.DER
write_bio = self._lib.i2d_PUBKEY_bio
key = evp_pkey
@@ -1681,7 +1761,8 @@ class Backend(object):
assert evp_pkey.type == self._lib.EVP_PKEY_RSA
if encoding is serialization.Encoding.PEM:
write_bio = self._lib.PEM_write_bio_RSAPublicKey
- elif encoding is serialization.Encoding.DER:
+ else:
+ assert encoding is serialization.Encoding.DER
write_bio = self._lib.i2d_RSAPublicKey_bio
key = cdata
diff --git a/src/cryptography/hazmat/backends/openssl/rsa.py b/src/cryptography/hazmat/backends/openssl/rsa.py
index 21414c05..822c7304 100644
--- a/src/cryptography/hazmat/backends/openssl/rsa.py
+++ b/src/cryptography/hazmat/backends/openssl/rsa.py
@@ -268,8 +268,9 @@ class _RSASignatureContext(object):
self._backend._lib.RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE):
reason = ("Salt length too long for key size. Try using "
"MAX_LENGTH instead.")
- elif (errors[0].reason ==
- self._backend._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY):
+ else:
+ assert (errors[0].reason ==
+ self._backend._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY)
reason = "Digest too large for key size. Use a larger key."
assert reason is not None
raise ValueError(reason)
diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py
index 472d8a70..ee9a3bbf 100644
--- a/src/cryptography/hazmat/backends/openssl/x509.py
+++ b/src/cryptography/hazmat/backends/openssl/x509.py
@@ -234,7 +234,15 @@ class _X509ExtensionParser(object):
"{0} is not currently supported".format(oid), oid
)
else:
- value = handler(backend, ext)
+ d2i = backend._lib.X509V3_EXT_d2i(ext)
+ if d2i == backend._ffi.NULL:
+ backend._consume_errors()
+ raise ValueError(
+ "The {0} extension is invalid and can't be "
+ "parsed".format(oid)
+ )
+
+ value = handler(backend, d2i)
extensions.append(x509.Extension(oid, critical, value))
seen_oids.add(oid)
@@ -358,12 +366,8 @@ class _Certificate(object):
return self._backend._read_mem_bio(bio)
-def _decode_certificate_policies(backend, ext):
- cp = backend._ffi.cast(
- "Cryptography_STACK_OF_POLICYINFO *",
- backend._lib.X509V3_EXT_d2i(ext)
- )
- assert cp != backend._ffi.NULL
+def _decode_certificate_policies(backend, cp):
+ cp = backend._ffi.cast("Cryptography_STACK_OF_POLICYINFO *", cp)
cp = backend._ffi.gc(cp, backend._lib.sk_POLICYINFO_free)
num = backend._lib.sk_POLICYINFO_num(cp)
certificate_policies = []
@@ -386,7 +390,8 @@ def _decode_certificate_policies(backend, ext):
pqi.d.cpsuri.data, pqi.d.cpsuri.length
)[:].decode('ascii')
qualifiers.append(cpsuri)
- elif pqualid == x509.OID_CPS_USER_NOTICE:
+ else:
+ assert pqualid == x509.OID_CPS_USER_NOTICE
user_notice = _decode_user_notice(
backend, pqi.d.usernotice
)
@@ -431,12 +436,8 @@ def _decode_user_notice(backend, un):
return x509.UserNotice(notice_reference, explicit_text)
-def _decode_basic_constraints(backend, ext):
- bc_st = backend._lib.X509V3_EXT_d2i(ext)
- assert bc_st != backend._ffi.NULL
- basic_constraints = backend._ffi.cast(
- "BASIC_CONSTRAINTS *", bc_st
- )
+def _decode_basic_constraints(backend, bc_st):
+ basic_constraints = backend._ffi.cast("BASIC_CONSTRAINTS *", bc_st)
basic_constraints = backend._ffi.gc(
basic_constraints, backend._lib.BASIC_CONSTRAINTS_free
)
@@ -447,19 +448,13 @@ def _decode_basic_constraints(backend, ext):
if basic_constraints.pathlen == backend._ffi.NULL:
path_length = None
else:
- path_length = _asn1_integer_to_int(
- backend, basic_constraints.pathlen
- )
+ path_length = _asn1_integer_to_int(backend, basic_constraints.pathlen)
return x509.BasicConstraints(ca, path_length)
-def _decode_subject_key_identifier(backend, ext):
- asn1_string = backend._lib.X509V3_EXT_d2i(ext)
- assert asn1_string != backend._ffi.NULL
- asn1_string = backend._ffi.cast(
- "ASN1_OCTET_STRING *", asn1_string
- )
+def _decode_subject_key_identifier(backend, asn1_string):
+ asn1_string = backend._ffi.cast("ASN1_OCTET_STRING *", asn1_string)
asn1_string = backend._ffi.gc(
asn1_string, backend._lib.ASN1_OCTET_STRING_free
)
@@ -468,13 +463,9 @@ def _decode_subject_key_identifier(backend, ext):
)
-def _decode_authority_key_identifier(backend, ext):
- akid = backend._lib.X509V3_EXT_d2i(ext)
- assert akid != backend._ffi.NULL
+def _decode_authority_key_identifier(backend, akid):
akid = backend._ffi.cast("AUTHORITY_KEYID *", akid)
- akid = backend._ffi.gc(
- akid, backend._lib.AUTHORITY_KEYID_free
- )
+ akid = backend._ffi.gc(akid, backend._lib.AUTHORITY_KEYID_free)
key_identifier = None
authority_cert_issuer = None
authority_cert_serial_number = None
@@ -499,15 +490,9 @@ def _decode_authority_key_identifier(backend, ext):
)
-def _decode_authority_information_access(backend, ext):
- aia = backend._lib.X509V3_EXT_d2i(ext)
- assert aia != backend._ffi.NULL
- aia = backend._ffi.cast(
- "Cryptography_STACK_OF_ACCESS_DESCRIPTION *", aia
- )
- aia = backend._ffi.gc(
- aia, backend._lib.sk_ACCESS_DESCRIPTION_free
- )
+def _decode_authority_information_access(backend, aia):
+ aia = backend._ffi.cast("Cryptography_STACK_OF_ACCESS_DESCRIPTION *", aia)
+ aia = backend._ffi.gc(aia, backend._lib.sk_ACCESS_DESCRIPTION_free)
num = backend._lib.sk_ACCESS_DESCRIPTION_num(aia)
access_descriptions = []
for i in range(num):
@@ -521,13 +506,9 @@ def _decode_authority_information_access(backend, ext):
return x509.AuthorityInformationAccess(access_descriptions)
-def _decode_key_usage(backend, ext):
- bit_string = backend._lib.X509V3_EXT_d2i(ext)
- assert bit_string != backend._ffi.NULL
+def _decode_key_usage(backend, bit_string):
bit_string = backend._ffi.cast("ASN1_BIT_STRING *", bit_string)
- bit_string = backend._ffi.gc(
- bit_string, backend._lib.ASN1_BIT_STRING_free
- )
+ bit_string = backend._ffi.gc(bit_string, backend._lib.ASN1_BIT_STRING_free)
get_bit = backend._lib.ASN1_BIT_STRING_get_bit
digital_signature = get_bit(bit_string, 0) == 1
content_commitment = get_bit(bit_string, 1) == 1
@@ -551,11 +532,8 @@ def _decode_key_usage(backend, ext):
)
-def _decode_general_names_extension(backend, ext):
- gns = backend._ffi.cast(
- "GENERAL_NAMES *", backend._lib.X509V3_EXT_d2i(ext)
- )
- assert gns != backend._ffi.NULL
+def _decode_general_names_extension(backend, gns):
+ gns = backend._ffi.cast("GENERAL_NAMES *", gns)
gns = backend._ffi.gc(gns, backend._lib.GENERAL_NAMES_free)
general_names = _decode_general_names(backend, gns)
return general_names
@@ -573,11 +551,8 @@ def _decode_issuer_alt_name(backend, ext):
)
-def _decode_name_constraints(backend, ext):
- nc = backend._ffi.cast(
- "NAME_CONSTRAINTS *", backend._lib.X509V3_EXT_d2i(ext)
- )
- assert nc != backend._ffi.NULL
+def _decode_name_constraints(backend, nc):
+ nc = backend._ffi.cast("NAME_CONSTRAINTS *", nc)
nc = backend._ffi.gc(nc, backend._lib.NAME_CONSTRAINTS_free)
permitted = _decode_general_subtrees(backend, nc.permittedSubtrees)
excluded = _decode_general_subtrees(backend, nc.excludedSubtrees)
@@ -602,12 +577,8 @@ def _decode_general_subtrees(backend, stack_subtrees):
return subtrees
-def _decode_extended_key_usage(backend, ext):
- sk = backend._ffi.cast(
- "Cryptography_STACK_OF_ASN1_OBJECT *",
- backend._lib.X509V3_EXT_d2i(ext)
- )
- assert sk != backend._ffi.NULL
+def _decode_extended_key_usage(backend, sk):
+ sk = backend._ffi.cast("Cryptography_STACK_OF_ASN1_OBJECT *", sk)
sk = backend._ffi.gc(sk, backend._lib.sk_ASN1_OBJECT_free)
num = backend._lib.sk_ASN1_OBJECT_num(sk)
ekus = []
@@ -621,14 +592,9 @@ def _decode_extended_key_usage(backend, ext):
return x509.ExtendedKeyUsage(ekus)
-def _decode_crl_distribution_points(backend, ext):
- cdps = backend._ffi.cast(
- "Cryptography_STACK_OF_DIST_POINT *",
- backend._lib.X509V3_EXT_d2i(ext)
- )
- assert cdps != backend._ffi.NULL
- cdps = backend._ffi.gc(
- cdps, backend._lib.sk_DIST_POINT_free)
+def _decode_crl_distribution_points(backend, cdps):
+ cdps = backend._ffi.cast("Cryptography_STACK_OF_DIST_POINT *", cdps)
+ cdps = backend._ffi.gc(cdps, backend._lib.sk_DIST_POINT_free)
num = backend._lib.sk_DIST_POINT_num(cdps)
dist_points = []
@@ -716,12 +682,8 @@ def _decode_crl_distribution_points(backend, ext):
return x509.CRLDistributionPoints(dist_points)
-def _decode_inhibit_any_policy(backend, ext):
- asn1_int = backend._ffi.cast(
- "ASN1_INTEGER *",
- backend._lib.X509V3_EXT_d2i(ext)
- )
- assert asn1_int != backend._ffi.NULL
+def _decode_inhibit_any_policy(backend, asn1_int):
+ asn1_int = backend._ffi.cast("ASN1_INTEGER *", asn1_int)
asn1_int = backend._ffi.gc(asn1_int, backend._lib.ASN1_INTEGER_free)
skip_certs = _asn1_integer_to_int(backend, asn1_int)
return x509.InhibitAnyPolicy(skip_certs)
@@ -789,33 +751,33 @@ class _CertificateSigningRequest(object):
return self._backend._read_mem_bio(bio)
+_EXTENSION_HANDLERS = {
+ x509.OID_BASIC_CONSTRAINTS: _decode_basic_constraints,
+ x509.OID_SUBJECT_KEY_IDENTIFIER: _decode_subject_key_identifier,
+ x509.OID_KEY_USAGE: _decode_key_usage,
+ x509.OID_SUBJECT_ALTERNATIVE_NAME: _decode_subject_alt_name,
+ x509.OID_EXTENDED_KEY_USAGE: _decode_extended_key_usage,
+ x509.OID_AUTHORITY_KEY_IDENTIFIER: _decode_authority_key_identifier,
+ x509.OID_AUTHORITY_INFORMATION_ACCESS: (
+ _decode_authority_information_access
+ ),
+ x509.OID_CERTIFICATE_POLICIES: _decode_certificate_policies,
+ x509.OID_CRL_DISTRIBUTION_POINTS: _decode_crl_distribution_points,
+ x509.OID_OCSP_NO_CHECK: _decode_ocsp_no_check,
+ x509.OID_INHIBIT_ANY_POLICY: _decode_inhibit_any_policy,
+ x509.OID_ISSUER_ALTERNATIVE_NAME: _decode_issuer_alt_name,
+ x509.OID_NAME_CONSTRAINTS: _decode_name_constraints,
+}
+
+
_CERTIFICATE_EXTENSION_PARSER = _X509ExtensionParser(
ext_count=lambda backend, x: backend._lib.X509_get_ext_count(x),
get_ext=lambda backend, x, i: backend._lib.X509_get_ext(x, i),
- handlers={
- x509.OID_BASIC_CONSTRAINTS: _decode_basic_constraints,
- x509.OID_SUBJECT_KEY_IDENTIFIER: _decode_subject_key_identifier,
- x509.OID_KEY_USAGE: _decode_key_usage,
- x509.OID_SUBJECT_ALTERNATIVE_NAME: _decode_subject_alt_name,
- x509.OID_EXTENDED_KEY_USAGE: _decode_extended_key_usage,
- x509.OID_AUTHORITY_KEY_IDENTIFIER: _decode_authority_key_identifier,
- x509.OID_AUTHORITY_INFORMATION_ACCESS: (
- _decode_authority_information_access
- ),
- x509.OID_CERTIFICATE_POLICIES: _decode_certificate_policies,
- x509.OID_CRL_DISTRIBUTION_POINTS: _decode_crl_distribution_points,
- x509.OID_OCSP_NO_CHECK: _decode_ocsp_no_check,
- x509.OID_INHIBIT_ANY_POLICY: _decode_inhibit_any_policy,
- x509.OID_ISSUER_ALTERNATIVE_NAME: _decode_issuer_alt_name,
- x509.OID_NAME_CONSTRAINTS: _decode_name_constraints,
- }
+ handlers=_EXTENSION_HANDLERS
)
_CSR_EXTENSION_PARSER = _X509ExtensionParser(
ext_count=lambda backend, x: backend._lib.sk_X509_EXTENSION_num(x),
get_ext=lambda backend, x, i: backend._lib.sk_X509_EXTENSION_value(x, i),
- handlers={
- x509.OID_BASIC_CONSTRAINTS: _decode_basic_constraints,
- x509.OID_SUBJECT_ALTERNATIVE_NAME: _decode_subject_alt_name,
- }
+ handlers=_EXTENSION_HANDLERS
)
diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py
index 9f6cda13..a831506e 100644
--- a/src/cryptography/x509.py
+++ b/src/cryptography/x509.py
@@ -1575,12 +1575,16 @@ class CertificateSigningRequestBuilder(object):
"""
if isinstance(extension, BasicConstraints):
extension = Extension(OID_BASIC_CONSTRAINTS, critical, extension)
+ elif isinstance(extension, ExtendedKeyUsage):
+ extension = Extension(OID_EXTENDED_KEY_USAGE, critical, extension)
elif isinstance(extension, SubjectAlternativeName):
extension = Extension(
OID_SUBJECT_ALTERNATIVE_NAME, critical, extension
)
elif isinstance(extension, KeyUsage):
extension = Extension(OID_KEY_USAGE, critical, extension)
+ elif isinstance(extension, InhibitAnyPolicy):
+ extension = Extension(OID_INHIBIT_ANY_POLICY, critical, extension)
else:
raise NotImplementedError('Unsupported X.509 extension.')
# TODO: This is quadratic in the number of extensions
diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py
index 5b611cd0..c2a4f544 100644
--- a/tests/hazmat/backends/test_openssl.py
+++ b/tests/hazmat/backends/test_openssl.py
@@ -36,6 +36,20 @@ from ..primitives.test_ec import _skip_curve_unsupported
from ...utils import load_vectors_from_file, raises_unsupported_algorithm
+def skip_if_libre_ssl(openssl_version):
+ if u'LibreSSL' in openssl_version:
+ pytest.skip("LibreSSL hard-codes RAND_bytes to use arc4random.")
+
+
+class TestLibreSkip(object):
+ def test_skip_no(self):
+ assert skip_if_libre_ssl(u"OpenSSL 0.9.8zf 19 Mar 2015") is None
+
+ def test_skip_yes(self):
+ with pytest.raises(pytest.skip.Exception):
+ skip_if_libre_ssl(u"LibreSSL 2.1.6")
+
+
@utils.register_interface(Mode)
class DummyMode(object):
name = "dummy-mode"
@@ -218,6 +232,19 @@ class TestOpenSSL(object):
bn = backend._int_to_bn(0)
assert backend._bn_to_int(bn) == 0
+ def test_actual_osrandom_bytes(self, monkeypatch):
+ skip_if_libre_ssl(backend.openssl_version_text())
+ sample_data = (b"\x01\x02\x03\x04" * 4)
+ length = len(sample_data)
+
+ def notrandom(size):
+ assert size == length
+ return sample_data
+ monkeypatch.setattr(os, "urandom", notrandom)
+ buf = backend._ffi.new("char[]", length)
+ backend._lib.RAND_bytes(buf, length)
+ assert backend._ffi.buffer(buf)[0:length] == sample_data
+
class TestOpenSSLRandomEngine(object):
def teardown_method(self, method):
diff --git a/tests/hazmat/bindings/test_openssl.py b/tests/hazmat/bindings/test_openssl.py
index f3f2eaf4..75a8e3f1 100644
--- a/tests/hazmat/bindings/test_openssl.py
+++ b/tests/hazmat/bindings/test_openssl.py
@@ -4,27 +4,11 @@
from __future__ import absolute_import, division, print_function
-import os
-
import pytest
from cryptography.hazmat.bindings.openssl.binding import Binding
-def skip_if_libre_ssl(openssl_version):
- if b'LibreSSL' in openssl_version:
- pytest.skip("LibreSSL hard-codes RAND_bytes to use arc4random.")
-
-
-class TestLibreSkip(object):
- def test_skip_no(self):
- assert skip_if_libre_ssl(b"OpenSSL 0.9.8zf 19 Mar 2015") is None
-
- def test_skip_yes(self):
- with pytest.raises(pytest.skip.Exception):
- skip_if_libre_ssl(b"LibreSSL 2.1.6")
-
-
class TestOpenSSL(object):
def test_binding_loads(self):
binding = Binding()
@@ -108,20 +92,6 @@ class TestOpenSSL(object):
with pytest.raises(RuntimeError):
b._register_osrandom_engine()
- def test_actual_osrandom_bytes(self, monkeypatch):
- b = Binding()
- skip_if_libre_ssl(b.ffi.string(b.lib.OPENSSL_VERSION_TEXT))
- sample_data = (b"\x01\x02\x03\x04" * 4)
- length = len(sample_data)
-
- def notrandom(size):
- assert size == length
- return sample_data
- monkeypatch.setattr(os, "urandom", notrandom)
- buf = b.ffi.new("char[]", length)
- b.lib.RAND_bytes(buf, length)
- assert b.ffi.buffer(buf)[0:length] == sample_data
-
def test_ssl_ctx_options(self):
# Test that we're properly handling 32-bit unsigned on all platforms.
b = Binding()
diff --git a/tests/test_utils.py b/tests/test_utils.py
index f71264ea..210e9292 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -3045,8 +3045,13 @@ d518475576730ed528779366568e46b7dd4ed787cb72d0733c93
assert expected == load_kasvs_dh_vectors(vector_data)
+def test_load_kasvs_ecdh_vectors_empty_vector_data():
+ assert [] == load_kasvs_ecdh_vectors([])
+
+
def test_load_kasvs_ecdh_vectors():
vector_data = textwrap.dedent("""
+ # CAVS 11.0
# Parameter set(s) supported: EA EB EC ED EE
# CAVSid: CAVSid (in hex: 434156536964)
# IUTid: In hex: a1b2c3d4e5
diff --git a/tests/test_x509.py b/tests/test_x509.py
index fb583965..ac20f649 100644
--- a/tests/test_x509.py
+++ b/tests/test_x509.py
@@ -1306,6 +1306,20 @@ class TestCertificateSigningRequestBuilder(object):
x509.SubjectAlternativeName([x509.DNSName(u"cryptography.io")]),
critical=False,
).add_extension(
+ x509.InhibitAnyPolicy(0),
+ critical=False
+ )
+ with pytest.raises(NotImplementedError):
+ builder.sign(private_key, hashes.SHA256(), backend)
+
+ def test_key_usage(self, backend):
+ private_key = RSA_KEY_2048.private_key(backend)
+ builder = x509.CertificateSigningRequestBuilder()
+ request = builder.subject_name(
+ x509.Name([
+ x509.NameAttribute(x509.OID_COUNTRY_NAME, u'US'),
+ ])
+ ).add_extension(
x509.KeyUsage(
digital_signature=True,
content_commitment=True,
@@ -1318,9 +1332,82 @@ class TestCertificateSigningRequestBuilder(object):
decipher_only=False
),
critical=False
+ ).sign(private_key, hashes.SHA256(), backend)
+ assert len(request.extensions) == 1
+ ext = request.extensions.get_extension_for_oid(x509.OID_KEY_USAGE)
+ assert ext.critical is False
+ assert ext.value == 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
+ )
+
+ def test_key_usage_key_agreement_bit(self, backend):
+ private_key = RSA_KEY_2048.private_key(backend)
+ builder = x509.CertificateSigningRequestBuilder()
+ request = builder.subject_name(
+ x509.Name([
+ x509.NameAttribute(x509.OID_COUNTRY_NAME, u'US'),
+ ])
+ ).add_extension(
+ x509.KeyUsage(
+ digital_signature=False,
+ content_commitment=False,
+ key_encipherment=False,
+ data_encipherment=False,
+ key_agreement=True,
+ key_cert_sign=True,
+ crl_sign=False,
+ encipher_only=False,
+ decipher_only=True
+ ),
+ critical=False
+ ).sign(private_key, hashes.SHA256(), backend)
+ assert len(request.extensions) == 1
+ ext = request.extensions.get_extension_for_oid(x509.OID_KEY_USAGE)
+ assert ext.critical is False
+ assert ext.value == x509.KeyUsage(
+ digital_signature=False,
+ content_commitment=False,
+ key_encipherment=False,
+ data_encipherment=False,
+ key_agreement=True,
+ key_cert_sign=True,
+ crl_sign=False,
+ encipher_only=False,
+ decipher_only=True
+ )
+
+ def test_add_two_extensions(self, backend):
+ private_key = RSA_KEY_2048.private_key(backend)
+ builder = x509.CertificateSigningRequestBuilder()
+ request = builder.subject_name(
+ x509.Name([x509.NameAttribute(x509.OID_COUNTRY_NAME, u'US')])
+ ).add_extension(
+ x509.SubjectAlternativeName([x509.DNSName(u"cryptography.io")]),
+ critical=False,
+ ).add_extension(
+ x509.BasicConstraints(ca=True, path_length=2), critical=True
+ ).sign(private_key, hashes.SHA1(), backend)
+
+ assert isinstance(request.signature_hash_algorithm, hashes.SHA1)
+ public_key = request.public_key()
+ assert isinstance(public_key, rsa.RSAPublicKey)
+ basic_constraints = request.extensions.get_extension_for_oid(
+ x509.OID_BASIC_CONSTRAINTS
)
- with pytest.raises(NotImplementedError):
- builder.sign(private_key, hashes.SHA256(), backend)
+ assert basic_constraints.value.ca is True
+ assert basic_constraints.value.path_length == 2
+ ext = request.extensions.get_extension_for_oid(
+ x509.OID_SUBJECT_ALTERNATIVE_NAME
+ )
+ assert list(ext.value) == [x509.DNSName(u"cryptography.io")]
def test_set_subject_twice(self):
builder = x509.CertificateSigningRequestBuilder()
@@ -1440,6 +1527,42 @@ class TestCertificateSigningRequestBuilder(object):
with pytest.raises(ValueError):
builder.sign(private_key, hashes.SHA256(), backend)
+ def test_extended_key_usage(self, backend):
+ private_key = RSA_KEY_2048.private_key(backend)
+ builder = x509.CertificateSigningRequestBuilder()
+ request = builder.subject_name(
+ x509.Name([x509.NameAttribute(x509.OID_COUNTRY_NAME, u'US')])
+ ).add_extension(
+ x509.ExtendedKeyUsage([
+ x509.OID_CLIENT_AUTH,
+ x509.OID_SERVER_AUTH,
+ x509.OID_CODE_SIGNING,
+ ]), critical=False
+ ).sign(private_key, hashes.SHA256(), backend)
+
+ eku = request.extensions.get_extension_for_oid(
+ x509.OID_EXTENDED_KEY_USAGE
+ )
+ assert eku.critical is False
+ assert eku.value == x509.ExtendedKeyUsage([
+ x509.OID_CLIENT_AUTH,
+ x509.OID_SERVER_AUTH,
+ x509.OID_CODE_SIGNING,
+ ])
+
+ @pytest.mark.requires_backend_interface(interface=RSABackend)
+ def test_rsa_key_too_small(self, backend):
+ private_key = rsa.generate_private_key(65537, 512, backend)
+ builder = x509.CertificateSigningRequestBuilder()
+ builder = builder.subject_name(
+ x509.Name([x509.NameAttribute(x509.OID_COUNTRY_NAME, u'US')])
+ )
+
+ with pytest.raises(ValueError) as exc:
+ builder.sign(private_key, hashes.SHA512(), backend)
+
+ assert str(exc.value) == "Digest too big for RSA key"
+
@pytest.mark.requires_backend_interface(interface=DSABackend)
@pytest.mark.requires_backend_interface(interface=X509Backend)
diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py
index 7b135828..890709ae 100644
--- a/tests/test_x509_ext.py
+++ b/tests/test_x509_ext.py
@@ -2853,3 +2853,18 @@ class TestInhibitAnyPolicyExtension(object):
x509.OID_INHIBIT_ANY_POLICY
).value
assert iap.skip_certs == 5
+
+
+@pytest.mark.requires_backend_interface(interface=RSABackend)
+@pytest.mark.requires_backend_interface(interface=X509Backend)
+class TestInvalidExtension(object):
+ def test_invalid_certificate_policies_data(self, backend):
+ cert = _load_cert(
+ os.path.join(
+ "x509", "custom", "cp_invalid.pem"
+ ),
+ x509.load_pem_x509_certificate,
+ backend
+ )
+ with pytest.raises(ValueError):
+ cert.extensions
diff --git a/tests/utils.py b/tests/utils.py
index 5083d48c..7e7abdf1 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -539,8 +539,8 @@ def load_fips_ecdsa_key_pair_vectors(vector_data):
elif line.startswith("Qy = "):
key_data["y"] = int(line.split("=")[1], 16)
- if key_data is not None:
- vectors.append(key_data)
+ assert key_data is not None
+ vectors.append(key_data)
return vectors
@@ -559,9 +559,6 @@ def load_fips_ecdsa_signing_vectors(vector_data):
for line in vector_data:
line = line.strip()
- if not line or line.startswith("#"):
- continue
-
curve_match = curve_rx.match(line)
if curve_match:
curve_name = _ECDSA_CURVE_NAMES[curve_match.group("curve")]
@@ -593,8 +590,8 @@ def load_fips_ecdsa_signing_vectors(vector_data):
elif line.startswith("Result = "):
data["fail"] = line.split("=")[1].strip()[0] == "F"
- if data is not None:
- vectors.append(data)
+ assert data is not None
+ vectors.append(data)
return vectors
diff --git a/vectors/cryptography_vectors/x509/custom/cp_invalid.pem b/vectors/cryptography_vectors/x509/custom/cp_invalid.pem
new file mode 100644
index 00000000..b7bcc079
--- /dev/null
+++ b/vectors/cryptography_vectors/x509/custom/cp_invalid.pem
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE-----
+MIIC8TCCAdmgAwIBAgITBmsoYWX1PCELRmm8qB2WJ2QdDjANBgkqhkiG9w0BAQUFADASMRAwDgYD
+VQQDDAdQeUNBIENBMB4XDTE1MDUxMTE4NTc0NVoXDTE2MDUxMDE4NTc0NVowEjEQMA4GA1UEAwwH
+UHlDQSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK3FTRITEY4b/Y1Uv4CtH61Y
+19TPxK2+H/XuqHwtYlPRyD35LLFES0wykf0V2m1DUmf9jQa9R63jBZxzCgJ/oIJzV28PgSg9P/Nn
+417fNASDduY2GPvYuwwKXcLY2fBBFjBrz7z/5tyXCADjLDkzoUTzQlYPbhOrFU5QwaqlckXBgt/4
+8GRDujoHy4RSMEDNjLUDgwx7Z/JK2ujbGJDguLRuBsHirk2h6xXEmSWxquKDXw4NnakwBqp8kKhQ
+2xTSWXxabNps8FCBM4sC78gKgONy3lbYdHFt/2BU4yAMyowJwtDEYHCqe1g4sVsB839Ol0SXb6vl
+eXQ6dx+zbi8UzTsCAwEAAaNAMD4wPAYDVR0gBDUwMzAxBgtghkgB4DkBAgMEATAiMCAGCCsGAQUF
+BwICFhRodHRwOi8vb3RoZXIuY29tL2NwczANBgkqhkiG9w0BAQUFAAOCAQEADpZIjHvu02euPNI8
+nzzDufRXEnjrF09xc9pudxTjWU2mSVApXPmTDyWzOD+2HmsNKHRE6sWjca5qPDeDbGq4JOw+TzYq
+9eoqwK2Sh0QHUpg5ZaAmIJ1qe5/sNETH5RFlXrlzW9S0rwViLgUaJp6MreTdGZbxdpNsfdkuNd+S
+Tz0MA/3ScbdUcj6uwQQ4JxQiTuPwD35pKwxfUzHjeTmqIEHDuCk17KqIRORdbeD3vFx0R5IQ3mQ6
+9zSGY2AGB0A9oS0qQ2/Mh59A6xyjbPH3Rr7g5MW58PPTWp2FSXkloy7Ze+doQ7wXE6PVmaeKz5qA
+9OGaCHIiC2iG9UcqWxfeWw==
+-----END CERTIFICATE-----