aboutsummaryrefslogtreecommitdiffstats
path: root/cryptography/hazmat
diff options
context:
space:
mode:
Diffstat (limited to 'cryptography/hazmat')
-rw-r--r--cryptography/hazmat/backends/__init__.py4
-rw-r--r--cryptography/hazmat/backends/multibackend.py7
-rw-r--r--cryptography/hazmat/backends/openssl/backend.py211
-rw-r--r--cryptography/hazmat/bindings/openssl/dsa.py2
-rw-r--r--cryptography/hazmat/bindings/openssl/ec.py149
-rw-r--r--cryptography/hazmat/bindings/openssl/err.py3
-rw-r--r--cryptography/hazmat/bindings/openssl/hmac.py6
-rw-r--r--cryptography/hazmat/bindings/openssl/rsa.py11
-rw-r--r--cryptography/hazmat/primitives/asymmetric/rsa.py17
-rw-r--r--cryptography/hazmat/primitives/interfaces.py92
-rw-r--r--cryptography/hazmat/primitives/twofactor/hotp.py8
11 files changed, 444 insertions, 66 deletions
diff --git a/cryptography/hazmat/backends/__init__.py b/cryptography/hazmat/backends/__init__.py
index 41d260a8..406b37e5 100644
--- a/cryptography/hazmat/backends/__init__.py
+++ b/cryptography/hazmat/backends/__init__.py
@@ -17,12 +17,14 @@ from cryptography.hazmat.bindings.commoncrypto.binding import (
Binding as CommonCryptoBinding
)
-_ALL_BACKENDS = [openssl.backend]
+_ALL_BACKENDS = []
if CommonCryptoBinding.is_available():
from cryptography.hazmat.backends import commoncrypto
_ALL_BACKENDS.append(commoncrypto.backend)
+_ALL_BACKENDS.append(openssl.backend)
+
_default_backend = MultiBackend(_ALL_BACKENDS)
diff --git a/cryptography/hazmat/backends/multibackend.py b/cryptography/hazmat/backends/multibackend.py
index f0017191..de1fff7c 100644
--- a/cryptography/hazmat/backends/multibackend.py
+++ b/cryptography/hazmat/backends/multibackend.py
@@ -112,3 +112,10 @@ class MultiBackend(object):
for b in self._filtered_backends(RSABackend):
return b.create_rsa_signature_ctx(private_key, padding, algorithm)
raise UnsupportedAlgorithm
+
+ def create_rsa_verification_ctx(self, public_key, signature, padding,
+ algorithm):
+ for b in self._filtered_backends(RSABackend):
+ return b.create_rsa_verification_ctx(public_key, signature,
+ padding, algorithm)
+ raise UnsupportedAlgorithm
diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py
index 47d2b106..5de506a0 100644
--- a/cryptography/hazmat/backends/openssl/backend.py
+++ b/cryptography/hazmat/backends/openssl/backend.py
@@ -13,12 +13,13 @@
from __future__ import absolute_import, division, print_function
+import collections
import itertools
from cryptography import utils
from cryptography.exceptions import (
InvalidTag, InternalError, AlreadyFinalized, UnsupportedPadding,
- UnsupportedCipher, UnsupportedHash
+ InvalidSignature
)
from cryptography.hazmat.backends.interfaces import (
CipherBackend, HashBackend, HMACBackend, PBKDF2HMACBackend, RSABackend
@@ -34,6 +35,10 @@ from cryptography.hazmat.primitives.ciphers.modes import (
)
+_OpenSSLError = collections.namedtuple("_OpenSSLError",
+ ["code", "lib", "func", "reason"])
+
+
@utils.register_interface(CipherBackend)
@utils.register_interface(HashBackend)
@utils.register_interface(HMACBackend)
@@ -228,43 +233,25 @@ class Backend(object):
self._lib.ERR_error_string_n(code, err_buf, 256)
return self._ffi.string(err_buf, 256)[:]
- def _handle_error(self, mode):
- code = self._lib.ERR_get_error()
- if not code and isinstance(mode, GCM):
- raise InvalidTag
- assert code != 0
-
- # consume any remaining errors on the stack
- ignored_code = None
- while ignored_code != 0:
- ignored_code = self._lib.ERR_get_error()
-
- # raise the first error we found
- return self._handle_error_code(code)
-
- def _handle_error_code(self, code):
- lib = self._lib.ERR_GET_LIB(code)
- func = self._lib.ERR_GET_FUNC(code)
- reason = self._lib.ERR_GET_REASON(code)
-
- if lib == self._lib.ERR_LIB_EVP:
- if func == self._lib.EVP_F_EVP_ENCRYPTFINAL_EX:
- if reason == self._lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH:
- raise ValueError(
- "The length of the provided data is not a multiple of "
- "the block length"
- )
- elif func == self._lib.EVP_F_EVP_DECRYPTFINAL_EX:
- if reason == self._lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH:
- raise ValueError(
- "The length of the provided data is not a multiple of "
- "the block length"
- )
-
- raise InternalError(
+ def _consume_errors(self):
+ errors = []
+ while True:
+ code = self._lib.ERR_get_error()
+ if code == 0:
+ break
+
+ lib = self._lib.ERR_GET_LIB(code)
+ func = self._lib.ERR_GET_FUNC(code)
+ reason = self._lib.ERR_GET_REASON(code)
+
+ errors.append(_OpenSSLError(code, lib, func, reason))
+ return errors
+
+ def _unknown_error(self, error):
+ return InternalError(
"Unknown error code {0} from OpenSSL, "
"you should probably file a bug. {1}".format(
- code, self._err_string(code)
+ error.code, self._err_string(error.code)
)
)
@@ -336,9 +323,22 @@ class Backend(object):
ctx.iqmp = self._int_to_bn(private_key.iqmp)
return ctx
+ def _rsa_cdata_from_public_key(self, public_key):
+ ctx = self._lib.RSA_new()
+ assert ctx != self._ffi.NULL
+ ctx = self._ffi.gc(ctx, self._lib.RSA_free)
+ ctx.e = self._int_to_bn(public_key.e)
+ ctx.n = self._int_to_bn(public_key.n)
+ return ctx
+
def create_rsa_signature_ctx(self, private_key, padding, algorithm):
return _RSASignatureContext(self, private_key, padding, algorithm)
+ def create_rsa_verification_ctx(self, public_key, signature, padding,
+ algorithm):
+ return _RSAVerificationContext(self, public_key, signature, padding,
+ algorithm)
+
class GetCipherByName(object):
def __init__(self, fmt):
@@ -451,7 +451,28 @@ class _CipherContext(object):
outlen = self._backend._ffi.new("int *")
res = self._backend._lib.EVP_CipherFinal_ex(self._ctx, buf, outlen)
if res == 0:
- self._backend._handle_error(self._mode)
+ errors = self._backend._consume_errors()
+
+ if not errors and isinstance(self._mode, GCM):
+ raise InvalidTag
+
+ assert errors
+
+ if errors[0][1:] == (
+ self._backend._lib.ERR_LIB_EVP,
+ self._backend._lib.EVP_F_EVP_ENCRYPTFINAL_EX,
+ self._backend._lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH
+ ) or errors[0][1:] == (
+ self._backend._lib.ERR_LIB_EVP,
+ self._backend._lib.EVP_F_EVP_DECRYPTFINAL_EX,
+ self._backend._lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH
+ ):
+ raise ValueError(
+ "The length of the provided data is not a multiple of "
+ "the block length."
+ )
+ else:
+ raise self._backend._unknown_error(errors[0])
if (isinstance(self._mode, GCM) and
self._operation == self._ENCRYPT):
@@ -521,13 +542,14 @@ class _HashContext(object):
def finalize(self):
buf = self._backend._ffi.new("unsigned char[]",
- self.algorithm.digest_size)
- res = self._backend._lib.EVP_DigestFinal_ex(self._ctx, buf,
- self._backend._ffi.NULL)
+ self._backend._lib.EVP_MAX_MD_SIZE)
+ outlen = self._backend._ffi.new("unsigned int *")
+ res = self._backend._lib.EVP_DigestFinal_ex(self._ctx, buf, outlen)
assert res != 0
+ assert outlen[0] == self.algorithm.digest_size
res = self._backend._lib.EVP_MD_CTX_cleanup(self._ctx)
assert res == 1
- return self._backend._ffi.buffer(buf)[:]
+ return self._backend._ffi.buffer(buf)[:outlen[0]]
@utils.register_interface(interfaces.HashContext)
@@ -579,15 +601,15 @@ class _HMACContext(object):
def finalize(self):
buf = self._backend._ffi.new("unsigned char[]",
- self.algorithm.digest_size)
- buflen = self._backend._ffi.new("unsigned int *",
- self.algorithm.digest_size)
+ self._backend._lib.EVP_MAX_MD_SIZE)
+ outlen = self._backend._ffi.new("unsigned int *")
res = self._backend._lib.Cryptography_HMAC_Final(
- self._ctx, buf, buflen
+ self._ctx, buf, outlen
)
assert res != 0
+ assert outlen[0] == self.algorithm.digest_size
self._backend._lib.HMAC_CTX_cleanup(self._ctx)
- return self._backend._ffi.buffer(buf)[:]
+ return self._backend._ffi.buffer(buf)[:outlen[0]]
@utils.register_interface(interfaces.AsymmetricSignatureContext)
@@ -686,4 +708,101 @@ class _RSASignatureContext(object):
return self._backend._ffi.buffer(sig_buf)[:sig_len[0]]
+@utils.register_interface(interfaces.AsymmetricVerificationContext)
+class _RSAVerificationContext(object):
+ def __init__(self, backend, public_key, signature, padding, algorithm):
+ self._backend = backend
+ self._public_key = public_key
+ self._signature = signature
+ if not isinstance(padding, interfaces.AsymmetricPadding):
+ raise TypeError(
+ "Expected provider of interfaces.AsymmetricPadding")
+
+ if padding.name == "EMSA-PKCS1-v1_5":
+ if self._backend._lib.Cryptography_HAS_PKEY_CTX:
+ self._verify_method = self._verify_pkey_ctx
+ self._padding_enum = self._backend._lib.RSA_PKCS1_PADDING
+ else:
+ self._verify_method = self._verify_pkcs1
+ else:
+ raise UnsupportedPadding
+
+ self._padding = padding
+ self._algorithm = algorithm
+ self._hash_ctx = _HashContext(backend, self._algorithm)
+
+ def update(self, data):
+ if self._hash_ctx is None:
+ raise AlreadyFinalized("Context has already been finalized")
+
+ self._hash_ctx.update(data)
+
+ def verify(self):
+ if self._hash_ctx is None:
+ raise AlreadyFinalized("Context has already been finalized")
+
+ evp_pkey = self._backend._lib.EVP_PKEY_new()
+ assert evp_pkey != self._backend._ffi.NULL
+ evp_pkey = backend._ffi.gc(evp_pkey, backend._lib.EVP_PKEY_free)
+ rsa_cdata = backend._rsa_cdata_from_public_key(self._public_key)
+ res = self._backend._lib.RSA_blinding_on(
+ rsa_cdata, self._backend._ffi.NULL)
+ assert res == 1
+ res = self._backend._lib.EVP_PKEY_set1_RSA(evp_pkey, rsa_cdata)
+ assert res == 1
+ evp_md = self._backend._lib.EVP_get_digestbyname(
+ self._algorithm.name.encode("ascii"))
+ assert evp_md != self._backend._ffi.NULL
+
+ self._verify_method(rsa_cdata, evp_pkey, evp_md)
+
+ def _verify_pkey_ctx(self, rsa_cdata, evp_pkey, evp_md):
+ pkey_ctx = self._backend._lib.EVP_PKEY_CTX_new(
+ evp_pkey, self._backend._ffi.NULL
+ )
+ assert pkey_ctx != self._backend._ffi.NULL
+ res = self._backend._lib.EVP_PKEY_verify_init(pkey_ctx)
+ assert res == 1
+ res = self._backend._lib.EVP_PKEY_CTX_set_signature_md(
+ pkey_ctx, evp_md)
+ assert res > 0
+
+ res = self._backend._lib.EVP_PKEY_CTX_set_rsa_padding(
+ pkey_ctx, self._padding_enum)
+ assert res > 0
+ data_to_verify = self._hash_ctx.finalize()
+ self._hash_ctx = None
+ res = self._backend._lib.EVP_PKEY_verify(
+ pkey_ctx,
+ self._signature,
+ len(self._signature),
+ data_to_verify,
+ len(data_to_verify)
+ )
+ # The previous call can return negative numbers in the event of an
+ # error. This is not a signature failure but we need to fail if it
+ # occurs.
+ assert res >= 0
+ if res == 0:
+ assert self._backend._consume_errors()
+ raise InvalidSignature
+
+ def _verify_pkcs1(self, rsa_cdata, evp_pkey, evp_md):
+ res = self._backend._lib.EVP_VerifyFinal(
+ self._hash_ctx._ctx,
+ self._signature,
+ len(self._signature),
+ evp_pkey
+ )
+ self._hash_ctx.finalize()
+ self._hash_ctx = None
+ # The previous call can return negative numbers in the event of an
+ # error. This is not a signature failure but we need to fail if it
+ # occurs.
+ assert res >= 0
+ if res == 0:
+ assert self._backend._consume_errors()
+ raise InvalidSignature
+
+
backend = Backend()
diff --git a/cryptography/hazmat/bindings/openssl/dsa.py b/cryptography/hazmat/bindings/openssl/dsa.py
index 609a33bf..e04507ca 100644
--- a/cryptography/hazmat/bindings/openssl/dsa.py
+++ b/cryptography/hazmat/bindings/openssl/dsa.py
@@ -39,6 +39,8 @@ void DSA_free(DSA *);
"""
MACROS = """
+int DSA_generate_parameters_ex(DSA *, int, unsigned char *, int,
+ int *, unsigned long *, BN_GENCB *);
"""
CUSTOMIZATIONS = """
diff --git a/cryptography/hazmat/bindings/openssl/ec.py b/cryptography/hazmat/bindings/openssl/ec.py
index 39403ff2..4a42960c 100644
--- a/cryptography/hazmat/bindings/openssl/ec.py
+++ b/cryptography/hazmat/bindings/openssl/ec.py
@@ -23,7 +23,31 @@ TYPES = """
static const int Cryptography_HAS_EC;
typedef ... EC_KEY;
+typedef struct {
+ int nid;
+ const char *comment;
+} EC_builtin_curve;
+static const int NID_X9_62_c2pnb163v1;
+static const int NID_X9_62_c2pnb163v2;
+static const int NID_X9_62_c2pnb163v3;
+static const int NID_X9_62_c2pnb176v1;
+static const int NID_X9_62_c2tnb191v1;
+static const int NID_X9_62_c2tnb191v2;
+static const int NID_X9_62_c2tnb191v3;
+static const int NID_X9_62_c2onb191v4;
+static const int NID_X9_62_c2onb191v5;
+static const int NID_X9_62_c2pnb208w1;
+static const int NID_X9_62_c2tnb239v1;
+static const int NID_X9_62_c2tnb239v2;
+static const int NID_X9_62_c2tnb239v3;
+static const int NID_X9_62_c2onb239v4;
+static const int NID_X9_62_c2onb239v5;
+static const int NID_X9_62_c2pnb272w1;
+static const int NID_X9_62_c2pnb304w1;
+static const int NID_X9_62_c2tnb359v1;
+static const int NID_X9_62_c2pnb368w1;
+static const int NID_X9_62_c2tnb431r1;
static const int NID_X9_62_prime192v1;
static const int NID_X9_62_prime192v2;
static const int NID_X9_62_prime192v3;
@@ -31,6 +55,122 @@ static const int NID_X9_62_prime239v1;
static const int NID_X9_62_prime239v2;
static const int NID_X9_62_prime239v3;
static const int NID_X9_62_prime256v1;
+static const int NID_secp112r1;
+static const int NID_secp112r2;
+static const int NID_secp128r1;
+static const int NID_secp128r2;
+static const int NID_secp160k1;
+static const int NID_secp160r1;
+static const int NID_secp160r2;
+static const int NID_sect163k1;
+static const int NID_sect163r1;
+static const int NID_sect163r2;
+static const int NID_secp192k1;
+static const int NID_secp224k1;
+static const int NID_secp224r1;
+static const int NID_secp256k1;
+static const int NID_secp384r1;
+static const int NID_secp521r1;
+static const int NID_sect113r1;
+static const int NID_sect113r2;
+static const int NID_sect131r1;
+static const int NID_sect131r2;
+static const int NID_sect193r1;
+static const int NID_sect193r2;
+static const int NID_sect233k1;
+static const int NID_sect233r1;
+static const int NID_sect239k1;
+static const int NID_sect283k1;
+static const int NID_sect283r1;
+static const int NID_sect409k1;
+static const int NID_sect409r1;
+static const int NID_sect571k1;
+static const int NID_sect571r1;
+static const int NID_wap_wsg_idm_ecid_wtls1;
+static const int NID_wap_wsg_idm_ecid_wtls3;
+static const int NID_wap_wsg_idm_ecid_wtls4;
+static const int NID_wap_wsg_idm_ecid_wtls5;
+static const int NID_wap_wsg_idm_ecid_wtls6;
+static const int NID_wap_wsg_idm_ecid_wtls7;
+static const int NID_wap_wsg_idm_ecid_wtls8;
+static const int NID_wap_wsg_idm_ecid_wtls9;
+static const int NID_wap_wsg_idm_ecid_wtls10;
+static const int NID_wap_wsg_idm_ecid_wtls11;
+static const int NID_wap_wsg_idm_ecid_wtls12;
+static const int NID_ipsec3;
+static const int NID_ipsec4;
+static const char *const SN_X9_62_c2pnb163v1;
+static const char *const SN_X9_62_c2pnb163v2;
+static const char *const SN_X9_62_c2pnb163v3;
+static const char *const SN_X9_62_c2pnb176v1;
+static const char *const SN_X9_62_c2tnb191v1;
+static const char *const SN_X9_62_c2tnb191v2;
+static const char *const SN_X9_62_c2tnb191v3;
+static const char *const SN_X9_62_c2onb191v4;
+static const char *const SN_X9_62_c2onb191v5;
+static const char *const SN_X9_62_c2pnb208w1;
+static const char *const SN_X9_62_c2tnb239v1;
+static const char *const SN_X9_62_c2tnb239v2;
+static const char *const SN_X9_62_c2tnb239v3;
+static const char *const SN_X9_62_c2onb239v4;
+static const char *const SN_X9_62_c2onb239v5;
+static const char *const SN_X9_62_c2pnb272w1;
+static const char *const SN_X9_62_c2pnb304w1;
+static const char *const SN_X9_62_c2tnb359v1;
+static const char *const SN_X9_62_c2pnb368w1;
+static const char *const SN_X9_62_c2tnb431r1;
+static const char *const SN_X9_62_prime192v1;
+static const char *const SN_X9_62_prime192v2;
+static const char *const SN_X9_62_prime192v3;
+static const char *const SN_X9_62_prime239v1;
+static const char *const SN_X9_62_prime239v2;
+static const char *const SN_X9_62_prime239v3;
+static const char *const SN_X9_62_prime256v1;
+static const char *const SN_secp112r1;
+static const char *const SN_secp112r2;
+static const char *const SN_secp128r1;
+static const char *const SN_secp128r2;
+static const char *const SN_secp160k1;
+static const char *const SN_secp160r1;
+static const char *const SN_secp160r2;
+static const char *const SN_sect163k1;
+static const char *const SN_sect163r1;
+static const char *const SN_sect163r2;
+static const char *const SN_secp192k1;
+static const char *const SN_secp224k1;
+static const char *const SN_secp224r1;
+static const char *const SN_secp256k1;
+static const char *const SN_secp384r1;
+static const char *const SN_secp521r1;
+static const char *const SN_sect113r1;
+static const char *const SN_sect113r2;
+static const char *const SN_sect131r1;
+static const char *const SN_sect131r2;
+static const char *const SN_sect193r1;
+static const char *const SN_sect193r2;
+static const char *const SN_sect233k1;
+static const char *const SN_sect233r1;
+static const char *const SN_sect239k1;
+static const char *const SN_sect283k1;
+static const char *const SN_sect283r1;
+static const char *const SN_sect409k1;
+static const char *const SN_sect409r1;
+static const char *const SN_sect571k1;
+static const char *const SN_sect571r1;
+static const char *const SN_wap_wsg_idm_ecid_wtls1;
+static const char *const SN_wap_wsg_idm_ecid_wtls3;
+static const char *const SN_wap_wsg_idm_ecid_wtls4;
+static const char *const SN_wap_wsg_idm_ecid_wtls5;
+static const char *const SN_wap_wsg_idm_ecid_wtls6;
+static const char *const SN_wap_wsg_idm_ecid_wtls7;
+static const char *const SN_wap_wsg_idm_ecid_wtls8;
+static const char *const SN_wap_wsg_idm_ecid_wtls9;
+static const char *const SN_wap_wsg_idm_ecid_wtls10;
+static const char *const SN_wap_wsg_idm_ecid_wtls11;
+static const char *const SN_wap_wsg_idm_ecid_wtls12;
+static const char *const SN_ipsec3;
+static const char *const SN_ipsec4;
+
"""
FUNCTIONS = """
@@ -39,14 +179,22 @@ FUNCTIONS = """
MACROS = """
EC_KEY *EC_KEY_new_by_curve_name(int);
void EC_KEY_free(EC_KEY *);
+
+size_t EC_get_builtin_curves(EC_builtin_curve *, size_t);
+
"""
CUSTOMIZATIONS = """
#ifdef OPENSSL_NO_EC
static const long Cryptography_HAS_EC = 0;
typedef void EC_KEY;
+typedef struct {
+ int nid;
+ const char *comment;
+} EC_builtin_curve;
EC_KEY* (*EC_KEY_new_by_curve_name)(int) = NULL;
void (*EC_KEY_free)(EC_KEY *) = NULL;
+size_t (*EC_get_builtin_curves)(EC_builtin_curve *, size_t) = NULL;
#else
static const long Cryptography_HAS_EC = 1;
#endif
@@ -56,5 +204,6 @@ CONDITIONAL_NAMES = {
"Cryptography_HAS_EC": [
"EC_KEY_new_by_curve_name",
"EC_KEY_free",
+ "EC_get_builtin_curves",
],
}
diff --git a/cryptography/hazmat/bindings/openssl/err.py b/cryptography/hazmat/bindings/openssl/err.py
index ddb60ef7..f2058ad8 100644
--- a/cryptography/hazmat/bindings/openssl/err.py
+++ b/cryptography/hazmat/bindings/openssl/err.py
@@ -151,7 +151,6 @@ static const int EVP_R_CTRL_OPERATION_NOT_IMPLEMENTED;
static const int EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH;
static const int EVP_R_DECODE_ERROR;
static const int EVP_R_DIFFERENT_KEY_TYPES;
-static const int EVP_R_DISABLED_FOR_FIPS;
static const int EVP_R_ENCODE_ERROR;
static const int EVP_R_INITIALIZATION_ERROR;
static const int EVP_R_INPUT_NOT_INITIALIZED;
@@ -266,7 +265,7 @@ static const long Cryptography_HAS_REMOVE_THREAD_STATE = 1;
#else
static const long Cryptography_HAS_REMOVE_THREAD_STATE = 0;
typedef uint32_t CRYPTO_THREADID;
-void (*ERR_remove_thread_state)(const CRYPTO_THREADID *);
+void (*ERR_remove_thread_state)(const CRYPTO_THREADID *) = NULL;
#endif
"""
diff --git a/cryptography/hazmat/bindings/openssl/hmac.py b/cryptography/hazmat/bindings/openssl/hmac.py
index 5f9e0945..4b81c9df 100644
--- a/cryptography/hazmat/bindings/openssl/hmac.py
+++ b/cryptography/hazmat/bindings/openssl/hmac.py
@@ -55,11 +55,11 @@ int Cryptography_HMAC_Update(HMAC_CTX *ctx, const unsigned char *data,
}
int Cryptography_HMAC_Final(HMAC_CTX *ctx, unsigned char *digest,
- unsigned int *digest_len) {
+ unsigned int *outlen) {
#if OPENSSL_VERSION_NUMBER >= 0x010000000
- return HMAC_Final(ctx, digest, digest_len);
+ return HMAC_Final(ctx, digest, outlen);
#else
- HMAC_Final(ctx, digest, digest_len);
+ HMAC_Final(ctx, digest, outlen);
return 1;
#endif
}
diff --git a/cryptography/hazmat/bindings/openssl/rsa.py b/cryptography/hazmat/bindings/openssl/rsa.py
index 359305c6..f895cd02 100644
--- a/cryptography/hazmat/bindings/openssl/rsa.py
+++ b/cryptography/hazmat/bindings/openssl/rsa.py
@@ -37,6 +37,7 @@ static const int RSA_PKCS1_PSS_PADDING;
static const int RSA_F4;
static const int Cryptography_HAS_PSS_PADDING;
+static const int Cryptography_HAS_MGF1_MD;
"""
FUNCTIONS = """
@@ -70,6 +71,7 @@ int RSA_padding_check_PKCS1_OAEP(unsigned char *, int, const unsigned char *,
MACROS = """
int EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX *, int);
int EVP_PKEY_CTX_set_rsa_pss_saltlen(EVP_PKEY_CTX *, int);
+int EVP_PKEY_CTX_set_rsa_mgf1_md(EVP_PKEY_CTX *, EVP_MD *);
"""
CUSTOMIZATIONS = """
@@ -82,6 +84,12 @@ int (*EVP_PKEY_CTX_set_rsa_padding)(EVP_PKEY_CTX *, int) = NULL;
int (*EVP_PKEY_CTX_set_rsa_pss_saltlen)(EVP_PKEY_CTX *, int) = NULL;
static const long RSA_PKCS1_PSS_PADDING = 0;
#endif
+#if OPENSSL_VERSION_NUMBER >= 0x1000100f
+static const long Cryptography_HAS_MGF1_MD = 1;
+#else
+static const long Cryptography_HAS_MGF1_MD = 0;
+int (*EVP_PKEY_CTX_set_rsa_mgf1_md)(EVP_PKEY_CTX *, EVP_MD *) = NULL;
+#endif
"""
CONDITIONAL_NAMES = {
@@ -92,4 +100,7 @@ CONDITIONAL_NAMES = {
"Cryptography_HAS_PSS_PADDING": [
"RSA_PKCS1_PSS_PADDING",
],
+ "Cryptography_HAS_MGF1_MD": [
+ "EVP_PKEY_CTX_set_rsa_mgf1_md",
+ ],
}
diff --git a/cryptography/hazmat/primitives/asymmetric/rsa.py b/cryptography/hazmat/primitives/asymmetric/rsa.py
index 2f9e4247..dfb43340 100644
--- a/cryptography/hazmat/primitives/asymmetric/rsa.py
+++ b/cryptography/hazmat/primitives/asymmetric/rsa.py
@@ -13,21 +13,12 @@
from __future__ import absolute_import, division, print_function
-import sys
-
import six
from cryptography import utils
from cryptography.hazmat.primitives import interfaces
-def _bit_length(x):
- if sys.version_info >= (2, 7):
- return x.bit_length()
- else:
- return len(bin(x)) - (2 + (x <= 0))
-
-
@utils.register_interface(interfaces.RSAPublicKey)
class RSAPublicKey(object):
def __init__(self, public_exponent, modulus):
@@ -49,9 +40,13 @@ class RSAPublicKey(object):
self._public_exponent = public_exponent
self._modulus = modulus
+ def verifier(self, signature, padding, algorithm, backend):
+ return backend.create_rsa_verification_ctx(self, signature, padding,
+ algorithm)
+
@property
def key_size(self):
- return _bit_length(self.modulus)
+ return utils.bit_length(self.modulus)
@property
def public_exponent(self):
@@ -140,7 +135,7 @@ class RSAPrivateKey(object):
@property
def key_size(self):
- return _bit_length(self.modulus)
+ return utils.bit_length(self.modulus)
def public_key(self):
return RSAPublicKey(self.public_exponent, self.modulus)
diff --git a/cryptography/hazmat/primitives/interfaces.py b/cryptography/hazmat/primitives/interfaces.py
index 11696160..3824bcde 100644
--- a/cryptography/hazmat/primitives/interfaces.py
+++ b/cryptography/hazmat/primitives/interfaces.py
@@ -287,6 +287,98 @@ class RSAPublicKey(six.with_metaclass(abc.ABCMeta)):
"""
+class DSAParameters(six.with_metaclass(abc.ABCMeta)):
+ @abc.abstractproperty
+ def modulus(self):
+ """
+ The prime modulus that's used in generating the DSA keypair and used
+ in the DSA signing and verification processes.
+ """
+
+ @abc.abstractproperty
+ def subgroup_order(self):
+ """
+ The subgroup order that's used in generating the DSA keypair
+ by the generator and used in the DSA signing and verification
+ processes.
+ """
+
+ @abc.abstractproperty
+ def generator(self):
+ """
+ The generator that is used in generating the DSA keypair and used
+ in the DSA signing and verification processes.
+ """
+
+ @abc.abstractproperty
+ def p(self):
+ """
+ The prime modulus that's used in generating the DSA keypair and used
+ in the DSA signing and verification processes. Alias for modulus.
+ """
+
+ @abc.abstractproperty
+ def q(self):
+ """
+ The subgroup order that's used in generating the DSA keypair
+ by the generator and used in the DSA signing and verification
+ processes. Alias for subgroup_order.
+ """
+
+ @abc.abstractproperty
+ def g(self):
+ """
+ The generator that is used in generating the DSA keypair and used
+ in the DSA signing and verification processes. Alias for generator.
+ """
+
+
+class DSAPrivateKey(six.with_metaclass(abc.ABCMeta)):
+ @abc.abstractproperty
+ def key_size(self):
+ """
+ The bit length of the prime modulus.
+ """
+
+ @abc.abstractmethod
+ def public_key(self):
+ """
+ The DSAPublicKey associated with this private key.
+ """
+
+ @abc.abstractproperty
+ def x(self):
+ """
+ The private key "x" in the DSA structure.
+ """
+
+ @abc.abstractproperty
+ def y(self):
+ """
+ The public key.
+ """
+
+ @abc.abstractmethod
+ def parameters(self):
+ """
+ The DSAParameters object associated with this private key.
+ """
+
+
+class DSAPublicKey(six.with_metaclass(abc.ABCMeta)):
+ @abc.abstractproperty
+ def y(self):
+ """
+ The public key.
+ """
+
+ @abc.abstractmethod
+ def parameters(self):
+ """
+ The DSAParameters object associated with this public key.
+ """
+
+
class AsymmetricSignatureContext(six.with_metaclass(abc.ABCMeta)):
@abc.abstractmethod
def update(self, data):
diff --git a/cryptography/hazmat/primitives/twofactor/hotp.py b/cryptography/hazmat/primitives/twofactor/hotp.py
index 24f5f465..83260225 100644
--- a/cryptography/hazmat/primitives/twofactor/hotp.py
+++ b/cryptography/hazmat/primitives/twofactor/hotp.py
@@ -17,7 +17,7 @@ import struct
import six
-from cryptography.exceptions import InvalidToken, UnsupportedAlgorithm
+from cryptography.exceptions import InvalidToken
from cryptography.hazmat.primitives import constant_time, hmac
from cryptography.hazmat.primitives.hashes import SHA1, SHA256, SHA512
@@ -27,12 +27,14 @@ class HOTP(object):
if len(key) < 16:
raise ValueError("Key length has to be at least 128 bits.")
+ if not isinstance(length, six.integer_types):
+ raise TypeError("Length parameter must be an integer type")
+
if length < 6 or length > 8:
raise ValueError("Length of HOTP has to be between 6 to 8.")
if not isinstance(algorithm, (SHA1, SHA256, SHA512)):
- raise UnsupportedAlgorithm(
- "Algorithm must be SHA1, SHA256 or SHA512")
+ raise TypeError("Algorithm must be SHA1, SHA256 or SHA512")
self._key = key
self._length = length