mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-07 19:30:50 +02:00
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
This commit is contained in:
+116
-16
@@ -18588,9 +18588,10 @@ static int ConfirmNameConstraints(Signer* signer, DecodedCert* cert)
|
||||
case ASN_DNS_TYPE:
|
||||
name = cert->altNames;
|
||||
|
||||
/* When no SAN is present, apply DNS name constraints to the
|
||||
* Subject CN. */
|
||||
if (cert->subjectCN != NULL && cert->altNames == NULL) {
|
||||
/* Apply DNS constraints to leaf Subject CN when no SAN
|
||||
* (legacy hostname-in-CN). Skipped for CAs. */
|
||||
if (cert->subjectCN != NULL && cert->altNames == NULL &&
|
||||
!cert->isCA) {
|
||||
subjectDnsName.next = NULL;
|
||||
subjectDnsName.type = ASN_DNS_TYPE;
|
||||
subjectDnsName.len = cert->subjectCNLen;
|
||||
@@ -23149,6 +23150,71 @@ Signer* findSignerByName(Signer *list, byte *hash)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifndef IGNORE_NAME_CONSTRAINTS
|
||||
/* Find a signer for cert in cm and extraCAList. Prefers AKID->SKID
|
||||
* with name-hash validation. Fall back to name-only when AKID is
|
||||
* absent. */
|
||||
static Signer* FindSignerByAkidOrName(void* cm, Signer* extraCAList,
|
||||
Signer* cert)
|
||||
{
|
||||
Signer* signer = NULL;
|
||||
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
|
||||
#ifndef NO_SKID
|
||||
Signer* exCaSigner;
|
||||
#endif
|
||||
#else
|
||||
(void)extraCAList;
|
||||
#endif
|
||||
|
||||
#ifndef NO_SKID
|
||||
if (cert->authKeyIdSet) {
|
||||
signer = GetCA(cm, cert->authKeyIdHash);
|
||||
if (signer != NULL &&
|
||||
XMEMCMP(signer->subjectNameHash, cert->issuerNameHash,
|
||||
SIGNER_DIGEST_SIZE) != 0) {
|
||||
signer = NULL;
|
||||
}
|
||||
/* AKID is authoritative; do not fall back to name when AKID
|
||||
* is set (could substitute a same-DN sibling). */
|
||||
}
|
||||
else {
|
||||
signer = GetCAByName(cm, cert->issuerNameHash);
|
||||
}
|
||||
#else
|
||||
signer = GetCA(cm, cert->issuerNameHash);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
|
||||
if (signer == NULL && extraCAList != NULL) {
|
||||
#ifndef NO_SKID
|
||||
if (cert->authKeyIdSet) {
|
||||
for (exCaSigner = extraCAList; exCaSigner != NULL;
|
||||
exCaSigner = exCaSigner->next) {
|
||||
if (XMEMCMP(exCaSigner->subjectKeyIdHash,
|
||||
cert->authKeyIdHash,
|
||||
SIGNER_DIGEST_SIZE) == 0 &&
|
||||
XMEMCMP(exCaSigner->subjectNameHash,
|
||||
cert->issuerNameHash,
|
||||
SIGNER_DIGEST_SIZE) == 0) {
|
||||
signer = exCaSigner;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* AKID is authoritative; do not fall back to name. */
|
||||
}
|
||||
else {
|
||||
signer = findSignerByName(extraCAList, cert->issuerNameHash);
|
||||
}
|
||||
#else
|
||||
signer = findSignerByName(extraCAList, cert->issuerNameHash);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
return signer;
|
||||
}
|
||||
#endif /* !IGNORE_NAME_CONSTRAINTS */
|
||||
|
||||
int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm,
|
||||
Signer *extraCAList)
|
||||
{
|
||||
@@ -23163,6 +23229,12 @@ int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm,
|
||||
int idx = 0;
|
||||
#endif
|
||||
byte* sce_tsip_encRsaKeyIdx;
|
||||
#ifndef IGNORE_NAME_CONSTRAINTS
|
||||
int ncDepth = 0;
|
||||
Signer* ncSigner = NULL;
|
||||
Signer* ncParent = NULL;
|
||||
Signer* ncPrev = NULL;
|
||||
#endif
|
||||
(void)extraCAList;
|
||||
|
||||
if (cert == NULL) {
|
||||
@@ -23795,18 +23867,6 @@ int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm,
|
||||
}
|
||||
#endif /* WOLFSSL_DUAL_ALG_CERTS */
|
||||
}
|
||||
#ifndef IGNORE_NAME_CONSTRAINTS
|
||||
if (verify == VERIFY || verify == VERIFY_OCSP ||
|
||||
verify == VERIFY_NAME || verify == VERIFY_SKIP_DATE) {
|
||||
/* check that this cert's name is permitted by the signer's
|
||||
* name constraints */
|
||||
if (!ConfirmNameConstraints(cert->ca, cert)) {
|
||||
WOLFSSL_MSG("Confirm name constraint failed");
|
||||
WOLFSSL_ERROR_VERBOSE(ASN_NAME_INVALID_E);
|
||||
return ASN_NAME_INVALID_E;
|
||||
}
|
||||
}
|
||||
#endif /* IGNORE_NAME_CONSTRAINTS */
|
||||
} /* cert->ca */
|
||||
#ifdef WOLFSSL_CERT_REQ
|
||||
else if (type == CERTREQ_TYPE) {
|
||||
@@ -23888,6 +23948,38 @@ int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm,
|
||||
}
|
||||
} /* verify != NO_VERIFY && type != CA_TYPE && type != TRUSTED_PEER_TYPE */
|
||||
|
||||
#ifndef IGNORE_NAME_CONSTRAINTS
|
||||
/* Apply each ancestor CA's name constraints to this cert.
|
||||
* Signer pointers between lookups are not lock-protected
|
||||
* (see wolfssl_cm_get_certs_der). */
|
||||
if ((verify == VERIFY || verify == VERIFY_OCSP ||
|
||||
verify == VERIFY_NAME || verify == VERIFY_SKIP_DATE) &&
|
||||
type != TRUSTED_PEER_TYPE && cert->ca != NULL) {
|
||||
ncSigner = cert->ca;
|
||||
while (ncSigner != NULL) {
|
||||
if (!ConfirmNameConstraints(ncSigner, cert)) {
|
||||
WOLFSSL_MSG("Confirm name constraint failed");
|
||||
WOLFSSL_ERROR_VERBOSE(ASN_NAME_INVALID_E);
|
||||
return ASN_NAME_INVALID_E;
|
||||
}
|
||||
/* Stop at trust anchor (self-issued). */
|
||||
if (ncSigner->selfSigned)
|
||||
break;
|
||||
ncParent = FindSignerByAkidOrName(cm, extraCAList, ncSigner);
|
||||
/* Stop on missing parent, self-loop, or A->B->A cycle. */
|
||||
if (ncParent == NULL || ncParent == ncSigner ||
|
||||
ncParent == ncPrev)
|
||||
break;
|
||||
if (++ncDepth >= WOLFSSL_MAX_CHAIN_DEPTH) {
|
||||
WOLFSSL_MSG("NC ancestor walk exceeded WOLFSSL_MAX_CHAIN_DEPTH");
|
||||
WOLFSSL_ERROR_VERBOSE(ASN_PATHLEN_SIZE_E);
|
||||
return ASN_PATHLEN_SIZE_E;
|
||||
}
|
||||
ncPrev = ncSigner;
|
||||
ncSigner = ncParent;
|
||||
}
|
||||
}
|
||||
#endif /* IGNORE_NAME_CONSTRAINTS */
|
||||
#if defined(WOLFSSL_NO_TRUSTED_CERTS_VERIFY) && !defined(NO_SKID)
|
||||
exit_pcr:
|
||||
#endif
|
||||
@@ -23966,10 +24058,18 @@ int FillSigner(Signer* signer, DecodedCert* cert, int type, DerBuffer *der)
|
||||
#ifndef NO_SKID
|
||||
XMEMCPY(signer->subjectKeyIdHash, cert->extSubjKeyId,
|
||||
SIGNER_DIGEST_SIZE);
|
||||
#ifndef IGNORE_NAME_CONSTRAINTS
|
||||
if (cert->extAuthKeyIdSet) {
|
||||
XMEMCPY(signer->authKeyIdHash, cert->extAuthKeyId,
|
||||
SIGNER_DIGEST_SIZE);
|
||||
signer->authKeyIdSet = 1;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
XMEMCPY(signer->subjectNameHash, cert->subjectHash,
|
||||
SIGNER_DIGEST_SIZE);
|
||||
#if defined(HAVE_OCSP) || defined(HAVE_CRL) || defined(WOLFSSL_AKID_NAME)
|
||||
#if defined(HAVE_OCSP) || defined(HAVE_CRL) || \
|
||||
defined(WOLFSSL_AKID_NAME) || !defined(IGNORE_NAME_CONSTRAINTS)
|
||||
XMEMCPY(signer->issuerNameHash, cert->issuerHash,
|
||||
SIGNER_DIGEST_SIZE);
|
||||
#endif
|
||||
|
||||
+18
-4
@@ -1736,6 +1736,11 @@ typedef struct EncodedName {
|
||||
#define WOLFSSL_MAX_PATH_LEN 127
|
||||
#endif
|
||||
|
||||
#ifndef WOLFSSL_MAX_CHAIN_DEPTH
|
||||
/* Max cert chain depth for ancestor walks. */
|
||||
#define WOLFSSL_MAX_CHAIN_DEPTH 20
|
||||
#endif
|
||||
|
||||
typedef struct DecodedName DecodedName;
|
||||
typedef struct DecodedCert DecodedCert;
|
||||
typedef struct Signer Signer;
|
||||
@@ -2207,6 +2212,10 @@ struct Signer {
|
||||
*/
|
||||
WC_BITFIELD extNameConstraintCrit:1;
|
||||
WC_BITFIELD extNameConstraintHasUnsupported:1;
|
||||
#ifndef NO_SKID
|
||||
WC_BITFIELD authKeyIdSet:1; /* true when authKeyIdHash holds the
|
||||
* AKID extension's keyId */
|
||||
#endif
|
||||
#endif
|
||||
const byte* publicKey;
|
||||
int nameLen;
|
||||
@@ -2218,15 +2227,20 @@ struct Signer {
|
||||
#endif
|
||||
byte subjectNameHash[SIGNER_DIGEST_SIZE];
|
||||
/* sha hash of names in certificate */
|
||||
#if defined(HAVE_OCSP) || defined(HAVE_CRL) || defined(WOLFSSL_AKID_NAME)
|
||||
#if defined(HAVE_OCSP) || defined(HAVE_CRL) || defined(WOLFSSL_AKID_NAME) || \
|
||||
!defined(IGNORE_NAME_CONSTRAINTS)
|
||||
byte issuerNameHash[SIGNER_DIGEST_SIZE];
|
||||
/* sha hash of issuer names in certificate.
|
||||
* Used in OCSP to check for authorized
|
||||
* responders. */
|
||||
/* sha hash of issuer names; used by
|
||||
* OCSP and name-constraint walk */
|
||||
#endif
|
||||
#ifndef NO_SKID
|
||||
byte subjectKeyIdHash[SIGNER_DIGEST_SIZE];
|
||||
/* sha hash of key in certificate */
|
||||
#ifndef IGNORE_NAME_CONSTRAINTS
|
||||
byte authKeyIdHash[SIGNER_DIGEST_SIZE];
|
||||
/* sha hash of AKID; locates signer
|
||||
* during name-constraint walk */
|
||||
#endif
|
||||
#endif
|
||||
#ifdef HAVE_OCSP
|
||||
byte subjectKeyHash[KEYID_SIZE];
|
||||
|
||||
Reference in New Issue
Block a user