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.

This commit is contained in:
Kareem
2025-04-16 16:16:32 -07:00
parent 43f94a5d7d
commit 025dbc3454
3 changed files with 107 additions and 3 deletions
+47
View File
@@ -6142,6 +6142,53 @@ int AddCA(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int type, int verify)
return ret == 0 ? WOLFSSL_SUCCESS : ret; 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 */ #endif /* !NO_CERTS */
+59 -3
View File
@@ -34,6 +34,8 @@
#ifdef OPENSSL_EXTRA #ifdef OPENSSL_EXTRA
static int X509StoreGetIssuerEx(WOLFSSL_X509 **issuer, static int X509StoreGetIssuerEx(WOLFSSL_X509 **issuer,
WOLFSSL_STACK *certs, WOLFSSL_X509 *x); 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, static int X509StoreAddCa(WOLFSSL_X509_STORE* store,
WOLFSSL_X509* x509, int type); WOLFSSL_X509* x509, int type);
#endif #endif
@@ -415,10 +417,12 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx)
int i = 0; int i = 0;
int numInterAdd = 0; int numInterAdd = 0;
int depth = 0; int depth = 0;
int origDepth = 0;
WOLFSSL_X509 *issuer = NULL; WOLFSSL_X509 *issuer = NULL;
WOLFSSL_X509 *orig = NULL; WOLFSSL_X509 *orig = NULL;
WOLF_STACK_OF(WOLFSSL_X509)* certs = NULL; WOLF_STACK_OF(WOLFSSL_X509)* certs = NULL;
WOLF_STACK_OF(WOLFSSL_X509)* certsToUse = NULL; WOLF_STACK_OF(WOLFSSL_X509)* certsToUse = NULL;
WOLF_STACK_OF(WOLFSSL_X509)* failedCerts = NULL;
WOLFSSL_ENTER("wolfSSL_X509_verify_cert"); WOLFSSL_ENTER("wolfSSL_X509_verify_cert");
if (ctx == NULL || ctx->store == NULL || ctx->store->cm == NULL 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; certs = ctx->store->certs;
if (certs == NULL) {
return WOLFSSL_FATAL_ERROR;
}
if (ctx->setTrustedSk != NULL) { if (ctx->setTrustedSk != NULL) {
certs = ctx->setTrustedSk; certs = ctx->setTrustedSk;
} }
@@ -450,6 +458,10 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx)
} }
ctx->chain = wolfSSL_sk_X509_new_null(); ctx->chain = wolfSSL_sk_X509_new_null();
failedCerts = wolfSSL_sk_X509_new_null();
if (!failedCerts)
return WOLFSSL_FATAL_ERROR;
if (ctx->depth > 0) { if (ctx->depth > 0) {
depth = ctx->depth + 1; depth = ctx->depth + 1;
} }
@@ -458,6 +470,7 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx)
} }
orig = ctx->current_cert; orig = ctx->current_cert;
origDepth = depth;
while(done == 0 && depth > 0) { while(done == 0 && depth > 0) {
issuer = NULL; issuer = NULL;
@@ -491,12 +504,14 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx)
ret = X509StoreAddCa(ctx->store, issuer, ret = X509StoreAddCa(ctx->store, issuer,
WOLFSSL_TEMP_CA); WOLFSSL_TEMP_CA);
if (ret != WOLFSSL_SUCCESS) { if (ret != WOLFSSL_SUCCESS) {
goto exit; goto retry;
} }
added = 1; added = 1;
ret = X509StoreVerifyCert(ctx); ret = X509StoreVerifyCert(ctx);
if (ret != WOLFSSL_SUCCESS) { 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 */ /* Add it to the current chain and look at the issuer cert next */
wolfSSL_sk_X509_push(ctx->chain, ctx->current_cert); 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)) { (added == 1)) {
wolfSSL_sk_X509_push(ctx->chain, ctx->current_cert); wolfSSL_sk_X509_push(ctx->chain, ctx->current_cert);
ret = WOLFSSL_SUCCESS; ret = WOLFSSL_SUCCESS;
} else {
goto retry;
} }
goto exit;
} }
/* Cert verified, finish building the chain */ /* Cert verified, finish building the chain */
@@ -548,6 +564,19 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx)
} }
depth--; 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: exit:
@@ -572,6 +601,17 @@ exit:
wolfSSL_sk_X509_free(certsToUse); 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; return ret == WOLFSSL_SUCCESS ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE;
} }
@@ -1057,6 +1097,22 @@ static int X509StoreGetIssuerEx(WOLFSSL_X509 **issuer,
return WOLFSSL_FAILURE; 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 #endif
/****************************************************************************** /******************************************************************************
+1
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 AddSigner(WOLFSSL_CERT_MANAGER* cm, Signer *s);
WOLFSSL_LOCAL WOLFSSL_LOCAL
int AddCA(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int type, int verify); int AddCA(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int type, int verify);
WOLFSSL_LOCAL int RemoveCA(WOLFSSL_CERT_MANAGER* cm, byte* hash);
WOLFSSL_LOCAL WOLFSSL_LOCAL
int AlreadySigner(WOLFSSL_CERT_MANAGER* cm, byte* hash); int AlreadySigner(WOLFSSL_CERT_MANAGER* cm, byte* hash);
#ifdef WOLFSSL_TRUST_PEER_CERT #ifdef WOLFSSL_TRUST_PEER_CERT