mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-06 07:30:50 +02:00
ocsp: bind responder authorization to CertID issuerKeyHash
Addresses ZD21675
This commit is contained in:
+54
-40
@@ -585,7 +585,7 @@ int CheckOcspRequest(WOLFSSL_OCSP* ocsp, OcspRequest* ocspRequest,
|
||||
|
||||
#ifndef WOLFSSL_NO_OCSP_ISSUER_CHAIN_CHECK
|
||||
static int CheckOcspResponderChain(OcspEntry* single, byte* issuerHash,
|
||||
void* vp, Signer* pendingCAs) {
|
||||
byte* issuerKeyHash, void* vp, Signer* pendingCAs) {
|
||||
/* Attempt to build a chain up to cert's issuer */
|
||||
WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp;
|
||||
Signer* ca = NULL;
|
||||
@@ -602,54 +602,61 @@ static int CheckOcspResponderChain(OcspEntry* single, byte* issuerHash,
|
||||
* in OCSP request
|
||||
*/
|
||||
|
||||
/* Walk up the issuer chain from the responder's direct issuer toward a
|
||||
* self-signed root, capturing prev before reassigning ca so the
|
||||
* (ca == prev) self-signed termination check is meaningful. */
|
||||
ca = GetCAByName(cm, single->issuerHash);
|
||||
if (issuerKeyHash == NULL)
|
||||
return 0;
|
||||
|
||||
/* Select CertID issuer by key hash so a same-DN / different-key trust
|
||||
* anchor cannot hijack the starting point. */
|
||||
ca = GetCAByKeyHash(cm, single->issuerKeyHash);
|
||||
if (ca != NULL && XMEMCMP(ca->subjectNameHash, single->issuerHash,
|
||||
OCSP_DIGEST_SIZE) != 0) {
|
||||
ca = NULL;
|
||||
}
|
||||
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
|
||||
if (ca == NULL && pendingCAs != NULL) {
|
||||
ca = findSignerByName(pendingCAs, single->issuerHash);
|
||||
ca = findSignerByKeyHash(pendingCAs, single->issuerKeyHash);
|
||||
if (ca != NULL && XMEMCMP(ca->subjectNameHash, single->issuerHash,
|
||||
OCSP_DIGEST_SIZE) != 0) {
|
||||
ca = NULL;
|
||||
}
|
||||
}
|
||||
#else
|
||||
(void)pendingCAs;
|
||||
#endif
|
||||
while (ca != NULL) {
|
||||
if (XMEMCMP(issuerHash, ca->issuerNameHash, OCSP_DIGEST_SIZE) == 0) {
|
||||
for (; ca != NULL && ca != prev;
|
||||
prev = ca) {
|
||||
Signer* parent = GetCAByName(cm, ca->issuerNameHash);
|
||||
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
|
||||
if (parent == NULL && pendingCAs != NULL) {
|
||||
parent = findSignerByName(pendingCAs, ca->issuerNameHash);
|
||||
}
|
||||
#endif
|
||||
if (parent == NULL || parent == ca)
|
||||
break;
|
||||
|
||||
if (XMEMCMP(parent->subjectNameHash, issuerHash,
|
||||
OCSP_DIGEST_SIZE) == 0 &&
|
||||
XMEMCMP(parent->subjectKeyHash, issuerKeyHash,
|
||||
KEYID_SIZE) == 0) {
|
||||
WOLFSSL_MSG("\tOCSP Response signed by authorized "
|
||||
"responder delegated by issuer "
|
||||
"(found in chain)");
|
||||
passed = 1;
|
||||
break;
|
||||
}
|
||||
prev = ca;
|
||||
ca = GetCAByName(cm, prev->issuerNameHash);
|
||||
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
|
||||
/* Look up by the in-flight name (prev's issuer), not by
|
||||
* single->issuerHash; the latter would re-anchor the pendingCAs
|
||||
* walk to the bottom of the chain on every iteration. */
|
||||
if (ca == NULL && pendingCAs != NULL) {
|
||||
ca = findSignerByName(pendingCAs, prev->issuerNameHash);
|
||||
}
|
||||
#endif
|
||||
if (ca == prev) {
|
||||
break;
|
||||
}
|
||||
ca = parent;
|
||||
}
|
||||
return passed;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Enforce https://www.rfc-editor.org/rfc/rfc6960#section-4.2.2.2
|
||||
* @param bs The basic OCSP response to verify
|
||||
* @param subjectHash The subject key hash of the OCSP responder certificate
|
||||
* @param extExtKeyUsage The extended key usage bits of the responder certificate
|
||||
* @param issuerHash The issuer name hash of the OCSP responder certificate
|
||||
* @param vp Unused (reserved for future use)
|
||||
* @return 1 if the responder is authorized to sign the response, 0 otherwise
|
||||
*/
|
||||
/* Enforce https://www.rfc-editor.org/rfc/rfc6960#section-4.2.2.2. Both halves
|
||||
* of CertID (issuerNameHash and issuerKeyHash) must match; name-only matching
|
||||
* would authorize a same-DN / different-key CA. issuerKeyHash may be NULL when
|
||||
* unavailable, which disables the delegated branch. */
|
||||
int CheckOcspResponder(OcspResponse *bs, byte* subjectHash,
|
||||
byte extExtKeyUsage, byte* issuerHash, void* vp)
|
||||
byte* subjectKeyHash, byte extExtKeyUsage, byte* issuerHash,
|
||||
byte* issuerKeyHash, void* vp)
|
||||
{
|
||||
int ret = 0;
|
||||
OcspEntry* single;
|
||||
@@ -667,26 +674,31 @@ int CheckOcspResponder(OcspResponse *bs, byte* subjectHash,
|
||||
if (bs == NULL || subjectHash == NULL || issuerHash == NULL)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
/* Traverse the list and check that the cert has the authority to provide
|
||||
* an OCSP response for each entry. */
|
||||
for (single = bs->single; single != NULL; single = single->next) {
|
||||
int passed = 0;
|
||||
|
||||
if (XMEMCMP(subjectHash, single->issuerHash, OCSP_DIGEST_SIZE) == 0) {
|
||||
if (subjectKeyHash != NULL &&
|
||||
XMEMCMP(subjectHash, single->issuerHash,
|
||||
OCSP_DIGEST_SIZE) == 0 &&
|
||||
XMEMCMP(subjectKeyHash, single->issuerKeyHash,
|
||||
OCSP_DIGEST_SIZE) == 0) {
|
||||
WOLFSSL_MSG("\tOCSP Response signed by issuer");
|
||||
passed = 1;
|
||||
}
|
||||
else if ((extExtKeyUsage & EXTKEYUSE_OCSP_SIGN) != 0) {
|
||||
if (XMEMCMP(issuerHash, single->issuerHash, OCSP_DIGEST_SIZE)
|
||||
== 0) {
|
||||
if (issuerKeyHash != NULL &&
|
||||
XMEMCMP(issuerHash, single->issuerHash,
|
||||
OCSP_DIGEST_SIZE) == 0 &&
|
||||
XMEMCMP(issuerKeyHash, single->issuerKeyHash,
|
||||
OCSP_DIGEST_SIZE) == 0) {
|
||||
WOLFSSL_MSG("\tOCSP Response signed by authorized responder "
|
||||
"delegated by issuer");
|
||||
passed = 1;
|
||||
}
|
||||
#ifndef WOLFSSL_NO_OCSP_ISSUER_CHAIN_CHECK
|
||||
else if (vp != NULL) {
|
||||
passed = CheckOcspResponderChain(single, issuerHash, vp,
|
||||
bs->pendingCAs);
|
||||
passed = CheckOcspResponderChain(single, issuerHash,
|
||||
issuerKeyHash, vp, bs->pendingCAs);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1090,8 +1102,10 @@ static int OcspVerifySigner(WOLFSSL_OCSP_BASICRESP *resp, DecodedCert *cert,
|
||||
}
|
||||
#ifndef WOLFSSL_NO_OCSP_ISSUER_CHECK
|
||||
if ((flags & WOLFSSL_OCSP_NOCHECKS) == 0) {
|
||||
ret = CheckOcspResponder(resp, c->subjectHash, c->extExtKeyUsage,
|
||||
c->issuerHash, st->cm);
|
||||
ret = CheckOcspResponder(resp, c->subjectHash, c->subjectKeyHash,
|
||||
c->extExtKeyUsage, c->issuerHash,
|
||||
(c->ca != NULL) ? c->ca->subjectKeyHash : NULL,
|
||||
st->cm);
|
||||
}
|
||||
else {
|
||||
ret = 0;
|
||||
|
||||
+16
-14
@@ -23211,17 +23211,15 @@ int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm,
|
||||
}
|
||||
|
||||
#ifdef HAVE_OCSP
|
||||
if (type != CA_TYPE &&
|
||||
type != TRUSTED_PEER_TYPE) {
|
||||
/* Need the CA's public key hash for OCSP */
|
||||
if (cert->ca) {
|
||||
XMEMCPY(cert->issuerKeyHash, cert->ca->subjectKeyHash,
|
||||
KEYID_SIZE);
|
||||
}
|
||||
else if (cert->selfSigned) {
|
||||
XMEMCPY(cert->issuerKeyHash, cert->subjectKeyHash,
|
||||
KEYID_SIZE);
|
||||
}
|
||||
/* Needed for OCSP requests, and for binding responder authorization
|
||||
* to CertID's issuerKeyHash when this cert becomes a Signer. */
|
||||
if (cert->ca) {
|
||||
XMEMCPY(cert->issuerKeyHash, cert->ca->subjectKeyHash,
|
||||
KEYID_SIZE);
|
||||
}
|
||||
else if (cert->selfSigned) {
|
||||
XMEMCPY(cert->issuerKeyHash, cert->subjectKeyHash,
|
||||
KEYID_SIZE);
|
||||
}
|
||||
#endif /* HAVE_OCSP */
|
||||
}
|
||||
@@ -23527,6 +23525,8 @@ int FillSigner(Signer* signer, DecodedCert* cert, int type, DerBuffer *der)
|
||||
#ifdef HAVE_OCSP
|
||||
XMEMCPY(signer->subjectKeyHash, cert->subjectKeyHash,
|
||||
KEYID_SIZE);
|
||||
XMEMCPY(signer->issuerKeyHash, cert->issuerKeyHash,
|
||||
KEYID_SIZE);
|
||||
#endif
|
||||
signer->keyUsage = cert->extKeyUsageSet ? cert->extKeyUsage
|
||||
: 0xFFFF;
|
||||
@@ -33617,7 +33617,8 @@ static int OcspRespCheck(OcspResponse *resp, Signer *responder, void* vp)
|
||||
return -1;
|
||||
|
||||
ret = CheckOcspResponder(resp, responder->subjectNameHash,
|
||||
responder->extKeyUsage, responder->issuerNameHash, vp);
|
||||
responder->subjectKeyHash, responder->extKeyUsage,
|
||||
responder->issuerNameHash, responder->issuerKeyHash, vp);
|
||||
if (ret != 0)
|
||||
return -1;
|
||||
|
||||
@@ -33705,8 +33706,9 @@ static int OcspCheckCert(OcspResponse *resp, int noVerify,
|
||||
|
||||
#ifndef WOLFSSL_NO_OCSP_ISSUER_CHECK
|
||||
if (ret == 0 && !noVerify) {
|
||||
ret = CheckOcspResponder(resp, cert->subjectHash, cert->extExtKeyUsage,
|
||||
cert->issuerHash, cm);
|
||||
ret = CheckOcspResponder(resp, cert->subjectHash, cert->subjectKeyHash,
|
||||
cert->extExtKeyUsage, cert->issuerHash,
|
||||
(cert->ca != NULL) ? cert->ca->subjectKeyHash : NULL, cm);
|
||||
if (ret != 0) {
|
||||
WOLFSSL_MSG("\tOCSP Responder certificate issuer check failed");
|
||||
goto err;
|
||||
|
||||
+2
-1
@@ -75,7 +75,8 @@ WOLFSSL_LOCAL int CheckOcspResponse(WOLFSSL_OCSP *ocsp, byte *response, int resp
|
||||
void* heap);
|
||||
|
||||
WOLFSSL_LOCAL int CheckOcspResponder(OcspResponse *bs, byte* subjectHash,
|
||||
byte extExtKeyUsage, byte* issuerHash, void* vp);
|
||||
byte* subjectKeyHash, byte extExtKeyUsage, byte* issuerHash,
|
||||
byte* issuerKeyHash, void* vp);
|
||||
|
||||
/* Allocates and initializes a WOLFSSL_OCSP object */
|
||||
WOLFSSL_API WOLFSSL_OCSP* wc_NewOCSP(WOLFSSL_CERT_MANAGER* cm);
|
||||
|
||||
@@ -2228,6 +2228,7 @@ struct Signer {
|
||||
#endif
|
||||
#ifdef HAVE_OCSP
|
||||
byte subjectKeyHash[KEYID_SIZE];
|
||||
byte issuerKeyHash[KEYID_SIZE]; /* key hash of verifying parent CA */
|
||||
#endif
|
||||
#if defined(WOLFSSL_AKID_NAME) || defined(HAVE_CRL)
|
||||
byte serialHash[SIGNER_DIGEST_SIZE]; /* serial number hash */
|
||||
|
||||
Reference in New Issue
Block a user