aboutsummaryrefslogtreecommitdiffstats
path: root/src/cryptography
diff options
context:
space:
mode:
Diffstat (limited to 'src/cryptography')
-rw-r--r--src/cryptography/hazmat/backends/multibackend.py7
-rw-r--r--src/cryptography/hazmat/backends/openssl/backend.py81
-rw-r--r--src/cryptography/hazmat/backends/openssl/decode_asn1.py54
-rw-r--r--src/cryptography/hazmat/backends/openssl/encode_asn1.py139
-rw-r--r--src/cryptography/hazmat/backends/openssl/hashes.py13
-rw-r--r--src/cryptography/hazmat/backends/openssl/hmac.py13
-rw-r--r--src/cryptography/hazmat/backends/openssl/rsa.py4
-rw-r--r--src/cryptography/hazmat/backends/openssl/x509.py74
-rw-r--r--src/cryptography/hazmat/bindings/openssl/_conditional.py25
-rw-r--r--src/cryptography/hazmat/bindings/openssl/binding.py27
-rw-r--r--src/cryptography/hazmat/primitives/ciphers/base.py2
-rw-r--r--src/cryptography/hazmat/primitives/ciphers/modes.py21
-rw-r--r--src/cryptography/hazmat/primitives/serialization.py14
-rw-r--r--src/cryptography/x509/base.py6
-rw-r--r--src/cryptography/x509/extensions.py8
-rw-r--r--src/cryptography/x509/name.py7
16 files changed, 332 insertions, 163 deletions
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 42d6c858..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
@@ -320,10 +322,9 @@ def _decode_basic_constraints(backend, bc_st):
# chooses to just map this to its ordinal value, so true is 255 and
# false is 0.
ca = basic_constraints.ca == 255
- if basic_constraints.pathlen == backend._ffi.NULL:
- path_length = None
- else:
- path_length = _asn1_integer_to_int(backend, basic_constraints.pathlen)
+ path_length = _asn1_integer_to_int_or_none(
+ backend, basic_constraints.pathlen
+ )
return x509.BasicConstraints(ca, path_length)
@@ -343,7 +344,6 @@ def _decode_authority_key_identifier(backend, akid):
akid = backend._ffi.gc(akid, backend._lib.AUTHORITY_KEYID_free)
key_identifier = None
authority_cert_issuer = None
- authority_cert_serial_number = None
if akid.keyid != backend._ffi.NULL:
key_identifier = backend._ffi.buffer(
@@ -355,10 +355,9 @@ def _decode_authority_key_identifier(backend, akid):
backend, akid.issuer
)
- if akid.serial != backend._ffi.NULL:
- authority_cert_serial_number = _asn1_integer_to_int(
- backend, akid.serial
- )
+ authority_cert_serial_number = _asn1_integer_to_int_or_none(
+ backend, akid.serial
+ )
return x509.AuthorityKeyIdentifier(
key_identifier, authority_cert_issuer, authority_cert_serial_number
@@ -452,6 +451,22 @@ def _decode_general_subtrees(backend, stack_subtrees):
return subtrees
+def _decode_policy_constraints(backend, pc):
+ pc = backend._ffi.cast("POLICY_CONSTRAINTS *", pc)
+ pc = backend._ffi.gc(pc, backend._lib.POLICY_CONSTRAINTS_free)
+
+ require_explicit_policy = _asn1_integer_to_int_or_none(
+ backend, pc.requireExplicitPolicy
+ )
+ inhibit_policy_mapping = _asn1_integer_to_int_or_none(
+ backend, pc.inhibitPolicyMapping
+ )
+
+ return x509.PolicyConstraints(
+ require_explicit_policy, inhibit_policy_mapping
+ )
+
+
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)
@@ -639,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
@@ -675,6 +691,13 @@ def _asn1_integer_to_int(backend, asn1_int):
return backend._bn_to_int(bn)
+def _asn1_integer_to_int_or_none(backend, asn1_int):
+ if asn1_int == backend._ffi.NULL:
+ return None
+ else:
+ return _asn1_integer_to_int(backend, asn1_int)
+
+
def _asn1_string_to_bytes(backend, asn1_string):
return backend._ffi.buffer(asn1_string.data, asn1_string.length)[:]
@@ -686,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])
@@ -729,6 +756,7 @@ _EXTENSION_HANDLERS = {
ExtensionOID.INHIBIT_ANY_POLICY: _decode_inhibit_any_policy,
ExtensionOID.ISSUER_ALTERNATIVE_NAME: _decode_issuer_alt_name,
ExtensionOID.NAME_CONSTRAINTS: _decode_name_constraints,
+ ExtensionOID.POLICY_CONSTRAINTS: _decode_policy_constraints,
}
_REVOKED_EXTENSION_HANDLERS = {
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/rsa.py b/src/cryptography/hazmat/backends/openssl/rsa.py
index a48b167d..ba9c5ab6 100644
--- a/src/cryptography/hazmat/backends/openssl/rsa.py
+++ b/src/cryptography/hazmat/backends/openssl/rsa.py
@@ -139,6 +139,10 @@ def _handle_rsa_enc_dec_error(backend, key):
backend._lib.RSA_R_BLOCK_TYPE_IS_NOT_01,
backend._lib.RSA_R_BLOCK_TYPE_IS_NOT_02,
backend._lib.RSA_R_OAEP_DECODING_ERROR,
+ # Though this error looks similar to the
+ # RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE, this occurs on decrypts,
+ # rather then on encrypts
+ backend._lib.RSA_R_DATA_TOO_LARGE_FOR_MODULUS,
]
if backend._lib.Cryptography_HAS_RSA_R_PKCS_DECODING_ERROR:
decoding_errors.append(backend._lib.RSA_R_PKCS_DECODING_ERROR)
diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py
index a6f7d69e..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,4 +389,22 @@ 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):
+ pkey = self._backend._lib.X509_REQ_get_pubkey(self._x509_req)
+ self._backend.openssl_assert(pkey != self._backend._ffi.NULL)
+ pkey = self._backend._ffi.gc(pkey, self._backend._lib.EVP_PKEY_free)
+ res = self._backend._lib.X509_REQ_verify(self._x509_req, pkey)
+
+ if res != 1:
+ self._backend._consume_errors()
+ return False
+
+ return True
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/hazmat/primitives/ciphers/base.py b/src/cryptography/hazmat/primitives/ciphers/base.py
index dae93655..496975ae 100644
--- a/src/cryptography/hazmat/primitives/ciphers/base.py
+++ b/src/cryptography/hazmat/primitives/ciphers/base.py
@@ -185,7 +185,7 @@ class _AEADCipherContext(object):
self._aad_bytes_processed += len(data)
if self._aad_bytes_processed > self._ctx._mode._MAX_AAD_BYTES:
raise ValueError(
- "{0} has a maximum AAD byte limit of {0}".format(
+ "{0} has a maximum AAD byte limit of {1}".format(
self._ctx._mode.name, self._ctx._mode._MAX_AAD_BYTES
)
)
diff --git a/src/cryptography/hazmat/primitives/ciphers/modes.py b/src/cryptography/hazmat/primitives/ciphers/modes.py
index 4284042d..802e544a 100644
--- a/src/cryptography/hazmat/primitives/ciphers/modes.py
+++ b/src/cryptography/hazmat/primitives/ciphers/modes.py
@@ -67,6 +67,9 @@ class CBC(object):
name = "CBC"
def __init__(self, initialization_vector):
+ if not isinstance(initialization_vector, bytes):
+ raise TypeError("initialization_vector must be bytes")
+
self._initialization_vector = initialization_vector
initialization_vector = utils.read_only_property("_initialization_vector")
@@ -87,6 +90,9 @@ class OFB(object):
name = "OFB"
def __init__(self, initialization_vector):
+ if not isinstance(initialization_vector, bytes):
+ raise TypeError("initialization_vector must be bytes")
+
self._initialization_vector = initialization_vector
initialization_vector = utils.read_only_property("_initialization_vector")
@@ -99,6 +105,9 @@ class CFB(object):
name = "CFB"
def __init__(self, initialization_vector):
+ if not isinstance(initialization_vector, bytes):
+ raise TypeError("initialization_vector must be bytes")
+
self._initialization_vector = initialization_vector
initialization_vector = utils.read_only_property("_initialization_vector")
@@ -111,6 +120,9 @@ class CFB8(object):
name = "CFB8"
def __init__(self, initialization_vector):
+ if not isinstance(initialization_vector, bytes):
+ raise TypeError("initialization_vector must be bytes")
+
self._initialization_vector = initialization_vector
initialization_vector = utils.read_only_property("_initialization_vector")
@@ -123,6 +135,9 @@ class CTR(object):
name = "CTR"
def __init__(self, nonce):
+ if not isinstance(nonce, bytes):
+ raise TypeError("nonce must be bytes")
+
self._nonce = nonce
nonce = utils.read_only_property("_nonce")
@@ -154,6 +169,12 @@ class GCM(object):
min_tag_length)
)
+ if not isinstance(initialization_vector, bytes):
+ raise TypeError("initialization_vector must be bytes")
+
+ if tag is not None and not isinstance(tag, bytes):
+ raise TypeError("tag must be bytes or None")
+
self._initialization_vector = initialization_vector
self._tag = tag
diff --git a/src/cryptography/hazmat/primitives/serialization.py b/src/cryptography/hazmat/primitives/serialization.py
index fc50456e..5c166c89 100644
--- a/src/cryptography/hazmat/primitives/serialization.py
+++ b/src/cryptography/hazmat/primitives/serialization.py
@@ -117,18 +117,8 @@ def _load_ssh_ecdsa_public_key(expected_key_type, decoded_data, backend):
"Compressed elliptic curve points are not supported"
)
- # key_size is in bits, and sometimes it's not evenly divisible by 8, so we
- # add 7 to round up the number of bytes.
- if len(data) != 1 + 2 * ((curve.key_size + 7) // 8):
- raise ValueError("Malformed key bytes")
-
- x = utils.int_from_bytes(
- data[1:1 + (curve.key_size + 7) // 8], byteorder='big'
- )
- y = utils.int_from_bytes(
- data[1 + (curve.key_size + 7) // 8:], byteorder='big'
- )
- return ec.EllipticCurvePublicNumbers(x, y, curve).public_key(backend)
+ numbers = ec.EllipticCurvePublicNumbers.from_encoded_point(curve, data)
+ return numbers.public_key(backend)
def _read_next_string(data):
diff --git a/src/cryptography/x509/base.py b/src/cryptography/x509/base.py
index 55e965f7..4a22ed02 100644
--- a/src/cryptography/x509/base.py
+++ b/src/cryptography/x509/base.py
@@ -288,6 +288,12 @@ class CertificateSigningRequest(object):
2986.
"""
+ @abc.abstractproperty
+ def is_signature_valid(self):
+ """
+ Verifies signature of signing request.
+ """
+
@six.add_metaclass(abc.ABCMeta)
class RevokedCertificate(object):
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/src/cryptography/x509/name.py b/src/cryptography/x509/name.py
index 9d93ece1..d62341d7 100644
--- a/src/cryptography/x509/name.py
+++ b/src/cryptography/x509/name.py
@@ -7,7 +7,7 @@ from __future__ import absolute_import, division, print_function
import six
from cryptography import utils
-from cryptography.x509.oid import ObjectIdentifier
+from cryptography.x509.oid import NameOID, ObjectIdentifier
class NameAttribute(object):
@@ -22,6 +22,11 @@ class NameAttribute(object):
"value argument must be a text type."
)
+ if oid == NameOID.COUNTRY_NAME and len(value.encode("utf8")) != 2:
+ raise ValueError(
+ "Country name must be a 2 character country code"
+ )
+
self._oid = oid
self._value = value