Retry all certificates passed into wolfSSL_X509_verify_cert until a valid chain is found, rather than failing out on the first invalid chain. This allows for registering multiple certs with the same subject key, ie. alt cert chains.

pull/8692/head
Kareem 2025-04-16 16:16:32 -07:00
parent 43f94a5d7d
commit 025dbc3454
3 changed files with 107 additions and 3 deletions

View File

@ -6142,6 +6142,53 @@ int AddCA(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int type, int verify)
return ret == 0 ? WOLFSSL_SUCCESS : ret;
}
/* Removes the CA with the passed in subject hash from the cert manager's CA cert store. */
int RemoveCA(WOLFSSL_CERT_MANAGER* cm, byte* hash)
{
Signer* current;
Signer* prev;
int ret = 0;
word32 row;
if (cm == NULL || hash == NULL) {
return ret;
}
row = HashSigner(hash);
if (wc_LockMutex(&cm->caLock) != 0) {
return ret;
}
current = cm->caTable[row];
prev = current;
while (current) {
byte* subjectHash;
#ifndef NO_SKID
subjectHash = current->subjectKeyIdHash;
#else
subjectHash = current->subjectNameHash;
#endif
if (XMEMCMP(hash, subjectHash, SIGNER_DIGEST_SIZE) == 0) {
if (current == cm->caTable[row]) {
cm->caTable[row] = cm->caTable[row]->next;
}
else {
prev->next = current->next;
}
FreeSigner(current, cm->heap);
ret = 1;
break;
}
prev = current;
current = current->next;
}
wc_UnLockMutex(&cm->caLock);
return ret;
}
#endif /* !NO_CERTS */

View File

@ -34,6 +34,8 @@
#ifdef OPENSSL_EXTRA
static int X509StoreGetIssuerEx(WOLFSSL_X509 **issuer,
WOLFSSL_STACK *certs, WOLFSSL_X509 *x);
static int X509StorePopCert(WOLFSSL_STACK *certs_stack, WOLFSSL_STACK *dest_stack,
WOLFSSL_X509 *cert);
static int X509StoreAddCa(WOLFSSL_X509_STORE* store,
WOLFSSL_X509* x509, int type);
#endif
@ -415,10 +417,12 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx)
int i = 0;
int numInterAdd = 0;
int depth = 0;
int origDepth = 0;
WOLFSSL_X509 *issuer = NULL;
WOLFSSL_X509 *orig = NULL;
WOLF_STACK_OF(WOLFSSL_X509)* certs = NULL;
WOLF_STACK_OF(WOLFSSL_X509)* certsToUse = NULL;
WOLF_STACK_OF(WOLFSSL_X509)* failedCerts = NULL;
WOLFSSL_ENTER("wolfSSL_X509_verify_cert");
if (ctx == NULL || ctx->store == NULL || ctx->store->cm == NULL
@ -427,6 +431,10 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx)
}
certs = ctx->store->certs;
if (certs == NULL) {
return WOLFSSL_FATAL_ERROR;
}
if (ctx->setTrustedSk != NULL) {
certs = ctx->setTrustedSk;
}
@ -450,6 +458,10 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx)
}
ctx->chain = wolfSSL_sk_X509_new_null();
failedCerts = wolfSSL_sk_X509_new_null();
if (!failedCerts)
return WOLFSSL_FATAL_ERROR;
if (ctx->depth > 0) {
depth = ctx->depth + 1;
}
@ -458,6 +470,7 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx)
}
orig = ctx->current_cert;
origDepth = depth;
while(done == 0 && depth > 0) {
issuer = NULL;
@ -491,12 +504,14 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx)
ret = X509StoreAddCa(ctx->store, issuer,
WOLFSSL_TEMP_CA);
if (ret != WOLFSSL_SUCCESS) {
goto exit;
goto retry;
}
added = 1;
ret = X509StoreVerifyCert(ctx);
if (ret != WOLFSSL_SUCCESS) {
goto exit;
if ((origDepth - depth) <= 1)
added = 0;
goto retry;
}
/* Add it to the current chain and look at the issuer cert next */
wolfSSL_sk_X509_push(ctx->chain, ctx->current_cert);
@ -515,8 +530,9 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx)
(added == 1)) {
wolfSSL_sk_X509_push(ctx->chain, ctx->current_cert);
ret = WOLFSSL_SUCCESS;
} else {
goto retry;
}
goto exit;
}
/* Cert verified, finish building the chain */
@ -548,6 +564,19 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx)
}
depth--;
continue;
retry:
/* Current certificate failed, but it is possible there is an alternative
* cert with the same subject key which will work. Retry until all
* possible candidate certs are exhausted. */
WOLFSSL_MSG("X509_verify_cert current cert failed, retrying with other certs.");
RemoveCA(ctx->store->cm, ctx->current_cert->subjKeyId);
X509StorePopCert(certs, failedCerts, ctx->current_cert);
if (numInterAdd > 0)
numInterAdd--;
ctx->current_cert = wolfSSL_sk_X509_pop(ctx->chain);
depth++;
}
exit:
@ -572,6 +601,17 @@ exit:
wolfSSL_sk_X509_free(certsToUse);
}
/* Copy back failed certs if verification failed. */
if (ret != WOLFSSL_SUCCESS) {
while (wolfSSL_sk_X509_num(failedCerts) > 0)
{
wolfSSL_sk_X509_push(certs, wolfSSL_sk_X509_pop(failedCerts));
}
}
if (failedCerts) {
wolfSSL_sk_X509_free(failedCerts);
}
return ret == WOLFSSL_SUCCESS ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE;
}
@ -1057,6 +1097,22 @@ static int X509StoreGetIssuerEx(WOLFSSL_X509 **issuer,
return WOLFSSL_FAILURE;
}
static int X509StorePopCert(WOLFSSL_STACK *certs_stack, WOLFSSL_STACK *dest_stack, WOLFSSL_X509 *cert) {
int i;
if (certs_stack == NULL || dest_stack == NULL || cert == NULL)
return WOLFSSL_FATAL_ERROR;
for (i = 0; i < wolfSSL_sk_X509_num(certs_stack); i++) {
if (wolfSSL_sk_X509_value(certs_stack, i) == cert) {
wolfSSL_sk_X509_push(dest_stack, wolfSSL_sk_pop_node(certs_stack, i));
return WOLFSSL_SUCCESS;
}
}
return WOLFSSL_FAILURE;
}
#endif
/******************************************************************************

View File

@ -4276,6 +4276,7 @@ int ProcessOldClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
WOLFSSL_LOCAL int AddSigner(WOLFSSL_CERT_MANAGER* cm, Signer *s);
WOLFSSL_LOCAL
int AddCA(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int type, int verify);
WOLFSSL_LOCAL int RemoveCA(WOLFSSL_CERT_MANAGER* cm, byte* hash);
WOLFSSL_LOCAL
int AlreadySigner(WOLFSSL_CERT_MANAGER* cm, byte* hash);
#ifdef WOLFSSL_TRUST_PEER_CERT