aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Kehrer <paul.l.kehrer@gmail.com>2015-01-04 15:55:22 -0600
committerPaul Kehrer <paul.l.kehrer@gmail.com>2015-02-19 18:13:29 -0600
commit99a249df88dcddb368c0f682a6aa8fc2bb1a279f (patch)
tree73979b50ef00c2cb089d57d64d31529b04fcbb45 /src
parentfa35ef8ae841708e31e23a43167fff3fd88ae969 (diff)
downloadcryptography-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.py74
-rw-r--r--src/cryptography/hazmat/primitives/serialization.py8
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' ')