diff options
Diffstat (limited to 'cryptography/hazmat')
-rw-r--r-- | cryptography/hazmat/backends/__init__.py | 4 | ||||
-rw-r--r-- | cryptography/hazmat/backends/multibackend.py | 7 | ||||
-rw-r--r-- | cryptography/hazmat/backends/openssl/backend.py | 211 | ||||
-rw-r--r-- | cryptography/hazmat/bindings/openssl/dsa.py | 2 | ||||
-rw-r--r-- | cryptography/hazmat/bindings/openssl/ec.py | 149 | ||||
-rw-r--r-- | cryptography/hazmat/bindings/openssl/err.py | 3 | ||||
-rw-r--r-- | cryptography/hazmat/bindings/openssl/hmac.py | 6 | ||||
-rw-r--r-- | cryptography/hazmat/bindings/openssl/rsa.py | 11 | ||||
-rw-r--r-- | cryptography/hazmat/primitives/asymmetric/rsa.py | 17 | ||||
-rw-r--r-- | cryptography/hazmat/primitives/interfaces.py | 92 | ||||
-rw-r--r-- | cryptography/hazmat/primitives/twofactor/hotp.py | 8 |
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 |