aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Gaynor <alex.gaynor@gmail.com>2018-08-31 18:25:52 -0500
committerPaul Kehrer <paul.l.kehrer@gmail.com>2018-08-31 19:25:52 -0400
commitdd6b78be80e9b31e07a9ef695aaa902ef042dcfd (patch)
treecaba9f7db963f92cd2d05a91ae356cc596409243
parent33dbd9365f4018c6e010d99f702dd9cad3e7c5c6 (diff)
downloadcryptography-dd6b78be80e9b31e07a9ef695aaa902ef042dcfd.tar.gz
cryptography-dd6b78be80e9b31e07a9ef695aaa902ef042dcfd.tar.bz2
cryptography-dd6b78be80e9b31e07a9ef695aaa902ef042dcfd.zip
Fixes #4333 -- added support for precert poison extension (#4442)
* Fixes #4333 -- added support for precert poison extension * Make work on all OpenSSL versions * fixed flake8 + docs * fix for older OpenSSLs * document this * spell
-rw-r--r--CHANGELOG.rst1
-rw-r--r--docs/x509/reference.rst23
-rw-r--r--src/cryptography/hazmat/backends/openssl/backend.py6
-rw-r--r--src/cryptography/hazmat/backends/openssl/decode_asn1.py21
-rw-r--r--src/cryptography/x509/__init__.py4
-rw-r--r--src/cryptography/x509/extensions.py5
-rw-r--r--src/cryptography/x509/oid.py3
-rw-r--r--tests/x509/test_x509_ext.py29
8 files changed, 86 insertions, 6 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index a614df84..8c08fcbc 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -13,6 +13,7 @@ Changelog
support, however we strongly encourage all users to upgrade or install
``cryptography`` from a wheel.
* Added initial :doc:`OCSP </x509/ocsp>` support.
+* Added support for :class:`~cryptography.x509.PrecertPoison`.
.. _v2-3-1:
diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst
index 5fa8471b..ede08aa5 100644
--- a/docs/x509/reference.rst
+++ b/docs/x509/reference.rst
@@ -1944,6 +1944,23 @@ X.509 Extensions
:attr:`~cryptography.x509.oid.ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS`.
+.. class:: PrecertPoison()
+
+ .. versionadded:: 2.4
+
+ This extension indicates that the certificate should not be treated as a
+ certificate for the purposes of validation, but is instead for submission
+ to a certificate transparency log in order to obtain SCTs which will be
+ embedded in a :class:`PrecertificateSignedCertificateTimestamps` extension
+ on the final certificate.
+
+ .. attribute:: oid
+
+ :type: :class:`ObjectIdentifier`
+
+ Returns :attr:`~cryptography.x509.oid.ExtensionOID.PRECERT_POISON`.
+
+
.. class:: DeltaCRLIndicator(crl_number)
.. versionadded:: 2.1
@@ -2804,6 +2821,12 @@ instances. The following common OIDs are available as constants.
Corresponds to the dotted string ``"1.3.6.1.4.1.11129.2.4.2"``.
+ .. attribute:: PRECERT_POISON
+
+ .. versionadded:: 2.4
+
+ Corresponds to the dotted string ``"1.3.6.1.4.1.11129.2.4.3"``.
+
.. attribute:: POLICY_CONSTRAINTS
Corresponds to the dotted string ``"2.5.29.36"``. The identifier for the
diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py
index 64d26afd..58fe492f 100644
--- a/src/cryptography/hazmat/backends/openssl/backend.py
+++ b/src/cryptography/hazmat/backends/openssl/backend.py
@@ -11,6 +11,8 @@ import contextlib
import itertools
from contextlib import contextmanager
+import asn1crypto.core
+
import six
from cryptography import utils, x509
@@ -965,6 +967,10 @@ class Backend(object):
asn1 = _Integers([x.value for x in extension.value]).dump()
value = _encode_asn1_str_gc(self, asn1, len(asn1))
return self._create_raw_x509_extension(extension, value)
+ elif isinstance(extension.value, x509.PrecertPoison):
+ asn1 = asn1crypto.core.Null().dump()
+ value = _encode_asn1_str_gc(self, asn1, len(asn1))
+ return self._create_raw_x509_extension(extension, value)
else:
try:
encode = handlers[extension.oid]
diff --git a/src/cryptography/hazmat/backends/openssl/decode_asn1.py b/src/cryptography/hazmat/backends/openssl/decode_asn1.py
index 31fb8cfc..47fa911e 100644
--- a/src/cryptography/hazmat/backends/openssl/decode_asn1.py
+++ b/src/cryptography/hazmat/backends/openssl/decode_asn1.py
@@ -7,7 +7,7 @@ from __future__ import absolute_import, division, print_function
import datetime
import ipaddress
-from asn1crypto.core import Integer, SequenceOf
+import asn1crypto.core
from cryptography import x509
from cryptography.x509.extensions import _TLS_FEATURE_TYPE_TO_ENUM
@@ -17,8 +17,8 @@ from cryptography.x509.oid import (
)
-class _Integers(SequenceOf):
- _child_spec = Integer
+class _Integers(asn1crypto.core.SequenceOf):
+ _child_spec = asn1crypto.core.Integer
def _obj2txt(backend, obj):
@@ -202,8 +202,8 @@ class _X509ExtensionParser(object):
"Duplicate {0} extension found".format(oid), oid
)
- # This OID is only supported in OpenSSL 1.1.0+ but we want
- # to support it in all versions of OpenSSL so we decode it
+ # These OIDs are only supported in OpenSSL 1.1.0+ but we want
+ # to support them in all versions of OpenSSL so we decode them
# ourselves.
if oid == ExtensionOID.TLS_FEATURE:
data = backend._lib.X509_EXTENSION_get_data(ext)
@@ -214,6 +214,17 @@ class _X509ExtensionParser(object):
extensions.append(x509.Extension(oid, critical, value))
seen_oids.add(oid)
continue
+ elif oid == ExtensionOID.PRECERT_POISON:
+ data = backend._lib.X509_EXTENSION_get_data(ext)
+ parsed = asn1crypto.core.Null.load(
+ _asn1_string_to_bytes(backend, data)
+ )
+ assert parsed == asn1crypto.core.Null()
+ extensions.append(x509.Extension(
+ oid, critical, x509.PrecertPoison()
+ ))
+ seen_oids.add(oid)
+ continue
try:
handler = self.handlers[oid]
diff --git a/src/cryptography/x509/__init__.py b/src/cryptography/x509/__init__.py
index d2f9b049..15459a12 100644
--- a/src/cryptography/x509/__init__.py
+++ b/src/cryptography/x509/__init__.py
@@ -22,7 +22,8 @@ from cryptography.x509.extensions import (
Extension, ExtensionNotFound, ExtensionType, Extensions, FreshestCRL,
GeneralNames, InhibitAnyPolicy, InvalidityDate, IssuerAlternativeName,
KeyUsage, NameConstraints, NoticeReference, OCSPNoCheck, PolicyConstraints,
- PolicyInformation, PrecertificateSignedCertificateTimestamps, ReasonFlags,
+ PolicyInformation, PrecertPoison,
+ PrecertificateSignedCertificateTimestamps, ReasonFlags,
SubjectAlternativeName, SubjectKeyIdentifier, TLSFeature, TLSFeatureType,
UnrecognizedExtension, UserNotice
)
@@ -182,4 +183,5 @@ __all__ = [
"UnrecognizedExtension",
"PolicyConstraints",
"PrecertificateSignedCertificateTimestamps",
+ "PrecertPoison",
]
diff --git a/src/cryptography/x509/extensions.py b/src/cryptography/x509/extensions.py
index eb4b927f..08af03c8 100644
--- a/src/cryptography/x509/extensions.py
+++ b/src/cryptography/x509/extensions.py
@@ -855,6 +855,11 @@ class OCSPNoCheck(object):
@utils.register_interface(ExtensionType)
+class PrecertPoison(object):
+ oid = ExtensionOID.PRECERT_POISON
+
+
+@utils.register_interface(ExtensionType)
class TLSFeature(object):
oid = ExtensionOID.TLS_FEATURE
diff --git a/src/cryptography/x509/oid.py b/src/cryptography/x509/oid.py
index 90003d79..77e3fa63 100644
--- a/src/cryptography/x509/oid.py
+++ b/src/cryptography/x509/oid.py
@@ -91,6 +91,9 @@ class ExtensionOID(object):
PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS = (
ObjectIdentifier("1.3.6.1.4.1.11129.2.4.2")
)
+ PRECERT_POISON = (
+ ObjectIdentifier("1.3.6.1.4.1.11129.2.4.3")
+ )
class CRLEntryExtensionOID(object):
diff --git a/tests/x509/test_x509_ext.py b/tests/x509/test_x509_ext.py
index c052f859..7e0ae220 100644
--- a/tests/x509/test_x509_ext.py
+++ b/tests/x509/test_x509_ext.py
@@ -4442,6 +4442,35 @@ class TestInhibitAnyPolicyExtension(object):
@pytest.mark.requires_backend_interface(interface=RSABackend)
@pytest.mark.requires_backend_interface(interface=X509Backend)
+class TestPrecertPoisonExtension(object):
+ def test_load(self, backend):
+ cert = _load_cert(
+ os.path.join("x509", "cryptography.io.precert.pem"),
+ x509.load_pem_x509_certificate,
+ backend
+ )
+ poison = cert.extensions.get_extension_for_oid(
+ ExtensionOID.PRECERT_POISON
+ ).value
+ assert isinstance(poison, x509.PrecertPoison)
+ poison = cert.extensions.get_extension_for_class(
+ x509.PrecertPoison
+ ).value
+ assert isinstance(poison, x509.PrecertPoison)
+
+ def test_generate(self, backend):
+ private_key = RSA_KEY_2048.private_key(backend)
+ cert = _make_certbuilder(private_key).add_extension(
+ x509.PrecertPoison(), critical=True
+ ).sign(private_key, hashes.SHA256(), backend)
+ poison = cert.extensions.get_extension_for_oid(
+ ExtensionOID.PRECERT_POISON
+ ).value
+ assert isinstance(poison, x509.PrecertPoison)
+
+
+@pytest.mark.requires_backend_interface(interface=RSABackend)
+@pytest.mark.requires_backend_interface(interface=X509Backend)
class TestPrecertificateSignedCertificateTimestampsExtension(object):
def test_init(self):
with pytest.raises(TypeError):