diff options
author | Jean-Paul Calderone <exarkun@twistedmatrix.com> | 2014-05-05 12:58:28 -0400 |
---|---|---|
committer | Jean-Paul Calderone <exarkun@twistedmatrix.com> | 2014-05-05 12:58:28 -0400 |
commit | 238fb74dc95828a8e9fb0369460f1096663f3b78 (patch) | |
tree | cfd18d1f98d46d828720890e80c2d055c6f86085 | |
parent | d4ff4e460f30d228407198ad9d0a38b7651735f3 (diff) | |
parent | f0ff13bd2d1909a466c52f0ae7986b0b96835a78 (diff) | |
download | pyopenssl-238fb74dc95828a8e9fb0369460f1096663f3b78.tar.gz |
Merge pull request #108 from pyca/pkcs12-without-passphrase
Re-enable support for loading PKCS12 containers that have no passphrase or an empty passphrase and let this be the default when no passphrase is passed to `load_pkcs12`.
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | OpenSSL/crypto.py | 9 | ||||
-rw-r--r-- | OpenSSL/test/test_crypto.py | 87 |
3 files changed, 92 insertions, 9 deletions
@@ -12,6 +12,11 @@ * OpenSSL/SSL.py: ``Connection.send`` and ``Connection.sendall`` now also accept the ``buffer`` type as data. +2014-04-05 Stephen Holsapple <sholsapp@gmail.com> + + * OpenSSL/crypto.py: Make ``load_pkcs12`` backwards compatible with + pyOpenSSL 0.13 by making passphrase optional. + 2014-03-30 Fedor Brunner <fedor.brunner@azet.sk> * OpenSSL/SSL.py: Add ``get_finished``, ``get_peer_finished`` diff --git a/OpenSSL/crypto.py b/OpenSSL/crypto.py index 03fe853..54569ea 100644 --- a/OpenSSL/crypto.py +++ b/OpenSSL/crypto.py @@ -2366,7 +2366,7 @@ def load_pkcs7_data(type, buffer): -def load_pkcs12(buffer, passphrase): +def load_pkcs12(buffer, passphrase=None): """ Load a PKCS12 object from a buffer @@ -2379,6 +2379,13 @@ def load_pkcs12(buffer, passphrase): bio = _new_mem_buf(buffer) + # Use null passphrase if passphrase is None or empty string. With PKCS#12 + # password based encryption no password and a zero length password are two + # different things, but OpenSSL implementation will try both to figure out + # which one works. + if not passphrase: + passphrase = _ffi.NULL + p12 = _lib.d2i_PKCS12_bio(bio, _ffi.NULL) if p12 == _ffi.NULL: _raise_current_error() diff --git a/OpenSSL/test/test_crypto.py b/OpenSSL/test/test_crypto.py index 34e60a3..bbe5d05 100644 --- a/OpenSSL/test/test_crypto.py +++ b/OpenSSL/test/test_crypto.py @@ -1941,6 +1941,21 @@ class PKCS12Tests(TestCase): self.assertEqual(recovered_cert[-len(ca):], ca) + def verify_pkcs12_container(self, p12): + """ + Verify that the PKCS#12 container contains the correct client + certificate and private key. + + :param p12: The PKCS12 instance to verify. + :type p12: :py:class:`PKCS12` + """ + cert_pem = dump_certificate(FILETYPE_PEM, p12.get_certificate()) + key_pem = dump_privatekey(FILETYPE_PEM, p12.get_privatekey()) + self.assertEqual( + (client_cert_pem, client_key_pem, None), + (cert_pem, key_pem, p12.get_ca_certificates())) + + def test_load_pkcs12(self): """ A PKCS12 string generated using the openssl command line can be loaded @@ -1950,14 +1965,70 @@ class PKCS12Tests(TestCase): pem = client_key_pem + client_cert_pem p12_str = _runopenssl( pem, b"pkcs12", b"-export", b"-clcerts", b"-passout", b"pass:" + passwd) - p12 = load_pkcs12(p12_str, passwd) - # verify - self.assertTrue(isinstance(p12, PKCS12)) - cert_pem = dump_certificate(FILETYPE_PEM, p12.get_certificate()) - self.assertEqual(cert_pem, client_cert_pem) - key_pem = dump_privatekey(FILETYPE_PEM, p12.get_privatekey()) - self.assertEqual(key_pem, client_key_pem) - self.assertEqual(None, p12.get_ca_certificates()) + p12 = load_pkcs12(p12_str, passphrase=passwd) + self.verify_pkcs12_container(p12) + + + def test_load_pkcs12_no_passphrase(self): + """ + A PKCS12 string generated using openssl command line can be loaded with + :py:obj:`load_pkcs12` without a passphrase and its components extracted + and examined. + """ + pem = client_key_pem + client_cert_pem + p12_str = _runopenssl( + pem, b"pkcs12", b"-export", b"-clcerts", b"-passout", b"pass:") + p12 = load_pkcs12(p12_str) + self.verify_pkcs12_container(p12) + + + def _dump_and_load(self, dump_passphrase, load_passphrase): + """ + A helper method to dump and load a PKCS12 object. + """ + p12 = self.gen_pkcs12(client_cert_pem, client_key_pem) + dumped_p12 = p12.export(passphrase=dump_passphrase, iter=2, maciter=3) + return load_pkcs12(dumped_p12, passphrase=load_passphrase) + + + def test_load_pkcs12_null_passphrase_load_empty(self): + """ + A PKCS12 string can be dumped with a null passphrase, loaded with an + empty passphrase with :py:obj:`load_pkcs12`, and its components + extracted and examined. + """ + self.verify_pkcs12_container( + self._dump_and_load(dump_passphrase=None, load_passphrase=b'')) + + + def test_load_pkcs12_null_passphrase_load_null(self): + """ + A PKCS12 string can be dumped with a null passphrase, loaded with a + null passphrase with :py:obj:`load_pkcs12`, and its components + extracted and examined. + """ + self.verify_pkcs12_container( + self._dump_and_load(dump_passphrase=None, load_passphrase=None)) + + + def test_load_pkcs12_empty_passphrase_load_empty(self): + """ + A PKCS12 string can be dumped with an empty passphrase, loaded with an + empty passphrase with :py:obj:`load_pkcs12`, and its components + extracted and examined. + """ + self.verify_pkcs12_container( + self._dump_and_load(dump_passphrase=b'', load_passphrase=b'')) + + + def test_load_pkcs12_empty_passphrase_load_null(self): + """ + A PKCS12 string can be dumped with an empty passphrase, loaded with a + null passphrase with :py:obj:`load_pkcs12`, and its components + extracted and examined. + """ + self.verify_pkcs12_container( + self._dump_and_load(dump_passphrase=b'', load_passphrase=None)) def test_load_pkcs12_garbage(self): |