aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Kehrer <paul.l.kehrer@gmail.com>2015-02-21 18:34:00 -0600
committerPaul Kehrer <paul.l.kehrer@gmail.com>2015-02-25 07:49:52 -0600
commitf83e25c81bb186ed8a96d4a569d5068546a24349 (patch)
treea34d97e993351ac1396e8d7481457cee21118171 /src
parent36394237388d19eacd3a80e79bf8c459cb234700 (diff)
downloadcryptography-f83e25c81bb186ed8a96d4a569d5068546a24349.tar.gz
cryptography-f83e25c81bb186ed8a96d4a569d5068546a24349.tar.bz2
cryptography-f83e25c81bb186ed8a96d4a569d5068546a24349.zip
Support for traditional OpenSSL and PKCS8 RSA private key serialization
Diffstat (limited to 'src')
-rw-r--r--src/cryptography/hazmat/backends/openssl/rsa.py61
-rw-r--r--src/cryptography/hazmat/primitives/asymmetric/rsa.py12
-rw-r--r--src/cryptography/hazmat/primitives/serialization.py47
-rw-r--r--src/cryptography/utils.py1
4 files changed, 118 insertions, 3 deletions
diff --git a/src/cryptography/hazmat/backends/openssl/rsa.py b/src/cryptography/hazmat/backends/openssl/rsa.py
index 00ddcda3..1357889f 100644
--- a/src/cryptography/hazmat/backends/openssl/rsa.py
+++ b/src/cryptography/hazmat/backends/openssl/rsa.py
@@ -17,8 +17,13 @@ from cryptography.hazmat.primitives.asymmetric import (
from cryptography.hazmat.primitives.asymmetric.padding import (
AsymmetricPadding, MGF1, OAEP, PKCS1v15, PSS
)
-from cryptography.hazmat.primitives.interfaces import (
- RSAPrivateKeyWithNumbers, RSAPublicKeyWithNumbers
+from cryptography.hazmat.primitives.asymmetric.rsa import (
+ RSAPrivateKeyWithNumbers, RSAPrivateKeyWithSerialization,
+ RSAPublicKeyWithNumbers
+)
+from cryptography.hazmat.primitives.serialization import (
+ BestAvailable, Encoding, KeySerializationEncryption, NoEncryption, PKCS8,
+ TraditionalOpenSSL
)
@@ -507,6 +512,7 @@ class _RSAVerificationContext(object):
@utils.register_interface(RSAPrivateKeyWithNumbers)
+@utils.register_interface(RSAPrivateKeyWithSerialization)
class _RSAPrivateKey(object):
def __init__(self, backend, rsa_cdata):
self._backend = backend
@@ -559,6 +565,57 @@ class _RSAPrivateKey(object):
)
)
+ def dump(self, serializer, encryption_algorithm):
+ if isinstance(serializer, PKCS8):
+ write_bio = self._backend._lib.PEM_write_bio_PKCS8PrivateKey
+ key = self._evp_pkey
+ elif isinstance(serializer, TraditionalOpenSSL):
+ write_bio = self._backend._lib.PEM_write_bio_RSAPrivateKey
+ key = self._rsa_cdata
+ else:
+ raise TypeError("serializer must be PKCS8 or TraditionalOpenSSL")
+
+ if serializer.encoding != Encoding.PEM:
+ raise ValueError("Only PEM encoding is supported by this backend")
+
+ if not isinstance(encryption_algorithm, KeySerializationEncryption):
+ raise TypeError(
+ "Encryption algorithm must be a KeySerializationEncryption "
+ "instance"
+ )
+
+ if isinstance(encryption_algorithm, NoEncryption):
+ password = b""
+ passlen = 0
+ evp_cipher = self._backend._ffi.NULL
+ elif isinstance(encryption_algorithm, BestAvailable):
+ # This is a curated value that we will update over time.
+ evp_cipher = self._backend._lib.EVP_get_cipherbyname(
+ b"aes-256-cbc"
+ )
+ password = encryption_algorithm.password
+ passlen = len(password)
+ if passlen > 1023:
+ raise ValueError(
+ "Passwords longer than 1023 bytes are not supported by "
+ "this backend"
+ )
+ else:
+ raise ValueError("Unsupported encryption type")
+
+ bio = self._backend._create_mem_bio()
+ res = write_bio(
+ bio,
+ key,
+ evp_cipher,
+ password,
+ passlen,
+ self._backend._ffi.NULL,
+ self._backend._ffi.NULL
+ )
+ assert res == 1
+ return self._backend._read_mem_bio(bio)
+
@utils.register_interface(RSAPublicKeyWithNumbers)
class _RSAPublicKey(object):
diff --git a/src/cryptography/hazmat/primitives/asymmetric/rsa.py b/src/cryptography/hazmat/primitives/asymmetric/rsa.py
index 332ad2c3..e994a9cc 100644
--- a/src/cryptography/hazmat/primitives/asymmetric/rsa.py
+++ b/src/cryptography/hazmat/primitives/asymmetric/rsa.py
@@ -42,13 +42,23 @@ class RSAPrivateKey(object):
@six.add_metaclass(abc.ABCMeta)
-class RSAPrivateKeyWithNumbers(RSAPrivateKey):
+class RSAPrivateKeyWithSerialization(RSAPrivateKey):
@abc.abstractmethod
def private_numbers(self):
"""
Returns an RSAPrivateNumbers.
"""
+ @abc.abstractmethod
+ def dump(self, serializer, encryption_algorithm):
+ """
+ Returns the PEM encoded key.
+ """
+
+
+# DeprecatedIn08
+RSAPrivateKeyWithNumbers = RSAPrivateKeyWithSerialization
+
@six.add_metaclass(abc.ABCMeta)
class RSAPublicKey(object):
diff --git a/src/cryptography/hazmat/primitives/serialization.py b/src/cryptography/hazmat/primitives/serialization.py
index 0f9506e1..9bfbc6b7 100644
--- a/src/cryptography/hazmat/primitives/serialization.py
+++ b/src/cryptography/hazmat/primitives/serialization.py
@@ -4,11 +4,14 @@
from __future__ import absolute_import, division, print_function
+import abc
import base64
import struct
+from enum import Enum
import six
+from cryptography import utils
from cryptography.exceptions import UnsupportedAlgorithm
from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa
@@ -164,3 +167,47 @@ else:
data = data[4:]
return result
+
+
+class Encoding(Enum):
+ PEM = "PEM"
+ DER = "DER"
+
+
+class PKCS8(object):
+ def __init__(self, encoding):
+ if not isinstance(encoding, Encoding):
+ raise TypeError(
+ "Encoding must be an element from the Encoding enum"
+ )
+
+ self.encoding = encoding
+
+
+class TraditionalOpenSSL(object):
+ def __init__(self, encoding):
+ if not isinstance(encoding, Encoding):
+ raise TypeError(
+ "Encoding must be an element from the Encoding enum"
+ )
+
+ self.encoding = encoding
+
+
+@six.add_metaclass(abc.ABCMeta)
+class KeySerializationEncryption(object):
+ pass
+
+
+@utils.register_interface(KeySerializationEncryption)
+class BestAvailable(object):
+ def __init__(self, password):
+ if not isinstance(password, bytes) or len(password) == 0:
+ raise ValueError("Password must be 1 or more bytes.")
+
+ self.password = password
+
+
+@utils.register_interface(KeySerializationEncryption)
+class NoEncryption(object):
+ pass
diff --git a/src/cryptography/utils.py b/src/cryptography/utils.py
index 78dcc1ca..77b6d253 100644
--- a/src/cryptography/utils.py
+++ b/src/cryptography/utils.py
@@ -12,6 +12,7 @@ import warnings
# DeprecatedIn07 objects exist. This comment exists to remind developers to
# look for them when it's time for the ninth release cycle deprecation dance.
+# DeprecatedIn08 objects also exist.
DeprecatedIn08 = PendingDeprecationWarning