diff options
author | Paul Kehrer <paul.l.kehrer@gmail.com> | 2015-01-04 15:55:22 -0600 |
---|---|---|
committer | Paul Kehrer <paul.l.kehrer@gmail.com> | 2015-02-19 18:13:29 -0600 |
commit | 99a249df88dcddb368c0f682a6aa8fc2bb1a279f (patch) | |
tree | 73979b50ef00c2cb089d57d64d31529b04fcbb45 /src | |
parent | fa35ef8ae841708e31e23a43167fff3fd88ae969 (diff) | |
download | cryptography-99a249df88dcddb368c0f682a6aa8fc2bb1a279f.tar.gz cryptography-99a249df88dcddb368c0f682a6aa8fc2bb1a279f.tar.bz2 cryptography-99a249df88dcddb368c0f682a6aa8fc2bb1a279f.zip |
support DER public and private key loading in the openssl backend
Diffstat (limited to 'src')
-rw-r--r-- | src/cryptography/hazmat/backends/openssl/backend.py | 74 | ||||
-rw-r--r-- | src/cryptography/hazmat/primitives/serialization.py | 8 |
2 files changed, 79 insertions, 3 deletions
diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 8441e891..3e95c88b 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -15,9 +15,9 @@ from cryptography.exceptions import ( InternalError, UnsupportedAlgorithm, _Reasons ) from cryptography.hazmat.backends.interfaces import ( - CMACBackend, CipherBackend, DSABackend, EllipticCurveBackend, HMACBackend, - HashBackend, PBKDF2HMACBackend, PEMSerializationBackend, RSABackend, - X509Backend + CMACBackend, CipherBackend, DERSerializationBackend, DSABackend, + EllipticCurveBackend, HMACBackend, HashBackend, PBKDF2HMACBackend, + PEMSerializationBackend, RSABackend, X509Backend ) from cryptography.hazmat.backends.openssl.ciphers import ( _AESCTRCipherContext, _CipherContext @@ -56,6 +56,7 @@ _OpenSSLError = collections.namedtuple("_OpenSSLError", @utils.register_interface(CipherBackend) @utils.register_interface(CMACBackend) +@utils.register_interface(DERSerializationBackend) @utils.register_interface(DSABackend) @utils.register_interface(EllipticCurveBackend) @utils.register_interface(HashBackend) @@ -696,6 +697,73 @@ class Backend(object): None, ) + def load_der_private_key(self, data, password): + # OpenSSL has a function called d2i_AutoPrivateKey that can simplify + # this. Unfortunately it doesn't properly support PKCS8 on OpenSSL + # 0.9.8 so we can't use it. Instead we sequentially try to load it 3 + # different ways. First we'll try to load it as a traditional key + key = self._evp_pkey_from_der_traditional_key(data, password) + if not key: + # Okay so it's not a traditional key. Let's try + # PKCS8 unencrypted. OpenSSL 0.9.8 can't load unencrypted + # PKCS8 keys using d2i_PKCS8PrivateKey_bio so we do this instead. + key = self._evp_pkey_from_der_unencrypted_pkcs8(data, password) + + if key: + return self._evp_pkey_to_private_key(key) + else: + # Finally we try to load it with the method that handles encrypted + # PKCS8 properly. + return self._load_key( + self._lib.d2i_PKCS8PrivateKey_bio, + self._evp_pkey_to_private_key, + data, + password, + ) + + def _evp_pkey_from_der_traditional_key(self, data, password): + mem_bio = self._bytes_to_bio(data) + key = self._lib.d2i_PrivateKey_bio(mem_bio.bio, self._ffi.NULL) + if key != self._ffi.NULL: + if password is not None: + raise TypeError( + "Password was given but private key is not encrypted." + ) + + key = self._ffi.gc(key, self._lib.EVP_PKEY_free) + return key + else: + self._consume_errors() + return None + + def _evp_pkey_from_der_unencrypted_pkcs8(self, data, password): + mem_bio = self._bytes_to_bio(data) + info = self._lib.d2i_PKCS8_PRIV_KEY_INFO_bio( + mem_bio.bio, self._ffi.NULL + ) + if info != self._ffi.NULL: + key = self._lib.EVP_PKCS82PKEY(info) + assert key != self._ffi.NULL + if password is not None: + raise TypeError( + "Password was given but private key is not encrypted." + ) + key = self._ffi.gc(key, self._lib.EVP_PKEY_free) + return key + else: + self._consume_errors() + return None + + def load_der_public_key(self, data): + mem_bio = self._bytes_to_bio(data) + evp_pkey = self._lib.d2i_PUBKEY_bio(mem_bio.bio, self._ffi.NULL) + if evp_pkey == self._ffi.NULL: + self._consume_errors() + raise ValueError("Could not unserialize key data.") + + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + return self._evp_pkey_to_public_key(evp_pkey) + def load_pem_x509_certificate(self, data): mem_bio = self._bytes_to_bio(data) x509 = self._lib.PEM_read_bio_X509( diff --git a/src/cryptography/hazmat/primitives/serialization.py b/src/cryptography/hazmat/primitives/serialization.py index dad419fe..0f9506e1 100644 --- a/src/cryptography/hazmat/primitives/serialization.py +++ b/src/cryptography/hazmat/primitives/serialization.py @@ -21,6 +21,14 @@ def load_pem_public_key(data, backend): return backend.load_pem_public_key(data) +def load_der_private_key(data, password, backend): + return backend.load_der_private_key(data, password) + + +def load_der_public_key(data, backend): + return backend.load_der_public_key(data) + + def load_ssh_public_key(data, backend): key_parts = data.split(b' ') |