diff options
Diffstat (limited to 'cryptography/hazmat')
-rw-r--r-- | cryptography/hazmat/backends/interfaces.py | 23 | ||||
-rw-r--r-- | cryptography/hazmat/backends/multibackend.py | 14 | ||||
-rw-r--r-- | cryptography/hazmat/backends/openssl/backend.py | 73 | ||||
-rw-r--r-- | cryptography/hazmat/bindings/openssl/err.py | 2 | ||||
-rw-r--r-- | cryptography/hazmat/primitives/serialization.py | 6 |
5 files changed, 108 insertions, 10 deletions
diff --git a/cryptography/hazmat/backends/interfaces.py b/cryptography/hazmat/backends/interfaces.py index 264c5afb..55d5cd78 100644 --- a/cryptography/hazmat/backends/interfaces.py +++ b/cryptography/hazmat/backends/interfaces.py @@ -129,6 +129,19 @@ class RSABackend(object): Returns encrypted bytes. """ + @abc.abstractmethod + def rsa_padding_supported(self, padding): + """ + Returns True if the backend supports the given padding options. + """ + + @abc.abstractmethod + def generate_rsa_parameters_supported(self, public_exponent, key_size): + """ + Returns True if the backend supports the given parameters for key + generation. + """ + @six.add_metaclass(abc.ABCMeta) class DSABackend(object): @@ -183,6 +196,16 @@ class TraditionalOpenSSLSerializationBackend(object): @six.add_metaclass(abc.ABCMeta) +class PKCS8SerializationBackend(object): + @abc.abstractmethod + def load_pkcs8_pem_private_key(self, data, password): + """ + Load a private key from PEM encoded data, using password if the data + is encrypted. + """ + + +@six.add_metaclass(abc.ABCMeta) class CMACBackend(object): @abc.abstractmethod def cmac_algorithm_supported(self, algorithm): diff --git a/cryptography/hazmat/backends/multibackend.py b/cryptography/hazmat/backends/multibackend.py index 21d307cf..b4cb6889 100644 --- a/cryptography/hazmat/backends/multibackend.py +++ b/cryptography/hazmat/backends/multibackend.py @@ -132,6 +132,14 @@ class MultiBackend(object): raise UnsupportedAlgorithm("RSA is not supported by the backend.", _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM) + def generate_rsa_parameters_supported(self, public_exponent, key_size): + for b in self._filtered_backends(RSABackend): + return b.generate_rsa_parameters_supported( + public_exponent, key_size + ) + raise UnsupportedAlgorithm("RSA is not supported by the backend.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM) + def create_rsa_signature_ctx(self, private_key, padding, algorithm): for b in self._filtered_backends(RSABackend): return b.create_rsa_signature_ctx(private_key, padding, algorithm) @@ -164,6 +172,12 @@ class MultiBackend(object): raise UnsupportedAlgorithm("RSA is not supported by the backend.", _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM) + def rsa_padding_supported(self, padding): + for b in self._filtered_backends(RSABackend): + return b.rsa_padding_supported(padding) + raise UnsupportedAlgorithm("RSA is not supported by the backend.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM) + def generate_dsa_parameters(self, key_size): for b in self._filtered_backends(DSABackend): return b.generate_dsa_parameters(key_size) diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py index 5d9626d0..a5f21787 100644 --- a/cryptography/hazmat/backends/openssl/backend.py +++ b/cryptography/hazmat/backends/openssl/backend.py @@ -26,7 +26,8 @@ from cryptography.exceptions import ( ) from cryptography.hazmat.backends.interfaces import ( CMACBackend, CipherBackend, DSABackend, HMACBackend, HashBackend, - PBKDF2HMACBackend, RSABackend, TraditionalOpenSSLSerializationBackend + PBKDF2HMACBackend, PKCS8SerializationBackend, RSABackend, + TraditionalOpenSSLSerializationBackend ) from cryptography.hazmat.bindings.openssl.binding import Binding from cryptography.hazmat.primitives import hashes, interfaces @@ -55,6 +56,7 @@ _OpenSSLError = collections.namedtuple("_OpenSSLError", @utils.register_interface(PBKDF2HMACBackend) @utils.register_interface(RSABackend) @utils.register_interface(TraditionalOpenSSLSerializationBackend) +@utils.register_interface(PKCS8SerializationBackend) class Backend(object): """ OpenSSL API binding interfaces. @@ -378,6 +380,10 @@ class Backend(object): return self._rsa_cdata_to_private_key(ctx) + def generate_rsa_parameters_supported(self, public_exponent, key_size): + return (public_exponent >= 3 and public_exponent & 1 != 0 and + key_size >= 512) + def _new_evp_pkey(self): evp_pkey = self._lib.EVP_PKEY_new() assert evp_pkey != self._ffi.NULL @@ -534,6 +540,16 @@ class Backend(object): else: return isinstance(algorithm, hashes.SHA1) + def rsa_padding_supported(self, padding): + if isinstance(padding, PKCS1v15): + return True + elif isinstance(padding, PSS) and isinstance(padding._mgf, MGF1): + return self.mgf1_hash_supported(padding._mgf._algorithm) + elif isinstance(padding, OAEP) and isinstance(padding._mgf, MGF1): + return isinstance(padding._mgf._algorithm, hashes.SHA1) + else: + return False + def generate_dsa_parameters(self, key_size): if key_size not in (1024, 2048, 3072): raise ValueError( @@ -763,6 +779,12 @@ class Backend(object): return _CMACContext(self, algorithm) def load_traditional_openssl_pem_private_key(self, data, password): + # OpenSSLs API for loading PKCS#8 certs can also load the traditional + # format so we just use that for both of them. + + return self.load_pkcs8_pem_private_key(data, password) + + def load_pkcs8_pem_private_key(self, data, password): mem_bio = self._bytes_to_bio(data) password_callback, password_func = self._pem_password_cb(password) @@ -779,10 +801,18 @@ class Backend(object): if not errors: raise ValueError("Could not unserialize key data.") - if errors[0][1:] == ( - self._lib.ERR_LIB_PEM, - self._lib.PEM_F_PEM_DO_HEADER, - self._lib.PEM_R_BAD_PASSWORD_READ + if ( + errors[0][1:] == ( + self._lib.ERR_LIB_PEM, + self._lib.PEM_F_PEM_DO_HEADER, + self._lib.PEM_R_BAD_PASSWORD_READ + ) + ) or ( + errors[0][1:] == ( + self._lib.ERR_LIB_PEM, + self._lib.PEM_F_PEM_READ_BIO_PRIVATEKEY, + self._lib.PEM_R_BAD_PASSWORD_READ + ) ): assert not password raise TypeError( @@ -797,13 +827,36 @@ class Backend(object): "Bad decrypt. Incorrect password?" ) - elif errors[0][1:] == ( - self._lib.ERR_LIB_PEM, - self._lib.PEM_F_PEM_GET_EVP_CIPHER_INFO, - self._lib.PEM_R_UNSUPPORTED_ENCRYPTION + elif errors[0][1:] in ( + ( + self._lib.ERR_LIB_PEM, + self._lib.PEM_F_PEM_GET_EVP_CIPHER_INFO, + self._lib.PEM_R_UNSUPPORTED_ENCRYPTION + ), + + ( + self._lib.ERR_LIB_EVP, + self._lib.EVP_F_EVP_PBE_CIPHERINIT, + self._lib.EVP_R_UNKNOWN_PBE_ALGORITHM + ) ): raise UnsupportedAlgorithm( - "PEM data is encrypted with an unsupported cipher") + "PEM data is encrypted with an unsupported cipher", + _Reasons.UNSUPPORTED_CIPHER + ) + + elif any( + error[1:] == ( + self._lib.ERR_LIB_EVP, + self._lib.EVP_F_EVP_PKCS82PKEY, + self._lib.EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM + ) + for error in errors + ): + raise UnsupportedAlgorithm( + "Unsupported public key algorithm.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM + ) else: assert errors[0][1] in ( diff --git a/cryptography/hazmat/bindings/openssl/err.py b/cryptography/hazmat/bindings/openssl/err.py index f6456d66..f685e494 100644 --- a/cryptography/hazmat/bindings/openssl/err.py +++ b/cryptography/hazmat/bindings/openssl/err.py @@ -135,6 +135,7 @@ static const int EVP_F_PKCS5_V2_PBE_KEYIVGEN; static const int EVP_F_PKCS8_SET_BROKEN; static const int EVP_F_RC2_MAGIC_TO_METH; 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; @@ -168,6 +169,7 @@ static const int EVP_R_UNSUPPORTED_CIPHER; static const int EVP_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION; static const int EVP_R_UNSUPPORTED_KEYLENGTH; static const int EVP_R_UNSUPPORTED_SALT_TYPE; +static const int EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM; static const int EVP_R_WRONG_FINAL_BLOCK_LENGTH; static const int EVP_R_WRONG_PUBLIC_KEY_TYPE; diff --git a/cryptography/hazmat/primitives/serialization.py b/cryptography/hazmat/primitives/serialization.py index 38937508..ed73c4c4 100644 --- a/cryptography/hazmat/primitives/serialization.py +++ b/cryptography/hazmat/primitives/serialization.py @@ -18,3 +18,9 @@ def load_pem_traditional_openssl_private_key(data, password, backend): return backend.load_traditional_openssl_pem_private_key( data, password ) + + +def load_pem_pkcs8_private_key(data, password, backend): + return backend.load_pkcs8_pem_private_key( + data, password + ) |