aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Kehrer <paul.l.kehrer@gmail.com>2018-10-30 10:23:30 +0800
committerAlex Gaynor <alex.gaynor@gmail.com>2018-10-29 22:23:30 -0400
commit74ce48c5d00e4846740d248a65d35b874f15afe2 (patch)
tree6926bba7f30e2d435dea5a86ec102130be084dd5
parentd91401d4d38d7f738392a69df43b4fd8b8e6c6e8 (diff)
downloadcryptography-74ce48c5d00e4846740d248a65d35b874f15afe2.tar.gz
cryptography-74ce48c5d00e4846740d248a65d35b874f15afe2.tar.bz2
cryptography-74ce48c5d00e4846740d248a65d35b874f15afe2.zip
Add eq/ne/hash to PrecertificateSignedCertificateTimestamps (#4534)
* Add eq/ne/hash to PrecertificateSignedCertificateTimestamps This requires adding it to SignedCertificateTimestamps as well * slightly more consistent * right, these need to be conditional * compare by signature * don't use private API
-rw-r--r--src/cryptography/hazmat/backends/openssl/x509.py20
-rw-r--r--src/cryptography/x509/extensions.py15
-rw-r--r--tests/x509/test_x509_ext.py154
3 files changed, 189 insertions, 0 deletions
diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py
index ad838b7f..ac1838c6 100644
--- a/src/cryptography/hazmat/backends/openssl/x509.py
+++ b/src/cryptography/hazmat/backends/openssl/x509.py
@@ -534,3 +534,23 @@ class _SignedCertificateTimestamp(object):
# we only have precerts.
assert entry_type == self._backend._lib.CT_LOG_ENTRY_TYPE_PRECERT
return x509.certificate_transparency.LogEntryType.PRE_CERTIFICATE
+
+ @property
+ def _signature(self):
+ ptrptr = self._backend._ffi.new("unsigned char **")
+ res = self._backend._lib.SCT_get0_signature(self._sct, ptrptr)
+ self._backend.openssl_assert(res > 0)
+ self._backend.openssl_assert(ptrptr[0] != self._backend._ffi.NULL)
+ return self._backend._ffi.buffer(ptrptr[0], res)[:]
+
+ def __hash__(self):
+ return hash(self._signature)
+
+ def __eq__(self, other):
+ if not isinstance(other, _SignedCertificateTimestamp):
+ return NotImplemented
+
+ return self._signature == other._signature
+
+ def __ne__(self, other):
+ return not self == other
diff --git a/src/cryptography/x509/extensions.py b/src/cryptography/x509/extensions.py
index b2d9908e..6301af5a 100644
--- a/src/cryptography/x509/extensions.py
+++ b/src/cryptography/x509/extensions.py
@@ -1402,6 +1402,21 @@ class PrecertificateSignedCertificateTimestamps(object):
)
)
+ def __hash__(self):
+ return hash(tuple(self._signed_certificate_timestamps))
+
+ def __eq__(self, other):
+ if not isinstance(other, PrecertificateSignedCertificateTimestamps):
+ return NotImplemented
+
+ return (
+ self._signed_certificate_timestamps ==
+ other._signed_certificate_timestamps
+ )
+
+ def __ne__(self, other):
+ return not self == other
+
@utils.register_interface(ExtensionType)
class OCSPNonce(object):
diff --git a/tests/x509/test_x509_ext.py b/tests/x509/test_x509_ext.py
index 7a43c851..9eac9a27 100644
--- a/tests/x509/test_x509_ext.py
+++ b/tests/x509/test_x509_ext.py
@@ -4471,6 +4471,85 @@ class TestPrecertPoisonExtension(object):
@pytest.mark.requires_backend_interface(interface=RSABackend)
@pytest.mark.requires_backend_interface(interface=X509Backend)
+class TestSignedCertificateTimestamps(object):
+ @pytest.mark.supported(
+ only_if=lambda backend: (
+ backend._lib.CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER),
+ skip_message="Requires OpenSSL 1.1.0f+",
+ )
+ def test_eq(self, backend):
+ sct = _load_cert(
+ os.path.join("x509", "badssl-sct.pem"),
+ x509.load_pem_x509_certificate,
+ backend
+ ).extensions.get_extension_for_class(
+ x509.PrecertificateSignedCertificateTimestamps
+ ).value[0]
+ sct2 = _load_cert(
+ os.path.join("x509", "badssl-sct.pem"),
+ x509.load_pem_x509_certificate,
+ backend
+ ).extensions.get_extension_for_class(
+ x509.PrecertificateSignedCertificateTimestamps
+ ).value[0]
+ assert sct == sct2
+
+ @pytest.mark.supported(
+ only_if=lambda backend: (
+ backend._lib.CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER),
+ skip_message="Requires OpenSSL 1.1.0f+",
+ )
+ def test_ne(self, backend):
+ sct = _load_cert(
+ os.path.join("x509", "badssl-sct.pem"),
+ x509.load_pem_x509_certificate,
+ backend
+ ).extensions.get_extension_for_class(
+ x509.PrecertificateSignedCertificateTimestamps
+ ).value[0]
+ sct2 = _load_cert(
+ os.path.join("x509", "cryptography-scts.pem"),
+ x509.load_pem_x509_certificate,
+ backend
+ ).extensions.get_extension_for_class(
+ x509.PrecertificateSignedCertificateTimestamps
+ ).value[0]
+ assert sct != sct2
+ assert sct != object()
+
+ @pytest.mark.supported(
+ only_if=lambda backend: (
+ backend._lib.CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER),
+ skip_message="Requires OpenSSL 1.1.0f+",
+ )
+ def test_hash(self, backend):
+ sct = _load_cert(
+ os.path.join("x509", "badssl-sct.pem"),
+ x509.load_pem_x509_certificate,
+ backend
+ ).extensions.get_extension_for_class(
+ x509.PrecertificateSignedCertificateTimestamps
+ ).value[0]
+ sct2 = _load_cert(
+ os.path.join("x509", "badssl-sct.pem"),
+ x509.load_pem_x509_certificate,
+ backend
+ ).extensions.get_extension_for_class(
+ x509.PrecertificateSignedCertificateTimestamps
+ ).value[0]
+ sct3 = _load_cert(
+ os.path.join("x509", "cryptography-scts.pem"),
+ x509.load_pem_x509_certificate,
+ backend
+ ).extensions.get_extension_for_class(
+ x509.PrecertificateSignedCertificateTimestamps
+ ).value[0]
+ assert hash(sct) == hash(sct2)
+ assert hash(sct) != hash(sct3)
+
+
+@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):
@@ -4486,6 +4565,81 @@ class TestPrecertificateSignedCertificateTimestampsExtension(object):
backend._lib.CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER),
skip_message="Requires OpenSSL 1.1.0f+",
)
+ def test_eq(self, backend):
+ psct1 = _load_cert(
+ os.path.join("x509", "badssl-sct.pem"),
+ x509.load_pem_x509_certificate,
+ backend
+ ).extensions.get_extension_for_class(
+ x509.PrecertificateSignedCertificateTimestamps
+ ).value
+ psct2 = _load_cert(
+ os.path.join("x509", "badssl-sct.pem"),
+ x509.load_pem_x509_certificate,
+ backend
+ ).extensions.get_extension_for_class(
+ x509.PrecertificateSignedCertificateTimestamps
+ ).value
+ assert psct1 == psct2
+
+ @pytest.mark.supported(
+ only_if=lambda backend: (
+ backend._lib.CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER),
+ skip_message="Requires OpenSSL 1.1.0f+",
+ )
+ def test_ne(self, backend):
+ psct1 = _load_cert(
+ os.path.join("x509", "cryptography-scts.pem"),
+ x509.load_pem_x509_certificate,
+ backend
+ ).extensions.get_extension_for_class(
+ x509.PrecertificateSignedCertificateTimestamps
+ ).value
+ psct2 = _load_cert(
+ os.path.join("x509", "badssl-sct.pem"),
+ x509.load_pem_x509_certificate,
+ backend
+ ).extensions.get_extension_for_class(
+ x509.PrecertificateSignedCertificateTimestamps
+ ).value
+ assert psct1 != psct2
+ assert psct1 != object()
+
+ @pytest.mark.supported(
+ only_if=lambda backend: (
+ backend._lib.CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER),
+ skip_message="Requires OpenSSL 1.1.0f+",
+ )
+ def test_hash(self, backend):
+ psct1 = _load_cert(
+ os.path.join("x509", "badssl-sct.pem"),
+ x509.load_pem_x509_certificate,
+ backend
+ ).extensions.get_extension_for_class(
+ x509.PrecertificateSignedCertificateTimestamps
+ ).value
+ psct2 = _load_cert(
+ os.path.join("x509", "badssl-sct.pem"),
+ x509.load_pem_x509_certificate,
+ backend
+ ).extensions.get_extension_for_class(
+ x509.PrecertificateSignedCertificateTimestamps
+ ).value
+ psct3 = _load_cert(
+ os.path.join("x509", "cryptography-scts.pem"),
+ x509.load_pem_x509_certificate,
+ backend
+ ).extensions.get_extension_for_class(
+ x509.PrecertificateSignedCertificateTimestamps
+ ).value
+ assert hash(psct1) == hash(psct2)
+ assert hash(psct1) != hash(psct3)
+
+ @pytest.mark.supported(
+ only_if=lambda backend: (
+ backend._lib.CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER),
+ skip_message="Requires OpenSSL 1.1.0f+",
+ )
def test_simple(self, backend):
cert = _load_cert(
os.path.join("x509", "badssl-sct.pem"),