Enable use of CRL (and more) in verify context. (#483)
* Enable use of CRL (and more) in verify context.
* flake8 fixes.
* Comments from Hynek & Paul.
* More updates from Paul & Hynek.
* Fix closing backtick.
* Remove commented out constants.
* More doc updates. Changelog update.
* Getting closer?
* Sphinx fix.
* Indent docstring.
* More Sphinx updates.
* Type updates for docstrings.
* Remove Enum subclassing.
* Docstring update.
* Docstrings updates.
* Round and round it goes. Where it ends, nobody knows.
* Remove TODO comment. Need @sholsapp to follow up.
* Time for lots of alcohol.
diff --git a/tests/test_crypto.py b/tests/test_crypto.py
index eeea306..e13f1e4 100644
--- a/tests/test_crypto.py
+++ b/tests/test_crypto.py
@@ -21,7 +21,11 @@
from OpenSSL.crypto import TYPE_RSA, TYPE_DSA, Error, PKey, PKeyType
from OpenSSL.crypto import X509, X509Type, X509Name, X509NameType
from OpenSSL.crypto import (
- X509Store, X509StoreType, X509StoreContext, X509StoreContextError
+ X509Store,
+ X509StoreFlags,
+ X509StoreType,
+ X509StoreContext,
+ X509StoreContextError
)
from OpenSSL.crypto import X509Req, X509ReqType
from OpenSSL.crypto import X509Extension, X509ExtensionType
@@ -3127,6 +3131,15 @@
cert = load_certificate(FILETYPE_PEM, cleartextCertificatePEM)
pkey = load_privatekey(FILETYPE_PEM, cleartextPrivateKeyPEM)
+ root_cert = load_certificate(FILETYPE_PEM, root_cert_pem)
+ root_key = load_privatekey(FILETYPE_PEM, root_key_pem)
+ intermediate_cert = load_certificate(FILETYPE_PEM, intermediate_cert_pem)
+ intermediate_key = load_privatekey(FILETYPE_PEM, intermediate_key_pem)
+ intermediate_server_cert = load_certificate(
+ FILETYPE_PEM, intermediate_server_cert_pem)
+ intermediate_server_key = load_privatekey(
+ FILETYPE_PEM, intermediate_server_key_pem)
+
def test_construction(self):
"""
Confirm we can create :py:obj:`OpenSSL.crypto.CRL`. Check
@@ -3407,6 +3420,15 @@
"""
self.assertRaises(Error, load_crl, FILETYPE_PEM, b"hello, world")
+ def test_get_issuer(self):
+ """
+ Load a known CRL and assert its issuer's common name is
+ what we expect from the encoded crlData string.
+ """
+ crl = load_crl(FILETYPE_PEM, crlData)
+ self.assertTrue(isinstance(crl.get_issuer(), X509Name))
+ self.assertEqual(crl.get_issuer().CN, 'Testing Root CA')
+
def test_dump_crl(self):
"""
The dumped CRL matches the original input.
@@ -3415,6 +3437,71 @@
buf = dump_crl(FILETYPE_PEM, crl)
assert buf == crlData
+ def _make_test_crl(self, issuer_cert, issuer_key, certs=()):
+ """
+ Create a CRL.
+
+ :param list[X509] certs: A list of certificates to revoke.
+ :rtype: CRL
+ """
+ crl = CRL()
+ for cert in certs:
+ revoked = Revoked()
+ # FIXME: This string splicing is an unfortunate implementation
+ # detail that has been reported in
+ # https://github.com/pyca/pyopenssl/issues/258
+ serial = hex(cert.get_serial_number())[2:].encode('utf-8')
+ revoked.set_serial(serial)
+ revoked.set_reason(b'unspecified')
+ revoked.set_rev_date(b'20140601000000Z')
+ crl.add_revoked(revoked)
+ crl.set_version(1)
+ crl.set_lastUpdate(b'20140601000000Z')
+ crl.set_nextUpdate(b'20180601000000Z')
+ crl.sign(issuer_cert, issuer_key, digest=b'sha512')
+ return crl
+
+ def test_verify_with_revoked(self):
+ """
+ :func:`verify_certificate` raises error when an intermediate
+ certificate is revoked.
+ """
+ store = X509Store()
+ store.add_cert(self.root_cert)
+ store.add_cert(self.intermediate_cert)
+ root_crl = self._make_test_crl(
+ self.root_cert, self.root_key, certs=[self.intermediate_cert])
+ intermediate_crl = self._make_test_crl(
+ self.intermediate_cert, self.intermediate_key, certs=[])
+ store.add_crl(root_crl)
+ store.add_crl(intermediate_crl)
+ store.set_flags(
+ X509StoreFlags.CRL_CHECK | X509StoreFlags.CRL_CHECK_ALL)
+ store_ctx = X509StoreContext(store, self.intermediate_server_cert)
+ e = self.assertRaises(
+ X509StoreContextError, store_ctx.verify_certificate)
+ self.assertEqual(e.args[0][2], 'certificate revoked')
+
+ def test_verify_with_missing_crl(self):
+ """
+ :func:`verify_certificate` raises error when an intermediate
+ certificate's CRL is missing.
+ """
+ store = X509Store()
+ store.add_cert(self.root_cert)
+ store.add_cert(self.intermediate_cert)
+ root_crl = self._make_test_crl(
+ self.root_cert, self.root_key, certs=[self.intermediate_cert])
+ store.add_crl(root_crl)
+ store.set_flags(
+ X509StoreFlags.CRL_CHECK | X509StoreFlags.CRL_CHECK_ALL)
+ store_ctx = X509StoreContext(store, self.intermediate_server_cert)
+ e = self.assertRaises(
+ X509StoreContextError, store_ctx.verify_certificate)
+ self.assertEqual(e.args[0][2], 'unable to get certificate CRL')
+ self.assertEqual(
+ e.certificate.get_subject().CN, 'intermediate-service')
+
class X509StoreContextTests(TestCase):
"""