aboutsummaryrefslogtreecommitdiffstats
path: root/cryptography/hazmat
diff options
context:
space:
mode:
Diffstat (limited to 'cryptography/hazmat')
-rw-r--r--cryptography/hazmat/backends/interfaces.py10
-rw-r--r--cryptography/hazmat/backends/multibackend.py20
-rw-r--r--cryptography/hazmat/backends/openssl/backend.py191
-rw-r--r--cryptography/hazmat/bindings/commoncrypto/binding.py6
-rw-r--r--cryptography/hazmat/bindings/openssl/bignum.py13
-rw-r--r--cryptography/hazmat/bindings/openssl/binding.py10
-rw-r--r--cryptography/hazmat/bindings/openssl/dsa.py13
-rw-r--r--cryptography/hazmat/bindings/openssl/ec.py2
-rw-r--r--cryptography/hazmat/bindings/openssl/err.py3
-rw-r--r--cryptography/hazmat/bindings/openssl/evp.py11
-rw-r--r--cryptography/hazmat/bindings/openssl/ssl.py28
-rw-r--r--cryptography/hazmat/bindings/openssl/x509.py54
-rw-r--r--cryptography/hazmat/bindings/utils.py5
-rw-r--r--cryptography/hazmat/primitives/asymmetric/padding.py13
-rw-r--r--cryptography/hazmat/primitives/asymmetric/rsa.py45
-rw-r--r--cryptography/hazmat/primitives/cmac.py75
16 files changed, 469 insertions, 30 deletions
diff --git a/cryptography/hazmat/backends/interfaces.py b/cryptography/hazmat/backends/interfaces.py
index 92413d8c..1ddf0785 100644
--- a/cryptography/hazmat/backends/interfaces.py
+++ b/cryptography/hazmat/backends/interfaces.py
@@ -117,6 +117,12 @@ class RSABackend(object):
Return True if the hash algorithm is supported for MGF1 in PSS.
"""
+ @abc.abstractmethod
+ def decrypt_rsa(self, private_key, ciphertext, padding):
+ """
+ Returns decrypted bytes.
+ """
+
@six.add_metaclass(abc.ABCMeta)
class DSABackend(object):
@@ -135,9 +141,9 @@ class DSABackend(object):
@six.add_metaclass(abc.ABCMeta)
-class OpenSSLSerializationBackend(object):
+class TraditionalOpenSSLSerializationBackend(object):
@abc.abstractmethod
- def load_openssl_pem_private_key(self, data, password):
+ def load_traditional_openssl_pem_private_key(self, data, password):
"""
Load a private key from PEM encoded data, using password if the data
is encrypted.
diff --git a/cryptography/hazmat/backends/multibackend.py b/cryptography/hazmat/backends/multibackend.py
index 86cded85..981a60bd 100644
--- a/cryptography/hazmat/backends/multibackend.py
+++ b/cryptography/hazmat/backends/multibackend.py
@@ -16,11 +16,12 @@ from __future__ import absolute_import, division, print_function
from cryptography import utils
from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
from cryptography.hazmat.backends.interfaces import (
- CipherBackend, DSABackend, HMACBackend, HashBackend, PBKDF2HMACBackend,
- RSABackend
+ CMACBackend, CipherBackend, DSABackend, HMACBackend, HashBackend,
+ PBKDF2HMACBackend, RSABackend
)
+@utils.register_interface(CMACBackend)
@utils.register_interface(CipherBackend)
@utils.register_interface(HashBackend)
@utils.register_interface(HMACBackend)
@@ -156,3 +157,18 @@ class MultiBackend(object):
return b.generate_dsa_private_key(parameters)
raise UnsupportedAlgorithm("DSA is not supported by the backend",
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
+
+ def cmac_algorithm_supported(self, algorithm):
+ return any(
+ b.cmac_algorithm_supported(algorithm)
+ for b in self._filtered_backends(CMACBackend)
+ )
+
+ def create_cmac_ctx(self, algorithm):
+ for b in self._filtered_backends(CMACBackend):
+ try:
+ return b.create_cmac_ctx(algorithm)
+ except UnsupportedAlgorithm:
+ pass
+ raise UnsupportedAlgorithm("This backend does not support CMAC",
+ _Reasons.UNSUPPORTED_CIPHER)
diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py
index 9ac062c2..2d7e2307 100644
--- a/cryptography/hazmat/backends/openssl/backend.py
+++ b/cryptography/hazmat/backends/openssl/backend.py
@@ -25,14 +25,14 @@ from cryptography.exceptions import (
UnsupportedAlgorithm, _Reasons
)
from cryptography.hazmat.backends.interfaces import (
- CipherBackend, DSABackend, HMACBackend, HashBackend, PBKDF2HMACBackend,
- RSABackend
+ CMACBackend, CipherBackend, DSABackend, HMACBackend, HashBackend,
+ PBKDF2HMACBackend, RSABackend
)
from cryptography.hazmat.bindings.openssl.binding import Binding
from cryptography.hazmat.primitives import hashes, interfaces
from cryptography.hazmat.primitives.asymmetric import dsa, rsa
from cryptography.hazmat.primitives.asymmetric.padding import (
- MGF1, PKCS1v15, PSS
+ MGF1, OAEP, PKCS1v15, PSS
)
from cryptography.hazmat.primitives.ciphers.algorithms import (
AES, ARC4, Blowfish, CAST5, Camellia, IDEA, SEED, TripleDES
@@ -47,6 +47,7 @@ _OpenSSLError = collections.namedtuple("_OpenSSLError",
@utils.register_interface(CipherBackend)
+@utils.register_interface(CMACBackend)
@utils.register_interface(DSABackend)
@utils.register_interface(HashBackend)
@utils.register_interface(HMACBackend)
@@ -293,7 +294,7 @@ class Backend(object):
self._lib.OPENSSL_free(hex_cdata)
return int(hex_str, 16)
- def _int_to_bn(self, num):
+ def _int_to_bn(self, num, bn=None):
"""
Converts a python integer to a BIGNUM. The returned BIGNUM will not
be garbage collected (to support adding them to structs that take
@@ -301,11 +302,14 @@ class Backend(object):
be discarded after use.
"""
+ if bn is None:
+ bn = self._ffi.NULL
+
if six.PY3:
# Python 3 has constant time to_bytes, so use that.
binary = num.to_bytes(int(num.bit_length() / 8.0 + 1), "big")
- bn_ptr = self._lib.BN_bin2bn(binary, len(binary), self._ffi.NULL)
+ bn_ptr = self._lib.BN_bin2bn(binary, len(binary), bn)
assert bn_ptr != self._ffi.NULL
return bn_ptr
@@ -314,6 +318,7 @@ class Backend(object):
hex_num = hex(num).rstrip("L").lstrip("0x").encode("ascii") or b"0"
bn_ptr = self._ffi.new("BIGNUM **")
+ bn_ptr[0] = bn
res = self._lib.BN_hex2bn(bn_ptr, hex_num)
assert res != 0
assert bn_ptr[0] != self._ffi.NULL
@@ -346,7 +351,7 @@ class Backend(object):
def _new_evp_pkey(self):
evp_pkey = self._lib.EVP_PKEY_new()
assert evp_pkey != self._ffi.NULL
- return self._ffi.gc(evp_pkey, backend._lib.EVP_PKEY_free)
+ return self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free)
def _rsa_private_key_to_evp_pkey(self, private_key):
evp_pkey = self._new_evp_pkey()
@@ -469,6 +474,120 @@ class Backend(object):
y=self._bn_to_int(ctx.pub_key)
)
+ def decrypt_rsa(self, private_key, ciphertext, padding):
+ if isinstance(padding, PKCS1v15):
+ padding_enum = self._lib.RSA_PKCS1_PADDING
+ elif isinstance(padding, OAEP):
+ padding_enum = self._lib.RSA_PKCS1_OAEP_PADDING
+ if not isinstance(padding._mgf, MGF1):
+ raise UnsupportedAlgorithm(
+ "Only MGF1 is supported by this backend",
+ _Reasons.UNSUPPORTED_MGF
+ )
+
+ if not isinstance(padding._mgf._algorithm, hashes.SHA1):
+ raise UnsupportedAlgorithm(
+ "This backend supports only SHA1 inside MGF1 when "
+ "using OAEP",
+ _Reasons.UNSUPPORTED_HASH
+ )
+
+ if padding._label is not None and padding._label != b"":
+ raise ValueError("This backend does not support OAEP labels")
+
+ if not isinstance(padding._algorithm, hashes.SHA1):
+ raise UnsupportedAlgorithm(
+ "This backend only supports SHA1 when using OAEP",
+ _Reasons.UNSUPPORTED_HASH
+ )
+ else:
+ raise UnsupportedAlgorithm(
+ "{0} is not supported by this backend".format(
+ padding.name
+ ),
+ _Reasons.UNSUPPORTED_PADDING
+ )
+
+ key_size_bytes = int(math.ceil(private_key.key_size / 8.0))
+ if key_size_bytes < len(ciphertext):
+ raise ValueError("Ciphertext too large for key size")
+
+ if self._lib.Cryptography_HAS_PKEY_CTX:
+ return self._decrypt_rsa_pkey_ctx(private_key, ciphertext,
+ padding_enum)
+ else:
+ return self._decrypt_rsa_098(private_key, ciphertext, padding_enum)
+
+ def _decrypt_rsa_pkey_ctx(self, private_key, ciphertext, padding_enum):
+ evp_pkey = self._rsa_private_key_to_evp_pkey(private_key)
+ pkey_ctx = self._lib.EVP_PKEY_CTX_new(
+ evp_pkey, self._ffi.NULL
+ )
+ assert pkey_ctx != self._ffi.NULL
+ pkey_ctx = self._ffi.gc(pkey_ctx, self._lib.EVP_PKEY_CTX_free)
+ res = self._lib.EVP_PKEY_decrypt_init(pkey_ctx)
+ assert res == 1
+ res = self._lib.EVP_PKEY_CTX_set_rsa_padding(
+ pkey_ctx, padding_enum)
+ assert res > 0
+ buf_size = self._lib.EVP_PKEY_size(evp_pkey)
+ assert buf_size > 0
+ outlen = self._ffi.new("size_t *", buf_size)
+ buf = self._ffi.new("char[]", buf_size)
+ res = self._lib.Cryptography_EVP_PKEY_decrypt(
+ pkey_ctx,
+ buf,
+ outlen,
+ ciphertext,
+ len(ciphertext)
+ )
+ if res <= 0:
+ errors = self._consume_errors()
+ assert errors
+ assert errors[0].lib == self._lib.ERR_LIB_RSA
+ assert (
+ errors[0].reason == self._lib.RSA_R_BLOCK_TYPE_IS_NOT_01 or
+ errors[0].reason == self._lib.RSA_R_BLOCK_TYPE_IS_NOT_02
+ )
+ raise ValueError("Decryption failed")
+
+ return self._ffi.buffer(buf)[:outlen[0]]
+
+ def _decrypt_rsa_098(self, private_key, ciphertext, padding_enum):
+ rsa_cdata = self._rsa_cdata_from_private_key(private_key)
+ rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free)
+ key_size = self._lib.RSA_size(rsa_cdata)
+ assert key_size > 0
+ buf = self._ffi.new("unsigned char[]", key_size)
+ res = self._lib.RSA_private_decrypt(
+ len(ciphertext),
+ ciphertext,
+ buf,
+ rsa_cdata,
+ padding_enum
+ )
+ if res < 0:
+ errors = self._consume_errors()
+ assert errors
+ assert errors[0].lib == self._lib.ERR_LIB_RSA
+ assert (
+ errors[0].reason == self._lib.RSA_R_BLOCK_TYPE_IS_NOT_01 or
+ errors[0].reason == self._lib.RSA_R_BLOCK_TYPE_IS_NOT_02
+ )
+ raise ValueError("Decryption failed")
+
+ return self._ffi.buffer(buf)[:res]
+
+ def cmac_algorithm_supported(self, algorithm):
+ return (
+ self._lib.Cryptography_HAS_CMAC == 1
+ and self.cipher_supported(algorithm, CBC(
+ b"\x00" * algorithm.block_size))
+ )
+
+ def create_cmac_ctx(self, algorithm):
+ return _CMACContext(self, algorithm)
+
class GetCipherByName(object):
def __init__(self, fmt):
@@ -1155,4 +1274,64 @@ class _RSAVerificationContext(object):
raise InvalidSignature
+@utils.register_interface(interfaces.CMACContext)
+class _CMACContext(object):
+ def __init__(self, backend, algorithm, ctx=None):
+ if not backend.cmac_algorithm_supported(algorithm):
+ raise UnsupportedAlgorithm("This backend does not support CMAC",
+ _Reasons.UNSUPPORTED_CIPHER)
+
+ self._backend = backend
+ self._key = algorithm.key
+ self._algorithm = algorithm
+ self._output_length = algorithm.block_size // 8
+
+ if ctx is None:
+ registry = self._backend._cipher_registry
+ adapter = registry[type(algorithm), CBC]
+
+ evp_cipher = adapter(self._backend, algorithm, CBC)
+
+ ctx = self._backend._lib.CMAC_CTX_new()
+
+ assert ctx != self._backend._ffi.NULL
+ ctx = self._backend._ffi.gc(ctx, self._backend._lib.CMAC_CTX_free)
+
+ self._backend._lib.CMAC_Init(
+ ctx, self._key, len(self._key),
+ evp_cipher, self._backend._ffi.NULL
+ )
+
+ self._ctx = ctx
+
+ def update(self, data):
+ res = self._backend._lib.CMAC_Update(self._ctx, data, len(data))
+ assert res == 1
+
+ def finalize(self):
+ buf = self._backend._ffi.new("unsigned char[]", self._output_length)
+ length = self._backend._ffi.new("size_t *", self._output_length)
+ res = self._backend._lib.CMAC_Final(
+ self._ctx, buf, length
+ )
+ assert res == 1
+
+ self._ctx = None
+
+ return self._backend._ffi.buffer(buf)[:]
+
+ def copy(self):
+ copied_ctx = self._backend._lib.CMAC_CTX_new()
+ copied_ctx = self._backend._ffi.gc(
+ copied_ctx, self._backend._lib.CMAC_CTX_free
+ )
+ res = self._backend._lib.CMAC_CTX_copy(
+ copied_ctx, self._ctx
+ )
+ assert res == 1
+ return _CMACContext(
+ self._backend, self._algorithm, ctx=copied_ctx
+ )
+
+
backend = Backend()
diff --git a/cryptography/hazmat/bindings/commoncrypto/binding.py b/cryptography/hazmat/bindings/commoncrypto/binding.py
index 3673ea36..144bb099 100644
--- a/cryptography/hazmat/bindings/commoncrypto/binding.py
+++ b/cryptography/hazmat/bindings/commoncrypto/binding.py
@@ -42,8 +42,10 @@ class Binding(object):
if cls.ffi is not None and cls.lib is not None:
return
- cls.ffi, cls.lib = build_ffi(cls._module_prefix, cls._modules,
- "", "", [])
+ cls.ffi, cls.lib = build_ffi(
+ module_prefix=cls._module_prefix,
+ modules=cls._modules,
+ )
@classmethod
def is_available(cls):
diff --git a/cryptography/hazmat/bindings/openssl/bignum.py b/cryptography/hazmat/bindings/openssl/bignum.py
index 94c2914e..1d944ee9 100644
--- a/cryptography/hazmat/bindings/openssl/bignum.py
+++ b/cryptography/hazmat/bindings/openssl/bignum.py
@@ -87,12 +87,25 @@ int BN_mod_exp(BIGNUM *, const BIGNUM *, const BIGNUM *, const BIGNUM *,
BN_CTX *);
int BN_gcd(BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
BIGNUM *BN_mod_inverse(BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
+
+int BN_set_bit(BIGNUM *, int);
+int BN_clear_bit(BIGNUM *, int);
+
+int BN_is_bit_set(const BIGNUM *, int);
+
+int BN_mask_bits(BIGNUM *, int);
"""
MACROS = """
int BN_zero(BIGNUM *);
int BN_one(BIGNUM *);
int BN_mod(BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
+
+int BN_lshift(BIGNUM *, const BIGNUM *, int);
+int BN_lshift1(BIGNUM *, BIGNUM *);
+
+int BN_rshift(BIGNUM *, BIGNUM *, int);
+int BN_rshift1(BIGNUM *, BIGNUM *);
"""
CUSTOMIZATIONS = """
diff --git a/cryptography/hazmat/bindings/openssl/binding.py b/cryptography/hazmat/bindings/openssl/binding.py
index cc40a108..f0ff3275 100644
--- a/cryptography/hazmat/bindings/openssl/binding.py
+++ b/cryptography/hazmat/bindings/openssl/binding.py
@@ -97,9 +97,13 @@ class Binding(object):
else: # pragma: no cover
libraries = ["libeay32", "ssleay32", "advapi32"]
- cls.ffi, cls.lib = build_ffi(cls._module_prefix, cls._modules,
- _OSX_PRE_INCLUDE, _OSX_POST_INCLUDE,
- libraries)
+ cls.ffi, cls.lib = build_ffi(
+ module_prefix=cls._module_prefix,
+ modules=cls._modules,
+ pre_include=_OSX_PRE_INCLUDE,
+ post_include=_OSX_POST_INCLUDE,
+ libraries=libraries,
+ )
res = cls.lib.Cryptography_add_osrandom_engine()
assert res != 0
diff --git a/cryptography/hazmat/bindings/openssl/dsa.py b/cryptography/hazmat/bindings/openssl/dsa.py
index 40d3b8ee..7db03326 100644
--- a/cryptography/hazmat/bindings/openssl/dsa.py
+++ b/cryptography/hazmat/bindings/openssl/dsa.py
@@ -31,6 +31,10 @@ typedef struct dsa_st {
BIGNUM *pub_key;
...;
} DSA;
+typedef struct {
+ BIGNUM *r;
+ BIGNUM *s;
+} DSA_SIG;
"""
FUNCTIONS = """
@@ -39,6 +43,15 @@ DSA *DSA_generate_parameters(int, unsigned char *, int, int *, unsigned long *,
int DSA_generate_key(DSA *);
DSA *DSA_new(void);
void DSA_free(DSA *);
+DSA_SIG *DSA_SIG_new(void);
+void DSA_SIG_free(DSA_SIG *);
+int i2d_DSA_SIG(const DSA_SIG *, unsigned char **);
+DSA_SIG *d2i_DSA_SIG(DSA_SIG **, const unsigned char **, long);
+int DSA_size(const DSA *);
+int DSA_sign(int, const unsigned char *, int, unsigned char *, unsigned int *,
+ DSA *);
+int DSA_verify(int, const unsigned char *, int, const unsigned char *, int,
+ DSA *);
"""
MACROS = """
diff --git a/cryptography/hazmat/bindings/openssl/ec.py b/cryptography/hazmat/bindings/openssl/ec.py
index 8ae2ae9a..45c17c2e 100644
--- a/cryptography/hazmat/bindings/openssl/ec.py
+++ b/cryptography/hazmat/bindings/openssl/ec.py
@@ -77,6 +77,7 @@ EC_KEY *EC_KEY_copy(EC_KEY *, const EC_KEY *);
EC_KEY *EC_KEY_dup(const EC_KEY *);
int EC_KEY_up_ref(EC_KEY *);
const EC_GROUP *EC_KEY_get0_group(const EC_KEY *);
+int EC_GROUP_get_order(const EC_GROUP *, BIGNUM *, BN_CTX *);
int EC_KEY_set_group(EC_KEY *, const EC_GROUP *);
const BIGNUM *EC_KEY_get0_private_key(const EC_KEY *);
int EC_KEY_set_private_key(EC_KEY *, const BIGNUM *);
@@ -214,6 +215,7 @@ EC_KEY *(*EC_KEY_copy)(EC_KEY *, const EC_KEY *) = NULL;
EC_KEY *(*EC_KEY_dup)(const EC_KEY *) = NULL;
int (*EC_KEY_up_ref)(EC_KEY *) = NULL;
const EC_GROUP *(*EC_KEY_get0_group)(const EC_KEY *) = NULL;
+int (*EC_GROUP_get_order)(const EC_GROUP *, BIGNUM *, BN_CTX *) = NULL;
int (*EC_KEY_set_group)(EC_KEY *, const EC_GROUP *) = NULL;
const BIGNUM *(*EC_KEY_get0_private_key)(const EC_KEY *) = NULL;
int (*EC_KEY_set_private_key)(EC_KEY *, const BIGNUM *) = NULL;
diff --git a/cryptography/hazmat/bindings/openssl/err.py b/cryptography/hazmat/bindings/openssl/err.py
index f51393aa..f6456d66 100644
--- a/cryptography/hazmat/bindings/openssl/err.py
+++ b/cryptography/hazmat/bindings/openssl/err.py
@@ -138,6 +138,7 @@ static const int EVP_F_RC5_CTRL;
static const int EVP_R_AES_KEY_SETUP_FAILED;
static const int EVP_R_ASN1_LIB;
static const int EVP_R_BAD_BLOCK_LENGTH;
+static const int EVP_R_BAD_DECRYPT;
static const int EVP_R_BAD_KEY_LENGTH;
static const int EVP_R_BN_DECODE_ERROR;
static const int EVP_R_BN_PUBKEY_ERROR;
@@ -216,6 +217,8 @@ static const int PEM_R_UNSUPPORTED_ENCRYPTION;
static const int RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE;
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;
"""
FUNCTIONS = """
diff --git a/cryptography/hazmat/bindings/openssl/evp.py b/cryptography/hazmat/bindings/openssl/evp.py
index 963537c8..b3d958e6 100644
--- a/cryptography/hazmat/bindings/openssl/evp.py
+++ b/cryptography/hazmat/bindings/openssl/evp.py
@@ -87,6 +87,8 @@ int EVP_PKEY_type(int);
int EVP_PKEY_bits(EVP_PKEY *);
int EVP_PKEY_size(EVP_PKEY *);
RSA *EVP_PKEY_get1_RSA(EVP_PKEY *);
+DSA *EVP_PKEY_get1_DSA(EVP_PKEY *);
+DH *EVP_PKEY_get1_DH(EVP_PKEY *);
int EVP_SignInit(EVP_MD_CTX *, const EVP_MD *);
int EVP_SignUpdate(EVP_MD_CTX *, const void *, size_t);
@@ -104,6 +106,7 @@ int PKCS5_PBKDF2_HMAC_SHA1(const char *, int, const unsigned char *, int, int,
int EVP_PKEY_set1_RSA(EVP_PKEY *, struct rsa_st *);
int EVP_PKEY_set1_DSA(EVP_PKEY *, struct dsa_st *);
+int EVP_PKEY_set1_DH(EVP_PKEY *, DH *);
int EVP_PKEY_get_attr_count(const EVP_PKEY *);
int EVP_PKEY_get_attr_by_NID(const EVP_PKEY *, int, int);
@@ -123,7 +126,11 @@ MACROS = """
void OpenSSL_add_all_algorithms(void);
int EVP_PKEY_assign_RSA(EVP_PKEY *, RSA *);
int EVP_PKEY_assign_DSA(EVP_PKEY *, DSA *);
+
int EVP_PKEY_assign_EC_KEY(EVP_PKEY *, EC_KEY *);
+EC_KEY *EVP_PKEY_get1_EC_KEY(EVP_PKEY *);
+int EVP_PKEY_set1_EC_KEY(EVP_PKEY *, EC_KEY *);
+
int EVP_CIPHER_CTX_block_size(const EVP_CIPHER_CTX *);
int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *, int, int, void *);
@@ -215,6 +222,8 @@ int (*Cryptography_EVP_PKEY_decrypt)(EVP_PKEY_CTX *, unsigned char *, size_t *,
#endif
#ifdef OPENSSL_NO_EC
int (*EVP_PKEY_assign_EC_KEY)(EVP_PKEY *, EC_KEY *) = NULL;
+EC_KEY *(*EVP_PKEY_get1_EC_KEY)(EVP_PKEY *) = NULL;
+int (*EVP_PKEY_set1_EC_KEY)(EVP_PKEY *, EC_KEY *) = NULL;
#endif
"""
@@ -245,5 +254,7 @@ CONDITIONAL_NAMES = {
],
"Cryptography_HAS_EC": [
"EVP_PKEY_assign_EC_KEY",
+ "EVP_PKEY_get1_EC_KEY",
+ "EVP_PKEY_set1_EC_KEY",
]
}
diff --git a/cryptography/hazmat/bindings/openssl/ssl.py b/cryptography/hazmat/bindings/openssl/ssl.py
index 094310f3..7ed42f9f 100644
--- a/cryptography/hazmat/bindings/openssl/ssl.py
+++ b/cryptography/hazmat/bindings/openssl/ssl.py
@@ -237,26 +237,28 @@ size_t SSL_get_peer_finished(const SSL *, void *, size_t);
"""
MACROS = """
-long SSL_set_mode(SSL *, long);
-long SSL_get_mode(SSL *);
+unsigned long SSL_set_mode(SSL *, unsigned long);
+unsigned long SSL_get_mode(SSL *);
-long SSL_set_options(SSL *, long);
-long SSL_get_options(SSL *);
+unsigned long SSL_set_options(SSL *, unsigned long);
+unsigned long SSL_get_options(SSL *);
int SSL_want_read(const SSL *);
int SSL_want_write(const SSL *);
long SSL_total_renegotiations(SSL *);
-long SSL_CTX_set_options(SSL_CTX *, long);
-long SSL_CTX_get_options(SSL_CTX *);
-long SSL_CTX_set_mode(SSL_CTX *, long);
-long SSL_CTX_get_mode(SSL_CTX *);
-long SSL_CTX_set_session_cache_mode(SSL_CTX *, long);
-long SSL_CTX_get_session_cache_mode(SSL_CTX *);
-long SSL_CTX_set_tmp_dh(SSL_CTX *, DH *);
-long SSL_CTX_set_tmp_ecdh(SSL_CTX *, EC_KEY *);
-long SSL_CTX_add_extra_chain_cert(SSL_CTX *, X509 *);
+/* Defined as unsigned long because SSL_OP_ALL is greater than signed 32-bit
+ and Windows defines long as 32-bit. */
+unsigned long SSL_CTX_set_options(SSL_CTX *, unsigned long);
+unsigned long SSL_CTX_get_options(SSL_CTX *);
+unsigned long SSL_CTX_set_mode(SSL_CTX *, unsigned long);
+unsigned long SSL_CTX_get_mode(SSL_CTX *);
+unsigned long SSL_CTX_set_session_cache_mode(SSL_CTX *, unsigned long);
+unsigned long SSL_CTX_get_session_cache_mode(SSL_CTX *);
+unsigned long SSL_CTX_set_tmp_dh(SSL_CTX *, DH *);
+unsigned long SSL_CTX_set_tmp_ecdh(SSL_CTX *, EC_KEY *);
+unsigned long SSL_CTX_add_extra_chain_cert(SSL_CTX *, X509 *);
/*- These aren't macros these functions are all const X on openssl > 1.0.x -*/
diff --git a/cryptography/hazmat/bindings/openssl/x509.py b/cryptography/hazmat/bindings/openssl/x509.py
index e800d272..36a15e4a 100644
--- a/cryptography/hazmat/bindings/openssl/x509.py
+++ b/cryptography/hazmat/bindings/openssl/x509.py
@@ -160,6 +160,8 @@ X509_REQ *d2i_X509_REQ_bio(BIO *, X509_REQ **);
int i2d_PrivateKey_bio(BIO *, EVP_PKEY *);
EVP_PKEY *d2i_PrivateKey_bio(BIO *, EVP_PKEY **);
+int i2d_PUBKEY_bio(BIO *, EVP_PKEY *);
+EVP_PKEY *d2i_PUBKEY_bio(BIO *, EVP_PKEY **);
ASN1_INTEGER *X509_get_serialNumber(X509 *);
int X509_set_serialNumber(X509 *, ASN1_INTEGER *);
@@ -178,6 +180,27 @@ const char *X509_get_default_cert_file(void);
const char *X509_get_default_cert_dir_env(void);
const char *X509_get_default_cert_file_env(void);
const char *X509_get_default_private_dir(void);
+
+int i2d_RSA_PUBKEY(RSA *, unsigned char **);
+RSA *d2i_RSA_PUBKEY(RSA **, const unsigned char **, long);
+RSA *d2i_RSAPublicKey(RSA **, const unsigned char **, long);
+RSA *d2i_RSAPrivateKey(RSA **, const unsigned char **, long);
+int i2d_DSA_PUBKEY(DSA *, unsigned char **);
+DSA *d2i_DSA_PUBKEY(DSA **, const unsigned char **, long);
+DSA *d2i_DSAPublicKey(DSA **, const unsigned char **, long);
+DSA *d2i_DSAPrivateKey(DSA **, const unsigned char **, long);
+
+
+RSA *d2i_RSAPrivateKey_bio(BIO *, RSA **);
+int i2d_RSAPrivateKey_bio(BIO *, RSA *);
+RSA *d2i_RSAPublicKey_bio(BIO *, RSA **);
+int i2d_RSAPublicKey_bio(BIO *, RSA *);
+RSA *d2i_RSA_PUBKEY_bio(BIO *, RSA **);
+int i2d_RSA_PUBKEY_bio(BIO *, RSA *);
+DSA *d2i_DSA_PUBKEY_bio(BIO *, DSA **);
+int i2d_DSA_PUBKEY_bio(BIO *, DSA *);
+DSA *d2i_DSAPrivateKey_bio(BIO *, DSA **);
+int i2d_DSAPrivateKey_bio(BIO *, DSA *);
"""
MACROS = """
@@ -205,6 +228,11 @@ void sk_X509_EXTENSION_free(X509_EXTENSIONS *);
int sk_X509_REVOKED_num(Cryptography_STACK_OF_X509_REVOKED *);
X509_REVOKED *sk_X509_REVOKED_value(Cryptography_STACK_OF_X509_REVOKED *, int);
+int i2d_RSAPublicKey(RSA *, unsigned char **);
+int i2d_RSAPrivateKey(RSA *, unsigned char **);
+int i2d_DSAPublicKey(DSA *, unsigned char **);
+int i2d_DSAPrivateKey(DSA *, unsigned char **);
+
/* These aren't macros these arguments are all const X on openssl > 1.0.x */
int X509_CRL_set_lastUpdate(X509_CRL *, ASN1_TIME *);
int X509_CRL_set_nextUpdate(X509_CRL *, ASN1_TIME *);
@@ -213,6 +241,13 @@ int X509_CRL_set_nextUpdate(X509_CRL *, ASN1_TIME *);
RHEL/CentOS 5 we should move these back to FUNCTIONS. */
int X509_REQ_add_extensions(X509_REQ *, X509_EXTENSIONS *);
X509_EXTENSIONS *X509_REQ_get_extensions(X509_REQ *);
+
+int i2d_EC_PUBKEY(EC_KEY *, unsigned char **);
+EC_KEY *d2i_EC_PUBKEY(EC_KEY **, const unsigned char **, long);
+EC_KEY *d2i_EC_PUBKEY_bio(BIO *, EC_KEY **);
+int i2d_EC_PUBKEY_bio(BIO *, EC_KEY *);
+EC_KEY *d2i_ECPrivateKey_bio(BIO *, EC_KEY **);
+int i2d_ECPrivateKey_bio(BIO *, EC_KEY *);
"""
CUSTOMIZATIONS = """
@@ -220,6 +255,23 @@ CUSTOMIZATIONS = """
#if OPENSSL_VERSION_NUMBER <= 0x0090805fL
typedef STACK_OF(X509_EXTENSION) X509_EXTENSIONS;
#endif
+#ifdef OPENSSL_NO_EC
+int (*i2d_EC_PUBKEY)(EC_KEY *, unsigned char **) = NULL;
+EC_KEY *(*d2i_EC_PUBKEY)(EC_KEY **, const unsigned char **, long) = NULL;
+EC_KEY *(*d2i_EC_PUBKEY_bio)(BIO *, EC_KEY **) = NULL;
+int (*i2d_EC_PUBKEY_bio)(BIO *, EC_KEY *) = NULL;
+EC_KEY *(*d2i_ECPrivateKey_bio)(BIO *, EC_KEY **) = NULL;
+int (*i2d_ECPrivateKey_bio)(BIO *, EC_KEY *) = NULL;
+#endif
"""
-CONDITIONAL_NAMES = {}
+CONDITIONAL_NAMES = {
+ "Cryptography_HAS_EC": [
+ "i2d_EC_PUBKEY",
+ "d2i_EC_PUBKEY",
+ "d2i_EC_PUBKEY_bio",
+ "i2d_EC_PUBKEY_bio",
+ "d2i_ECPrivateKey_bio",
+ "i2d_ECPrivateKey_bio",
+ ]
+}
diff --git a/cryptography/hazmat/bindings/utils.py b/cryptography/hazmat/bindings/utils.py
index 318b82bb..1c48116e 100644
--- a/cryptography/hazmat/bindings/utils.py
+++ b/cryptography/hazmat/bindings/utils.py
@@ -20,7 +20,8 @@ import sys
import cffi
-def build_ffi(module_prefix, modules, pre_include, post_include, libraries):
+def build_ffi(module_prefix, modules, pre_include="", post_include="",
+ libraries=[], extra_compile_args=[], extra_link_args=[]):
"""
Modules listed in ``modules`` should have the following attributes:
@@ -75,6 +76,8 @@ def build_ffi(module_prefix, modules, pre_include, post_include, libraries):
modulename=_create_modulename(cdef_sources, source, sys.version),
libraries=libraries,
ext_package="cryptography",
+ extra_compile_args=extra_compile_args,
+ extra_link_args=extra_link_args,
)
for name in modules:
diff --git a/cryptography/hazmat/primitives/asymmetric/padding.py b/cryptography/hazmat/primitives/asymmetric/padding.py
index 72806a61..dcc6fe06 100644
--- a/cryptography/hazmat/primitives/asymmetric/padding.py
+++ b/cryptography/hazmat/primitives/asymmetric/padding.py
@@ -54,6 +54,19 @@ class PSS(object):
self._salt_length = salt_length
+@utils.register_interface(interfaces.AsymmetricPadding)
+class OAEP(object):
+ name = "EME-OAEP"
+
+ def __init__(self, mgf, algorithm, label):
+ if not isinstance(algorithm, interfaces.HashAlgorithm):
+ raise TypeError("Expected instance of interfaces.HashAlgorithm.")
+
+ self._mgf = mgf
+ self._algorithm = algorithm
+ self._label = label
+
+
class MGF1(object):
MAX_LENGTH = object()
diff --git a/cryptography/hazmat/primitives/asymmetric/rsa.py b/cryptography/hazmat/primitives/asymmetric/rsa.py
index 94cc4645..cffd4e98 100644
--- a/cryptography/hazmat/primitives/asymmetric/rsa.py
+++ b/cryptography/hazmat/primitives/asymmetric/rsa.py
@@ -73,6 +73,42 @@ class RSAPublicKey(object):
return self.modulus
+def _modinv(e, m):
+ """
+ Modular Multiplicative Inverse. Returns x such that: (x*e) mod m == 1
+ """
+ x1, y1, x2, y2 = 1, 0, 0, 1
+ a, b = e, m
+ while b > 0:
+ q, r = divmod(a, b)
+ xn, yn = x1 - q * x2, y1 - q * y2
+ a, b, x1, y1, x2, y2 = b, r, x2, y2, xn, yn
+ return x1 % m
+
+
+def rsa_crt_iqmp(p, q):
+ """
+ Compute the CRT (q ** -1) % p value from RSA primes p and q.
+ """
+ return _modinv(q, p)
+
+
+def rsa_crt_dmp1(private_exponent, p):
+ """
+ Compute the CRT private_exponent % (p - 1) value from the RSA
+ private_exponent and p.
+ """
+ return private_exponent % (p - 1)
+
+
+def rsa_crt_dmq1(private_exponent, q):
+ """
+ Compute the CRT private_exponent % (q - 1) value from the RSA
+ private_exponent and q.
+ """
+ return private_exponent % (q - 1)
+
+
@utils.register_interface(interfaces.RSAPrivateKey)
class RSAPrivateKey(object):
def __init__(self, p, q, private_exponent, dmp1, dmq1, iqmp,
@@ -153,6 +189,15 @@ class RSAPrivateKey(object):
return backend.create_rsa_signature_ctx(self, padding, algorithm)
+ def decrypt(self, ciphertext, padding, backend):
+ if not isinstance(backend, RSABackend):
+ raise UnsupportedAlgorithm(
+ "Backend object does not implement RSABackend",
+ _Reasons.BACKEND_MISSING_INTERFACE
+ )
+
+ return backend.decrypt_rsa(self, ciphertext, padding)
+
@property
def key_size(self):
return utils.bit_length(self.modulus)
diff --git a/cryptography/hazmat/primitives/cmac.py b/cryptography/hazmat/primitives/cmac.py
new file mode 100644
index 00000000..7e7f65ab
--- /dev/null
+++ b/cryptography/hazmat/primitives/cmac.py
@@ -0,0 +1,75 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import absolute_import, division, print_function
+
+import six
+
+from cryptography import utils
+from cryptography.exceptions import (
+ AlreadyFinalized, InvalidSignature, UnsupportedAlgorithm, _Reasons
+)
+from cryptography.hazmat.backends.interfaces import CMACBackend
+from cryptography.hazmat.primitives import constant_time, interfaces
+
+
+@utils.register_interface(interfaces.CMACContext)
+class CMAC(object):
+ def __init__(self, algorithm, backend, ctx=None):
+ if not isinstance(backend, CMACBackend):
+ raise UnsupportedAlgorithm(
+ "Backend object does not implement CMACBackend",
+ _Reasons.BACKEND_MISSING_INTERFACE
+ )
+
+ if not isinstance(algorithm, interfaces.BlockCipherAlgorithm):
+ raise TypeError(
+ "Expected instance of interfaces.BlockCipherAlgorithm"
+ )
+ self._algorithm = algorithm
+
+ self._backend = backend
+ if ctx is None:
+ self._ctx = self._backend.create_cmac_ctx(self._algorithm)
+ else:
+ self._ctx = ctx
+
+ def update(self, data):
+ if self._ctx is None:
+ raise AlreadyFinalized("Context was already finalized")
+ if isinstance(data, six.text_type):
+ raise TypeError("Unicode-objects must be encoded before hashing")
+ self._ctx.update(data)
+
+ def finalize(self):
+ if self._ctx is None:
+ raise AlreadyFinalized("Context was already finalized")
+ digest = self._ctx.finalize()
+ self._ctx = None
+ return digest
+
+ def verify(self, signature):
+ if isinstance(signature, six.text_type):
+ raise TypeError("Unicode-objects must be encoded before verifying")
+ digest = self.finalize()
+ if not constant_time.bytes_eq(digest, signature):
+ raise InvalidSignature("Signature did not match digest.")
+
+ def copy(self):
+ if self._ctx is None:
+ raise AlreadyFinalized("Context was already finalized")
+ return CMAC(
+ self._algorithm,
+ backend=self._backend,
+ ctx=self._ctx.copy()
+ )