From a3204baf9bcfd2288d049c4f27e75c535b4397ed Mon Sep 17 00:00:00 2001 From: michael-hart Date: Tue, 23 Sep 2014 23:10:32 +0100 Subject: Part 1 of rebase, with corrections for pep8 --- cryptography/hazmat/backends/interfaces.py | 6 ++++ cryptography/hazmat/backends/multibackend.py | 11 +++++-- cryptography/hazmat/backends/openssl/backend.py | 29 +++++++++++++++++ cryptography/hazmat/primitives/serialization.py | 4 +++ .../hazmat/primitives/asymmetric/serialization.rst | 21 +++++++++++++ tests/hazmat/primitives/test_serialization.py | 36 +++++++++++++++++++++- .../asymmetric/PEM_Serialization/README.txt | 4 +-- 7 files changed, 106 insertions(+), 5 deletions(-) diff --git a/cryptography/hazmat/backends/interfaces.py b/cryptography/hazmat/backends/interfaces.py index 3761e254..187d7fc5 100644 --- a/cryptography/hazmat/backends/interfaces.py +++ b/cryptography/hazmat/backends/interfaces.py @@ -281,6 +281,12 @@ class PEMSerializationBackend(object): if the data is encrypted. """ + @abc.abstractmethod + def load_pem_public_key(self, data, password): + """ + Loads a public key from PEM encoded data. + """ + @six.add_metaclass(abc.ABCMeta) class TraditionalOpenSSLSerializationBackend(object): diff --git a/cryptography/hazmat/backends/multibackend.py b/cryptography/hazmat/backends/multibackend.py index 221f1a1e..925e762d 100644 --- a/cryptography/hazmat/backends/multibackend.py +++ b/cryptography/hazmat/backends/multibackend.py @@ -187,14 +187,12 @@ class MultiBackend(object): def load_rsa_private_numbers(self, numbers): for b in self._filtered_backends(RSABackend): return b.load_rsa_private_numbers(numbers) - raise UnsupportedAlgorithm("RSA is not supported by the backend", _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM) def load_rsa_public_numbers(self, numbers): for b in self._filtered_backends(RSABackend): return b.load_rsa_public_numbers(numbers) - raise UnsupportedAlgorithm("RSA is not supported by the backend", _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM) @@ -329,6 +327,15 @@ class MultiBackend(object): _Reasons.UNSUPPORTED_SERIALIZATION ) + def load_pem_public_key(self, data): + for b in self._filtered_backends(PEMSerializationBackend): + return b.load_pem_public_key(data) + + raise UnsupportedAlgorithm( + "This backend does not support this key serialization.", + _Reasons.UNSUPPORTED_SERIALIZATION + ) + def load_pkcs8_pem_private_key(self, data, password): for b in self._filtered_backends(PKCS8SerializationBackend): return b.load_pkcs8_pem_private_key(data, password) diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py index cb988ac9..dd50fd3b 100644 --- a/cryptography/hazmat/backends/openssl/backend.py +++ b/cryptography/hazmat/backends/openssl/backend.py @@ -483,6 +483,27 @@ class Backend(object): else: raise UnsupportedAlgorithm("Unsupported key type.") + def _evp_pkey_to_public_key(self, evp_pkey): + """ + Return the appropriate type of PublicKey given an evp_pkey cdata + pointer. + """ + + type = evp_pkey.type + + if type == self._lib.EVP_PKEY_RSA: + rsa_cdata = self._lib.EVP_PKEY_get1_RSA(evp_pkey) + assert rsa_cdata != self._ffi.NULL + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + return _RSAPublicKey(self, rsa_cdata) + elif type == self._lib.EVP_PKEY_DSA: + dsa_cdata = self._lib.EVP_PKEY_get1_DSA(evp_pkey) + assert dsa_cdata != self._ffi.NULL + dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) + return _DSAPublicKey(self, dsa_cdata) + else: + raise UnsupportedAlgorithm("Unsupported key type.") + def _pem_password_cb(self, password): """ Generate a pem_password_cb function pointer that copied the password to @@ -787,6 +808,14 @@ class Backend(object): password, ) + def load_pem_public_key(self, data): + return self._load_key( + self._lib.PEM_read_bio_PUBKEY, + self._evp_pkey_to_public_key, + data, + None, + ) + def load_traditional_openssl_pem_private_key(self, data, password): warnings.warn( "load_traditional_openssl_pem_private_key is deprecated and will " diff --git a/cryptography/hazmat/primitives/serialization.py b/cryptography/hazmat/primitives/serialization.py index cf1ca8ec..0fb560e0 100644 --- a/cryptography/hazmat/primitives/serialization.py +++ b/cryptography/hazmat/primitives/serialization.py @@ -44,3 +44,7 @@ def load_pem_pkcs8_private_key(data, password, backend): def load_pem_private_key(data, password, backend): return backend.load_pem_private_key(data, password) + + +def load_pem_public_key(data, backend): + return backend.load_pem_public_key(data) diff --git a/docs/hazmat/primitives/asymmetric/serialization.rst b/docs/hazmat/primitives/asymmetric/serialization.rst index 7a953d9b..18b89c44 100644 --- a/docs/hazmat/primitives/asymmetric/serialization.rst +++ b/docs/hazmat/primitives/asymmetric/serialization.rst @@ -92,6 +92,27 @@ all begin with ``-----BEGIN {format}-----`` and end with ``-----END is not supported by the backend or if the key is encrypted with a symmetric cipher that is not supported by the backend. +.. function:: load_pem_public_key(data, backend): + + .. versionadded:: 0.6 + + Deserialize a public key from PEM encoded data to one of the supported + asymmetric public key types. + + :param bytes data: The PEM encoded key data. + + :param backend: A + :class:`~cryptography.hazmat.backends.interfaces.PEMSerializationBackend` + provider. + + :returns: A new instance of a public key. + + :raises ValueError: If the PEM data could not be decrypted or if its + structure could not be decoded successfully. + + :raises UnsupportedAlgorithm: If the serialized key is of a type that + is not supported by the backend. + PKCS #8 Format ~~~~~~~~~~~~~~ diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py index d369e8f4..4bc7e811 100644 --- a/tests/hazmat/primitives/test_serialization.py +++ b/tests/hazmat/primitives/test_serialization.py @@ -24,6 +24,7 @@ from cryptography.hazmat.primitives import interfaces from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives.serialization import ( load_pem_pkcs8_private_key, load_pem_private_key, + load_pem_public_key, load_pem_traditional_openssl_private_key ) @@ -38,7 +39,7 @@ class TestPEMSerialization(object): def test_load_pem_rsa_private_key(self, backend): key = load_vectors_from_file( os.path.join( - "asymmetric", "Traditional_OpenSSL_Serialization", "key1.pem"), + "asymmetric", "PEM_Serialization", "rsa_private_key.pem"), lambda pemfile: load_pem_private_key( pemfile.read().encode(), b"123456", backend ) @@ -49,6 +50,17 @@ class TestPEMSerialization(object): if isinstance(key, interfaces.RSAPrivateKeyWithNumbers): _check_rsa_private_numbers(key.private_numbers()) + def test_load_dsa_private_key(self, backend): + key = load_vectors_from_file( + os.path.join( + "asymmetric", "PEM_Serialization", "dsa_private_key.pem"), + lambda pemfile: load_pem_private_key( + pemfile.read().encode(), b"123456", backend + ) + ) + assert key + assert isinstance(key, interfaces.DSAPrivateKey) + @pytest.mark.parametrize( ("key_file", "password"), [ @@ -70,6 +82,28 @@ class TestPEMSerialization(object): assert key assert isinstance(key, interfaces.EllipticCurvePrivateKey) + def test_load_pem_rsa_public_key(self, backend): + key = load_vectors_from_file( + os.path.join( + "asymmetric", "PEM_Serialization", "rsa_public_key.pem"), + lambda pemfile: load_pem_public_key( + pemfile.read().encode(), backend + ) + ) + assert key + assert isinstance(key, interfaces.RSAPublicKey) + + def test_load_pem_dsa_public_key(self, backend): + key = load_vectors_from_file( + os.path.join( + "asymmetric", "PEM_Serialization", "dsa_public_key.pem"), + lambda pemfile: load_pem_public_key( + pemfile.read().encode(), backend + ) + ) + assert key + assert isinstance(key, interfaces.DSAPublicKey) + @pytest.mark.traditional_openssl_serialization class TestTraditionalOpenSSLSerialization(object): diff --git a/vectors/cryptography_vectors/asymmetric/PEM_Serialization/README.txt b/vectors/cryptography_vectors/asymmetric/PEM_Serialization/README.txt index 6963d2b5..865fbc9e 100644 --- a/vectors/cryptography_vectors/asymmetric/PEM_Serialization/README.txt +++ b/vectors/cryptography_vectors/asymmetric/PEM_Serialization/README.txt @@ -3,13 +3,13 @@ Example test files for PEM Serialization Backend tests Contains 1. ec_private_key.pem - Contains an Elliptic Curve key generated using OpenSSL, from the curve secp256r1. -2. ec_private_key_encrypted.pem - Contains the same Elliptic Curve key as ec_private_key.pem, except that +2. ec_private_key_encrypted.pem - Contains the same Elliptic Curve key as ec_private_key.pem, except that it is encrypted with AES-256 with the password "123456". 3. ec_public_key.pem - Contains the public key corresponding to ec_private_key.pem, generated using OpenSSL. 4. rsa_private_key.pem - Contains an RSA 2048 bit key generated using OpenSSL, protected by the secret "123456" with DES3 encryption. 5. rsa_public_key.pem - Contains an RSA 2048 bit public generated using OpenSSL from rsa_private_key.pem. 6. dsaparam.pem - Contains 2048-bit DSA parameters generated using OpenSSL; contains no keys. -7. dsa_private_key.pem - Contains a DSA 2048 bit key generated using OpenSSL from the parameters in +7. dsa_private_key.pem - Contains a DSA 2048 bit key generated using OpenSSL from the parameters in dsaparam.pem, protected by the secret "123456" with DES3 encryption. 8. dsa_public_key.pem - Contains a DSA 2048 bit key generated using OpenSSL from dsa_private_key.pem. \ No newline at end of file -- cgit v1.2.3 From cd76c42245efd4dd4c779db28fde7de467493e13 Mon Sep 17 00:00:00 2001 From: michael-hart Date: Fri, 26 Sep 2014 00:32:25 +0100 Subject: Added all changes lost in merge reset --- cryptography/hazmat/backends/interfaces.py | 4 +-- docs/hazmat/backends/interfaces.rst | 6 +++++ tests/hazmat/backends/test_multibackend.py | 6 +++++ tests/hazmat/backends/test_openssl.py | 2 ++ tests/hazmat/primitives/test_serialization.py | 37 +++++++++++++++++++++++---- 5 files changed, 48 insertions(+), 7 deletions(-) diff --git a/cryptography/hazmat/backends/interfaces.py b/cryptography/hazmat/backends/interfaces.py index 187d7fc5..dc720ad3 100644 --- a/cryptography/hazmat/backends/interfaces.py +++ b/cryptography/hazmat/backends/interfaces.py @@ -282,7 +282,7 @@ class PEMSerializationBackend(object): """ @abc.abstractmethod - def load_pem_public_key(self, data, password): + def load_pem_public_key(self, data): """ Loads a public key from PEM encoded data. """ @@ -303,6 +303,6 @@ 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 + Load a private key from PKCS8 encoded data, using password if the data is encrypted. """ diff --git a/docs/hazmat/backends/interfaces.rst b/docs/hazmat/backends/interfaces.rst index f8341d11..e8e1bac2 100644 --- a/docs/hazmat/backends/interfaces.rst +++ b/docs/hazmat/backends/interfaces.rst @@ -595,6 +595,12 @@ A specific ``backend`` may provide one or more of these interfaces. :raises cryptography.exceptions.UnsupportedAlgorithm: If the data is encrypted with an unsupported algorithm. + .. method:: load_pem_public_key(data) + + :param bytes data: PEM data to load. + :return: A new instance of the appropriate type of public key serialized data contains. + :raises ValueError: If the data could not be deserialized. + .. class:: TraditionalOpenSSLSerializationBackend .. versionadded:: 0.3 diff --git a/tests/hazmat/backends/test_multibackend.py b/tests/hazmat/backends/test_multibackend.py index 655acc44..e4a05aae 100644 --- a/tests/hazmat/backends/test_multibackend.py +++ b/tests/hazmat/backends/test_multibackend.py @@ -217,6 +217,9 @@ class DummyPEMSerializationBackend(object): def load_pem_private_key(self, data, password): pass + def load_pem_public_key(self, data): + pass + class TestMultiBackend(object): def test_ciphers(self): @@ -532,7 +535,10 @@ class TestMultiBackend(object): backend = MultiBackend([DummyPEMSerializationBackend()]) backend.load_pem_private_key(b"keydata", None) + backend.load_pem_public_key(b"keydata") backend = MultiBackend([]) with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_SERIALIZATION): backend.load_pem_private_key(b"keydata", None) + with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_SERIALIZATION): + backend.load_pem_public_key(b"keydata") diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py index cf70f109..d4c5e2e7 100644 --- a/tests/hazmat/backends/test_openssl.py +++ b/tests/hazmat/backends/test_openssl.py @@ -473,6 +473,8 @@ class TestOpenSSLSerialisationWithOpenSSL(object): key = pretend.stub(type="unsupported") with raises_unsupported_algorithm(None): backend._evp_pkey_to_private_key(key) + with raises_unsupported_algorithm(None): + backend._evp_pkey_to_public_key(key) def test_very_long_pem_serialization_password(self): password = "x" * 1024 diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py index 4bc7e811..2ee096be 100644 --- a/tests/hazmat/primitives/test_serialization.py +++ b/tests/hazmat/primitives/test_serialization.py @@ -82,21 +82,40 @@ class TestPEMSerialization(object): assert key assert isinstance(key, interfaces.EllipticCurvePrivateKey) - def test_load_pem_rsa_public_key(self, backend): - key = load_vectors_from_file( + @pytest.mark.parametrize( + ("key_file"), + [ + os.path.join("asymmetric", "PKCS8", "unenc-rsa-pkcs8.pub.pem"), os.path.join( "asymmetric", "PEM_Serialization", "rsa_public_key.pem"), + ), + ] + ) + def test_load_pem_rsa_public_key(self, key_file, backend): + key = load_vectors_from_file( + key_file, lambda pemfile: load_pem_public_key( pemfile.read().encode(), backend ) ) assert key assert isinstance(key, interfaces.RSAPublicKey) + if isinstance(key, interfaces.RSAPublicKeyWithNumbers): + numbers = key.public_numbers() + assert numbers.e == 65537 - def test_load_pem_dsa_public_key(self, backend): + @pytest.mark.parametrize( + ("key_file"), + [ + os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pub.pem"), + os.path.join( + "asymmetric", "PEM_Serialization", + "dsa_public_key.pem" +), ), + ] + def test_load_pem_dsa_public_key(self, keyfile, backend): key = load_vectors_from_file( - os.path.join( - "asymmetric", "PEM_Serialization", "dsa_public_key.pem"), + keyfile, lambda pemfile: load_pem_public_key( pemfile.read().encode(), backend ) @@ -104,6 +123,14 @@ class TestPEMSerialization(object): assert key assert isinstance(key, interfaces.DSAPublicKey) + def test_load_pem_ec_public_key(self, backend): + key = load_vectors_from_file( + os.path.join("asymmetric", "PEM_Serialization", + "ec_public_key.pem"), + lambda pemfile: load_pem_public_key( + pemfile.read().encode(), backend + ) + ) @pytest.mark.traditional_openssl_serialization class TestTraditionalOpenSSLSerialization(object): -- cgit v1.2.3 From b53fab7d3db4a7b75c0703d3b6f8add69e097bfe Mon Sep 17 00:00:00 2001 From: michael-hart Date: Fri, 26 Sep 2014 01:01:50 +0100 Subject: Corrected tests --- tests/hazmat/backends/test_multibackend.py | 2 +- tests/hazmat/primitives/test_serialization.py | 27 +++++++++------------------ 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/tests/hazmat/backends/test_multibackend.py b/tests/hazmat/backends/test_multibackend.py index e4a05aae..45c12b34 100644 --- a/tests/hazmat/backends/test_multibackend.py +++ b/tests/hazmat/backends/test_multibackend.py @@ -218,7 +218,7 @@ class DummyPEMSerializationBackend(object): pass def load_pem_public_key(self, data): - pass + pass class TestMultiBackend(object): diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py index 2ee096be..7cbd3f71 100644 --- a/tests/hazmat/primitives/test_serialization.py +++ b/tests/hazmat/primitives/test_serialization.py @@ -88,7 +88,6 @@ class TestPEMSerialization(object): os.path.join("asymmetric", "PKCS8", "unenc-rsa-pkcs8.pub.pem"), os.path.join( "asymmetric", "PEM_Serialization", "rsa_public_key.pem"), - ), ] ) def test_load_pem_rsa_public_key(self, key_file, backend): @@ -105,17 +104,17 @@ class TestPEMSerialization(object): assert numbers.e == 65537 @pytest.mark.parametrize( - ("key_file"), - [ - os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pub.pem"), - os.path.join( + ("key_file"), + [ + os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pub.pem"), + os.path.join( "asymmetric", "PEM_Serialization", - "dsa_public_key.pem" -), ), - ] - def test_load_pem_dsa_public_key(self, keyfile, backend): + "dsa_public_key.pem"), + ] + ) + def test_load_pem_dsa_public_key(self, key_file, backend): key = load_vectors_from_file( - keyfile, + key_file, lambda pemfile: load_pem_public_key( pemfile.read().encode(), backend ) @@ -123,14 +122,6 @@ class TestPEMSerialization(object): assert key assert isinstance(key, interfaces.DSAPublicKey) - def test_load_pem_ec_public_key(self, backend): - key = load_vectors_from_file( - os.path.join("asymmetric", "PEM_Serialization", - "ec_public_key.pem"), - lambda pemfile: load_pem_public_key( - pemfile.read().encode(), backend - ) - ) @pytest.mark.traditional_openssl_serialization class TestTraditionalOpenSSLSerialization(object): -- cgit v1.2.3 From b72f0f192146221b0613831e828694fb769834b2 Mon Sep 17 00:00:00 2001 From: michael-hart Date: Tue, 23 Sep 2014 23:10:32 +0100 Subject: Part 1 of rebase, with corrections for pep8 --- cryptography/hazmat/backends/interfaces.py | 6 ++++ cryptography/hazmat/backends/multibackend.py | 11 +++++-- cryptography/hazmat/backends/openssl/backend.py | 29 +++++++++++++++++ cryptography/hazmat/primitives/serialization.py | 4 +++ .../hazmat/primitives/asymmetric/serialization.rst | 21 +++++++++++++ tests/hazmat/primitives/test_serialization.py | 36 +++++++++++++++++++++- .../asymmetric/PEM_Serialization/README.txt | 4 +-- 7 files changed, 106 insertions(+), 5 deletions(-) diff --git a/cryptography/hazmat/backends/interfaces.py b/cryptography/hazmat/backends/interfaces.py index 3761e254..187d7fc5 100644 --- a/cryptography/hazmat/backends/interfaces.py +++ b/cryptography/hazmat/backends/interfaces.py @@ -281,6 +281,12 @@ class PEMSerializationBackend(object): if the data is encrypted. """ + @abc.abstractmethod + def load_pem_public_key(self, data, password): + """ + Loads a public key from PEM encoded data. + """ + @six.add_metaclass(abc.ABCMeta) class TraditionalOpenSSLSerializationBackend(object): diff --git a/cryptography/hazmat/backends/multibackend.py b/cryptography/hazmat/backends/multibackend.py index 221f1a1e..925e762d 100644 --- a/cryptography/hazmat/backends/multibackend.py +++ b/cryptography/hazmat/backends/multibackend.py @@ -187,14 +187,12 @@ class MultiBackend(object): def load_rsa_private_numbers(self, numbers): for b in self._filtered_backends(RSABackend): return b.load_rsa_private_numbers(numbers) - raise UnsupportedAlgorithm("RSA is not supported by the backend", _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM) def load_rsa_public_numbers(self, numbers): for b in self._filtered_backends(RSABackend): return b.load_rsa_public_numbers(numbers) - raise UnsupportedAlgorithm("RSA is not supported by the backend", _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM) @@ -329,6 +327,15 @@ class MultiBackend(object): _Reasons.UNSUPPORTED_SERIALIZATION ) + def load_pem_public_key(self, data): + for b in self._filtered_backends(PEMSerializationBackend): + return b.load_pem_public_key(data) + + raise UnsupportedAlgorithm( + "This backend does not support this key serialization.", + _Reasons.UNSUPPORTED_SERIALIZATION + ) + def load_pkcs8_pem_private_key(self, data, password): for b in self._filtered_backends(PKCS8SerializationBackend): return b.load_pkcs8_pem_private_key(data, password) diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py index cb988ac9..dd50fd3b 100644 --- a/cryptography/hazmat/backends/openssl/backend.py +++ b/cryptography/hazmat/backends/openssl/backend.py @@ -483,6 +483,27 @@ class Backend(object): else: raise UnsupportedAlgorithm("Unsupported key type.") + def _evp_pkey_to_public_key(self, evp_pkey): + """ + Return the appropriate type of PublicKey given an evp_pkey cdata + pointer. + """ + + type = evp_pkey.type + + if type == self._lib.EVP_PKEY_RSA: + rsa_cdata = self._lib.EVP_PKEY_get1_RSA(evp_pkey) + assert rsa_cdata != self._ffi.NULL + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + return _RSAPublicKey(self, rsa_cdata) + elif type == self._lib.EVP_PKEY_DSA: + dsa_cdata = self._lib.EVP_PKEY_get1_DSA(evp_pkey) + assert dsa_cdata != self._ffi.NULL + dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) + return _DSAPublicKey(self, dsa_cdata) + else: + raise UnsupportedAlgorithm("Unsupported key type.") + def _pem_password_cb(self, password): """ Generate a pem_password_cb function pointer that copied the password to @@ -787,6 +808,14 @@ class Backend(object): password, ) + def load_pem_public_key(self, data): + return self._load_key( + self._lib.PEM_read_bio_PUBKEY, + self._evp_pkey_to_public_key, + data, + None, + ) + def load_traditional_openssl_pem_private_key(self, data, password): warnings.warn( "load_traditional_openssl_pem_private_key is deprecated and will " diff --git a/cryptography/hazmat/primitives/serialization.py b/cryptography/hazmat/primitives/serialization.py index cf1ca8ec..0fb560e0 100644 --- a/cryptography/hazmat/primitives/serialization.py +++ b/cryptography/hazmat/primitives/serialization.py @@ -44,3 +44,7 @@ def load_pem_pkcs8_private_key(data, password, backend): def load_pem_private_key(data, password, backend): return backend.load_pem_private_key(data, password) + + +def load_pem_public_key(data, backend): + return backend.load_pem_public_key(data) diff --git a/docs/hazmat/primitives/asymmetric/serialization.rst b/docs/hazmat/primitives/asymmetric/serialization.rst index 7a953d9b..18b89c44 100644 --- a/docs/hazmat/primitives/asymmetric/serialization.rst +++ b/docs/hazmat/primitives/asymmetric/serialization.rst @@ -92,6 +92,27 @@ all begin with ``-----BEGIN {format}-----`` and end with ``-----END is not supported by the backend or if the key is encrypted with a symmetric cipher that is not supported by the backend. +.. function:: load_pem_public_key(data, backend): + + .. versionadded:: 0.6 + + Deserialize a public key from PEM encoded data to one of the supported + asymmetric public key types. + + :param bytes data: The PEM encoded key data. + + :param backend: A + :class:`~cryptography.hazmat.backends.interfaces.PEMSerializationBackend` + provider. + + :returns: A new instance of a public key. + + :raises ValueError: If the PEM data could not be decrypted or if its + structure could not be decoded successfully. + + :raises UnsupportedAlgorithm: If the serialized key is of a type that + is not supported by the backend. + PKCS #8 Format ~~~~~~~~~~~~~~ diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py index d369e8f4..4bc7e811 100644 --- a/tests/hazmat/primitives/test_serialization.py +++ b/tests/hazmat/primitives/test_serialization.py @@ -24,6 +24,7 @@ from cryptography.hazmat.primitives import interfaces from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives.serialization import ( load_pem_pkcs8_private_key, load_pem_private_key, + load_pem_public_key, load_pem_traditional_openssl_private_key ) @@ -38,7 +39,7 @@ class TestPEMSerialization(object): def test_load_pem_rsa_private_key(self, backend): key = load_vectors_from_file( os.path.join( - "asymmetric", "Traditional_OpenSSL_Serialization", "key1.pem"), + "asymmetric", "PEM_Serialization", "rsa_private_key.pem"), lambda pemfile: load_pem_private_key( pemfile.read().encode(), b"123456", backend ) @@ -49,6 +50,17 @@ class TestPEMSerialization(object): if isinstance(key, interfaces.RSAPrivateKeyWithNumbers): _check_rsa_private_numbers(key.private_numbers()) + def test_load_dsa_private_key(self, backend): + key = load_vectors_from_file( + os.path.join( + "asymmetric", "PEM_Serialization", "dsa_private_key.pem"), + lambda pemfile: load_pem_private_key( + pemfile.read().encode(), b"123456", backend + ) + ) + assert key + assert isinstance(key, interfaces.DSAPrivateKey) + @pytest.mark.parametrize( ("key_file", "password"), [ @@ -70,6 +82,28 @@ class TestPEMSerialization(object): assert key assert isinstance(key, interfaces.EllipticCurvePrivateKey) + def test_load_pem_rsa_public_key(self, backend): + key = load_vectors_from_file( + os.path.join( + "asymmetric", "PEM_Serialization", "rsa_public_key.pem"), + lambda pemfile: load_pem_public_key( + pemfile.read().encode(), backend + ) + ) + assert key + assert isinstance(key, interfaces.RSAPublicKey) + + def test_load_pem_dsa_public_key(self, backend): + key = load_vectors_from_file( + os.path.join( + "asymmetric", "PEM_Serialization", "dsa_public_key.pem"), + lambda pemfile: load_pem_public_key( + pemfile.read().encode(), backend + ) + ) + assert key + assert isinstance(key, interfaces.DSAPublicKey) + @pytest.mark.traditional_openssl_serialization class TestTraditionalOpenSSLSerialization(object): diff --git a/vectors/cryptography_vectors/asymmetric/PEM_Serialization/README.txt b/vectors/cryptography_vectors/asymmetric/PEM_Serialization/README.txt index 6963d2b5..865fbc9e 100644 --- a/vectors/cryptography_vectors/asymmetric/PEM_Serialization/README.txt +++ b/vectors/cryptography_vectors/asymmetric/PEM_Serialization/README.txt @@ -3,13 +3,13 @@ Example test files for PEM Serialization Backend tests Contains 1. ec_private_key.pem - Contains an Elliptic Curve key generated using OpenSSL, from the curve secp256r1. -2. ec_private_key_encrypted.pem - Contains the same Elliptic Curve key as ec_private_key.pem, except that +2. ec_private_key_encrypted.pem - Contains the same Elliptic Curve key as ec_private_key.pem, except that it is encrypted with AES-256 with the password "123456". 3. ec_public_key.pem - Contains the public key corresponding to ec_private_key.pem, generated using OpenSSL. 4. rsa_private_key.pem - Contains an RSA 2048 bit key generated using OpenSSL, protected by the secret "123456" with DES3 encryption. 5. rsa_public_key.pem - Contains an RSA 2048 bit public generated using OpenSSL from rsa_private_key.pem. 6. dsaparam.pem - Contains 2048-bit DSA parameters generated using OpenSSL; contains no keys. -7. dsa_private_key.pem - Contains a DSA 2048 bit key generated using OpenSSL from the parameters in +7. dsa_private_key.pem - Contains a DSA 2048 bit key generated using OpenSSL from the parameters in dsaparam.pem, protected by the secret "123456" with DES3 encryption. 8. dsa_public_key.pem - Contains a DSA 2048 bit key generated using OpenSSL from dsa_private_key.pem. \ No newline at end of file -- cgit v1.2.3 From 5e80fcc5765b920dce51b03dda5f090b02cd3ebb Mon Sep 17 00:00:00 2001 From: michael-hart Date: Fri, 26 Sep 2014 00:32:25 +0100 Subject: Added all changes lost in merge reset --- cryptography/hazmat/backends/interfaces.py | 4 +-- docs/hazmat/backends/interfaces.rst | 6 +++++ tests/hazmat/backends/test_multibackend.py | 6 +++++ tests/hazmat/backends/test_openssl.py | 2 ++ tests/hazmat/primitives/test_serialization.py | 37 +++++++++++++++++++++++---- 5 files changed, 48 insertions(+), 7 deletions(-) diff --git a/cryptography/hazmat/backends/interfaces.py b/cryptography/hazmat/backends/interfaces.py index 187d7fc5..dc720ad3 100644 --- a/cryptography/hazmat/backends/interfaces.py +++ b/cryptography/hazmat/backends/interfaces.py @@ -282,7 +282,7 @@ class PEMSerializationBackend(object): """ @abc.abstractmethod - def load_pem_public_key(self, data, password): + def load_pem_public_key(self, data): """ Loads a public key from PEM encoded data. """ @@ -303,6 +303,6 @@ 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 + Load a private key from PKCS8 encoded data, using password if the data is encrypted. """ diff --git a/docs/hazmat/backends/interfaces.rst b/docs/hazmat/backends/interfaces.rst index f8341d11..e8e1bac2 100644 --- a/docs/hazmat/backends/interfaces.rst +++ b/docs/hazmat/backends/interfaces.rst @@ -595,6 +595,12 @@ A specific ``backend`` may provide one or more of these interfaces. :raises cryptography.exceptions.UnsupportedAlgorithm: If the data is encrypted with an unsupported algorithm. + .. method:: load_pem_public_key(data) + + :param bytes data: PEM data to load. + :return: A new instance of the appropriate type of public key serialized data contains. + :raises ValueError: If the data could not be deserialized. + .. class:: TraditionalOpenSSLSerializationBackend .. versionadded:: 0.3 diff --git a/tests/hazmat/backends/test_multibackend.py b/tests/hazmat/backends/test_multibackend.py index 655acc44..e4a05aae 100644 --- a/tests/hazmat/backends/test_multibackend.py +++ b/tests/hazmat/backends/test_multibackend.py @@ -217,6 +217,9 @@ class DummyPEMSerializationBackend(object): def load_pem_private_key(self, data, password): pass + def load_pem_public_key(self, data): + pass + class TestMultiBackend(object): def test_ciphers(self): @@ -532,7 +535,10 @@ class TestMultiBackend(object): backend = MultiBackend([DummyPEMSerializationBackend()]) backend.load_pem_private_key(b"keydata", None) + backend.load_pem_public_key(b"keydata") backend = MultiBackend([]) with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_SERIALIZATION): backend.load_pem_private_key(b"keydata", None) + with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_SERIALIZATION): + backend.load_pem_public_key(b"keydata") diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py index cf70f109..d4c5e2e7 100644 --- a/tests/hazmat/backends/test_openssl.py +++ b/tests/hazmat/backends/test_openssl.py @@ -473,6 +473,8 @@ class TestOpenSSLSerialisationWithOpenSSL(object): key = pretend.stub(type="unsupported") with raises_unsupported_algorithm(None): backend._evp_pkey_to_private_key(key) + with raises_unsupported_algorithm(None): + backend._evp_pkey_to_public_key(key) def test_very_long_pem_serialization_password(self): password = "x" * 1024 diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py index 4bc7e811..2ee096be 100644 --- a/tests/hazmat/primitives/test_serialization.py +++ b/tests/hazmat/primitives/test_serialization.py @@ -82,21 +82,40 @@ class TestPEMSerialization(object): assert key assert isinstance(key, interfaces.EllipticCurvePrivateKey) - def test_load_pem_rsa_public_key(self, backend): - key = load_vectors_from_file( + @pytest.mark.parametrize( + ("key_file"), + [ + os.path.join("asymmetric", "PKCS8", "unenc-rsa-pkcs8.pub.pem"), os.path.join( "asymmetric", "PEM_Serialization", "rsa_public_key.pem"), + ), + ] + ) + def test_load_pem_rsa_public_key(self, key_file, backend): + key = load_vectors_from_file( + key_file, lambda pemfile: load_pem_public_key( pemfile.read().encode(), backend ) ) assert key assert isinstance(key, interfaces.RSAPublicKey) + if isinstance(key, interfaces.RSAPublicKeyWithNumbers): + numbers = key.public_numbers() + assert numbers.e == 65537 - def test_load_pem_dsa_public_key(self, backend): + @pytest.mark.parametrize( + ("key_file"), + [ + os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pub.pem"), + os.path.join( + "asymmetric", "PEM_Serialization", + "dsa_public_key.pem" +), ), + ] + def test_load_pem_dsa_public_key(self, keyfile, backend): key = load_vectors_from_file( - os.path.join( - "asymmetric", "PEM_Serialization", "dsa_public_key.pem"), + keyfile, lambda pemfile: load_pem_public_key( pemfile.read().encode(), backend ) @@ -104,6 +123,14 @@ class TestPEMSerialization(object): assert key assert isinstance(key, interfaces.DSAPublicKey) + def test_load_pem_ec_public_key(self, backend): + key = load_vectors_from_file( + os.path.join("asymmetric", "PEM_Serialization", + "ec_public_key.pem"), + lambda pemfile: load_pem_public_key( + pemfile.read().encode(), backend + ) + ) @pytest.mark.traditional_openssl_serialization class TestTraditionalOpenSSLSerialization(object): -- cgit v1.2.3 From 15b59ee8d0b8dc814439243c8dd9cfadd8999653 Mon Sep 17 00:00:00 2001 From: michael-hart Date: Fri, 26 Sep 2014 01:01:50 +0100 Subject: Corrected tests --- tests/hazmat/backends/test_multibackend.py | 2 +- tests/hazmat/primitives/test_serialization.py | 27 +++++++++------------------ 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/tests/hazmat/backends/test_multibackend.py b/tests/hazmat/backends/test_multibackend.py index e4a05aae..45c12b34 100644 --- a/tests/hazmat/backends/test_multibackend.py +++ b/tests/hazmat/backends/test_multibackend.py @@ -218,7 +218,7 @@ class DummyPEMSerializationBackend(object): pass def load_pem_public_key(self, data): - pass + pass class TestMultiBackend(object): diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py index 2ee096be..7cbd3f71 100644 --- a/tests/hazmat/primitives/test_serialization.py +++ b/tests/hazmat/primitives/test_serialization.py @@ -88,7 +88,6 @@ class TestPEMSerialization(object): os.path.join("asymmetric", "PKCS8", "unenc-rsa-pkcs8.pub.pem"), os.path.join( "asymmetric", "PEM_Serialization", "rsa_public_key.pem"), - ), ] ) def test_load_pem_rsa_public_key(self, key_file, backend): @@ -105,17 +104,17 @@ class TestPEMSerialization(object): assert numbers.e == 65537 @pytest.mark.parametrize( - ("key_file"), - [ - os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pub.pem"), - os.path.join( + ("key_file"), + [ + os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pub.pem"), + os.path.join( "asymmetric", "PEM_Serialization", - "dsa_public_key.pem" -), ), - ] - def test_load_pem_dsa_public_key(self, keyfile, backend): + "dsa_public_key.pem"), + ] + ) + def test_load_pem_dsa_public_key(self, key_file, backend): key = load_vectors_from_file( - keyfile, + key_file, lambda pemfile: load_pem_public_key( pemfile.read().encode(), backend ) @@ -123,14 +122,6 @@ class TestPEMSerialization(object): assert key assert isinstance(key, interfaces.DSAPublicKey) - def test_load_pem_ec_public_key(self, backend): - key = load_vectors_from_file( - os.path.join("asymmetric", "PEM_Serialization", - "ec_public_key.pem"), - lambda pemfile: load_pem_public_key( - pemfile.read().encode(), backend - ) - ) @pytest.mark.traditional_openssl_serialization class TestTraditionalOpenSSLSerialization(object): -- cgit v1.2.3 From 8fee6049ae99c1f68f31d71759d56e4faf0847e2 Mon Sep 17 00:00:00 2001 From: michael-hart Date: Fri, 26 Sep 2014 08:51:59 +0100 Subject: Added code and tests of EC public keys --- cryptography/hazmat/backends/openssl/backend.py | 6 ++++++ tests/hazmat/primitives/test_serialization.py | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py index dd50fd3b..0b129d1a 100644 --- a/cryptography/hazmat/backends/openssl/backend.py +++ b/cryptography/hazmat/backends/openssl/backend.py @@ -501,6 +501,12 @@ class Backend(object): assert dsa_cdata != self._ffi.NULL dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) return _DSAPublicKey(self, dsa_cdata) + elif self._lib.Cryptography_HAS_EC == 1 \ + and type == self._lib.EVP_PKEY_EC: + ec_cdata = self._lib.EVP_PKEY_get1_EC_KEY(evp_pkey) + assert ec_cdata != self._ffi.NULL + ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free) + return _EllipticCurvePublicKey(self, ec_cdata, None) else: raise UnsupportedAlgorithm("Unsupported key type.") diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py index 7cbd3f71..a97e38f5 100644 --- a/tests/hazmat/primitives/test_serialization.py +++ b/tests/hazmat/primitives/test_serialization.py @@ -122,6 +122,18 @@ class TestPEMSerialization(object): assert key assert isinstance(key, interfaces.DSAPublicKey) + @pytest.mark.elliptic + def test_load_ec_public_key(self, backend): + _skip_curve_unsupported(backend, ec.SECP256R1()) + key = load_vectors_from_file( + os.path.join("asymmetric", "PEM_Serialization", "ec_public_key.pem"), + lambda pemfile: load_pem_public_key( + pemfile.read().encode(), backend + ) + ) + assert key + assert isinstance(key, interfaces.EllipticCurvePublicKey) + @pytest.mark.traditional_openssl_serialization class TestTraditionalOpenSSLSerialization(object): -- cgit v1.2.3 From 606f5f6b3158e8e5ee116f16315ca99fd3d9b53f Mon Sep 17 00:00:00 2001 From: michael-hart Date: Fri, 26 Sep 2014 09:00:37 +0100 Subject: flake8 --- tests/hazmat/primitives/test_serialization.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py index a97e38f5..8405f4b2 100644 --- a/tests/hazmat/primitives/test_serialization.py +++ b/tests/hazmat/primitives/test_serialization.py @@ -126,7 +126,9 @@ class TestPEMSerialization(object): def test_load_ec_public_key(self, backend): _skip_curve_unsupported(backend, ec.SECP256R1()) key = load_vectors_from_file( - os.path.join("asymmetric", "PEM_Serialization", "ec_public_key.pem"), + os.path.join( + "asymmetric", "PEM_Serialization", + "ec_public_key.pem"), lambda pemfile: load_pem_public_key( pemfile.read().encode(), backend ) -- cgit v1.2.3 From f5362b2a9bb490cc27a3a794258b8e052528eac2 Mon Sep 17 00:00:00 2001 From: michael-hart Date: Fri, 26 Sep 2014 18:04:46 +0100 Subject: Update multibackend.py Inserted missing newlines --- cryptography/hazmat/backends/multibackend.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cryptography/hazmat/backends/multibackend.py b/cryptography/hazmat/backends/multibackend.py index 925e762d..163dd0ee 100644 --- a/cryptography/hazmat/backends/multibackend.py +++ b/cryptography/hazmat/backends/multibackend.py @@ -187,12 +187,14 @@ class MultiBackend(object): def load_rsa_private_numbers(self, numbers): for b in self._filtered_backends(RSABackend): return b.load_rsa_private_numbers(numbers) + raise UnsupportedAlgorithm("RSA is not supported by the backend", _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM) def load_rsa_public_numbers(self, numbers): for b in self._filtered_backends(RSABackend): return b.load_rsa_public_numbers(numbers) + raise UnsupportedAlgorithm("RSA is not supported by the backend", _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM) -- cgit v1.2.3 From 190e0d44b14ad071d45acfff1c5ace3f01c95c20 Mon Sep 17 00:00:00 2001 From: michael-hart Date: Fri, 26 Sep 2014 18:28:49 +0100 Subject: Added missing newline, corrected changes --- .travis/install.sh | 15 ++++++++------- .../asymmetric/PEM_Serialization/README.txt | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/.travis/install.sh b/.travis/install.sh index fafc4cad..0c64ba93 100755 --- a/.travis/install.sh +++ b/.travis/install.sh @@ -33,7 +33,10 @@ if [[ "${TOX_ENV}" == "docs" ]]; then fi if [[ "$DARWIN" = true ]]; then - if which pyenv > /dev/null; then eval "$(pyenv init -)"; fi + if which pyenv > /dev/null; then + eval "$(pyenv init -)" + fi + case "${TOX_ENV}" in py26) curl -O https://bootstrap.pypa.io/get-pip.py @@ -46,8 +49,10 @@ if [[ "$DARWIN" = true ]]; then sudo pip install virtualenv ;; pypy) - pyenv install pypy-2.3.1 - pyenv global pypy-2.3.1 + brew update + brew upgrade pyenv + pyenv install pypy-2.4.0 + pyenv global pypy-2.4.0 pip install virtualenv ;; py32) @@ -105,7 +110,3 @@ fi virtualenv ~/.venv source ~/.venv/bin/activate pip install tox coveralls - -if [[ "$DARWIN" = true ]]; then - pyenv rehash -fi diff --git a/vectors/cryptography_vectors/asymmetric/PEM_Serialization/README.txt b/vectors/cryptography_vectors/asymmetric/PEM_Serialization/README.txt index 865fbc9e..14f91514 100644 --- a/vectors/cryptography_vectors/asymmetric/PEM_Serialization/README.txt +++ b/vectors/cryptography_vectors/asymmetric/PEM_Serialization/README.txt @@ -12,4 +12,4 @@ Contains 6. dsaparam.pem - Contains 2048-bit DSA parameters generated using OpenSSL; contains no keys. 7. dsa_private_key.pem - Contains a DSA 2048 bit key generated using OpenSSL from the parameters in dsaparam.pem, protected by the secret "123456" with DES3 encryption. -8. dsa_public_key.pem - Contains a DSA 2048 bit key generated using OpenSSL from dsa_private_key.pem. \ No newline at end of file +8. dsa_public_key.pem - Contains a DSA 2048 bit key generated using OpenSSL from dsa_private_key.pem. -- cgit v1.2.3 From b45731b94d7a50b4b4ca39e6a571fc5c19f509b4 Mon Sep 17 00:00:00 2001 From: michael-hart Date: Tue, 23 Sep 2014 23:10:32 +0100 Subject: Part 1 of rebase, with corrections for pep8 --- cryptography/hazmat/backends/interfaces.py | 6 ++++ cryptography/hazmat/backends/multibackend.py | 11 +++++-- cryptography/hazmat/backends/openssl/backend.py | 29 +++++++++++++++++ cryptography/hazmat/primitives/serialization.py | 4 +++ .../hazmat/primitives/asymmetric/serialization.rst | 21 +++++++++++++ tests/hazmat/primitives/test_serialization.py | 36 +++++++++++++++++++++- .../asymmetric/PEM_Serialization/README.txt | 4 +-- 7 files changed, 106 insertions(+), 5 deletions(-) diff --git a/cryptography/hazmat/backends/interfaces.py b/cryptography/hazmat/backends/interfaces.py index 3761e254..187d7fc5 100644 --- a/cryptography/hazmat/backends/interfaces.py +++ b/cryptography/hazmat/backends/interfaces.py @@ -281,6 +281,12 @@ class PEMSerializationBackend(object): if the data is encrypted. """ + @abc.abstractmethod + def load_pem_public_key(self, data, password): + """ + Loads a public key from PEM encoded data. + """ + @six.add_metaclass(abc.ABCMeta) class TraditionalOpenSSLSerializationBackend(object): diff --git a/cryptography/hazmat/backends/multibackend.py b/cryptography/hazmat/backends/multibackend.py index 221f1a1e..925e762d 100644 --- a/cryptography/hazmat/backends/multibackend.py +++ b/cryptography/hazmat/backends/multibackend.py @@ -187,14 +187,12 @@ class MultiBackend(object): def load_rsa_private_numbers(self, numbers): for b in self._filtered_backends(RSABackend): return b.load_rsa_private_numbers(numbers) - raise UnsupportedAlgorithm("RSA is not supported by the backend", _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM) def load_rsa_public_numbers(self, numbers): for b in self._filtered_backends(RSABackend): return b.load_rsa_public_numbers(numbers) - raise UnsupportedAlgorithm("RSA is not supported by the backend", _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM) @@ -329,6 +327,15 @@ class MultiBackend(object): _Reasons.UNSUPPORTED_SERIALIZATION ) + def load_pem_public_key(self, data): + for b in self._filtered_backends(PEMSerializationBackend): + return b.load_pem_public_key(data) + + raise UnsupportedAlgorithm( + "This backend does not support this key serialization.", + _Reasons.UNSUPPORTED_SERIALIZATION + ) + def load_pkcs8_pem_private_key(self, data, password): for b in self._filtered_backends(PKCS8SerializationBackend): return b.load_pkcs8_pem_private_key(data, password) diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py index cb988ac9..dd50fd3b 100644 --- a/cryptography/hazmat/backends/openssl/backend.py +++ b/cryptography/hazmat/backends/openssl/backend.py @@ -483,6 +483,27 @@ class Backend(object): else: raise UnsupportedAlgorithm("Unsupported key type.") + def _evp_pkey_to_public_key(self, evp_pkey): + """ + Return the appropriate type of PublicKey given an evp_pkey cdata + pointer. + """ + + type = evp_pkey.type + + if type == self._lib.EVP_PKEY_RSA: + rsa_cdata = self._lib.EVP_PKEY_get1_RSA(evp_pkey) + assert rsa_cdata != self._ffi.NULL + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + return _RSAPublicKey(self, rsa_cdata) + elif type == self._lib.EVP_PKEY_DSA: + dsa_cdata = self._lib.EVP_PKEY_get1_DSA(evp_pkey) + assert dsa_cdata != self._ffi.NULL + dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) + return _DSAPublicKey(self, dsa_cdata) + else: + raise UnsupportedAlgorithm("Unsupported key type.") + def _pem_password_cb(self, password): """ Generate a pem_password_cb function pointer that copied the password to @@ -787,6 +808,14 @@ class Backend(object): password, ) + def load_pem_public_key(self, data): + return self._load_key( + self._lib.PEM_read_bio_PUBKEY, + self._evp_pkey_to_public_key, + data, + None, + ) + def load_traditional_openssl_pem_private_key(self, data, password): warnings.warn( "load_traditional_openssl_pem_private_key is deprecated and will " diff --git a/cryptography/hazmat/primitives/serialization.py b/cryptography/hazmat/primitives/serialization.py index cf1ca8ec..0fb560e0 100644 --- a/cryptography/hazmat/primitives/serialization.py +++ b/cryptography/hazmat/primitives/serialization.py @@ -44,3 +44,7 @@ def load_pem_pkcs8_private_key(data, password, backend): def load_pem_private_key(data, password, backend): return backend.load_pem_private_key(data, password) + + +def load_pem_public_key(data, backend): + return backend.load_pem_public_key(data) diff --git a/docs/hazmat/primitives/asymmetric/serialization.rst b/docs/hazmat/primitives/asymmetric/serialization.rst index 7a953d9b..18b89c44 100644 --- a/docs/hazmat/primitives/asymmetric/serialization.rst +++ b/docs/hazmat/primitives/asymmetric/serialization.rst @@ -92,6 +92,27 @@ all begin with ``-----BEGIN {format}-----`` and end with ``-----END is not supported by the backend or if the key is encrypted with a symmetric cipher that is not supported by the backend. +.. function:: load_pem_public_key(data, backend): + + .. versionadded:: 0.6 + + Deserialize a public key from PEM encoded data to one of the supported + asymmetric public key types. + + :param bytes data: The PEM encoded key data. + + :param backend: A + :class:`~cryptography.hazmat.backends.interfaces.PEMSerializationBackend` + provider. + + :returns: A new instance of a public key. + + :raises ValueError: If the PEM data could not be decrypted or if its + structure could not be decoded successfully. + + :raises UnsupportedAlgorithm: If the serialized key is of a type that + is not supported by the backend. + PKCS #8 Format ~~~~~~~~~~~~~~ diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py index d369e8f4..4bc7e811 100644 --- a/tests/hazmat/primitives/test_serialization.py +++ b/tests/hazmat/primitives/test_serialization.py @@ -24,6 +24,7 @@ from cryptography.hazmat.primitives import interfaces from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives.serialization import ( load_pem_pkcs8_private_key, load_pem_private_key, + load_pem_public_key, load_pem_traditional_openssl_private_key ) @@ -38,7 +39,7 @@ class TestPEMSerialization(object): def test_load_pem_rsa_private_key(self, backend): key = load_vectors_from_file( os.path.join( - "asymmetric", "Traditional_OpenSSL_Serialization", "key1.pem"), + "asymmetric", "PEM_Serialization", "rsa_private_key.pem"), lambda pemfile: load_pem_private_key( pemfile.read().encode(), b"123456", backend ) @@ -49,6 +50,17 @@ class TestPEMSerialization(object): if isinstance(key, interfaces.RSAPrivateKeyWithNumbers): _check_rsa_private_numbers(key.private_numbers()) + def test_load_dsa_private_key(self, backend): + key = load_vectors_from_file( + os.path.join( + "asymmetric", "PEM_Serialization", "dsa_private_key.pem"), + lambda pemfile: load_pem_private_key( + pemfile.read().encode(), b"123456", backend + ) + ) + assert key + assert isinstance(key, interfaces.DSAPrivateKey) + @pytest.mark.parametrize( ("key_file", "password"), [ @@ -70,6 +82,28 @@ class TestPEMSerialization(object): assert key assert isinstance(key, interfaces.EllipticCurvePrivateKey) + def test_load_pem_rsa_public_key(self, backend): + key = load_vectors_from_file( + os.path.join( + "asymmetric", "PEM_Serialization", "rsa_public_key.pem"), + lambda pemfile: load_pem_public_key( + pemfile.read().encode(), backend + ) + ) + assert key + assert isinstance(key, interfaces.RSAPublicKey) + + def test_load_pem_dsa_public_key(self, backend): + key = load_vectors_from_file( + os.path.join( + "asymmetric", "PEM_Serialization", "dsa_public_key.pem"), + lambda pemfile: load_pem_public_key( + pemfile.read().encode(), backend + ) + ) + assert key + assert isinstance(key, interfaces.DSAPublicKey) + @pytest.mark.traditional_openssl_serialization class TestTraditionalOpenSSLSerialization(object): diff --git a/vectors/cryptography_vectors/asymmetric/PEM_Serialization/README.txt b/vectors/cryptography_vectors/asymmetric/PEM_Serialization/README.txt index 6963d2b5..865fbc9e 100644 --- a/vectors/cryptography_vectors/asymmetric/PEM_Serialization/README.txt +++ b/vectors/cryptography_vectors/asymmetric/PEM_Serialization/README.txt @@ -3,13 +3,13 @@ Example test files for PEM Serialization Backend tests Contains 1. ec_private_key.pem - Contains an Elliptic Curve key generated using OpenSSL, from the curve secp256r1. -2. ec_private_key_encrypted.pem - Contains the same Elliptic Curve key as ec_private_key.pem, except that +2. ec_private_key_encrypted.pem - Contains the same Elliptic Curve key as ec_private_key.pem, except that it is encrypted with AES-256 with the password "123456". 3. ec_public_key.pem - Contains the public key corresponding to ec_private_key.pem, generated using OpenSSL. 4. rsa_private_key.pem - Contains an RSA 2048 bit key generated using OpenSSL, protected by the secret "123456" with DES3 encryption. 5. rsa_public_key.pem - Contains an RSA 2048 bit public generated using OpenSSL from rsa_private_key.pem. 6. dsaparam.pem - Contains 2048-bit DSA parameters generated using OpenSSL; contains no keys. -7. dsa_private_key.pem - Contains a DSA 2048 bit key generated using OpenSSL from the parameters in +7. dsa_private_key.pem - Contains a DSA 2048 bit key generated using OpenSSL from the parameters in dsaparam.pem, protected by the secret "123456" with DES3 encryption. 8. dsa_public_key.pem - Contains a DSA 2048 bit key generated using OpenSSL from dsa_private_key.pem. \ No newline at end of file -- cgit v1.2.3 From 801e8c1b88b77e9feb8ad57af166c4b52b15f22a Mon Sep 17 00:00:00 2001 From: michael-hart Date: Fri, 26 Sep 2014 00:32:25 +0100 Subject: Added all changes lost in merge reset --- cryptography/hazmat/backends/interfaces.py | 4 +-- docs/hazmat/backends/interfaces.rst | 6 +++++ tests/hazmat/backends/test_multibackend.py | 6 +++++ tests/hazmat/backends/test_openssl.py | 2 ++ tests/hazmat/primitives/test_serialization.py | 37 +++++++++++++++++++++++---- 5 files changed, 48 insertions(+), 7 deletions(-) diff --git a/cryptography/hazmat/backends/interfaces.py b/cryptography/hazmat/backends/interfaces.py index 187d7fc5..dc720ad3 100644 --- a/cryptography/hazmat/backends/interfaces.py +++ b/cryptography/hazmat/backends/interfaces.py @@ -282,7 +282,7 @@ class PEMSerializationBackend(object): """ @abc.abstractmethod - def load_pem_public_key(self, data, password): + def load_pem_public_key(self, data): """ Loads a public key from PEM encoded data. """ @@ -303,6 +303,6 @@ 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 + Load a private key from PKCS8 encoded data, using password if the data is encrypted. """ diff --git a/docs/hazmat/backends/interfaces.rst b/docs/hazmat/backends/interfaces.rst index f8341d11..e8e1bac2 100644 --- a/docs/hazmat/backends/interfaces.rst +++ b/docs/hazmat/backends/interfaces.rst @@ -595,6 +595,12 @@ A specific ``backend`` may provide one or more of these interfaces. :raises cryptography.exceptions.UnsupportedAlgorithm: If the data is encrypted with an unsupported algorithm. + .. method:: load_pem_public_key(data) + + :param bytes data: PEM data to load. + :return: A new instance of the appropriate type of public key serialized data contains. + :raises ValueError: If the data could not be deserialized. + .. class:: TraditionalOpenSSLSerializationBackend .. versionadded:: 0.3 diff --git a/tests/hazmat/backends/test_multibackend.py b/tests/hazmat/backends/test_multibackend.py index 655acc44..e4a05aae 100644 --- a/tests/hazmat/backends/test_multibackend.py +++ b/tests/hazmat/backends/test_multibackend.py @@ -217,6 +217,9 @@ class DummyPEMSerializationBackend(object): def load_pem_private_key(self, data, password): pass + def load_pem_public_key(self, data): + pass + class TestMultiBackend(object): def test_ciphers(self): @@ -532,7 +535,10 @@ class TestMultiBackend(object): backend = MultiBackend([DummyPEMSerializationBackend()]) backend.load_pem_private_key(b"keydata", None) + backend.load_pem_public_key(b"keydata") backend = MultiBackend([]) with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_SERIALIZATION): backend.load_pem_private_key(b"keydata", None) + with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_SERIALIZATION): + backend.load_pem_public_key(b"keydata") diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py index cf70f109..d4c5e2e7 100644 --- a/tests/hazmat/backends/test_openssl.py +++ b/tests/hazmat/backends/test_openssl.py @@ -473,6 +473,8 @@ class TestOpenSSLSerialisationWithOpenSSL(object): key = pretend.stub(type="unsupported") with raises_unsupported_algorithm(None): backend._evp_pkey_to_private_key(key) + with raises_unsupported_algorithm(None): + backend._evp_pkey_to_public_key(key) def test_very_long_pem_serialization_password(self): password = "x" * 1024 diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py index 4bc7e811..2ee096be 100644 --- a/tests/hazmat/primitives/test_serialization.py +++ b/tests/hazmat/primitives/test_serialization.py @@ -82,21 +82,40 @@ class TestPEMSerialization(object): assert key assert isinstance(key, interfaces.EllipticCurvePrivateKey) - def test_load_pem_rsa_public_key(self, backend): - key = load_vectors_from_file( + @pytest.mark.parametrize( + ("key_file"), + [ + os.path.join("asymmetric", "PKCS8", "unenc-rsa-pkcs8.pub.pem"), os.path.join( "asymmetric", "PEM_Serialization", "rsa_public_key.pem"), + ), + ] + ) + def test_load_pem_rsa_public_key(self, key_file, backend): + key = load_vectors_from_file( + key_file, lambda pemfile: load_pem_public_key( pemfile.read().encode(), backend ) ) assert key assert isinstance(key, interfaces.RSAPublicKey) + if isinstance(key, interfaces.RSAPublicKeyWithNumbers): + numbers = key.public_numbers() + assert numbers.e == 65537 - def test_load_pem_dsa_public_key(self, backend): + @pytest.mark.parametrize( + ("key_file"), + [ + os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pub.pem"), + os.path.join( + "asymmetric", "PEM_Serialization", + "dsa_public_key.pem" +), ), + ] + def test_load_pem_dsa_public_key(self, keyfile, backend): key = load_vectors_from_file( - os.path.join( - "asymmetric", "PEM_Serialization", "dsa_public_key.pem"), + keyfile, lambda pemfile: load_pem_public_key( pemfile.read().encode(), backend ) @@ -104,6 +123,14 @@ class TestPEMSerialization(object): assert key assert isinstance(key, interfaces.DSAPublicKey) + def test_load_pem_ec_public_key(self, backend): + key = load_vectors_from_file( + os.path.join("asymmetric", "PEM_Serialization", + "ec_public_key.pem"), + lambda pemfile: load_pem_public_key( + pemfile.read().encode(), backend + ) + ) @pytest.mark.traditional_openssl_serialization class TestTraditionalOpenSSLSerialization(object): -- cgit v1.2.3 From fe2cd085cffe05fbdec02164a93de7812acb44dd Mon Sep 17 00:00:00 2001 From: michael-hart Date: Fri, 26 Sep 2014 01:01:50 +0100 Subject: Corrected tests --- tests/hazmat/backends/test_multibackend.py | 2 +- tests/hazmat/primitives/test_serialization.py | 27 +++++++++------------------ 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/tests/hazmat/backends/test_multibackend.py b/tests/hazmat/backends/test_multibackend.py index e4a05aae..45c12b34 100644 --- a/tests/hazmat/backends/test_multibackend.py +++ b/tests/hazmat/backends/test_multibackend.py @@ -218,7 +218,7 @@ class DummyPEMSerializationBackend(object): pass def load_pem_public_key(self, data): - pass + pass class TestMultiBackend(object): diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py index 2ee096be..7cbd3f71 100644 --- a/tests/hazmat/primitives/test_serialization.py +++ b/tests/hazmat/primitives/test_serialization.py @@ -88,7 +88,6 @@ class TestPEMSerialization(object): os.path.join("asymmetric", "PKCS8", "unenc-rsa-pkcs8.pub.pem"), os.path.join( "asymmetric", "PEM_Serialization", "rsa_public_key.pem"), - ), ] ) def test_load_pem_rsa_public_key(self, key_file, backend): @@ -105,17 +104,17 @@ class TestPEMSerialization(object): assert numbers.e == 65537 @pytest.mark.parametrize( - ("key_file"), - [ - os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pub.pem"), - os.path.join( + ("key_file"), + [ + os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pub.pem"), + os.path.join( "asymmetric", "PEM_Serialization", - "dsa_public_key.pem" -), ), - ] - def test_load_pem_dsa_public_key(self, keyfile, backend): + "dsa_public_key.pem"), + ] + ) + def test_load_pem_dsa_public_key(self, key_file, backend): key = load_vectors_from_file( - keyfile, + key_file, lambda pemfile: load_pem_public_key( pemfile.read().encode(), backend ) @@ -123,14 +122,6 @@ class TestPEMSerialization(object): assert key assert isinstance(key, interfaces.DSAPublicKey) - def test_load_pem_ec_public_key(self, backend): - key = load_vectors_from_file( - os.path.join("asymmetric", "PEM_Serialization", - "ec_public_key.pem"), - lambda pemfile: load_pem_public_key( - pemfile.read().encode(), backend - ) - ) @pytest.mark.traditional_openssl_serialization class TestTraditionalOpenSSLSerialization(object): -- cgit v1.2.3 From 2ca899115b80dba47b65a8255bbbce1cce2ce238 Mon Sep 17 00:00:00 2001 From: michael-hart Date: Tue, 23 Sep 2014 23:10:32 +0100 Subject: Part 1 of rebase, with corrections for pep8 --- cryptography/hazmat/backends/interfaces.py | 2 +- tests/hazmat/primitives/test_serialization.py | 28 +++++---------------------- 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/cryptography/hazmat/backends/interfaces.py b/cryptography/hazmat/backends/interfaces.py index dc720ad3..f3d64820 100644 --- a/cryptography/hazmat/backends/interfaces.py +++ b/cryptography/hazmat/backends/interfaces.py @@ -282,7 +282,7 @@ class PEMSerializationBackend(object): """ @abc.abstractmethod - def load_pem_public_key(self, data): + def load_pem_public_key(self, data, password): """ Loads a public key from PEM encoded data. """ diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py index 7cbd3f71..4bc7e811 100644 --- a/tests/hazmat/primitives/test_serialization.py +++ b/tests/hazmat/primitives/test_serialization.py @@ -82,39 +82,21 @@ class TestPEMSerialization(object): assert key assert isinstance(key, interfaces.EllipticCurvePrivateKey) - @pytest.mark.parametrize( - ("key_file"), - [ - os.path.join("asymmetric", "PKCS8", "unenc-rsa-pkcs8.pub.pem"), + def test_load_pem_rsa_public_key(self, backend): + key = load_vectors_from_file( os.path.join( "asymmetric", "PEM_Serialization", "rsa_public_key.pem"), - ] - ) - def test_load_pem_rsa_public_key(self, key_file, backend): - key = load_vectors_from_file( - key_file, lambda pemfile: load_pem_public_key( pemfile.read().encode(), backend ) ) assert key assert isinstance(key, interfaces.RSAPublicKey) - if isinstance(key, interfaces.RSAPublicKeyWithNumbers): - numbers = key.public_numbers() - assert numbers.e == 65537 - @pytest.mark.parametrize( - ("key_file"), - [ - os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pub.pem"), - os.path.join( - "asymmetric", "PEM_Serialization", - "dsa_public_key.pem"), - ] - ) - def test_load_pem_dsa_public_key(self, key_file, backend): + def test_load_pem_dsa_public_key(self, backend): key = load_vectors_from_file( - key_file, + os.path.join( + "asymmetric", "PEM_Serialization", "dsa_public_key.pem"), lambda pemfile: load_pem_public_key( pemfile.read().encode(), backend ) -- cgit v1.2.3 From 254811fd619188610298485a66885784944c1de8 Mon Sep 17 00:00:00 2001 From: michael-hart Date: Fri, 26 Sep 2014 00:32:25 +0100 Subject: Added all changes lost in merge reset --- cryptography/hazmat/backends/interfaces.py | 2 +- tests/hazmat/backends/test_multibackend.py | 2 +- tests/hazmat/primitives/test_serialization.py | 37 +++++++++++++++++++++++---- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/cryptography/hazmat/backends/interfaces.py b/cryptography/hazmat/backends/interfaces.py index f3d64820..dc720ad3 100644 --- a/cryptography/hazmat/backends/interfaces.py +++ b/cryptography/hazmat/backends/interfaces.py @@ -282,7 +282,7 @@ class PEMSerializationBackend(object): """ @abc.abstractmethod - def load_pem_public_key(self, data, password): + def load_pem_public_key(self, data): """ Loads a public key from PEM encoded data. """ diff --git a/tests/hazmat/backends/test_multibackend.py b/tests/hazmat/backends/test_multibackend.py index 45c12b34..e4a05aae 100644 --- a/tests/hazmat/backends/test_multibackend.py +++ b/tests/hazmat/backends/test_multibackend.py @@ -218,7 +218,7 @@ class DummyPEMSerializationBackend(object): pass def load_pem_public_key(self, data): - pass + pass class TestMultiBackend(object): diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py index 4bc7e811..2ee096be 100644 --- a/tests/hazmat/primitives/test_serialization.py +++ b/tests/hazmat/primitives/test_serialization.py @@ -82,21 +82,40 @@ class TestPEMSerialization(object): assert key assert isinstance(key, interfaces.EllipticCurvePrivateKey) - def test_load_pem_rsa_public_key(self, backend): - key = load_vectors_from_file( + @pytest.mark.parametrize( + ("key_file"), + [ + os.path.join("asymmetric", "PKCS8", "unenc-rsa-pkcs8.pub.pem"), os.path.join( "asymmetric", "PEM_Serialization", "rsa_public_key.pem"), + ), + ] + ) + def test_load_pem_rsa_public_key(self, key_file, backend): + key = load_vectors_from_file( + key_file, lambda pemfile: load_pem_public_key( pemfile.read().encode(), backend ) ) assert key assert isinstance(key, interfaces.RSAPublicKey) + if isinstance(key, interfaces.RSAPublicKeyWithNumbers): + numbers = key.public_numbers() + assert numbers.e == 65537 - def test_load_pem_dsa_public_key(self, backend): + @pytest.mark.parametrize( + ("key_file"), + [ + os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pub.pem"), + os.path.join( + "asymmetric", "PEM_Serialization", + "dsa_public_key.pem" +), ), + ] + def test_load_pem_dsa_public_key(self, keyfile, backend): key = load_vectors_from_file( - os.path.join( - "asymmetric", "PEM_Serialization", "dsa_public_key.pem"), + keyfile, lambda pemfile: load_pem_public_key( pemfile.read().encode(), backend ) @@ -104,6 +123,14 @@ class TestPEMSerialization(object): assert key assert isinstance(key, interfaces.DSAPublicKey) + def test_load_pem_ec_public_key(self, backend): + key = load_vectors_from_file( + os.path.join("asymmetric", "PEM_Serialization", + "ec_public_key.pem"), + lambda pemfile: load_pem_public_key( + pemfile.read().encode(), backend + ) + ) @pytest.mark.traditional_openssl_serialization class TestTraditionalOpenSSLSerialization(object): -- cgit v1.2.3 From 0a4c401431f2864b03e6e8baf3c0478bfe74b8b2 Mon Sep 17 00:00:00 2001 From: michael-hart Date: Fri, 26 Sep 2014 01:01:50 +0100 Subject: Corrected tests --- tests/hazmat/backends/test_multibackend.py | 2 +- tests/hazmat/primitives/test_serialization.py | 27 +++++++++------------------ 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/tests/hazmat/backends/test_multibackend.py b/tests/hazmat/backends/test_multibackend.py index e4a05aae..45c12b34 100644 --- a/tests/hazmat/backends/test_multibackend.py +++ b/tests/hazmat/backends/test_multibackend.py @@ -218,7 +218,7 @@ class DummyPEMSerializationBackend(object): pass def load_pem_public_key(self, data): - pass + pass class TestMultiBackend(object): diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py index 2ee096be..7cbd3f71 100644 --- a/tests/hazmat/primitives/test_serialization.py +++ b/tests/hazmat/primitives/test_serialization.py @@ -88,7 +88,6 @@ class TestPEMSerialization(object): os.path.join("asymmetric", "PKCS8", "unenc-rsa-pkcs8.pub.pem"), os.path.join( "asymmetric", "PEM_Serialization", "rsa_public_key.pem"), - ), ] ) def test_load_pem_rsa_public_key(self, key_file, backend): @@ -105,17 +104,17 @@ class TestPEMSerialization(object): assert numbers.e == 65537 @pytest.mark.parametrize( - ("key_file"), - [ - os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pub.pem"), - os.path.join( + ("key_file"), + [ + os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pub.pem"), + os.path.join( "asymmetric", "PEM_Serialization", - "dsa_public_key.pem" -), ), - ] - def test_load_pem_dsa_public_key(self, keyfile, backend): + "dsa_public_key.pem"), + ] + ) + def test_load_pem_dsa_public_key(self, key_file, backend): key = load_vectors_from_file( - keyfile, + key_file, lambda pemfile: load_pem_public_key( pemfile.read().encode(), backend ) @@ -123,14 +122,6 @@ class TestPEMSerialization(object): assert key assert isinstance(key, interfaces.DSAPublicKey) - def test_load_pem_ec_public_key(self, backend): - key = load_vectors_from_file( - os.path.join("asymmetric", "PEM_Serialization", - "ec_public_key.pem"), - lambda pemfile: load_pem_public_key( - pemfile.read().encode(), backend - ) - ) @pytest.mark.traditional_openssl_serialization class TestTraditionalOpenSSLSerialization(object): -- cgit v1.2.3 From bdceabc6ad5c48038ee767d64d856e15e016ca7a Mon Sep 17 00:00:00 2001 From: michael-hart Date: Fri, 26 Sep 2014 08:51:59 +0100 Subject: Added code and tests of EC public keys --- cryptography/hazmat/backends/openssl/backend.py | 6 ++++++ tests/hazmat/primitives/test_serialization.py | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py index dd50fd3b..0b129d1a 100644 --- a/cryptography/hazmat/backends/openssl/backend.py +++ b/cryptography/hazmat/backends/openssl/backend.py @@ -501,6 +501,12 @@ class Backend(object): assert dsa_cdata != self._ffi.NULL dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) return _DSAPublicKey(self, dsa_cdata) + elif self._lib.Cryptography_HAS_EC == 1 \ + and type == self._lib.EVP_PKEY_EC: + ec_cdata = self._lib.EVP_PKEY_get1_EC_KEY(evp_pkey) + assert ec_cdata != self._ffi.NULL + ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free) + return _EllipticCurvePublicKey(self, ec_cdata, None) else: raise UnsupportedAlgorithm("Unsupported key type.") diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py index 7cbd3f71..a97e38f5 100644 --- a/tests/hazmat/primitives/test_serialization.py +++ b/tests/hazmat/primitives/test_serialization.py @@ -122,6 +122,18 @@ class TestPEMSerialization(object): assert key assert isinstance(key, interfaces.DSAPublicKey) + @pytest.mark.elliptic + def test_load_ec_public_key(self, backend): + _skip_curve_unsupported(backend, ec.SECP256R1()) + key = load_vectors_from_file( + os.path.join("asymmetric", "PEM_Serialization", "ec_public_key.pem"), + lambda pemfile: load_pem_public_key( + pemfile.read().encode(), backend + ) + ) + assert key + assert isinstance(key, interfaces.EllipticCurvePublicKey) + @pytest.mark.traditional_openssl_serialization class TestTraditionalOpenSSLSerialization(object): -- cgit v1.2.3 From 48060f25c43e4c8d05ef6a8c940321cdb3913d54 Mon Sep 17 00:00:00 2001 From: michael-hart Date: Fri, 26 Sep 2014 09:00:37 +0100 Subject: flake8 --- tests/hazmat/primitives/test_serialization.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py index a97e38f5..8405f4b2 100644 --- a/tests/hazmat/primitives/test_serialization.py +++ b/tests/hazmat/primitives/test_serialization.py @@ -126,7 +126,9 @@ class TestPEMSerialization(object): def test_load_ec_public_key(self, backend): _skip_curve_unsupported(backend, ec.SECP256R1()) key = load_vectors_from_file( - os.path.join("asymmetric", "PEM_Serialization", "ec_public_key.pem"), + os.path.join( + "asymmetric", "PEM_Serialization", + "ec_public_key.pem"), lambda pemfile: load_pem_public_key( pemfile.read().encode(), backend ) -- cgit v1.2.3 From b5c448012d5fc98f9d14483ffd71b0caefd30bb7 Mon Sep 17 00:00:00 2001 From: michael-hart Date: Fri, 26 Sep 2014 18:04:46 +0100 Subject: Update multibackend.py Inserted missing newlines --- cryptography/hazmat/backends/multibackend.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cryptography/hazmat/backends/multibackend.py b/cryptography/hazmat/backends/multibackend.py index 925e762d..163dd0ee 100644 --- a/cryptography/hazmat/backends/multibackend.py +++ b/cryptography/hazmat/backends/multibackend.py @@ -187,12 +187,14 @@ class MultiBackend(object): def load_rsa_private_numbers(self, numbers): for b in self._filtered_backends(RSABackend): return b.load_rsa_private_numbers(numbers) + raise UnsupportedAlgorithm("RSA is not supported by the backend", _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM) def load_rsa_public_numbers(self, numbers): for b in self._filtered_backends(RSABackend): return b.load_rsa_public_numbers(numbers) + raise UnsupportedAlgorithm("RSA is not supported by the backend", _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM) -- cgit v1.2.3 From df1e16de589ee0e295bbe21f854b3c6113dc72a5 Mon Sep 17 00:00:00 2001 From: michael-hart Date: Fri, 26 Sep 2014 18:28:49 +0100 Subject: Added missing newline, corrected changes --- vectors/cryptography_vectors/asymmetric/PEM_Serialization/README.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vectors/cryptography_vectors/asymmetric/PEM_Serialization/README.txt b/vectors/cryptography_vectors/asymmetric/PEM_Serialization/README.txt index 865fbc9e..14f91514 100644 --- a/vectors/cryptography_vectors/asymmetric/PEM_Serialization/README.txt +++ b/vectors/cryptography_vectors/asymmetric/PEM_Serialization/README.txt @@ -12,4 +12,4 @@ Contains 6. dsaparam.pem - Contains 2048-bit DSA parameters generated using OpenSSL; contains no keys. 7. dsa_private_key.pem - Contains a DSA 2048 bit key generated using OpenSSL from the parameters in dsaparam.pem, protected by the secret "123456" with DES3 encryption. -8. dsa_public_key.pem - Contains a DSA 2048 bit key generated using OpenSSL from dsa_private_key.pem. \ No newline at end of file +8. dsa_public_key.pem - Contains a DSA 2048 bit key generated using OpenSSL from dsa_private_key.pem. -- cgit v1.2.3