Skip to content

Commit bc26ce0

Browse files
committed
walk cert chain to apply ancestor name constraints
- Ancestor walk added to ParseCertRelative - FindSignerByAkidOrName helper: AKID->SKID with name-hash validation, name-only fallback only when AKID is absent - Signer fields: authKeyIdSet, authKeyIdHash - issuerNameHash ifdef widened to include !IGNORE_NAME_CONSTRAINTS - WOLFSSL_MAX_CHAIN_DEPTH macro (default 20) - Self-loop and A->B->A cycle termination - CN-as-DNS fallback in ConfirmNameConstraints gated on !cert->isCA
1 parent 3876746 commit bc26ce0

2 files changed

Lines changed: 134 additions & 20 deletions

File tree

wolfcrypt/src/asn.c

Lines changed: 116 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18588,9 +18588,10 @@ static int ConfirmNameConstraints(Signer* signer, DecodedCert* cert)
1858818588
case ASN_DNS_TYPE:
1858918589
name = cert->altNames;
1859018590

18591-
/* When no SAN is present, apply DNS name constraints to the
18592-
* Subject CN. */
18593-
if (cert->subjectCN != NULL && cert->altNames == NULL) {
18591+
/* Apply DNS constraints to leaf Subject CN when no SAN
18592+
* (legacy hostname-in-CN). Skipped for CAs. */
18593+
if (cert->subjectCN != NULL && cert->altNames == NULL &&
18594+
!cert->isCA) {
1859418595
subjectDnsName.next = NULL;
1859518596
subjectDnsName.type = ASN_DNS_TYPE;
1859618597
subjectDnsName.len = cert->subjectCNLen;
@@ -23149,6 +23150,71 @@ Signer* findSignerByName(Signer *list, byte *hash)
2314923150
return NULL;
2315023151
}
2315123152

23153+
#ifndef IGNORE_NAME_CONSTRAINTS
23154+
/* Find a signer for cert in cm and extraCAList. Prefers AKID->SKID
23155+
* with name-hash validation. Fall back to name-only when AKID is
23156+
* absent. */
23157+
static Signer* FindSignerByAkidOrName(void* cm, Signer* extraCAList,
23158+
Signer* cert)
23159+
{
23160+
Signer* signer = NULL;
23161+
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
23162+
#ifndef NO_SKID
23163+
Signer* exCaSigner;
23164+
#endif
23165+
#else
23166+
(void)extraCAList;
23167+
#endif
23168+
23169+
#ifndef NO_SKID
23170+
if (cert->authKeyIdSet) {
23171+
signer = GetCA(cm, cert->authKeyIdHash);
23172+
if (signer != NULL &&
23173+
XMEMCMP(signer->subjectNameHash, cert->issuerNameHash,
23174+
SIGNER_DIGEST_SIZE) != 0) {
23175+
signer = NULL;
23176+
}
23177+
/* AKID is authoritative; do not fall back to name when AKID
23178+
* is set (could substitute a same-DN sibling). */
23179+
}
23180+
else {
23181+
signer = GetCAByName(cm, cert->issuerNameHash);
23182+
}
23183+
#else
23184+
signer = GetCA(cm, cert->issuerNameHash);
23185+
#endif
23186+
23187+
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
23188+
if (signer == NULL && extraCAList != NULL) {
23189+
#ifndef NO_SKID
23190+
if (cert->authKeyIdSet) {
23191+
for (exCaSigner = extraCAList; exCaSigner != NULL;
23192+
exCaSigner = exCaSigner->next) {
23193+
if (XMEMCMP(exCaSigner->subjectKeyIdHash,
23194+
cert->authKeyIdHash,
23195+
SIGNER_DIGEST_SIZE) == 0 &&
23196+
XMEMCMP(exCaSigner->subjectNameHash,
23197+
cert->issuerNameHash,
23198+
SIGNER_DIGEST_SIZE) == 0) {
23199+
signer = exCaSigner;
23200+
break;
23201+
}
23202+
}
23203+
/* AKID is authoritative; do not fall back to name. */
23204+
}
23205+
else {
23206+
signer = findSignerByName(extraCAList, cert->issuerNameHash);
23207+
}
23208+
#else
23209+
signer = findSignerByName(extraCAList, cert->issuerNameHash);
23210+
#endif
23211+
}
23212+
#endif
23213+
23214+
return signer;
23215+
}
23216+
#endif /* !IGNORE_NAME_CONSTRAINTS */
23217+
2315223218
int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm,
2315323219
Signer *extraCAList)
2315423220
{
@@ -23163,6 +23229,12 @@ int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm,
2316323229
int idx = 0;
2316423230
#endif
2316523231
byte* sce_tsip_encRsaKeyIdx;
23232+
#ifndef IGNORE_NAME_CONSTRAINTS
23233+
int ncDepth = 0;
23234+
Signer* ncSigner = NULL;
23235+
Signer* ncParent = NULL;
23236+
Signer* ncPrev = NULL;
23237+
#endif
2316623238
(void)extraCAList;
2316723239

2316823240
if (cert == NULL) {
@@ -23795,18 +23867,6 @@ int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm,
2379523867
}
2379623868
#endif /* WOLFSSL_DUAL_ALG_CERTS */
2379723869
}
23798-
#ifndef IGNORE_NAME_CONSTRAINTS
23799-
if (verify == VERIFY || verify == VERIFY_OCSP ||
23800-
verify == VERIFY_NAME || verify == VERIFY_SKIP_DATE) {
23801-
/* check that this cert's name is permitted by the signer's
23802-
* name constraints */
23803-
if (!ConfirmNameConstraints(cert->ca, cert)) {
23804-
WOLFSSL_MSG("Confirm name constraint failed");
23805-
WOLFSSL_ERROR_VERBOSE(ASN_NAME_INVALID_E);
23806-
return ASN_NAME_INVALID_E;
23807-
}
23808-
}
23809-
#endif /* IGNORE_NAME_CONSTRAINTS */
2381023870
} /* cert->ca */
2381123871
#ifdef WOLFSSL_CERT_REQ
2381223872
else if (type == CERTREQ_TYPE) {
@@ -23888,6 +23948,38 @@ int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm,
2388823948
}
2388923949
} /* verify != NO_VERIFY && type != CA_TYPE && type != TRUSTED_PEER_TYPE */
2389023950

23951+
#ifndef IGNORE_NAME_CONSTRAINTS
23952+
/* Apply each ancestor CA's name constraints to this cert.
23953+
* Signer pointers between lookups are not lock-protected
23954+
* (see wolfssl_cm_get_certs_der). */
23955+
if ((verify == VERIFY || verify == VERIFY_OCSP ||
23956+
verify == VERIFY_NAME || verify == VERIFY_SKIP_DATE) &&
23957+
type != TRUSTED_PEER_TYPE && cert->ca != NULL) {
23958+
ncSigner = cert->ca;
23959+
while (ncSigner != NULL) {
23960+
if (!ConfirmNameConstraints(ncSigner, cert)) {
23961+
WOLFSSL_MSG("Confirm name constraint failed");
23962+
WOLFSSL_ERROR_VERBOSE(ASN_NAME_INVALID_E);
23963+
return ASN_NAME_INVALID_E;
23964+
}
23965+
/* Stop at trust anchor (self-issued). */
23966+
if (ncSigner->selfSigned)
23967+
break;
23968+
ncParent = FindSignerByAkidOrName(cm, extraCAList, ncSigner);
23969+
/* Stop on missing parent, self-loop, or A->B->A cycle. */
23970+
if (ncParent == NULL || ncParent == ncSigner ||
23971+
ncParent == ncPrev)
23972+
break;
23973+
if (++ncDepth >= WOLFSSL_MAX_CHAIN_DEPTH) {
23974+
WOLFSSL_MSG("NC ancestor walk exceeded WOLFSSL_MAX_CHAIN_DEPTH");
23975+
WOLFSSL_ERROR_VERBOSE(ASN_PATHLEN_SIZE_E);
23976+
return ASN_PATHLEN_SIZE_E;
23977+
}
23978+
ncPrev = ncSigner;
23979+
ncSigner = ncParent;
23980+
}
23981+
}
23982+
#endif /* IGNORE_NAME_CONSTRAINTS */
2389123983
#if defined(WOLFSSL_NO_TRUSTED_CERTS_VERIFY) && !defined(NO_SKID)
2389223984
exit_pcr:
2389323985
#endif
@@ -23966,10 +24058,18 @@ int FillSigner(Signer* signer, DecodedCert* cert, int type, DerBuffer *der)
2396624058
#ifndef NO_SKID
2396724059
XMEMCPY(signer->subjectKeyIdHash, cert->extSubjKeyId,
2396824060
SIGNER_DIGEST_SIZE);
24061+
#ifndef IGNORE_NAME_CONSTRAINTS
24062+
if (cert->extAuthKeyIdSet) {
24063+
XMEMCPY(signer->authKeyIdHash, cert->extAuthKeyId,
24064+
SIGNER_DIGEST_SIZE);
24065+
signer->authKeyIdSet = 1;
24066+
}
24067+
#endif
2396924068
#endif
2397024069
XMEMCPY(signer->subjectNameHash, cert->subjectHash,
2397124070
SIGNER_DIGEST_SIZE);
23972-
#if defined(HAVE_OCSP) || defined(HAVE_CRL) || defined(WOLFSSL_AKID_NAME)
24071+
#if defined(HAVE_OCSP) || defined(HAVE_CRL) || \
24072+
defined(WOLFSSL_AKID_NAME) || !defined(IGNORE_NAME_CONSTRAINTS)
2397324073
XMEMCPY(signer->issuerNameHash, cert->issuerHash,
2397424074
SIGNER_DIGEST_SIZE);
2397524075
#endif

wolfssl/wolfcrypt/asn.h

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1736,6 +1736,11 @@ typedef struct EncodedName {
17361736
#define WOLFSSL_MAX_PATH_LEN 127
17371737
#endif
17381738

1739+
#ifndef WOLFSSL_MAX_CHAIN_DEPTH
1740+
/* Max cert chain depth for ancestor walks. */
1741+
#define WOLFSSL_MAX_CHAIN_DEPTH 20
1742+
#endif
1743+
17391744
typedef struct DecodedName DecodedName;
17401745
typedef struct DecodedCert DecodedCert;
17411746
typedef struct Signer Signer;
@@ -2207,6 +2212,10 @@ struct Signer {
22072212
*/
22082213
WC_BITFIELD extNameConstraintCrit:1;
22092214
WC_BITFIELD extNameConstraintHasUnsupported:1;
2215+
#ifndef NO_SKID
2216+
WC_BITFIELD authKeyIdSet:1; /* true when authKeyIdHash holds the
2217+
* AKID extension's keyId */
2218+
#endif
22102219
#endif
22112220
const byte* publicKey;
22122221
int nameLen;
@@ -2218,15 +2227,20 @@ struct Signer {
22182227
#endif
22192228
byte subjectNameHash[SIGNER_DIGEST_SIZE];
22202229
/* sha hash of names in certificate */
2221-
#if defined(HAVE_OCSP) || defined(HAVE_CRL) || defined(WOLFSSL_AKID_NAME)
2230+
#if defined(HAVE_OCSP) || defined(HAVE_CRL) || defined(WOLFSSL_AKID_NAME) || \
2231+
!defined(IGNORE_NAME_CONSTRAINTS)
22222232
byte issuerNameHash[SIGNER_DIGEST_SIZE];
2223-
/* sha hash of issuer names in certificate.
2224-
* Used in OCSP to check for authorized
2225-
* responders. */
2233+
/* sha hash of issuer names; used by
2234+
* OCSP and name-constraint walk */
22262235
#endif
22272236
#ifndef NO_SKID
22282237
byte subjectKeyIdHash[SIGNER_DIGEST_SIZE];
22292238
/* sha hash of key in certificate */
2239+
#ifndef IGNORE_NAME_CONSTRAINTS
2240+
byte authKeyIdHash[SIGNER_DIGEST_SIZE];
2241+
/* sha hash of AKID; locates signer
2242+
* during name-constraint walk */
2243+
#endif
22302244
#endif
22312245
#ifdef HAVE_OCSP
22322246
byte subjectKeyHash[KEYID_SIZE];

0 commit comments

Comments
 (0)