Skip to content

Commit d9ed9de

Browse files
committed
ocsp: bind responder authorization to CertID issuerKeyHash
Addresses ZD21675
1 parent 936f8e5 commit d9ed9de

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)