aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Gaynor <alex.gaynor@gmail.com>2015-03-07 12:33:01 -0500
committerAlex Gaynor <alex.gaynor@gmail.com>2015-03-07 12:33:01 -0500
commit7d5483b7cd0065b1f21b068ac2278ba74c21dc67 (patch)
tree17924147ce3ec236095543cf70564ff0c970b6a7
parente37a0a5c8d29cbede67f4731ec0edd69b63a89c0 (diff)
parent791afc0d63f6985227ea18752ccb12fa0987c420 (diff)
downloadcryptography-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.rst4
-rw-r--r--src/cryptography/hazmat/backends/openssl/backend.py48
-rw-r--r--tests/hazmat/primitives/test_serialization.py10
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("""\