aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/x509/ocsp.rst113
-rw-r--r--src/_cffi_src/openssl/ocsp.py2
-rw-r--r--src/cryptography/hazmat/backends/openssl/backend.py16
-rw-r--r--src/cryptography/x509/ocsp.py30
-rw-r--r--tests/x509/test_ocsp.py64
5 files changed, 225 insertions, 0 deletions
diff --git a/docs/x509/ocsp.rst b/docs/x509/ocsp.rst
index 72227f07..afbb2ef7 100644
--- a/docs/x509/ocsp.rst
+++ b/docs/x509/ocsp.rst
@@ -5,6 +5,69 @@ OCSP
.. testsetup::
+ import base64
+ pem_cert = b"""
+ -----BEGIN CERTIFICATE-----
+ MIIFvTCCBKWgAwIBAgICPyAwDQYJKoZIhvcNAQELBQAwRzELMAkGA1UEBhMCVVMx
+ FjAUBgNVBAoTDUdlb1RydXN0IEluYy4xIDAeBgNVBAMTF1JhcGlkU1NMIFNIQTI1
+ NiBDQSAtIEczMB4XDTE0MTAxNTEyMDkzMloXDTE4MTExNjAxMTUwM1owgZcxEzAR
+ BgNVBAsTCkdUNDg3NDI5NjUxMTAvBgNVBAsTKFNlZSB3d3cucmFwaWRzc2wuY29t
+ L3Jlc291cmNlcy9jcHMgKGMpMTQxLzAtBgNVBAsTJkRvbWFpbiBDb250cm9sIFZh
+ bGlkYXRlZCAtIFJhcGlkU1NMKFIpMRwwGgYDVQQDExN3d3cuY3J5cHRvZ3JhcGh5
+ LmlvMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAom/FebKJIot7Sp3s
+ itG1sicpe3thCssjI+g1JDAS7I3GLVNmbms1DOdIIqwf01gZkzzXBN2+9sOnyRaR
+ PPfCe1jTr3dk2y6rPE559vPa1nZQkhlzlhMhlPyjaT+S7g4Tio4qV2sCBZU01DZJ
+ CaksfohN+5BNVWoJzTbOcrHOEJ+M8B484KlBCiSxqf9cyNQKru4W3bHaCVNVJ8eu
+ 6i6KyhzLa0L7yK3LXwwXVs583C0/vwFhccGWsFODqD/9xHUzsBIshE8HKjdjDi7Y
+ 3BFQzVUQFjBB50NSZfAA/jcdt1blxJouc7z9T8Oklh+V5DDBowgAsrT4b6Z2Fq6/
+ r7D1GqivLK/ypUQmxq2WXWAUBb/Q6xHgxASxI4Br+CByIUQJsm8L2jzc7k+mF4hW
+ ltAIUkbo8fGiVnat0505YJgxWEDKOLc4Gda6d/7GVd5AvKrz242bUqeaWo6e4MTx
+ diku2Ma3rhdcr044Qvfh9hGyjqNjvhWY/I+VRWgihU7JrYvgwFdJqsQ5eiKT4OHi
+ gsejvWwkZzDtiQ+aQTrzM1FsY2swJBJsLSX4ofohlVRlIJCn/ME+XErj553431Lu
+ YQ5SzMd3nXzN78Vj6qzTfMUUY72UoT1/AcFiUMobgIqrrmwuNxfrkbVE2b6Bga74
+ FsJX63prvrJ41kuHK/16RQBM7fcCAwEAAaOCAWAwggFcMB8GA1UdIwQYMBaAFMOc
+ 8/zTRgg0u85Gf6B8W/PiCMtZMFcGCCsGAQUFBwEBBEswSTAfBggrBgEFBQcwAYYT
+ aHR0cDovL2d2LnN5bWNkLmNvbTAmBggrBgEFBQcwAoYaaHR0cDovL2d2LnN5bWNi
+ LmNvbS9ndi5jcnQwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMB
+ BggrBgEFBQcDAjAvBgNVHREEKDAmghN3d3cuY3J5cHRvZ3JhcGh5Lmlvgg9jcnlw
+ dG9ncmFwaHkuaW8wKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL2d2LnN5bWNiLmNv
+ bS9ndi5jcmwwDAYDVR0TAQH/BAIwADBFBgNVHSAEPjA8MDoGCmCGSAGG+EUBBzYw
+ LDAqBggrBgEFBQcCARYeaHR0cHM6Ly93d3cucmFwaWRzc2wuY29tL2xlZ2FsMA0G
+ CSqGSIb3DQEBCwUAA4IBAQAzIYO2jx7h17FBT74tJ2zbV9OKqGb7QF8y3wUtP4xc
+ dH80vprI/Cfji8s86kr77aAvAqjDjaVjHn7UzebhSUivvRPmfzRgyWBacomnXTSt
+ Xlt2dp2nDQuwGyK2vB7dMfKnQAkxwq1sYUXznB8i0IhhCAoXp01QGPKq51YoIlnF
+ 7DRMk6iEaL1SJbkIrLsCQyZFDf0xtfW9DqXugMMLoxeCsBhZJQzNyS2ryirrv9LH
+ aK3+6IZjrcyy9bkpz/gzJucyhU+75c4My/mnRCrtItRbCQuiI5pd5poDowm+HH9i
+ GVI9+0lAFwxOUnOnwsoI40iOoxjLMGB+CgFLKCGUcWxP
+ -----END CERTIFICATE-----
+ """
+ pem_issuer = b"""
+ -----BEGIN CERTIFICATE-----
+ MIIEJTCCAw2gAwIBAgIDAjp3MA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNVBAYTAlVT
+ MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
+ YWwgQ0EwHhcNMTQwODI5MjEzOTMyWhcNMjIwNTIwMjEzOTMyWjBHMQswCQYDVQQG
+ EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXUmFwaWRTU0wg
+ U0hBMjU2IENBIC0gRzMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCv
+ VJvZWF0eLFbG1eh/9H0WA//Qi1rkjqfdVC7UBMBdmJyNkA+8EGVf2prWRHzAn7Xp
+ SowLBkMEu/SW4ib2YQGRZjEiwzQ0Xz8/kS9EX9zHFLYDn4ZLDqP/oIACg8PTH2lS
+ 1p1kD8mD5xvEcKyU58Okaiy9uJ5p2L4KjxZjWmhxgHsw3hUEv8zTvz5IBVV6s9cQ
+ DAP8m/0Ip4yM26eO8R5j3LMBL3+vV8M8SKeDaCGnL+enP/C1DPz1hNFTvA5yT2AM
+ QriYrRmIV9cE7Ie/fodOoyH5U/02mEiN1vi7SPIpyGTRzFRIU4uvt2UevykzKdkp
+ YEj4/5G8V1jlNS67abZZAgMBAAGjggEdMIIBGTAfBgNVHSMEGDAWgBTAephojYn7
+ qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUw5zz/NNGCDS7zkZ/oHxb8+IIy1kwEgYD
+ VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwNQYDVR0fBC4wLDAqoCig
+ JoYkaHR0cDovL2cuc3ltY2IuY29tL2NybHMvZ3RnbG9iYWwuY3JsMC4GCCsGAQUF
+ BwEBBCIwIDAeBggrBgEFBQcwAYYSaHR0cDovL2cuc3ltY2QuY29tMEwGA1UdIARF
+ MEMwQQYKYIZIAYb4RQEHNjAzMDEGCCsGAQUFBwIBFiVodHRwOi8vd3d3Lmdlb3Ry
+ dXN0LmNvbS9yZXNvdXJjZXMvY3BzMA0GCSqGSIb3DQEBCwUAA4IBAQCjWB7GQzKs
+ rC+TeLfqrlRARy1+eI1Q9vhmrNZPc9ZE768LzFvB9E+aj0l+YK/CJ8cW8fuTgZCp
+ fO9vfm5FlBaEvexJ8cQO9K8EWYOHDyw7l8NaEpt7BDV7o5UzCHuTcSJCs6nZb0+B
+ kvwHtnm8hEqddwnxxYny8LScVKoSew26T++TGezvfU5ho452nFnPjJSxhJf3GrkH
+ uLLGTxN5279PURt/aQ1RKsHWFf83UTRlUfQevjhq7A6rvz17OQV79PP7GqHQyH5O
+ ZI3NjGFVkP46yl0lD/gdo0p0Vk8aVUBwdSWmMy66S6VdU5oNMOGNX2Esr8zvsJmh
+ gP8L8mJMcCaY
+ -----END CERTIFICATE-----
+ """
der_ocsp_req = (
b"0V0T0R0P0N0\t\x06\x05+\x0e\x03\x02\x1a\x05\x00\x04\x148\xcaF\x8c"
b"\x07D\x8d\xf4\x81\x96\xc7mmLpQ\x9e`\xa7\xbd\x04\x14yu\xbb\x84:\xcb"
@@ -39,6 +102,56 @@ Loading Requests
872625873161273451176241581705670534707360122361
+Creating Requests
+~~~~~~~~~~~~~~~~~
+
+.. class:: OCSPRequestBuilder
+
+ .. versionadded:: 2.4
+
+ This class is used to create :class:`~cryptography.x509.ocsp.OCSPRequest`
+ objects.
+
+
+ .. method:: add_request(cert, issuer, algorithm)
+
+ Adds a request using a certificate, issuer certificate, and hash
+ algorithm.
+
+ :param cert: The :class:`~cryptography.x509.Certificate` whose validity
+ is being checked.
+
+ :param issuer: The issuer :class:`~cryptography.x509.Certificate` of
+ the certificate that is being checked.
+
+ :param algorithm: A
+ :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`
+ instance. For OCSP only
+ :class:`~cryptography.hazmat.primitives.hashes.SHA1`,
+ :class:`~cryptography.hazmat.primitives.hashes.SHA224`,
+ :class:`~cryptography.hazmat.primitives.hashes.SHA256`,
+ :class:`~cryptography.hazmat.primitives.hashes.SHA384`, and
+ :class:`~cryptography.hazmat.primitives.hashes.SHA512` are allowed.
+
+ .. method:: build()
+
+ :returns: A new :class:`~cryptography.x509.ocsp.OCSPRequest`.
+
+ .. doctest::
+
+ >>> from cryptography.hazmat.backends import default_backend
+ >>> from cryptography.hazmat.primitives import serialization
+ >>> from cryptography.hazmat.primitives.hashes import SHA256
+ >>> from cryptography.x509 import load_pem_x509_certificate, ocsp
+ >>> cert = load_pem_x509_certificate(pem_cert, default_backend())
+ >>> issuer = load_pem_x509_certificate(pem_issuer, default_backend())
+ >>> builder = ocsp.OCSPRequestBuilder()
+ >>> builder = builder.add_request(cert, issuer, SHA256())
+ >>> req = builder.build()
+ >>> base64.b64encode(req.public_bytes(serialization.Encoding.DER))
+ b'MF8wXTBbMFkwVzANBglghkgBZQMEAgEFAAQgn3BowBaoh77h17ULfkX6781dUDPD82Taj8wO1jZWhZoEINxPgjoQth3w7q4AouKKerMxIMIuUG4EuWU2pZfwih52AgI/IA=='
+
+
Interfaces
~~~~~~~~~~
diff --git a/src/_cffi_src/openssl/ocsp.py b/src/_cffi_src/openssl/ocsp.py
index 1701f41c..61546027 100644
--- a/src/_cffi_src/openssl/ocsp.py
+++ b/src/_cffi_src/openssl/ocsp.py
@@ -35,6 +35,8 @@ OCSP_ONEREQ *OCSP_request_onereq_get0(OCSP_REQUEST *, int);
int OCSP_ONEREQ_get_ext_count(OCSP_ONEREQ *);
X509_EXTENSION *OCSP_ONEREQ_get_ext(OCSP_ONEREQ *, int);
OCSP_CERTID *OCSP_onereq_get0_id(OCSP_ONEREQ *);
+OCSP_ONEREQ *OCSP_request_add0_id(OCSP_REQUEST *, OCSP_CERTID *);
+OCSP_CERTID *OCSP_cert_to_id(const EVP_MD *, const X509 *, const X509 *);
OCSP_BASICRESP *OCSP_BASICRESP_new(void);
diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py
index 6a0446bc..bdf8f370 100644
--- a/src/cryptography/hazmat/backends/openssl/backend.py
+++ b/src/cryptography/hazmat/backends/openssl/backend.py
@@ -1430,6 +1430,22 @@ class Backend(object):
request = self._ffi.gc(request, self._lib.OCSP_REQUEST_free)
return _OCSPRequest(self, request)
+ def create_ocsp_request(self, builder):
+ ocsp_req = self._lib.OCSP_REQUEST_new()
+ self.openssl_assert(ocsp_req != self._ffi.NULL)
+ ocsp_req = self._ffi.gc(ocsp_req, self._lib.OCSP_REQUEST_free)
+ for cert, issuer, algorithm in builder._requests:
+ evp_md = self._lib.EVP_get_digestbyname(
+ algorithm.name.encode("ascii"))
+ self.openssl_assert(evp_md != self._ffi.NULL)
+ certid = self._lib.OCSP_cert_to_id(
+ evp_md, cert._x509, issuer._x509
+ )
+ self.openssl_assert(certid != self._ffi.NULL)
+ onereq = self._lib.OCSP_request_add0_id(ocsp_req, certid)
+ self.openssl_assert(onereq != self._ffi.NULL)
+ return _OCSPRequest(self, ocsp_req)
+
def elliptic_curve_exchange_algorithm_supported(self, algorithm, curve):
return (
self.elliptic_curve_supported(curve) and
diff --git a/src/cryptography/x509/ocsp.py b/src/cryptography/x509/ocsp.py
index 22894dde..0567197d 100644
--- a/src/cryptography/x509/ocsp.py
+++ b/src/cryptography/x509/ocsp.py
@@ -9,6 +9,7 @@ import abc
import six
from cryptography.hazmat.primitives import hashes
+from cryptography.x509 import Certificate
_OIDS_TO_HASH = {
@@ -25,6 +26,35 @@ def load_der_ocsp_request(data):
return backend.load_der_ocsp_request(data)
+class OCSPRequestBuilder(object):
+ def __init__(self, requests=[]):
+ self._requests = requests
+
+ def add_request(self, cert, issuer, algorithm):
+ allowed_hashes = (
+ hashes.SHA1, hashes.SHA224, hashes.SHA256,
+ hashes.SHA384, hashes.SHA512
+ )
+ if not isinstance(algorithm, allowed_hashes):
+ raise ValueError(
+ "Algorithm must be SHA1, SHA224, SHA256, SHA384, or SHA512"
+ )
+ if (
+ not isinstance(cert, Certificate) or
+ not isinstance(issuer, Certificate)
+ ):
+ raise TypeError("cert and issuer must be a Certificate")
+
+ return OCSPRequestBuilder(self._requests + [(cert, issuer, algorithm)])
+
+ def build(self):
+ from cryptography.hazmat.backends.openssl.backend import backend
+ if len(self._requests) == 0:
+ raise ValueError("You must add a request before building")
+
+ return backend.create_ocsp_request(self)
+
+
@six.add_metaclass(abc.ABCMeta)
class OCSPRequest(object):
@abc.abstractmethod
diff --git a/tests/x509/test_ocsp.py b/tests/x509/test_ocsp.py
index 22f34df2..709ef6f4 100644
--- a/tests/x509/test_ocsp.py
+++ b/tests/x509/test_ocsp.py
@@ -4,14 +4,17 @@
from __future__ import absolute_import, division, print_function
+import base64
import os
import pytest
+from cryptography import x509
from cryptography.exceptions import UnsupportedAlgorithm
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.x509 import ocsp
+from .test_x509 import _load_cert
from ..utils import load_vectors_from_file
@@ -23,6 +26,21 @@ def _load_data(filename, loader):
)
+def _cert_and_issuer():
+ from cryptography.hazmat.backends.openssl.backend import backend
+ cert = _load_cert(
+ os.path.join("x509", "cryptography.io.pem"),
+ x509.load_pem_x509_certificate,
+ backend
+ )
+ issuer = _load_cert(
+ os.path.join("x509", "rapidssl_sha256_ca_g3.pem"),
+ x509.load_pem_x509_certificate,
+ backend
+ )
+ return cert, issuer
+
+
class TestOCSPRequest(object):
def test_bad_request(self):
with pytest.raises(ValueError):
@@ -113,3 +131,49 @@ class TestOCSPRequest(object):
req.public_bytes("invalid")
with pytest.raises(ValueError):
req.public_bytes(serialization.Encoding.PEM)
+
+
+class TestOCSPRequestBuilder(object):
+ def test_create_ocsp_request_no_req(self):
+ builder = ocsp.OCSPRequestBuilder()
+ with pytest.raises(ValueError):
+ builder.build()
+
+ def test_create_ocsp_request_invalid_alg(self):
+ cert, issuer = _cert_and_issuer()
+ builder = ocsp.OCSPRequestBuilder()
+ with pytest.raises(ValueError):
+ builder.add_request(cert, issuer, hashes.MD5())
+
+ def test_create_ocsp_request_invalid_cert(self):
+ cert, issuer = _cert_and_issuer()
+ builder = ocsp.OCSPRequestBuilder()
+ with pytest.raises(TypeError):
+ builder.add_request(b"notacert", issuer, hashes.SHA1())
+
+ with pytest.raises(TypeError):
+ builder.add_request(cert, b"notacert", hashes.SHA1())
+
+ def test_create_ocsp_request(self):
+ cert, issuer = _cert_and_issuer()
+ builder = ocsp.OCSPRequestBuilder()
+ builder = builder.add_request(cert, issuer, hashes.SHA1())
+ req = builder.build()
+ serialized = req.public_bytes(serialization.Encoding.DER)
+ assert serialized == base64.b64decode(
+ b"MEMwQTA/MD0wOzAJBgUrDgMCGgUABBRAC0Z68eay0wmDug1gfn5ZN0gkxAQUw5zz"
+ b"/NNGCDS7zkZ/oHxb8+IIy1kCAj8g"
+ )
+
+ def test_create_ocsp_request_two_reqs(self):
+ builder = ocsp.OCSPRequestBuilder()
+ cert, issuer = _cert_and_issuer()
+ builder = builder.add_request(cert, issuer, hashes.SHA1())
+ builder = builder.add_request(cert, issuer, hashes.SHA1())
+ req = builder.build()
+ serialized = req.public_bytes(serialization.Encoding.DER)
+ assert serialized == base64.b64decode(
+ b"MIGDMIGAMH4wPTA7MAkGBSsOAwIaBQAEFEALRnrx5rLTCYO6DWB+flk3SCTEBBTD"
+ b"nPP800YINLvORn+gfFvz4gjLWQICPyAwPTA7MAkGBSsOAwIaBQAEFEALRnrx5rLT"
+ b"CYO6DWB+flk3SCTEBBTDnPP800YINLvORn+gfFvz4gjLWQICPyA="
+ )