diff options
author | Alex Gaynor <alex.gaynor@gmail.com> | 2015-03-07 12:33:01 -0500 |
---|---|---|
committer | Alex Gaynor <alex.gaynor@gmail.com> | 2015-03-07 12:33:01 -0500 |
commit | 7d5483b7cd0065b1f21b068ac2278ba74c21dc67 (patch) | |
tree | 17924147ce3ec236095543cf70564ff0c970b6a7 | |
parent | e37a0a5c8d29cbede67f4731ec0edd69b63a89c0 (diff) | |
parent | 791afc0d63f6985227ea18752ccb12fa0987c420 (diff) | |
download | cryptography-7d5483b7cd0065b1f21b068ac2278ba74c21dc67.tar.gz cryptography-7d5483b7cd0065b1f21b068ac2278ba74c21dc67.tar.bz2 cryptography-7d5483b7cd0065b1f21b068ac2278ba74c21dc67.zip |
Merge pull request #1715 from reaperhulk/rsa-pkcs1-public-key
RSA PKCS1 public key loading support
-rw-r--r-- | CHANGELOG.rst | 4 | ||||
-rw-r--r-- | src/cryptography/hazmat/backends/openssl/backend.py | 48 | ||||
-rw-r--r-- | tests/hazmat/primitives/test_serialization.py | 10 |
3 files changed, 51 insertions, 11 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst index ccc2e20b..70fd7a53 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -79,6 +79,10 @@ Changelog * Fixed building against LibreSSL, a compile-time substitute for OpenSSL. * FreeBSD 9.2 was removed from the continuous integration system. * Updated Windows wheels to be compiled against OpenSSL 1.0.2. +* :func:`~cryptography.hazmat.primitives.serialization.load_pem_public_key` + and :func:`~cryptography.hazmat.primitives.serialization.load_der_public_key` + now support PKCS1 RSA public keys (in addition to the previous support for + SubjectPublicKeyInfo format for RSA, EC, and DSA). * Added :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKeyWithSerialization` and deprecated diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 27d5e353..42dcc0fb 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -692,12 +692,28 @@ class Backend(object): ) 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, + mem_bio = self._bytes_to_bio(data) + evp_pkey = self._lib.PEM_read_bio_PUBKEY( + mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL ) + if evp_pkey != self._ffi.NULL: + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + return self._evp_pkey_to_public_key(evp_pkey) + else: + # It's not a (RSA/DSA/ECDSA) subjectPublicKeyInfo, but we still + # need to check to see if it is a pure PKCS1 RSA public key (not + # embedded in a subjectPublicKeyInfo) + self._consume_errors() + res = self._lib.BIO_reset(mem_bio.bio) + assert res == 1 + rsa_cdata = self._lib.PEM_read_bio_RSAPublicKey( + mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL + ) + if rsa_cdata != self._ffi.NULL: + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + return _RSAPublicKey(self, rsa_cdata) + else: + self._handle_key_loading_error() def load_der_private_key(self, data, password): # OpenSSL has a function called d2i_AutoPrivateKey that can simplify @@ -762,12 +778,24 @@ class Backend(object): 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: + if evp_pkey != self._ffi.NULL: + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + return self._evp_pkey_to_public_key(evp_pkey) + else: + # It's not a (RSA/DSA/ECDSA) subjectPublicKeyInfo, but we still + # need to check to see if it is a pure PKCS1 RSA public key (not + # embedded in a subjectPublicKeyInfo) 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) + res = self._lib.BIO_reset(mem_bio.bio) + assert res == 1 + rsa_cdata = self._lib.d2i_RSAPublicKey_bio( + mem_bio.bio, self._ffi.NULL + ) + if rsa_cdata != self._ffi.NULL: + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + return _RSAPublicKey(self, rsa_cdata) + else: + self._handle_key_loading_error() def load_pem_x509_certificate(self, data): mem_bio = self._bytes_to_bio(data) diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py index fc8f8664..07a8f02e 100644 --- a/tests/hazmat/primitives/test_serialization.py +++ b/tests/hazmat/primitives/test_serialization.py @@ -233,6 +233,7 @@ class TestDERSerialization(object): "asymmetric", "DER_Serialization", "unenc-rsa-pkcs8.pub.der"), os.path.join( "asymmetric", "DER_Serialization", "rsa_public_key.der"), + os.path.join("asymmetric", "public", "PKCS1", "rsa.pub.der"), ] ) @pytest.mark.requires_backend_interface(interface=RSABackend) @@ -384,6 +385,7 @@ class TestPEMSerialization(object): os.path.join("asymmetric", "PKCS8", "unenc-rsa-pkcs8.pub.pem"), os.path.join( "asymmetric", "PEM_Serialization", "rsa_public_key.pem"), + os.path.join("asymmetric", "public", "PKCS1", "rsa.pub.pem"), ] ) def test_load_pem_rsa_public_key(self, key_file, backend): @@ -537,7 +539,7 @@ class TestPEMSerialization(object): ) ) - def test_wrong_format(self, backend): + def test_wrong_private_format(self, backend): key_data = b"---- NOT A KEY ----\n" with pytest.raises(ValueError): @@ -550,6 +552,12 @@ class TestPEMSerialization(object): key_data, b"this password will not be used", backend ) + def test_wrong_public_format(self, backend): + key_data = b"---- NOT A KEY ----\n" + + with pytest.raises(ValueError): + load_pem_public_key(key_data, backend) + def test_corrupt_traditional_format(self, backend): # privkey.pem with a bunch of data missing. key_data = textwrap.dedent("""\ |