From 60f264b0f293bfded7a0b4395715669d355a6185 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Thu, 10 Jan 2019 15:37:03 -0800 Subject: add signature_hash_algorithm to OCSPResponse (#4681) * add signature_hash_algorithm to OCSPResponse * fix pointless asserts --- CHANGELOG.rst | 2 + docs/development/test-vectors.rst | 2 + docs/x509/ocsp.rst | 10 +++++ src/cryptography/hazmat/backends/openssl/ocsp.py | 11 +++++ src/cryptography/x509/ocsp.py | 6 +++ tests/x509/test_ocsp.py | 50 +++++++++++++-------- .../x509/ocsp/resp-invalid-signature-oid.der | Bin 0 -> 527 bytes 7 files changed, 63 insertions(+), 18 deletions(-) create mode 100644 vectors/cryptography_vectors/x509/ocsp/resp-invalid-signature-oid.der diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 191d8042..42772af0 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -35,6 +35,8 @@ Changelog which immediately checks if the point is on the curve and supports compressed points. Deprecated the previous method :meth:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicNumbers.from_encoded_point`. +* Added :attr:`~cryptography.x509.ocsp.OCSPResponse.signature_hash_algorithm` + to ``OCSPResponse``. .. _v2-4-2: diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst index eb9ba4b4..a10125ac 100644 --- a/docs/development/test-vectors.rst +++ b/docs/development/test-vectors.rst @@ -471,6 +471,8 @@ X.509 OCSP Test Vectors revocation reason. * ``x509/ocsp/resp-revoked-no-next-update.der`` - An OCSP response that contains a revoked certificate and no ``nextUpdate`` value. +* ``x509/ocsp/resp-invalid-signature-oid.der`` - An OCSP response that was + modified to contain an MD2 signature algorithm object identifier. Custom X.509 OCSP Test Vectors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/x509/ocsp.rst b/docs/x509/ocsp.rst index 535ffdda..d3815d6f 100644 --- a/docs/x509/ocsp.rst +++ b/docs/x509/ocsp.rst @@ -426,6 +426,16 @@ Interfaces :raises ValueError: If ``response_status`` is not :class:`~cryptography.x509.ocsp.OCSPResponseStatus.SUCCESSFUL`. + .. attribute:: signature_hash_algorithm + + .. versionadded:: 2.5 + + :type: :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` + + Returns the + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` which + was used in signing this response. + .. attribute:: signature :type: bytes diff --git a/src/cryptography/hazmat/backends/openssl/ocsp.py b/src/cryptography/hazmat/backends/openssl/ocsp.py index 32e26a0a..16dbbc2a 100644 --- a/src/cryptography/hazmat/backends/openssl/ocsp.py +++ b/src/cryptography/hazmat/backends/openssl/ocsp.py @@ -126,6 +126,17 @@ class _OCSPResponse(object): oid = _obj2txt(self._backend, alg.algorithm) return x509.ObjectIdentifier(oid) + @property + @_requires_successful_response + def signature_hash_algorithm(self): + oid = self.signature_algorithm_oid + try: + return x509._SIG_OIDS_TO_HASH[oid] + except KeyError: + raise UnsupportedAlgorithm( + "Signature algorithm OID:{0} not recognized".format(oid) + ) + @property @_requires_successful_response def signature(self): diff --git a/src/cryptography/x509/ocsp.py b/src/cryptography/x509/ocsp.py index 2b0b1dc3..97933b1f 100644 --- a/src/cryptography/x509/ocsp.py +++ b/src/cryptography/x509/ocsp.py @@ -314,6 +314,12 @@ class OCSPResponse(object): The ObjectIdentifier of the signature algorithm """ + @abc.abstractproperty + def signature_hash_algorithm(self): + """ + Returns a HashAlgorithm corresponding to the type of the digest signed + """ + @abc.abstractproperty def signature(self): """ diff --git a/tests/x509/test_ocsp.py b/tests/x509/test_ocsp.py index fad48dab..3abaff50 100644 --- a/tests/x509/test_ocsp.py +++ b/tests/x509/test_ocsp.py @@ -583,6 +583,7 @@ class TestOCSPResponse(object): assert resp.response_status == ocsp.OCSPResponseStatus.SUCCESSFUL assert (resp.signature_algorithm_oid == x509.SignatureAlgorithmOID.RSA_WITH_SHA256) + assert isinstance(resp.signature_hash_algorithm, hashes.SHA256) assert resp.signature == base64.b64decode( b"I9KUlyLV/2LbNCVu1BQphxdNlU/jBzXsPYVscPjW5E93pCrSO84GkIWoOJtqsnt" b"78DLcQPnF3W24NXGzSGKlSWfXIsyoXCxnBm0mIbD5ZMnKyXEnqSR33Z9He/A+ML" @@ -602,7 +603,7 @@ class TestOCSPResponse(object): resp.signature, resp.tbs_response_bytes, PKCS1v15(), - hashes.SHA256() + resp.signature_hash_algorithm ) assert resp.certificates == [] assert resp.responder_key_hash is None @@ -630,39 +631,41 @@ class TestOCSPResponse(object): ) assert resp.response_status == ocsp.OCSPResponseStatus.UNAUTHORIZED with pytest.raises(ValueError): - assert resp.signature_algorithm_oid + resp.signature_algorithm_oid with pytest.raises(ValueError): - assert resp.signature + resp.signature_hash_algorithm with pytest.raises(ValueError): - assert resp.tbs_response_bytes + resp.signature with pytest.raises(ValueError): - assert resp.certificates + resp.tbs_response_bytes with pytest.raises(ValueError): - assert resp.responder_key_hash + resp.certificates with pytest.raises(ValueError): - assert resp.responder_name + resp.responder_key_hash with pytest.raises(ValueError): - assert resp.produced_at + resp.responder_name with pytest.raises(ValueError): - assert resp.certificate_status + resp.produced_at with pytest.raises(ValueError): - assert resp.revocation_time + resp.certificate_status with pytest.raises(ValueError): - assert resp.revocation_reason + resp.revocation_time with pytest.raises(ValueError): - assert resp.this_update + resp.revocation_reason with pytest.raises(ValueError): - assert resp.next_update + resp.this_update with pytest.raises(ValueError): - assert resp.issuer_key_hash + resp.next_update with pytest.raises(ValueError): - assert resp.issuer_name_hash + resp.issuer_key_hash with pytest.raises(ValueError): - assert resp.hash_algorithm + resp.issuer_name_hash with pytest.raises(ValueError): - assert resp.serial_number + resp.hash_algorithm with pytest.raises(ValueError): - assert resp.extensions + resp.serial_number + with pytest.raises(ValueError): + resp.extensions def test_load_revoked(self): resp = _load_data( @@ -684,6 +687,17 @@ class TestOCSPResponse(object): assert isinstance(resp.certificates[0], x509.Certificate) assert resp.certificate_status == ocsp.OCSPCertStatus.UNKNOWN + def test_load_invalid_signature_oid(self): + resp = _load_data( + os.path.join("x509", "ocsp", "resp-invalid-signature-oid.der"), + ocsp.load_der_ocsp_response, + ) + assert resp.signature_algorithm_oid == x509.ObjectIdentifier( + "1.2.840.113549.1.1.2" + ) + with pytest.raises(UnsupportedAlgorithm): + resp.signature_hash_algorithm + def test_load_responder_key_hash(self): resp = _load_data( os.path.join("x509", "ocsp", "resp-responder-key-hash.der"), diff --git a/vectors/cryptography_vectors/x509/ocsp/resp-invalid-signature-oid.der b/vectors/cryptography_vectors/x509/ocsp/resp-invalid-signature-oid.der new file mode 100644 index 00000000..e2c7dd87 Binary files /dev/null and b/vectors/cryptography_vectors/x509/ocsp/resp-invalid-signature-oid.der differ -- cgit v1.2.3