aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Kehrer <paul.l.kehrer@gmail.com>2015-12-25 23:55:47 -0600
committerPaul Kehrer <paul.l.kehrer@gmail.com>2015-12-27 08:36:38 -0600
commite5f152b0a93b105cc32fe5adf06899f4f5cd0936 (patch)
tree1332ab20e70a057dc5fd5a69ab5144ed5fc76286 /src
parent28077b621390965fbe1bca3409691974c894251d (diff)
downloadcryptography-e5f152b0a93b105cc32fe5adf06899f4f5cd0936.tar.gz
cryptography-e5f152b0a93b105cc32fe5adf06899f4f5cd0936.tar.bz2
cryptography-e5f152b0a93b105cc32fe5adf06899f4f5cd0936.zip
support CRL entry extension encoding in the RevokedCertificateBuilder
Diffstat (limited to 'src')
-rw-r--r--src/cryptography/hazmat/backends/openssl/backend.py80
-rw-r--r--src/cryptography/x509/base.py15
2 files changed, 92 insertions, 3 deletions
diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py
index c0c9ebe2..6c7a6840 100644
--- a/src/cryptography/hazmat/backends/openssl/backend.py
+++ b/src/cryptography/hazmat/backends/openssl/backend.py
@@ -53,7 +53,7 @@ from cryptography.hazmat.primitives.ciphers.algorithms import (
from cryptography.hazmat.primitives.ciphers.modes import (
CBC, CFB, CFB8, CTR, ECB, GCM, OFB
)
-from cryptography.x509.oid import ExtensionOID, NameOID
+from cryptography.x509.oid import CRLEntryExtensionOID, ExtensionOID, NameOID
_MemoryBIO = collections.namedtuple("_MemoryBIO", ["bio", "char_ptr"])
@@ -164,6 +164,68 @@ def _encode_crl_number(backend, crl_number):
return pp, r
+_CRL_ENTRY_REASONFLAGS = {
+ x509.ReasonFlags.unspecified: 0,
+ x509.ReasonFlags.key_compromise: 1,
+ x509.ReasonFlags.ca_compromise: 2,
+ x509.ReasonFlags.affiliation_changed: 3,
+ x509.ReasonFlags.superseded: 4,
+ x509.ReasonFlags.cessation_of_operation: 5,
+ x509.ReasonFlags.certificate_hold: 6,
+ x509.ReasonFlags.remove_from_crl: 8,
+ x509.ReasonFlags.privilege_withdrawn: 9,
+ x509.ReasonFlags.aa_compromise: 10
+}
+
+
+def _encode_crl_reason(backend, crl_reason):
+ asn1enum = backend._lib.ASN1_ENUMERATED_new()
+ backend.openssl_assert(asn1enum != backend._ffi.NULL)
+ asn1enum = backend._ffi.gc(asn1enum, backend._lib.ASN1_ENUMERATED_free)
+ res = backend._lib.ASN1_ENUMERATED_set(
+ asn1enum, _CRL_ENTRY_REASONFLAGS[crl_reason.reason]
+ )
+ backend.openssl_assert(res == 1)
+ pp = backend._ffi.new('unsigned char **')
+ r = backend._lib.i2d_ASN1_ENUMERATED(asn1enum, pp)
+ backend.openssl_assert(r > 0)
+ pp = backend._ffi.gc(
+ pp, lambda pointer: backend._lib.OPENSSL_free(pointer[0])
+ )
+ return pp, r
+
+
+def _encode_invalidity_date(backend, invalidity_date):
+ time = backend._lib.ASN1_GENERALIZEDTIME_set(
+ backend._ffi.NULL, calendar.timegm(
+ invalidity_date.invalidity_date.timetuple()
+ )
+ )
+ backend.openssl_assert(time != backend._ffi.NULL)
+ time = backend._ffi.gc(time, backend._lib.ASN1_GENERALIZEDTIME_free)
+ pp = backend._ffi.new('unsigned char **')
+ r = backend._lib.i2d_ASN1_GENERALIZEDTIME(time, pp)
+ backend.openssl_assert(r > 0)
+ pp = backend._ffi.gc(
+ pp, lambda pointer: backend._lib.OPENSSL_free(pointer[0])
+ )
+ return pp, r
+
+
+def _encode_certificate_issuer(backend, certificate_issuer):
+ general_names = _encode_general_names(backend, certificate_issuer)
+ general_names = backend._ffi.gc(
+ general_names, backend._lib.GENERAL_NAMES_free
+ )
+ pp = backend._ffi.new("unsigned char **")
+ r = backend._lib.i2d_GENERAL_NAMES(general_names, pp)
+ backend.openssl_assert(r > 0)
+ pp = backend._ffi.gc(
+ pp, lambda pointer: backend._lib.OPENSSL_free(pointer[0])
+ )
+ return pp, r
+
+
def _encode_certificate_policies(backend, certificate_policies):
cp = backend._lib.sk_POLICYINFO_new_null()
backend.openssl_assert(cp != backend._ffi.NULL)
@@ -645,6 +707,12 @@ _CRL_EXTENSION_ENCODE_HANDLERS = {
ExtensionOID.CRL_NUMBER: _encode_crl_number,
}
+_CRL_ENTRY_EXTENSION_ENCODE_HANDLERS = {
+ CRLEntryExtensionOID.CERTIFICATE_ISSUER: _encode_certificate_issuer,
+ CRLEntryExtensionOID.CRL_REASON: _encode_crl_reason,
+ CRLEntryExtensionOID.INVALIDITY_DATE: _encode_invalidity_date,
+}
+
class _PasswordUserdata(object):
def __init__(self, password):
@@ -1505,7 +1573,6 @@ class Backend(object):
next_update = self._ffi.gc(next_update, self._lib.ASN1_TIME_free)
res = self._lib.X509_CRL_set_nextUpdate(x509_crl, next_update)
self.openssl_assert(res == 1)
- # TODO: support revoked certificates
# Add extensions.
self._create_x509_extensions(
@@ -1583,7 +1650,14 @@ class Backend(object):
calendar.timegm(builder._revocation_date.timetuple())
)
self.openssl_assert(res != self._ffi.NULL)
- # TODO: add crl entry extensions
+ # add CRL entry extensions
+ self._create_x509_extensions(
+ extensions=builder._extensions,
+ handlers=_CRL_ENTRY_EXTENSION_ENCODE_HANDLERS,
+ x509_obj=x509_revoked,
+ add_func=self._lib.X509_REVOKED_add_ext,
+ gc=True
+ )
return _RevokedCertificate(self, None, x509_revoked)
def load_pem_private_key(self, data, password):
diff --git a/src/cryptography/x509/base.py b/src/cryptography/x509/base.py
index bc927e87..55e965f7 100644
--- a/src/cryptography/x509/base.py
+++ b/src/cryptography/x509/base.py
@@ -650,6 +650,21 @@ class RevokedCertificateBuilder(object):
self._serial_number, time, self._extensions
)
+ def add_extension(self, extension, critical):
+ if not isinstance(extension, ExtensionType):
+ raise TypeError("extension must be an ExtensionType")
+
+ extension = Extension(extension.oid, critical, extension)
+
+ # TODO: This is quadratic in the number of extensions
+ for e in self._extensions:
+ if e.oid == extension.oid:
+ raise ValueError('This extension has already been set.')
+ return RevokedCertificateBuilder(
+ self._serial_number, self._revocation_date,
+ self._extensions + [extension]
+ )
+
def build(self, backend):
if self._serial_number is None:
raise ValueError("A revoked certificate must have a serial number")