aboutsummaryrefslogtreecommitdiffstats
path: root/src/cryptography
diff options
context:
space:
mode:
Diffstat (limited to 'src/cryptography')
-rw-r--r--src/cryptography/hazmat/backends/openssl/backend.py19
-rw-r--r--src/cryptography/hazmat/backends/openssl/x509.py40
-rw-r--r--src/cryptography/hazmat/bindings/openssl/binding.py49
-rw-r--r--src/cryptography/hazmat/primitives/ciphers/base.py19
-rw-r--r--src/cryptography/hazmat/primitives/ciphers/modes.py2
5 files changed, 112 insertions, 17 deletions
diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py
index 51f68899..f05b0515 100644
--- a/src/cryptography/hazmat/backends/openssl/backend.py
+++ b/src/cryptography/hazmat/backends/openssl/backend.py
@@ -217,7 +217,7 @@ class Backend(object):
self.activate_builtin_random()
# Fetches an engine by id and returns it. This creates a structural
# reference.
- e = self._lib.ENGINE_by_id(self._lib.Cryptography_osrandom_engine_id)
+ e = self._lib.ENGINE_by_id(self._binding._osrandom_engine_id)
assert e != self._ffi.NULL
# Initialize the engine for use. This adds a functional reference.
res = self._lib.ENGINE_init(e)
@@ -872,25 +872,20 @@ class Backend(object):
)
for extension in builder._extensions:
if isinstance(extension.value, x509.BasicConstraints):
- pp, r = _encode_basic_constraints(
- self, extension.value,
- )
+ pp, r = _encode_basic_constraints(self, extension.value)
elif isinstance(extension.value, x509.SubjectAlternativeName):
- pp, r = _encode_subject_alt_name(
- self, extension.value,
- )
+ pp, r = _encode_subject_alt_name(self, extension.value)
else:
raise NotImplementedError('Extension not yet supported.')
obj = _txt2obj(self, extension.oid.dotted_string)
- extension = backend._lib.X509_EXTENSION_create_by_OBJ(
- backend._ffi.NULL,
+ extension = self._lib.X509_EXTENSION_create_by_OBJ(
+ self._ffi.NULL,
obj,
1 if extension.critical else 0,
- _encode_asn1_str(backend, pp[0], r)
+ _encode_asn1_str(self, pp[0], r),
)
- assert extension != backend._ffi.NULL
-
+ assert extension != self._ffi.NULL
res = self._lib.sk_X509_EXTENSION_push(extensions, extension)
assert res == 1
res = self._lib.X509_REQ_add_extensions(x509_req, extensions)
diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py
index 804bce66..80e5f2b1 100644
--- a/src/cryptography/hazmat/backends/openssl/x509.py
+++ b/src/cryptography/hazmat/backends/openssl/x509.py
@@ -86,13 +86,17 @@ def _decode_general_name(backend, gn):
# This is a wildcard name. We need to remove the leading wildcard,
# IDNA decode, then re-add the wildcard. Wildcard characters should
# always be left-most (RFC 2595 section 2.4).
- data = u"*." + idna.decode(data[2:])
+ decoded = u"*." + idna.decode(data[2:])
else:
# Not a wildcard, decode away. If the string has a * in it anywhere
# invalid this will raise an InvalidCodePoint
- data = idna.decode(data)
+ decoded = idna.decode(data)
+ if data.startswith(b"."):
+ # idna strips leading periods. Name constraints can have that
+ # so we need to re-add it. Sigh.
+ decoded = u"." + decoded
- return x509.DNSName(data)
+ return x509.DNSName(decoded)
elif gn.type == backend._lib.GEN_URI:
data = backend._ffi.buffer(
gn.d.uniformResourceIdentifier.data,
@@ -537,6 +541,35 @@ 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
+ nc = backend._ffi.gc(nc, backend._lib.NAME_CONSTRAINTS_free)
+ permitted = _decode_general_subtrees(backend, nc.permittedSubtrees)
+ excluded = _decode_general_subtrees(backend, nc.excludedSubtrees)
+ return x509.NameConstraints(
+ permitted_subtrees=permitted, excluded_subtrees=excluded
+ )
+
+
+def _decode_general_subtrees(backend, stack_subtrees):
+ if stack_subtrees == backend._ffi.NULL:
+ return None
+
+ num = backend._lib.sk_GENERAL_SUBTREE_num(stack_subtrees)
+ subtrees = []
+
+ for i in range(num):
+ obj = backend._lib.sk_GENERAL_SUBTREE_value(stack_subtrees, i)
+ assert obj != backend._ffi.NULL
+ name = _decode_general_name(backend, obj.base)
+ subtrees.append(name)
+
+ return subtrees
+
+
def _decode_extended_key_usage(backend, ext):
sk = backend._ffi.cast(
"Cryptography_STACK_OF_ASN1_OBJECT *",
@@ -728,6 +761,7 @@ _CERTIFICATE_EXTENSION_PARSER = _X509ExtensionParser(
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,
}
)
diff --git a/src/cryptography/hazmat/bindings/openssl/binding.py b/src/cryptography/hazmat/bindings/openssl/binding.py
index e0a83972..b7178bb2 100644
--- a/src/cryptography/hazmat/bindings/openssl/binding.py
+++ b/src/cryptography/hazmat/bindings/openssl/binding.py
@@ -4,11 +4,25 @@
from __future__ import absolute_import, division, print_function
+import os
import threading
from cryptography.hazmat.bindings._openssl import ffi, lib
+@ffi.callback("int (*)(unsigned char *, int)", error=-1)
+def _osrandom_rand_bytes(buf, size):
+ signed = ffi.cast("char *", buf)
+ result = os.urandom(size)
+ signed[0:size] = result
+ return 1
+
+
+@ffi.callback("int (*)(void)")
+def _osrandom_rand_status():
+ return 1
+
+
class Binding(object):
"""
OpenSSL API wrapper.
@@ -21,10 +35,42 @@ class Binding(object):
_init_lock = threading.Lock()
_lock_init_lock = threading.Lock()
+ _osrandom_engine_id = ffi.new("const char[]", b"osrandom")
+ _osrandom_engine_name = ffi.new("const char[]", b"osrandom_engine")
+ _osrandom_method = ffi.new(
+ "RAND_METHOD *",
+ dict(bytes=_osrandom_rand_bytes, pseudorand=_osrandom_rand_bytes,
+ status=_osrandom_rand_status)
+ )
+
def __init__(self):
self._ensure_ffi_initialized()
@classmethod
+ def _register_osrandom_engine(cls):
+ assert cls.lib.ERR_peek_error() == 0
+ looked_up_engine = cls.lib.ENGINE_by_id(cls._osrandom_engine_id)
+ if looked_up_engine != ffi.NULL:
+ raise RuntimeError("osrandom engine already registered")
+
+ cls.lib.ERR_clear_error()
+
+ engine = cls.lib.ENGINE_new()
+ assert engine != cls.ffi.NULL
+ try:
+ result = cls.lib.ENGINE_set_id(engine, cls._osrandom_engine_id)
+ assert result == 1
+ result = cls.lib.ENGINE_set_name(engine, cls._osrandom_engine_name)
+ assert result == 1
+ result = cls.lib.ENGINE_set_RAND(engine, cls._osrandom_method)
+ assert result == 1
+ result = cls.lib.ENGINE_add(engine)
+ assert result == 1
+ finally:
+ result = cls.lib.ENGINE_free(engine)
+ assert result == 1
+
+ @classmethod
def _ensure_ffi_initialized(cls):
if cls._lib_loaded:
return
@@ -32,8 +78,7 @@ class Binding(object):
with cls._init_lock:
if not cls._lib_loaded:
cls._lib_loaded = True
- res = cls.lib.Cryptography_add_osrandom_engine()
- assert res != 0
+ cls._register_osrandom_engine()
@classmethod
def init_static_locks(cls):
diff --git a/src/cryptography/hazmat/primitives/ciphers/base.py b/src/cryptography/hazmat/primitives/ciphers/base.py
index 8f3028fc..dae93655 100644
--- a/src/cryptography/hazmat/primitives/ciphers/base.py
+++ b/src/cryptography/hazmat/primitives/ciphers/base.py
@@ -149,6 +149,8 @@ class _CipherContext(object):
class _AEADCipherContext(object):
def __init__(self, ctx):
self._ctx = ctx
+ self._bytes_processed = 0
+ self._aad_bytes_processed = 0
self._tag = None
self._updated = False
@@ -156,6 +158,14 @@ class _AEADCipherContext(object):
if self._ctx is None:
raise AlreadyFinalized("Context was already finalized.")
self._updated = True
+ self._bytes_processed += len(data)
+ if self._bytes_processed > self._ctx._mode._MAX_ENCRYPTED_BYTES:
+ raise ValueError(
+ "{0} has a maximum encrypted byte limit of {1}".format(
+ self._ctx._mode.name, self._ctx._mode._MAX_ENCRYPTED_BYTES
+ )
+ )
+
return self._ctx.update(data)
def finalize(self):
@@ -171,6 +181,15 @@ class _AEADCipherContext(object):
raise AlreadyFinalized("Context was already finalized.")
if self._updated:
raise AlreadyUpdated("Update has been called on this context.")
+
+ 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(
+ self._ctx._mode.name, self._ctx._mode._MAX_AAD_BYTES
+ )
+ )
+
self._ctx.authenticate_additional_data(data)
diff --git a/src/cryptography/hazmat/primitives/ciphers/modes.py b/src/cryptography/hazmat/primitives/ciphers/modes.py
index e31c9060..4284042d 100644
--- a/src/cryptography/hazmat/primitives/ciphers/modes.py
+++ b/src/cryptography/hazmat/primitives/ciphers/modes.py
@@ -139,6 +139,8 @@ class CTR(object):
@utils.register_interface(ModeWithAuthenticationTag)
class GCM(object):
name = "GCM"
+ _MAX_ENCRYPTED_BYTES = (2 ** 39 - 256) // 8
+ _MAX_AAD_BYTES = (2 ** 64) // 8
def __init__(self, initialization_vector, tag=None, min_tag_length=16):
# len(initialization_vector) must in [1, 2 ** 64), but it's impossible