mirror of https://github.com/wolfSSL/wolfssl.git
ocsp: add tests
parent
3a3238eb9f
commit
2fe413d80f
|
@ -2511,6 +2511,7 @@ if(WOLFSSL_EXAMPLES)
|
|||
tests/api/test_ripemd.c
|
||||
tests/api/test_hash.c
|
||||
tests/api/test_ascon.c
|
||||
tests/api/test_ocsp.c
|
||||
tests/hash.c
|
||||
tests/srp.c
|
||||
tests/suites.c
|
||||
|
|
|
@ -36,4 +36,5 @@ EXTRA_DIST += \
|
|||
certs/ocsp/test-response.der \
|
||||
certs/ocsp/test-response-rsapss.der \
|
||||
certs/ocsp/test-response-nointern.der \
|
||||
certs/ocsp/test-multi-response.der
|
||||
certs/ocsp/test-multi-response.der \
|
||||
certs/ocsp/test-leaf-response.der
|
||||
|
|
|
@ -100,6 +100,16 @@ openssl ocsp -issuer ./root-ca-cert.pem -cert ./intermediate1-ca-cert.pem -cert
|
|||
kill $PID
|
||||
wait $PID
|
||||
|
||||
# Create a response DER buffer for testing leaf certificate
|
||||
openssl ocsp -port 22221 -ndays 1000 -index \
|
||||
./index-intermediate1-ca-issued-certs.txt -rsigner ocsp-responder-cert.pem \
|
||||
-rkey ocsp-responder-key.pem -CA intermediate1-ca-cert.pem -partial_chain &
|
||||
PID=$!
|
||||
sleep 1 # Make sure server is ready
|
||||
|
||||
openssl ocsp -issuer ./intermediate1-ca-cert.pem -cert ./server1-cert.pem -url http://localhost:22221/ -respout test-leaf-response.der -noverify
|
||||
kill $PID
|
||||
wait $PID
|
||||
|
||||
# now start up a responder that signs using rsa-pss
|
||||
openssl ocsp -port 22221 -ndays 1000 -index index-ca-and-intermediate-cas.txt -rsigner ocsp-responder-cert.pem -rkey ocsp-responder-key.pem -CA root-ca-cert.pem -rsigopt rsa_padding_mode:pss &
|
||||
|
|
Binary file not shown.
|
@ -301,6 +301,7 @@
|
|||
#include <tests/api/test_hash.h>
|
||||
#include <tests/api/test_ascon.h>
|
||||
#include <tests/api/test_dtls.h>
|
||||
#include <tests/api/test_ocsp.h>
|
||||
|
||||
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && !defined(NO_TLS) && \
|
||||
!defined(NO_RSA) && !defined(SINGLE_THREADED) && \
|
||||
|
@ -99372,6 +99373,9 @@ TEST_CASE testCases[] = {
|
|||
TEST_DECL(test_wolfSSL_SSLDisableRead),
|
||||
TEST_DECL(test_wolfSSL_inject),
|
||||
TEST_DECL(test_wolfSSL_dtls_cid_parse),
|
||||
TEST_DECL(test_ocsp_status_callback),
|
||||
TEST_DECL(test_ocsp_basic_verify),
|
||||
TEST_DECL(test_ocsp_response_parsing),
|
||||
/* This test needs to stay at the end to clean up any caches allocated. */
|
||||
TEST_DECL(test_wolfSSL_Cleanup)
|
||||
};
|
||||
|
|
|
@ -0,0 +1,415 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
This is a simple generator of OCSP responses that will be used to test
|
||||
wolfSSL OCSP implementation
|
||||
"""
|
||||
from pyasn1_modules import rfc6960
|
||||
from pyasn1.codec.der.encoder import encode
|
||||
from pyasn1.codec.der.decoder import decode
|
||||
from pyasn1.type import univ, tag, useful, namedtype
|
||||
from base64 import b64decode
|
||||
from hashlib import sha1, sha256
|
||||
from datetime import datetime
|
||||
from cryptography.hazmat.primitives import serialization, hashes
|
||||
from cryptography.hazmat.primitives.asymmetric import rsa, padding
|
||||
from cryptography import x509
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
|
||||
WOLFSSL_OCSP_CERT_PATH = './certs/ocsp/'
|
||||
|
||||
def response_status(value: int) -> rfc6960.OCSPResponseStatus:
|
||||
return rfc6960.OCSPResponseStatus(value)
|
||||
|
||||
def response_type() -> univ.ObjectIdentifier:
|
||||
return rfc6960.id_pkix_ocsp_basic
|
||||
|
||||
sha256WithRSAEncryption = (1, 2, 840, 113549, 1, 1, 11)
|
||||
sha1_alg_id = (1, 3, 14, 3, 2, 26)
|
||||
def cert_id_sha1_alg_id() -> rfc6960.AlgorithmIdentifier:
|
||||
return algorithm(sha1_alg_id)
|
||||
|
||||
def signature_algorithm() -> rfc6960.AlgorithmIdentifier:
|
||||
return algorithm(sha256WithRSAEncryption)
|
||||
|
||||
def algorithm(value) -> rfc6960.AlgorithmIdentifier:
|
||||
ai = rfc6960.AlgorithmIdentifier()
|
||||
ai['algorithm'] = univ.ObjectIdentifier(value=value)
|
||||
return ai
|
||||
|
||||
def cert_pem_to_der(cert_path: str) -> bytes:
|
||||
beg_cert = '-----BEGIN CERTIFICATE-----'
|
||||
end_cert = '-----END CERTIFICATE-----'
|
||||
with open(cert_path, 'r') as f:
|
||||
pem = f.read()
|
||||
cert = pem.split(beg_cert)[1].split(end_cert)[0]
|
||||
return b64decode(cert)
|
||||
|
||||
def certs(cert_path: list[str]) -> univ.SequenceOf | None:
|
||||
if len(cert_path) == 0:
|
||||
return None
|
||||
certs = rfc6960.BasicOCSPResponse()['certs']
|
||||
for cp in cert_path:
|
||||
cert_der = cert_pem_to_der(cp)
|
||||
cert, _ = decode(bytes(cert_der), asn1Spec=rfc6960.Certificate())
|
||||
certs.append(cert)
|
||||
return certs
|
||||
|
||||
def signature(bitstr: str) -> univ.BitString:
|
||||
return univ.BitString(hexValue=bitstr)
|
||||
|
||||
def resp_id_by_name(cert_path: str) -> rfc6960.ResponderID:
|
||||
cert_der = cert_pem_to_der(cert_path)
|
||||
cert, _ = decode(bytes(cert_der), asn1Spec=rfc6960.Certificate())
|
||||
subj = cert['tbsCertificate']['subject']
|
||||
rid = rfc6960.ResponderID()
|
||||
rdi_name = rid['byName']
|
||||
rdi_name['rdnSequence'] = subj['rdnSequence']
|
||||
return rid
|
||||
|
||||
def resp_id_by_key(cert_path: str) -> rfc6960.ResponderID:
|
||||
cert_der = cert_pem_to_der(cert_path)
|
||||
cert, _ = decode(bytes(cert_der), asn1Spec=rfc6960.Certificate())
|
||||
key = get_key(cert)
|
||||
key_hash = sha1(key.asOctets()).digest()
|
||||
rid = rfc6960.ResponderID()
|
||||
rid['byKey'] = rfc6960.KeyHash(value=key_hash).subtype(explicitTag=
|
||||
tag.Tag(
|
||||
tag.tagClassContext,
|
||||
tag.tagFormatSimple,
|
||||
2))
|
||||
return rid
|
||||
|
||||
def get_key(cert: rfc6960.Certificate) -> univ.BitString:
|
||||
return cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']
|
||||
|
||||
def get_name(cert: rfc6960.Certificate) -> rfc6960.Name:
|
||||
return cert['tbsCertificate']['subject']
|
||||
|
||||
def cert_id_from_hash(issuer_name_hash: bytes, issuer_key_hash: bytes,
|
||||
serial: int) -> rfc6960.CertID:
|
||||
cert_id = rfc6960.CertID()
|
||||
cert_id['hashAlgorithm'] = cert_id_sha1_alg_id()
|
||||
cert_id['issuerNameHash'] = univ.OctetString(value=issuer_name_hash)
|
||||
cert_id['issuerKeyHash'] = univ.OctetString(value=issuer_key_hash)
|
||||
cert_id['serialNumber'] = rfc6960.CertificateSerialNumber(serial)
|
||||
return cert_id
|
||||
|
||||
def cert_id(issuer_cert_path: str, serial: int) -> rfc6960.CertID:
|
||||
issuer_cert = cert_pem_to_der(issuer_cert_path)
|
||||
issuer, _ = decode(bytes(issuer_cert), asn1Spec=rfc6960.Certificate())
|
||||
issuer_name = get_name(issuer)
|
||||
issuer_key = get_key(issuer)
|
||||
issuer_name_hash = sha1(encode(issuer_name)).digest()
|
||||
issuer_key_hash = sha1(issuer_key.asOctets()).digest()
|
||||
cert_id = rfc6960.CertID()
|
||||
cert_id['hashAlgorithm'] = cert_id_sha1_alg_id()
|
||||
cert_id['issuerNameHash'] = univ.OctetString(value=issuer_name_hash)
|
||||
cert_id['issuerKeyHash'] = univ.OctetString(value=issuer_key_hash)
|
||||
cert_id['serialNumber'] = rfc6960.CertificateSerialNumber(serial)
|
||||
|
||||
return cert_id
|
||||
|
||||
CERT_GOOD = 0
|
||||
CERT_REVOKED = 1
|
||||
CERT_UNKNOWN = 2
|
||||
def cert_status(value: int) -> rfc6960.CertStatus:
|
||||
cs = rfc6960.CertStatus()
|
||||
|
||||
if value == CERT_GOOD:
|
||||
good = univ.Null('').subtype(implicitTag=tag.Tag(tag.tagClassContext,
|
||||
tag.tagFormatSimple,
|
||||
0))
|
||||
cs['good'] = good
|
||||
elif value == CERT_REVOKED:
|
||||
revoked = rfc6960.RevokedInfo().subtype(implicitTag=tag.Tag(
|
||||
tag.tagClassContext, tag.tagFormatSimple, 1))
|
||||
revoked['revocationTime'] = useful.GeneralizedTime().fromDateTime(
|
||||
datetime.now())
|
||||
cs['revoked'] = revoked
|
||||
|
||||
return cs
|
||||
|
||||
def single_response(issuer_cert_path: str, serial: int,
|
||||
status: int) -> rfc6960.SingleResponse:
|
||||
cid = cert_id(issuer_cert_path, serial)
|
||||
cs = cert_status(status)
|
||||
sr = rfc6960.SingleResponse().clone()
|
||||
sr.setComponentByName('certID', cid)
|
||||
sr['certStatus'] = cs
|
||||
sr['thisUpdate'] = useful.GeneralizedTime().fromDateTime(datetime.now())
|
||||
return sr
|
||||
|
||||
def response_data(rid: rfc6960.ResponderID | None,
|
||||
responses: list[rfc6960.SingleResponse]) -> rfc6960.ResponseData:
|
||||
rd = rfc6960.ResponseData()
|
||||
rd['version'] = rfc6960.Version('v1').subtype(explicitTag=tag.Tag(
|
||||
tag.tagClassContext, tag.tagFormatSimple, 0))
|
||||
if rid:
|
||||
rd['responderID'] = rid
|
||||
rd['producedAt'] = useful.GeneralizedTime().fromDateTime(datetime.now())
|
||||
rs = univ.SequenceOf(componentType=rfc6960.SingleResponse())
|
||||
rs.extend(responses)
|
||||
rd['responses'] = rs
|
||||
return rd
|
||||
|
||||
def read_key_der_from_pem(key_path: str) -> bytes:
|
||||
with open(key_path, 'r') as f:
|
||||
pem = f.readlines()
|
||||
pem_start = [i for i, line in enumerate(pem) if '-----BEGIN' in line][0]
|
||||
pem_end = [i for i, line in enumerate(pem) if '-----END' in line][0]
|
||||
key = ''.join(pem[pem_start+1:pem_end])
|
||||
return b64decode(key)
|
||||
|
||||
def basic_ocsp_response(rd: rfc6960.ResponseData, sig_alg:
|
||||
rfc6960.AlgorithmIdentifier, sig: univ.BitString,
|
||||
certs: univ.SequenceOf|None = None) -> rfc6960.BasicOCSPResponse:
|
||||
br = rfc6960.BasicOCSPResponse()
|
||||
|
||||
br['tbsResponseData'] = rd
|
||||
br['signatureAlgorithm'] = sig_alg
|
||||
br['signature'] = sig
|
||||
if certs is not None:
|
||||
br['certs'] = certs
|
||||
return br
|
||||
|
||||
def response_bytes(br: rfc6960.BasicOCSPResponse) -> rfc6960.ResponseBytes:
|
||||
rb = rfc6960.ResponseBytes().subtype(explicitTag=tag.Tag(
|
||||
tag.tagClassContext, tag.tagFormatConstructed, 0))
|
||||
rb['responseType'] = response_type()
|
||||
rb['response'] = encode(br)
|
||||
return rb
|
||||
|
||||
def ocsp_response(status: rfc6960.OCSPResponseStatus,
|
||||
response_bytes: rfc6960.ResponseBytes) -> rfc6960.OCSPResponse:
|
||||
orsp = rfc6960.OCSPResponse()
|
||||
orsp['responseStatus'] = status
|
||||
orsp['responseBytes'] = response_bytes
|
||||
return orsp
|
||||
|
||||
def get_priv_key(pem_path) -> rsa.RSAPrivateKey:
|
||||
key_der = read_key_der_from_pem(pem_path)
|
||||
private_key = serialization.load_der_private_key(
|
||||
key_der,
|
||||
password=None,
|
||||
)
|
||||
return private_key
|
||||
|
||||
def sign_repsonse_data(rd: rfc6960.ResponseData,
|
||||
key: rsa.RSAPrivateKey) -> univ.BitString:
|
||||
sig = key.sign(encode(rd), padding.PKCS1v15(), hashes.SHA256())
|
||||
return univ.BitString(hexValue=sig.hex())
|
||||
|
||||
def get_pub_key(cert_path: str) -> rsa.RSAPublicKey:
|
||||
with open(cert_path, 'rb') as f:
|
||||
cert = f.read()
|
||||
cert = x509.load_pem_x509_certificate(cert, default_backend())
|
||||
return cert.public_key()
|
||||
|
||||
def test_signature(ocsp_resp_path: str, key: rsa.RSAPublicKey):
|
||||
with open(ocsp_resp_path, 'rb') as f:
|
||||
ocsp_resp = f.read()
|
||||
ocsp_resp, _ = decode(ocsp_resp, asn1Spec=rfc6960.OCSPResponse())
|
||||
response = ocsp_resp.getComponentByName(
|
||||
'responseBytes').getComponentByName('response')
|
||||
br, _ = decode(response, asn1Spec=rfc6960.BasicOCSPResponse())
|
||||
rd = br.getComponentByName('tbsResponseData')
|
||||
rd_hash = sha256(encode(rd)).digest()
|
||||
di = rfc8017.DigestInfo()
|
||||
di['digestAlgorithm'] = signature_algorithm()
|
||||
di['digest'] = univ.OctetString(rd_hash)
|
||||
sig = br.getComponentByName('signature')
|
||||
key.verify(sig.asOctets(), encode(rd), padding.PKCS1v15(), hashes.SHA256())
|
||||
|
||||
def single_response_from_cert(cert_path: str,
|
||||
status: int) -> rfc6960.SingleResponse:
|
||||
cert_der = cert_pem_to_der(cert_path)
|
||||
cert, _ = decode(bytes(cert_der), asn1Spec=rfc6960.Certificate())
|
||||
serial = cert['tbsCertificate']['serialNumber']
|
||||
issuer = cert['tbsCertificate']['issuer']
|
||||
serialHash = sha1(serial.asOctets()).digest()
|
||||
issuerHash = sha1(encode(issuer)).digest()
|
||||
cid = cert_id_from_hash(issuerHash, serialHash, serial)
|
||||
cs = cert_status(status)
|
||||
sr = rfc6960.SingleResponse().clone()
|
||||
sr.setComponentByName('certID', cid)
|
||||
sr['certStatus'] = cs
|
||||
sr['thisUpdate'] = useful.GeneralizedTime().fromDateTime(datetime.now())
|
||||
return sr
|
||||
|
||||
RESPONSE_STATUS_GOOD = 0
|
||||
|
||||
def write_buffer(name: str, data: bytes, f):
|
||||
f.write(f"unsigned char {name}[] = {{\n")
|
||||
for i in range(0, len(data), 12):
|
||||
f.write(" " + ", ".join(f"0x{b:02x}" for b in data[i:i+12]) + ",\n")
|
||||
f.write("};\n\n")
|
||||
|
||||
def create_response(rd: dict) -> rfc6960.OCSPResponse:
|
||||
"""create a response using definition in rd"""
|
||||
cs = response_status(rd.get('response_status', RESPONSE_STATUS_GOOD))
|
||||
sa = rd.get('signature_algorithm', signature_algorithm())
|
||||
c = certs(rd.get('certs_path', []))
|
||||
rid = None
|
||||
if rd.get('responder_by_name') is not None:
|
||||
rid = resp_id_by_name(
|
||||
rd.get(
|
||||
'responder_cert', WOLFSSL_OCSP_CERT_PATH + 'ocsp-responder-cert.pem'))
|
||||
elif rd.get('responder_by_key', None) is not None:
|
||||
rid = resp_id_by_key(
|
||||
rd.get('responder_cert', WOLFSSL_OCSP_CERT_PATH + 'ocsp-responder-cert.pem'))
|
||||
# implement responder byhash
|
||||
responses = []
|
||||
for entry in rd.get('responses', []):
|
||||
if entry.get('certificate'):
|
||||
sr = single_response_from_cert(entry['certificate'], entry['status'])
|
||||
else:
|
||||
sr = single_response(entry['issuer_cert'], entry['serial'], entry['status'])
|
||||
responses.append(sr)
|
||||
rd_data = response_data(rid, responses)
|
||||
k = get_priv_key(rd.get('responder_key', WOLFSSL_OCSP_CERT_PATH + 'ocsp-responder-key.pem'))
|
||||
s = sign_repsonse_data(rd_data, k)
|
||||
br = basic_ocsp_response(rd_data, sa, s, c)
|
||||
rb = response_bytes(br)
|
||||
ocspr = ocsp_response(cs, rb)
|
||||
return ocspr
|
||||
|
||||
def create_and_write_response(rd: dict, f):
|
||||
ocspr = create_response(rd)
|
||||
encoded_response = encode(ocspr)
|
||||
write_buffer(rd['name'].replace('-', '_').replace('.', '_'), encoded_response, f)
|
||||
|
||||
def add_certificate(cert_path: str, f):
|
||||
cert_der = cert_pem_to_der(cert_path)
|
||||
write_buffer(cert_path.split('/')[-1].replace('-', '_').replace('.', '_'), cert_der, f)
|
||||
|
||||
class badOCSPResponse(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.OptionalNamedType('responseBytes', rfc6960.ResponseBytes().subtype(
|
||||
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0)))
|
||||
)
|
||||
|
||||
def create_bad_response(rd: dict) -> bytes:
|
||||
"""Creates a malformed OCSP response by removing the response status field"""
|
||||
r = create_response(rd)
|
||||
br = badOCSPResponse()
|
||||
br['responseBytes'] = r['responseBytes']
|
||||
return encode(br)
|
||||
|
||||
if __name__ == '__main__':
|
||||
useful.GeneralizedTime._hasSubsecond = False
|
||||
response_definitions = [
|
||||
{
|
||||
'response_status': 0,
|
||||
'signature_algorithm': signature_algorithm(),
|
||||
'certs_path': [WOLFSSL_OCSP_CERT_PATH + 'ocsp-responder-cert.pem'],
|
||||
'responder_by_name': True,
|
||||
'responses': [
|
||||
{
|
||||
'issuer_cert': WOLFSSL_OCSP_CERT_PATH + 'root-ca-cert.pem',
|
||||
'serial': 0x01,
|
||||
'status': CERT_GOOD
|
||||
}
|
||||
],
|
||||
'responder_key': WOLFSSL_OCSP_CERT_PATH + 'ocsp-responder-key.pem',
|
||||
'name': 'resp'
|
||||
},
|
||||
{
|
||||
'response_status': 0,
|
||||
'signature_algorithm': signature_algorithm(),
|
||||
'certs_path': [WOLFSSL_OCSP_CERT_PATH + 'ocsp-responder-cert.pem'],
|
||||
'responder_by_key': True,
|
||||
'responses': [
|
||||
{
|
||||
'issuer_cert': WOLFSSL_OCSP_CERT_PATH + 'root-ca-cert.pem',
|
||||
'serial': 0x01,
|
||||
'status': CERT_GOOD
|
||||
}
|
||||
],
|
||||
'responder_key': WOLFSSL_OCSP_CERT_PATH + 'ocsp-responder-key.pem',
|
||||
'name': 'resp_rid_bykey',
|
||||
},
|
||||
{
|
||||
'response_status': 0,
|
||||
'signature_algorithm': signature_algorithm(),
|
||||
'responder_by_name': True,
|
||||
'responses': [
|
||||
{
|
||||
'issuer_cert': WOLFSSL_OCSP_CERT_PATH + 'root-ca-cert.pem',
|
||||
'serial': 0x01,
|
||||
'status': CERT_GOOD
|
||||
}
|
||||
],
|
||||
'responder_key': WOLFSSL_OCSP_CERT_PATH + 'ocsp-responder-key.pem',
|
||||
'name': 'resp_nocert'
|
||||
},
|
||||
{
|
||||
'response_status': 0,
|
||||
'signature_algorithm': signature_algorithm(),
|
||||
'responder_by_name': True,
|
||||
'responses': [
|
||||
{
|
||||
'issuer_cert': WOLFSSL_OCSP_CERT_PATH + 'root-ca-cert.pem',
|
||||
'serial': 0x01,
|
||||
'status': CERT_GOOD
|
||||
},
|
||||
{
|
||||
'issuer_cert': WOLFSSL_OCSP_CERT_PATH + 'root-ca-cert.pem',
|
||||
'serial': 0x02,
|
||||
'status': CERT_GOOD
|
||||
}
|
||||
],
|
||||
'responder_key': WOLFSSL_OCSP_CERT_PATH + 'root-ca-key.pem',
|
||||
'responder_cert': WOLFSSL_OCSP_CERT_PATH + 'root-ca-cert.pem',
|
||||
'name': 'resp_multi'
|
||||
},
|
||||
{
|
||||
'response_status': 0,
|
||||
'signature_algorithm': signature_algorithm(),
|
||||
'responder_by_name': True,
|
||||
'responses': [
|
||||
{
|
||||
'issuer_cert': WOLFSSL_OCSP_CERT_PATH + 'root-ca-cert.pem',
|
||||
'serial': 0x01,
|
||||
'status': CERT_GOOD
|
||||
},
|
||||
{
|
||||
'issuer_cert': WOLFSSL_OCSP_CERT_PATH + '../ca-cert.pem',
|
||||
'serial': 0x01,
|
||||
'status': CERT_GOOD
|
||||
}
|
||||
],
|
||||
'responder_key': WOLFSSL_OCSP_CERT_PATH + 'root-ca-key.pem',
|
||||
'responder_cert': WOLFSSL_OCSP_CERT_PATH + 'root-ca-cert.pem',
|
||||
'name': 'resp_bad_noauth'
|
||||
},
|
||||
]
|
||||
|
||||
with open('./tests/api/ocsp_test_blobs.h', 'w') as f:
|
||||
f.write(
|
||||
"""/*
|
||||
* This file is generated automatically by running ./tests/api/create_ocsp_test_blobs.py.
|
||||
*/
|
||||
""")
|
||||
f.write("#ifndef OCSP_TEST_BLOBS_H\n")
|
||||
f.write("#define OCSP_TEST_BLOBS_H\n\n")
|
||||
for rd in response_definitions:
|
||||
create_and_write_response(rd, f)
|
||||
add_certificate(WOLFSSL_OCSP_CERT_PATH + 'ocsp-responder-cert.pem', f)
|
||||
add_certificate(WOLFSSL_OCSP_CERT_PATH + 'root-ca-cert.pem', f)
|
||||
add_certificate(WOLFSSL_OCSP_CERT_PATH + '../ca-cert.pem', f)
|
||||
add_certificate(WOLFSSL_OCSP_CERT_PATH + '../server-cert.pem', f)
|
||||
add_certificate(WOLFSSL_OCSP_CERT_PATH + 'intermediate1-ca-cert.pem', f)
|
||||
br = create_bad_response({
|
||||
'response_status': 0,
|
||||
'responder_by_key': True,
|
||||
'responses': [
|
||||
{
|
||||
'issuer_cert': WOLFSSL_OCSP_CERT_PATH + 'root-ca-cert.pem',
|
||||
'serial': 0x01,
|
||||
'status': CERT_GOOD
|
||||
}
|
||||
],
|
||||
'name': 'resp_bad'
|
||||
})
|
||||
write_buffer('resp_bad', br, f)
|
||||
f.write("#endif // OCSP_TEST_BLOBS_H\n")
|
|
@ -14,6 +14,7 @@ tests_unit_test_SOURCES += tests/api/test_ripemd.c
|
|||
tests_unit_test_SOURCES += tests/api/test_hash.c
|
||||
tests_unit_test_SOURCES += tests/api/test_ascon.c
|
||||
tests_unit_test_SOURCES += tests/api/test_dtls.c
|
||||
tests_unit_test_SOURCES += tests/api/test_ocsp.c
|
||||
endif
|
||||
EXTRA_DIST += tests/api/api.h
|
||||
EXTRA_DIST += tests/api/test_md5.h
|
||||
|
@ -29,4 +30,7 @@ EXTRA_DIST += tests/api/test_ascon.h
|
|||
EXTRA_DIST += tests/api/test_ascon.h
|
||||
EXTRA_DIST += tests/api/test_ascon_kats.h
|
||||
EXTRA_DIST += tests/api/test_dtls.h
|
||||
EXTRA_DIST += tests/api/test_ocsp.h
|
||||
EXTRA_DIST += tests/api/test_ocsp_test_blobs.h
|
||||
EXTRA_DIST += tests/api/create_ocsp_test_blobs.py
|
||||
|
||||
|
|
|
@ -0,0 +1,568 @@
|
|||
/* ocsp.c
|
||||
*
|
||||
* Copyright (C) 2006-2025 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL.
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
#if !defined(WOLFSSL_USER_SETTINGS) && !defined(WOLFSSL_NO_OPTIONS_H)
|
||||
#include <wolfssl/options.h>
|
||||
#endif
|
||||
#include <wolfssl/wolfcrypt/settings.h>
|
||||
|
||||
#include <tests/api/test_ocsp.h>
|
||||
#include <tests/api/test_ocsp_test_blobs.h>
|
||||
#include <tests/unit.h>
|
||||
#include <wolfssl/internal.h>
|
||||
#include <wolfssl/ocsp.h>
|
||||
#include <wolfssl/ssl.h>
|
||||
|
||||
#if defined(HAVE_OCSP)
|
||||
struct ocsp_cb_ctx {
|
||||
byte* response;
|
||||
int responseSz;
|
||||
};
|
||||
|
||||
struct test_conf {
|
||||
unsigned char* resp;
|
||||
int respSz;
|
||||
unsigned char* ca0;
|
||||
int ca0Sz;
|
||||
unsigned char* ca1;
|
||||
int ca1Sz;
|
||||
unsigned char* targetCert;
|
||||
int targetCertSz;
|
||||
};
|
||||
|
||||
static int ocsp_cb(void* ctx, const char* url, int urlSz, unsigned char* req,
|
||||
int reqSz, unsigned char** respBuf)
|
||||
{
|
||||
struct ocsp_cb_ctx* cb_ctx = (struct ocsp_cb_ctx*)ctx;
|
||||
(void)url;
|
||||
(void)urlSz;
|
||||
(void)req;
|
||||
(void)reqSz;
|
||||
|
||||
*respBuf = cb_ctx->response;
|
||||
return cb_ctx->responseSz;
|
||||
}
|
||||
|
||||
static int test_ocsp_response_with_cm(struct test_conf* c)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
WOLFSSL_CERT_MANAGER* cm = NULL;
|
||||
struct ocsp_cb_ctx cb_ctx;
|
||||
int ret;
|
||||
|
||||
cm = wolfSSL_CertManagerNew();
|
||||
ExpectPtrNE(cm, NULL);
|
||||
ret = wolfSSL_CertManagerEnableOCSP(cm,
|
||||
WOLFSSL_OCSP_URL_OVERRIDE | WOLFSSL_OCSP_NO_NONCE);
|
||||
ExpectIntEQ(ret, WOLFSSL_SUCCESS);
|
||||
ret = wolfSSL_CertManagerSetOCSPOverrideURL(cm, "http://foo.com");
|
||||
ExpectIntEQ(ret, WOLFSSL_SUCCESS);
|
||||
cb_ctx.response = (byte*)c->resp;
|
||||
cb_ctx.responseSz = c->respSz;
|
||||
ret = wolfSSL_CertManagerSetOCSP_Cb(cm, ocsp_cb, NULL, (void*)&cb_ctx);
|
||||
ExpectIntEQ(ret, WOLFSSL_SUCCESS);
|
||||
/* add ca in cm */
|
||||
if (c->ca0 != NULL) {
|
||||
ret = wolfSSL_CertManagerLoadCABuffer(cm, c->ca0, c->ca0Sz,
|
||||
WOLFSSL_FILETYPE_ASN1);
|
||||
ExpectIntEQ(ret, WOLFSSL_SUCCESS);
|
||||
}
|
||||
if (c->ca1 != NULL) {
|
||||
ret = wolfSSL_CertManagerLoadCABuffer(cm, c->ca1, c->ca1Sz,
|
||||
WOLFSSL_FILETYPE_ASN1);
|
||||
ExpectIntEQ(ret, WOLFSSL_SUCCESS);
|
||||
}
|
||||
/* check cert */
|
||||
ret = wolfSSL_CertManagerCheckOCSP(cm, c->targetCert, c->targetCertSz);
|
||||
wolfSSL_CertManagerFree(cm);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int test_ocsp_response_parsing(void)
|
||||
{
|
||||
struct test_conf conf;
|
||||
int ret;
|
||||
EXPECT_DECLS;
|
||||
conf.resp = (unsigned char*)resp;
|
||||
conf.respSz = sizeof(resp);
|
||||
conf.ca0 = root_ca_cert_pem;
|
||||
conf.ca0Sz = sizeof(root_ca_cert_pem);
|
||||
conf.ca1 = NULL;
|
||||
conf.ca1Sz = 0;
|
||||
conf.targetCert = intermediate1_ca_cert_pem;
|
||||
conf.targetCertSz = sizeof(intermediate1_ca_cert_pem);
|
||||
ret = test_ocsp_response_with_cm(&conf);
|
||||
ExpectIntEQ(ret, WOLFSSL_SUCCESS);
|
||||
|
||||
conf.resp = (unsigned char*)resp_multi;
|
||||
conf.respSz = sizeof(resp_multi);
|
||||
conf.ca0 = root_ca_cert_pem;
|
||||
conf.ca0Sz = sizeof(root_ca_cert_pem);
|
||||
conf.ca1 = NULL;
|
||||
conf.ca1Sz = 0;
|
||||
conf.targetCert = intermediate1_ca_cert_pem;
|
||||
conf.targetCertSz = sizeof(intermediate1_ca_cert_pem);
|
||||
ret = test_ocsp_response_with_cm(&conf);
|
||||
ExpectIntEQ(ret, WOLFSSL_SUCCESS);
|
||||
|
||||
conf.resp = (unsigned char*)resp_bad_noauth;
|
||||
conf.respSz = sizeof(resp_bad_noauth);
|
||||
conf.ca0 = root_ca_cert_pem;
|
||||
conf.ca0Sz = sizeof(root_ca_cert_pem);
|
||||
conf.ca1 = ca_cert_pem;
|
||||
conf.ca1Sz = sizeof(ca_cert_pem);
|
||||
conf.targetCert = server_cert_pem;
|
||||
conf.targetCertSz = sizeof(server_cert_pem);
|
||||
ret = test_ocsp_response_with_cm(&conf);
|
||||
#ifndef WOLFSSL_NO_OCSP_ISSUER_CHECK
|
||||
ExpectIntNE(ret, WOLFSSL_SUCCESS);
|
||||
#else
|
||||
ExpectIntEQ(ret, WOLFSSL_SUCCESS);
|
||||
#endif
|
||||
return EXPECT_SUCCESS();
|
||||
}
|
||||
#else /* HAVE_OCSP */
|
||||
int test_ocsp_response_parsing(void) { return TEST_SKIPPED; }
|
||||
#endif /* HAVE_OCSP */
|
||||
|
||||
#if defined(HAVE_OCSP) && (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA))
|
||||
static int test_ocsp_create_x509store(WOLFSSL_X509_STORE** store,
|
||||
unsigned char* ca, int caSz)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
WOLFSSL_X509* cert = NULL;
|
||||
int ret;
|
||||
|
||||
*store = wolfSSL_X509_STORE_new();
|
||||
ExpectPtrNE(*store, NULL);
|
||||
cert = wolfSSL_X509_d2i(&cert, ca, caSz);
|
||||
ExpectPtrNE(cert, NULL);
|
||||
ret = wolfSSL_X509_STORE_add_cert(*store, cert);
|
||||
wolfSSL_X509_free(cert);
|
||||
ExpectIntEQ(ret, WOLFSSL_SUCCESS);
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
static int test_create_stack_of_x509(WOLF_STACK_OF(WOLFSSL_X509) * *certs,
|
||||
unsigned char* der, int derSz)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
WOLFSSL_X509* cert = NULL;
|
||||
int ret;
|
||||
|
||||
*certs = wolfSSL_sk_X509_new_null();
|
||||
ExpectPtrNE(*certs, NULL);
|
||||
cert = wolfSSL_X509_d2i(&cert, der, derSz);
|
||||
ExpectPtrNE(cert, NULL);
|
||||
ret = wolfSSL_sk_X509_push(*certs, cert);
|
||||
ExpectIntEQ(ret, 1);
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
int test_ocsp_basic_verify(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
WOLF_STACK_OF(WOLFSSL_X509) * certs;
|
||||
OcspResponse* response = NULL;
|
||||
WOLFSSL_X509_STORE* store;
|
||||
const unsigned char* ptr;
|
||||
DecodedCert cert;
|
||||
int ret;
|
||||
|
||||
wc_InitDecodedCert(&cert, ocsp_responder_cert_pem,
|
||||
sizeof(ocsp_responder_cert_pem), NULL);
|
||||
ret = wc_ParseCert(&cert, CERT_TYPE, 0, NULL);
|
||||
ExpectIntEQ(ret, 0);
|
||||
|
||||
/* just decoding */
|
||||
ptr = (const unsigned char*)resp;
|
||||
response = wolfSSL_d2i_OCSP_RESPONSE(NULL, &ptr, sizeof(resp));
|
||||
ExpectPtrNE(response, NULL);
|
||||
ExpectIntEQ(response->responseStatus, 0);
|
||||
ExpectIntEQ(response->responderIdType, OCSP_RESPONDER_ID_NAME);
|
||||
ExpectBufEQ(response->responderId.nameHash, cert.subjectHash,
|
||||
OCSP_DIGEST_SIZE);
|
||||
wolfSSL_OCSP_RESPONSE_free(response);
|
||||
|
||||
/* responder Id by key hash */
|
||||
ptr = (const unsigned char*)resp_rid_bykey;
|
||||
response = wolfSSL_d2i_OCSP_RESPONSE(NULL, &ptr, sizeof(resp_rid_bykey));
|
||||
ExpectPtrNE(response, NULL);
|
||||
ExpectIntEQ(response->responseStatus, 0);
|
||||
ExpectIntEQ(response->responderIdType, OCSP_RESPONDER_ID_KEY);
|
||||
ExpectBufEQ(response->responderId.keyHash, cert.subjectKeyHash,
|
||||
OCSP_DIGEST_SIZE);
|
||||
wc_FreeDecodedCert(&cert);
|
||||
wolfSSL_OCSP_RESPONSE_free(response);
|
||||
|
||||
/* decoding with no embedded certificates */
|
||||
ptr = (const unsigned char*)resp_nocert;
|
||||
response = wolfSSL_d2i_OCSP_RESPONSE(NULL, &ptr, sizeof(resp_nocert));
|
||||
ExpectPtrNE(response, NULL);
|
||||
ExpectIntEQ(response->responseStatus, 0);
|
||||
wolfSSL_OCSP_RESPONSE_free(response);
|
||||
|
||||
/* decoding an invalid response */
|
||||
ptr = (const unsigned char*)resp_bad;
|
||||
response = wolfSSL_d2i_OCSP_RESPONSE(NULL, &ptr, sizeof(resp_bad));
|
||||
ExpectPtrEq(response, NULL);
|
||||
|
||||
ptr = (const unsigned char*)resp;
|
||||
response = wolfSSL_d2i_OCSP_RESPONSE(NULL, &ptr, sizeof(resp));
|
||||
ExpectPtrNE(response, NULL);
|
||||
/* no verify signer certificate */
|
||||
ret = wolfSSL_OCSP_basic_verify(response, NULL, NULL, OCSP_NOVERIFY);
|
||||
ExpectIntEQ(ret, WOLFSSL_SUCCESS);
|
||||
/* verify that the signature is checked */
|
||||
response->sig[0] ^= 0xff;
|
||||
ret = wolfSSL_OCSP_basic_verify(response, NULL, NULL, OCSP_NOVERIFY);
|
||||
ExpectIntEQ(ret, WOLFSSL_FAILURE);
|
||||
wolfSSL_OCSP_RESPONSE_free(response);
|
||||
|
||||
/* populate a store with root-ca-cert */
|
||||
ret = test_ocsp_create_x509store(&store, root_ca_cert_pem,
|
||||
sizeof(root_ca_cert_pem));
|
||||
ExpectIntEQ(ret, TEST_SUCCESS);
|
||||
|
||||
/* populate a WOLF_STACK_OF(WOLFSSL_X509) with responder certificate */
|
||||
ret = test_create_stack_of_x509(&certs, ocsp_responder_cert_pem,
|
||||
sizeof(ocsp_responder_cert_pem));
|
||||
ExpectIntEQ(ret, TEST_SUCCESS);
|
||||
|
||||
/* cert not embedded, cert in certs, validated using store */
|
||||
ptr = (const unsigned char*)resp_nocert;
|
||||
response = wolfSSL_d2i_OCSP_RESPONSE(NULL, &ptr, sizeof(resp_nocert));
|
||||
ExpectPtrNE(response, NULL);
|
||||
ret = wolfSSL_OCSP_basic_verify(response, certs, store, 0);
|
||||
ExpectIntEQ(ret, WOLFSSL_SUCCESS);
|
||||
wolfSSL_OCSP_RESPONSE_free(response);
|
||||
|
||||
/* cert embedded, verified using store */
|
||||
ptr = (const unsigned char*)resp;
|
||||
response = wolfSSL_d2i_OCSP_RESPONSE(NULL, &ptr, sizeof(resp));
|
||||
ExpectPtrNE(response, NULL);
|
||||
ret = wolfSSL_OCSP_basic_verify(response, NULL, store, 0);
|
||||
ExpectIntEQ(ret, WOLFSSL_SUCCESS);
|
||||
/* make invalid signature */
|
||||
response->sig[0] ^= 0xff;
|
||||
ret = wolfSSL_OCSP_basic_verify(response, NULL, store, 0);
|
||||
ExpectIntEQ(ret, WOLFSSL_FAILURE);
|
||||
response->sig[0] ^= 0xff;
|
||||
|
||||
/* cert embedded and in certs, no store needed bc OCSP_TRUSTOTHER */
|
||||
ret = wolfSSL_OCSP_basic_verify(response, certs, NULL, OCSP_TRUSTOTHER);
|
||||
ExpectIntEQ(ret, WOLFSSL_SUCCESS);
|
||||
/* this should also pass */
|
||||
ret = wolfSSL_OCSP_basic_verify(response, certs, store, OCSP_NOINTERN);
|
||||
;
|
||||
ExpectIntEQ(ret, WOLFSSL_SUCCESS);
|
||||
/* this should not */
|
||||
ret = wolfSSL_OCSP_basic_verify(response, NULL, store, OCSP_NOINTERN);
|
||||
;
|
||||
ExpectIntNE(ret, WOLFSSL_SUCCESS);
|
||||
wolfSSL_OCSP_RESPONSE_free(response);
|
||||
|
||||
/* cert not embedded, not certs */
|
||||
ptr = (const unsigned char*)resp_nocert;
|
||||
response = wolfSSL_d2i_OCSP_RESPONSE(NULL, &ptr, sizeof(resp_nocert));
|
||||
ExpectPtrNE(response, NULL);
|
||||
ret = wolfSSL_OCSP_basic_verify(response, NULL, store, 0);
|
||||
ExpectIntNE(ret, WOLFSSL_SUCCESS);
|
||||
wolfSSL_OCSP_RESPONSE_free(response);
|
||||
|
||||
wolfSSL_sk_X509_pop_free(certs, wolfSSL_X509_free);
|
||||
wolfSSL_X509_STORE_free(store);
|
||||
|
||||
ret = test_ocsp_create_x509store(&store, root_ca_cert_pem,
|
||||
sizeof(root_ca_cert_pem));
|
||||
ExpectIntEQ(ret, TEST_SUCCESS);
|
||||
ret = test_create_stack_of_x509(&certs, root_ca_cert_pem,
|
||||
sizeof(root_ca_cert_pem));
|
||||
ExpectIntEQ(ret, TEST_SUCCESS);
|
||||
|
||||
/* multiple responses in a ocsp response */
|
||||
ptr = (const unsigned char*)resp_multi;
|
||||
response = wolfSSL_d2i_OCSP_RESPONSE(NULL, &ptr, sizeof(resp_multi));
|
||||
ExpectPtrNE(response, NULL);
|
||||
ret = wolfSSL_OCSP_basic_verify(response, certs, store, 0);
|
||||
ExpectIntEQ(ret, WOLFSSL_SUCCESS);
|
||||
wolfSSL_OCSP_RESPONSE_free(response);
|
||||
|
||||
/* cert in certs, cert verified on store, not authorized to verify all
|
||||
* responses */
|
||||
ptr = (const unsigned char*)resp_bad_noauth;
|
||||
response = wolfSSL_d2i_OCSP_RESPONSE(NULL, &ptr, sizeof(resp_bad_noauth));
|
||||
ExpectPtrNE(response, NULL);
|
||||
ret = wolfSSL_OCSP_basic_verify(response, certs, store, 0);
|
||||
#ifndef WOLFSSL_NO_OCSP_ISSUER_CHECK
|
||||
ExpectIntEQ(ret, WOLFSSL_FAILURE);
|
||||
#else
|
||||
ExpectIntEQ(ret, WOLFSSL_SUCCESS);
|
||||
#endif
|
||||
/* should pass with OCSP_NOCHECKS ...*/
|
||||
ret = wolfSSL_OCSP_basic_verify(response, certs, store, OCSP_NOCHECKS);
|
||||
ExpectIntEQ(ret, WOLFSSL_SUCCESS);
|
||||
/* or with OSCP_TRUSTOTHER */
|
||||
ret = wolfSSL_OCSP_basic_verify(response, certs, store, OCSP_TRUSTOTHER);
|
||||
ExpectIntEQ(ret, WOLFSSL_SUCCESS);
|
||||
wolfSSL_OCSP_RESPONSE_free(response);
|
||||
|
||||
wolfSSL_sk_X509_pop_free(certs, wolfSSL_X509_free);
|
||||
wolfSSL_X509_STORE_free(store);
|
||||
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
#else
|
||||
int test_ocsp_basic_verify(void) { return TEST_SKIPPED; }
|
||||
#endif /* HAVE_OCSP && (OPENSSL_ALL || OPENSSL_EXTRA) */
|
||||
|
||||
#if defined(HAVE_OCSP) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
|
||||
defined(HAVE_CERTIFICATE_STATUS_REQUEST) && !defined(WOLFSSL_NO_TLS12) && \
|
||||
(defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA))
|
||||
|
||||
struct _test_ocsp_status_callback_ctx {
|
||||
byte* ocsp_resp;
|
||||
int ocsp_resp_sz;
|
||||
int invoked;
|
||||
};
|
||||
|
||||
static int test_ocsp_status_callback_cb(WOLFSSL* ssl, void* ctx)
|
||||
{
|
||||
struct _test_ocsp_status_callback_ctx* _ctx =
|
||||
(struct _test_ocsp_status_callback_ctx*)ctx;
|
||||
byte* allocated;
|
||||
|
||||
_ctx->invoked++;
|
||||
allocated = (byte*)XMALLOC(_ctx->ocsp_resp_sz, NULL, 0);
|
||||
if (allocated == NULL)
|
||||
return SSL_TLSEXT_ERR_ALERT_FATAL;
|
||||
XMEMCPY(allocated, _ctx->ocsp_resp, _ctx->ocsp_resp_sz);
|
||||
SSL_set_tlsext_status_ocsp_resp(ssl, allocated, _ctx->ocsp_resp_sz);
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
|
||||
static int test_ocsp_status_callback_cb_noack(WOLFSSL* ssl, void* ctx)
|
||||
{
|
||||
struct _test_ocsp_status_callback_ctx* _ctx =
|
||||
(struct _test_ocsp_status_callback_ctx*)ctx;
|
||||
(void)ssl;
|
||||
|
||||
_ctx->invoked++;
|
||||
return SSL_TLSEXT_ERR_NOACK;
|
||||
}
|
||||
|
||||
static int test_ocsp_status_callback_cb_err(WOLFSSL* ssl, void* ctx)
|
||||
{
|
||||
struct _test_ocsp_status_callback_ctx* _ctx =
|
||||
(struct _test_ocsp_status_callback_ctx*)ctx;
|
||||
(void)ssl;
|
||||
|
||||
_ctx->invoked++;
|
||||
return SSL_TLSEXT_ERR_ALERT_FATAL;
|
||||
}
|
||||
|
||||
static int test_ocsp_status_callback_test_setup(
|
||||
struct _test_ocsp_status_callback_ctx* cb_ctx,
|
||||
struct test_ssl_memio_ctx* test_ctx, method_provider cm, method_provider sm)
|
||||
{
|
||||
int ret;
|
||||
|
||||
cb_ctx->invoked = 0;
|
||||
XMEMSET(test_ctx, 0, sizeof(*test_ctx));
|
||||
test_ctx->c_cb.caPemFile = "./certs/ocsp/root-ca-cert.pem";
|
||||
test_ctx->s_cb.certPemFile = "./certs/ocsp/server1-cert.pem";
|
||||
test_ctx->s_cb.keyPemFile = "./certs/ocsp/server1-key.pem";
|
||||
test_ctx->c_cb.method = cm;
|
||||
test_ctx->s_cb.method = sm;
|
||||
ret = test_ssl_memio_setup(test_ctx);
|
||||
wolfSSL_set_verify(test_ctx->c_ssl, WOLFSSL_VERIFY_DEFAULT, NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int test_ocsp_status_callback(void)
|
||||
{
|
||||
struct test_params {
|
||||
method_provider c_method;
|
||||
method_provider s_method;
|
||||
};
|
||||
|
||||
const char* responseFile = "./certs/ocsp/test-leaf-response.der";
|
||||
struct _test_ocsp_status_callback_ctx cb_ctx;
|
||||
struct test_ssl_memio_ctx test_ctx;
|
||||
int enable_client_ocsp;
|
||||
int enable_must_staple;
|
||||
XFILE f = XBADFILE;
|
||||
byte data[4096];
|
||||
unsigned int i;
|
||||
EXPECT_DECLS;
|
||||
|
||||
struct test_params params[] = {
|
||||
{wolfTLSv1_2_client_method, wolfTLSv1_2_server_method},
|
||||
#if defined(WOLFSSL_TLS13)
|
||||
{wolfTLSv1_3_client_method, wolfTLSv1_3_server_method},
|
||||
#endif
|
||||
#if defined(WOLFSSL_DTLS)
|
||||
{wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method},
|
||||
#endif
|
||||
#if defined(WOLFSSL_DTLS13)
|
||||
{wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method},
|
||||
#endif
|
||||
};
|
||||
|
||||
XMEMSET(&cb_ctx, 0, sizeof(cb_ctx));
|
||||
f = XFOPEN(responseFile, "rb");
|
||||
if (f == XBADFILE)
|
||||
return -1;
|
||||
cb_ctx.ocsp_resp_sz = (word32)XFREAD(data, 1, 4096, f);
|
||||
if (f != XBADFILE) {
|
||||
XFCLOSE(f);
|
||||
f = XBADFILE;
|
||||
}
|
||||
cb_ctx.ocsp_resp = data;
|
||||
|
||||
for (i = 0; i < sizeof(params) / sizeof(params[0]); i++) {
|
||||
for (enable_client_ocsp = 0; enable_client_ocsp <= 1;
|
||||
enable_client_ocsp++) {
|
||||
ExpectIntEQ(test_ocsp_status_callback_test_setup(&cb_ctx, &test_ctx,
|
||||
params[i].c_method, params[i].s_method),
|
||||
TEST_SUCCESS);
|
||||
ExpectIntEQ(SSL_CTX_set_tlsext_status_cb(test_ctx.s_ctx,
|
||||
test_ocsp_status_callback_cb),
|
||||
SSL_SUCCESS);
|
||||
ExpectIntEQ(
|
||||
SSL_CTX_set_tlsext_status_arg(test_ctx.s_ctx, (void*)&cb_ctx),
|
||||
SSL_SUCCESS);
|
||||
if (enable_client_ocsp) {
|
||||
ExpectIntEQ(wolfSSL_UseOCSPStapling(test_ctx.c_ssl,
|
||||
WOLFSSL_CSR_OCSP, 0),
|
||||
WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(wolfSSL_CTX_EnableOCSPStapling(test_ctx.c_ctx),
|
||||
WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(wolfSSL_CTX_EnableOCSPMustStaple(test_ctx.c_ctx),
|
||||
WOLFSSL_SUCCESS);
|
||||
}
|
||||
ExpectIntEQ(test_ssl_memio_do_handshake(&test_ctx, 10, NULL),
|
||||
TEST_SUCCESS);
|
||||
ExpectIntEQ(cb_ctx.invoked, enable_client_ocsp ? 1 : 0);
|
||||
test_ssl_memio_cleanup(&test_ctx);
|
||||
if (!EXPECT_SUCCESS())
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
}
|
||||
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
|
||||
/* test client sending both OCSPv1 and OCSPv2/MultiOCSP */
|
||||
/* StatusCb only supports OCSPv1 */
|
||||
ExpectIntEQ(test_ocsp_status_callback_test_setup(&cb_ctx, &test_ctx,
|
||||
wolfTLSv1_2_client_method, wolfTLSv1_2_server_method),
|
||||
TEST_SUCCESS);
|
||||
ExpectIntEQ(SSL_CTX_set_tlsext_status_cb(test_ctx.s_ctx,
|
||||
test_ocsp_status_callback_cb),
|
||||
SSL_SUCCESS);
|
||||
ExpectIntEQ(SSL_CTX_set_tlsext_status_arg(test_ctx.s_ctx, (void*)&cb_ctx),
|
||||
SSL_SUCCESS);
|
||||
ExpectIntEQ(wolfSSL_CTX_EnableOCSPStapling(test_ctx.c_ctx),
|
||||
WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(wolfSSL_CTX_EnableOCSPMustStaple(test_ctx.c_ctx),
|
||||
WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(wolfSSL_UseOCSPStapling(test_ctx.c_ssl, WOLFSSL_CSR_OCSP, 0),
|
||||
WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(
|
||||
wolfSSL_UseOCSPStaplingV2(test_ctx.c_ssl, WOLFSSL_CSR2_OCSP_MULTI, 0),
|
||||
WOLFSSL_SUCCESS);
|
||||
wolfSSL_set_verify(test_ctx.c_ssl, WOLFSSL_VERIFY_DEFAULT, NULL);
|
||||
ExpectIntEQ(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
|
||||
ExpectIntEQ(cb_ctx.invoked, 1);
|
||||
test_ssl_memio_cleanup(&test_ctx);
|
||||
|
||||
if (!EXPECT_SUCCESS())
|
||||
return EXPECT_RESULT();
|
||||
#endif /* defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) */
|
||||
/* test cb returning NO_ACK, not acking the OCSP */
|
||||
for (i = 0; i < sizeof(params) / sizeof(params[0]); i++) {
|
||||
for (enable_must_staple = 0; enable_must_staple <= 1;
|
||||
enable_must_staple++) {
|
||||
ExpectIntEQ(test_ocsp_status_callback_test_setup(&cb_ctx, &test_ctx,
|
||||
params[i].c_method, params[i].s_method),
|
||||
TEST_SUCCESS);
|
||||
ExpectIntEQ(SSL_CTX_set_tlsext_status_cb(test_ctx.s_ctx,
|
||||
test_ocsp_status_callback_cb_noack),
|
||||
SSL_SUCCESS);
|
||||
ExpectIntEQ(
|
||||
SSL_CTX_set_tlsext_status_arg(test_ctx.s_ctx, (void*)&cb_ctx),
|
||||
SSL_SUCCESS);
|
||||
ExpectIntEQ(wolfSSL_CTX_EnableOCSPStapling(test_ctx.c_ctx),
|
||||
WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(
|
||||
wolfSSL_UseOCSPStapling(test_ctx.c_ssl, WOLFSSL_CSR_OCSP, 0),
|
||||
WOLFSSL_SUCCESS);
|
||||
if (enable_must_staple)
|
||||
ExpectIntEQ(wolfSSL_CTX_EnableOCSPMustStaple(test_ctx.c_ctx),
|
||||
WOLFSSL_SUCCESS);
|
||||
wolfSSL_set_verify(test_ctx.c_ssl, WOLFSSL_VERIFY_DEFAULT, NULL);
|
||||
ExpectIntEQ(test_ssl_memio_do_handshake(&test_ctx, 10, NULL),
|
||||
enable_must_staple ? TEST_FAIL : TEST_SUCCESS);
|
||||
ExpectIntEQ(cb_ctx.invoked, 1);
|
||||
test_ssl_memio_cleanup(&test_ctx);
|
||||
if (!EXPECT_SUCCESS())
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
}
|
||||
|
||||
/* test cb returning err aborting handshake */
|
||||
for (i = 0; i < sizeof(params) / sizeof(params[0]); i++) {
|
||||
for (enable_client_ocsp = 0; enable_client_ocsp <= 1;
|
||||
enable_client_ocsp++) {
|
||||
ExpectIntEQ(test_ocsp_status_callback_test_setup(&cb_ctx, &test_ctx,
|
||||
params[i].c_method, params[i].s_method),
|
||||
TEST_SUCCESS);
|
||||
ExpectIntEQ(SSL_CTX_set_tlsext_status_cb(test_ctx.s_ctx,
|
||||
test_ocsp_status_callback_cb_err),
|
||||
SSL_SUCCESS);
|
||||
ExpectIntEQ(
|
||||
SSL_CTX_set_tlsext_status_arg(test_ctx.s_ctx, (void*)&cb_ctx),
|
||||
SSL_SUCCESS);
|
||||
if (enable_client_ocsp)
|
||||
ExpectIntEQ(wolfSSL_CTX_EnableOCSPStapling(test_ctx.c_ctx),
|
||||
WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(
|
||||
wolfSSL_UseOCSPStapling(test_ctx.c_ssl, WOLFSSL_CSR_OCSP, 0),
|
||||
WOLFSSL_SUCCESS);
|
||||
wolfSSL_set_verify(test_ctx.c_ssl, WOLFSSL_VERIFY_DEFAULT, NULL);
|
||||
ExpectIntEQ(test_ssl_memio_do_handshake(&test_ctx, 10, NULL),
|
||||
enable_client_ocsp ? TEST_FAIL : TEST_SUCCESS);
|
||||
ExpectIntEQ(cb_ctx.invoked, enable_client_ocsp ? 1 : 0);
|
||||
test_ssl_memio_cleanup(&test_ctx);
|
||||
if (!EXPECT_SUCCESS())
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
}
|
||||
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
#else
|
||||
int test_ocsp_status_callback(void) { return TEST_SKIPPED; }
|
||||
#endif /* defined(HAVE_OCSP) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) \
|
||||
&& defined(HAVE_CERTIFICATE_STATUS_REQUEST) && !defined(WOLFSSL_NO_TLS12) \
|
||||
&& (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) */
|
|
@ -0,0 +1,29 @@
|
|||
/* ocsp.h
|
||||
*
|
||||
* Copyright (C) 2006-2025 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL.
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
#ifndef WOLFSSL_TEST_OCSP_H
|
||||
#define WOLFSSL_TEST_OCSP_H
|
||||
|
||||
int test_ocsp_status_callback(void);
|
||||
int test_ocsp_basic_verify(void);
|
||||
int test_ocsp_response_parsing(void);
|
||||
#endif /* WOLFSSL_TEST_OCSP_H */
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue