Skip to content

Commit 06a3569

Browse files
committed
ocsp: bind responder authorization to CertID issuerKeyHash
CheckOcspResponder only compared issuer name hashes, so a same-DN / different-key trust anchor (or a responder it issued) could sign OCSP status for another CA's certificates. Both halves of CertID are now required to match per RFC 6960 4.2.2.2, and Signer gained issuerKeyHash so the CM-signer path can bind too.
1 parent 936f8e5 commit 06a3569

4 files changed

Lines changed: 72 additions & 46 deletions

File tree

src/ocsp.c

Lines changed: 53 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -585,7 +585,7 @@ int CheckOcspRequest(WOLFSSL_OCSP* ocsp, OcspRequest* ocspRequest,
585585

586586
#ifndef WOLFSSL_NO_OCSP_ISSUER_CHAIN_CHECK
587587
static int CheckOcspResponderChain(OcspEntry* single, byte* issuerHash,
588-
void* vp, Signer* pendingCAs) {
588+
byte* issuerKeyHash, void* vp, Signer* pendingCAs) {
589589
/* Attempt to build a chain up to cert's issuer */
590590
WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp;
591591
Signer* ca = NULL;
@@ -602,47 +602,62 @@ static int CheckOcspResponderChain(OcspEntry* single, byte* issuerHash,
602602
* in OCSP request
603603
*/
604604

605-
/* End loop if no more issuers found or if we have found a self
606-
* signed cert (ca == prev) */
607-
ca = GetCAByName(cm, single->issuerHash);
605+
if (issuerKeyHash == NULL)
606+
return 0;
607+
608+
/* Select CertID issuer by key hash so a same-DN / different-key trust
609+
* anchor cannot hijack the starting point. */
610+
ca = GetCAByKeyHash(cm, single->issuerKeyHash);
611+
if (ca != NULL && XMEMCMP(ca->subjectNameHash, single->issuerHash,
612+
OCSP_DIGEST_SIZE) != 0) {
613+
ca = NULL;
614+
}
608615
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
609616
if (ca == NULL && pendingCAs != NULL) {
610-
ca = findSignerByName(pendingCAs, single->issuerHash);
617+
ca = findSignerByKeyHash(pendingCAs, single->issuerKeyHash);
618+
if (ca != NULL && XMEMCMP(ca->subjectNameHash, single->issuerHash,
619+
OCSP_DIGEST_SIZE) != 0) {
620+
ca = NULL;
621+
}
611622
}
612623
#else
613624
(void)pendingCAs;
614625
#endif
615626
for (; ca != NULL && ca != prev;
616627
prev = ca) {
617-
if (XMEMCMP(issuerHash, ca->issuerNameHash, OCSP_DIGEST_SIZE) == 0) {
628+
Signer* parent = GetCAByName(cm, ca->issuerNameHash);
629+
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
630+
if (parent == NULL && pendingCAs != NULL) {
631+
parent = findSignerByName(pendingCAs, ca->issuerNameHash);
632+
}
633+
#endif
634+
if (parent == NULL || parent == ca)
635+
break;
636+
637+
if (XMEMCMP(parent->subjectNameHash, issuerHash,
638+
OCSP_DIGEST_SIZE) == 0 &&
639+
XMEMCMP(parent->subjectKeyHash, issuerKeyHash,
640+
OCSP_DIGEST_SIZE) == 0) {
618641
WOLFSSL_MSG("\tOCSP Response signed by authorized "
619642
"responder delegated by issuer "
620643
"(found in chain)");
621644
passed = 1;
622645
break;
623646
}
624-
ca = GetCAByName(cm, ca->issuerNameHash);
625-
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
626-
if (ca == NULL && pendingCAs != NULL) {
627-
ca = findSignerByName(pendingCAs, single->issuerHash);
628-
}
629-
#endif
647+
648+
ca = parent;
630649
}
631650
return passed;
632651
}
633652
#endif
634653

635-
/**
636-
* Enforce https://www.rfc-editor.org/rfc/rfc6960#section-4.2.2.2
637-
* @param bs The basic OCSP response to verify
638-
* @param subjectHash The subject key hash of the OCSP responder certificate
639-
* @param extExtKeyUsage The extended key usage bits of the responder certificate
640-
* @param issuerHash The issuer name hash of the OCSP responder certificate
641-
* @param vp Unused (reserved for future use)
642-
* @return 1 if the responder is authorized to sign the response, 0 otherwise
643-
*/
654+
/* Enforce https://www.rfc-editor.org/rfc/rfc6960#section-4.2.2.2. Both halves
655+
* of CertID (issuerNameHash and issuerKeyHash) must match; name-only matching
656+
* would authorize a same-DN / different-key CA. issuerKeyHash may be NULL when
657+
* unavailable, which disables the delegated branch. */
644658
int CheckOcspResponder(OcspResponse *bs, byte* subjectHash,
645-
byte extExtKeyUsage, byte* issuerHash, void* vp)
659+
byte* subjectKeyHash, byte extExtKeyUsage, byte* issuerHash,
660+
byte* issuerKeyHash, void* vp)
646661
{
647662
int ret = 0;
648663
OcspEntry* single;
@@ -660,26 +675,31 @@ int CheckOcspResponder(OcspResponse *bs, byte* subjectHash,
660675
if (bs == NULL || subjectHash == NULL || issuerHash == NULL)
661676
return BAD_FUNC_ARG;
662677

663-
/* Traverse the list and check that the cert has the authority to provide
664-
* an OCSP response for each entry. */
665678
for (single = bs->single; single != NULL; single = single->next) {
666679
int passed = 0;
667680

668-
if (XMEMCMP(subjectHash, single->issuerHash, OCSP_DIGEST_SIZE) == 0) {
681+
if (subjectKeyHash != NULL &&
682+
XMEMCMP(subjectHash, single->issuerHash,
683+
OCSP_DIGEST_SIZE) == 0 &&
684+
XMEMCMP(subjectKeyHash, single->issuerKeyHash,
685+
OCSP_DIGEST_SIZE) == 0) {
669686
WOLFSSL_MSG("\tOCSP Response signed by issuer");
670687
passed = 1;
671688
}
672689
else if ((extExtKeyUsage & EXTKEYUSE_OCSP_SIGN) != 0) {
673-
if (XMEMCMP(issuerHash, single->issuerHash, OCSP_DIGEST_SIZE)
674-
== 0) {
690+
if (issuerKeyHash != NULL &&
691+
XMEMCMP(issuerHash, single->issuerHash,
692+
OCSP_DIGEST_SIZE) == 0 &&
693+
XMEMCMP(issuerKeyHash, single->issuerKeyHash,
694+
OCSP_DIGEST_SIZE) == 0) {
675695
WOLFSSL_MSG("\tOCSP Response signed by authorized responder "
676696
"delegated by issuer");
677697
passed = 1;
678698
}
679699
#ifndef WOLFSSL_NO_OCSP_ISSUER_CHAIN_CHECK
680700
else if (vp != NULL) {
681-
passed = CheckOcspResponderChain(single, issuerHash, vp,
682-
bs->pendingCAs);
701+
passed = CheckOcspResponderChain(single, issuerHash,
702+
issuerKeyHash, vp, bs->pendingCAs);
683703
}
684704
#endif
685705
}
@@ -1083,8 +1103,10 @@ static int OcspVerifySigner(WOLFSSL_OCSP_BASICRESP *resp, DecodedCert *cert,
10831103
}
10841104
#ifndef WOLFSSL_NO_OCSP_ISSUER_CHECK
10851105
if ((flags & WOLFSSL_OCSP_NOCHECKS) == 0) {
1086-
ret = CheckOcspResponder(resp, c->subjectHash, c->extExtKeyUsage,
1087-
c->issuerHash, st->cm);
1106+
ret = CheckOcspResponder(resp, c->subjectHash, c->subjectKeyHash,
1107+
c->extExtKeyUsage, c->issuerHash,
1108+
(c->ca != NULL) ? c->ca->subjectKeyHash : NULL,
1109+
st->cm);
10881110
}
10891111
else {
10901112
ret = 0;

wolfcrypt/src/asn.c

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22546,17 +22546,15 @@ int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm,
2254622546
}
2254722547

2254822548
#ifdef HAVE_OCSP
22549-
if (type != CA_TYPE &&
22550-
type != TRUSTED_PEER_TYPE) {
22551-
/* Need the CA's public key hash for OCSP */
22552-
if (cert->ca) {
22553-
XMEMCPY(cert->issuerKeyHash, cert->ca->subjectKeyHash,
22554-
KEYID_SIZE);
22555-
}
22556-
else if (cert->selfSigned) {
22557-
XMEMCPY(cert->issuerKeyHash, cert->subjectKeyHash,
22558-
KEYID_SIZE);
22559-
}
22549+
/* Needed for OCSP requests, and for binding responder authorization
22550+
* to CertID's issuerKeyHash when this cert becomes a Signer. */
22551+
if (cert->ca) {
22552+
XMEMCPY(cert->issuerKeyHash, cert->ca->subjectKeyHash,
22553+
KEYID_SIZE);
22554+
}
22555+
else if (cert->selfSigned) {
22556+
XMEMCPY(cert->issuerKeyHash, cert->subjectKeyHash,
22557+
KEYID_SIZE);
2256022558
}
2256122559
#endif /* HAVE_OCSP */
2256222560
}
@@ -22859,6 +22857,8 @@ int FillSigner(Signer* signer, DecodedCert* cert, int type, DerBuffer *der)
2285922857
#ifdef HAVE_OCSP
2286022858
XMEMCPY(signer->subjectKeyHash, cert->subjectKeyHash,
2286122859
KEYID_SIZE);
22860+
XMEMCPY(signer->issuerKeyHash, cert->issuerKeyHash,
22861+
KEYID_SIZE);
2286222862
#endif
2286322863
signer->keyUsage = cert->extKeyUsageSet ? cert->extKeyUsage
2286422864
: 0xFFFF;
@@ -32876,7 +32876,8 @@ static int OcspRespCheck(OcspResponse *resp, Signer *responder, void* vp)
3287632876
return -1;
3287732877

3287832878
ret = CheckOcspResponder(resp, responder->subjectNameHash,
32879-
responder->extKeyUsage, responder->issuerNameHash, vp);
32879+
responder->subjectKeyHash, responder->extKeyUsage,
32880+
responder->issuerNameHash, responder->issuerKeyHash, vp);
3288032881
if (ret != 0)
3288132882
return -1;
3288232883

@@ -32964,8 +32965,9 @@ static int OcspCheckCert(OcspResponse *resp, int noVerify,
3296432965

3296532966
#ifndef WOLFSSL_NO_OCSP_ISSUER_CHECK
3296632967
if (ret == 0 && !noVerify) {
32967-
ret = CheckOcspResponder(resp, cert->subjectHash, cert->extExtKeyUsage,
32968-
cert->issuerHash, cm);
32968+
ret = CheckOcspResponder(resp, cert->subjectHash, cert->subjectKeyHash,
32969+
cert->extExtKeyUsage, cert->issuerHash,
32970+
(cert->ca != NULL) ? cert->ca->subjectKeyHash : NULL, cm);
3296932971
if (ret != 0) {
3297032972
WOLFSSL_MSG("\tOCSP Responder certificate issuer check failed");
3297132973
goto err;

wolfssl/ocsp.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ WOLFSSL_LOCAL int CheckOcspResponse(WOLFSSL_OCSP *ocsp, byte *response, int resp
7575
void* heap);
7676

7777
WOLFSSL_LOCAL int CheckOcspResponder(OcspResponse *bs, byte* subjectHash,
78-
byte extExtKeyUsage, byte* issuerHash, void* vp);
78+
byte* subjectKeyHash, byte extExtKeyUsage, byte* issuerHash,
79+
byte* issuerKeyHash, void* vp);
7980

8081
/* Allocates and initializes a WOLFSSL_OCSP object */
8182
WOLFSSL_API WOLFSSL_OCSP* wc_NewOCSP(WOLFSSL_CERT_MANAGER* cm);

wolfssl/wolfcrypt/asn.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2152,6 +2152,7 @@ struct Signer {
21522152
#endif
21532153
#ifdef HAVE_OCSP
21542154
byte subjectKeyHash[KEYID_SIZE];
2155+
byte issuerKeyHash[KEYID_SIZE]; /* key hash of verifying parent CA */
21552156
#endif
21562157
#if defined(WOLFSSL_AKID_NAME) || defined(HAVE_CRL)
21572158
byte serialHash[SIGNER_DIGEST_SIZE]; /* serial number hash */

0 commit comments

Comments
 (0)