csrv2multi: pending ca list

This commit is contained in:
Marco Oliverio
2024-07-01 13:56:26 +02:00
parent 7814e4c264
commit b5206e8504
7 changed files with 347 additions and 87 deletions

View File

@@ -14022,6 +14022,7 @@ static int ProcessPeerCertParse(WOLFSSL* ssl, ProcPeerCertArgs* args,
buffer* cert;
byte* subjectHash = NULL;
int alreadySigner = 0;
Signer *extraSigners = NULL;
#if defined(HAVE_RPK)
int cType;
#endif
@@ -14123,9 +14124,13 @@ PRAGMA_GCC_DIAG_POP
return ret;
#endif
}
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
if (verify != NO_VERIFY && TLSX_CSR2_IsMulti(ssl->extensions)) {
extraSigners = TLSX_CSR2_GetPendingSigners(ssl->extensions);
}
#endif
/* Parse Certificate */
ret = ParseCertRelative(args->dCert, certType, verify, SSL_CM(ssl));
ret = ParseCertRelativeEx(args->dCert, certType, verify, SSL_CM(ssl), extraSigners);
#if defined(HAVE_RPK)
/* if cert type has negotiated with peer, confirm the cert received has
@@ -14358,6 +14363,9 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
byte* subjectHash = NULL;
int alreadySigner = 0;
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
int addToPendingCAs = 0;
#endif
WOLFSSL_ENTER("ProcessPeerCerts");
#if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLFSSL_NONBLOCK_OCSP)
@@ -14783,9 +14791,11 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
if (ret == 0) {
#ifdef HAVE_OCSP
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
if (ssl->status_request_v2) {
addToPendingCAs = 0;
if (ssl->status_request_v2 && TLSX_CSR2_IsMulti(ssl->extensions)) {
ret = TLSX_CSR2_InitRequests(ssl->extensions,
args->dCert, 0, ssl->heap);
addToPendingCAs = 1;
}
else /* skips OCSP and force CRL check */
#endif /* HAVE_CERTIFICATE_STATUS_REQUEST_V2 */
@@ -14930,6 +14940,45 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
skipAddCA = 1;
}
#endif
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
if (ret == 0 && addToPendingCAs && !alreadySigner) {
DecodedCert dCertAdd;
DerBuffer *derBuffer;
buffer* cert = &args->certs[args->certIdx];
Signer *s;
InitDecodedCert(&dCertAdd, cert->buffer, cert->length, ssl->heap);
ret = ParseCert(&dCertAdd, CA_TYPE, NO_VERIFY, SSL_CM(ssl));
if (ret != 0) {
FreeDecodedCert(&dCertAdd);
goto exit_ppc;
}
ret = AllocDer(&derBuffer, cert->length, CA_TYPE, ssl->heap);
if (ret != 0 || derBuffer == NULL) {
FreeDecodedCert(&dCertAdd);
goto exit_ppc;
}
XMEMCPY(derBuffer->buffer, cert->buffer, cert->length);
s = MakeSigner(SSL_CM(ssl)->heap);
if (s == NULL) {
FreeDecodedCert(&dCertAdd);
ret = MEMORY_E;
goto exit_ppc;
}
ret = FillSigner(s, &dCertAdd, CA_TYPE, derBuffer);
FreeDecodedCert(&dCertAdd);
FreeDer(&derBuffer);
if (ret != 0) {
FreeSigner(s, SSL_CM(ssl)->heap);
goto exit_ppc;
}
skipAddCA = 1;
ret = TLSX_CSR2_AddPendingSigner(ssl->extensions, s);
if (ret != 0) {
FreeSigner(s, ssl->heap);
goto exit_ppc;
}
}
#endif
/* If valid CA then add to Certificate Manager */
if (ret == 0 && args->dCert->isCA &&
@@ -16082,6 +16131,7 @@ static int DoCertificateStatus(WOLFSSL* ssl, byte* input, word32* inOutIdx,
OcspRequest* request;
word32 list_length = status_length;
byte idx = 0;
Signer *pendingCAs = NULL;
#ifdef WOLFSSL_SMALL_STACK
CertStatus* status;
@@ -16098,6 +16148,8 @@ static int DoCertificateStatus(WOLFSSL* ssl, byte* input, word32* inOutIdx,
ssl->status_request_v2 = 0;
pendingCAs = TLSX_CSR2_GetPendingSigners(ssl->extensions);
#ifdef WOLFSSL_SMALL_STACK
status = (CertStatus*)XMALLOC(sizeof(CertStatus), ssl->heap,
DYNAMIC_TYPE_OCSP_STATUS);
@@ -16136,7 +16188,7 @@ static int DoCertificateStatus(WOLFSSL* ssl, byte* input, word32* inOutIdx,
if (status_length) {
InitOcspResponse(response, single, status, input +*inOutIdx,
status_length, ssl->heap);
response->pendingCAs = pendingCAs;
if ((OcspResponseDecode(response, SSL_CM(ssl), ssl->heap,
0) != 0)
|| (response->responseStatus != OCSP_SUCCESSFUL)
@@ -16180,6 +16232,17 @@ static int DoCertificateStatus(WOLFSSL* ssl, byte* input, word32* inOutIdx,
ret = BUFFER_ERROR;
}
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
if (ret == 0) {
if (TLSX_CSR2_MergePendingCA(ssl) < 0) {
WOLFSSL_MSG("Failed to merge pending CAs");
}
}
else {
TLSX_CSR2_ClearPendingCA(ssl);
}
#endif
if (ret != 0) {
WOLFSSL_ERROR_VERBOSE(ret);
SendAlert(ssl, alert_fatal, bad_certificate_status_response);

View File

@@ -328,7 +328,12 @@ int CheckOcspResponse(WOLFSSL_OCSP *ocsp, byte *response, int responseSz,
#endif
InitOcspResponse(ocspResponse, newSingle, newStatus, response,
(word32)responseSz, ocsp->cm->heap);
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
if (ocspRequest != NULL && ocspRequest->ssl != NULL &&
TLSX_CSR2_IsMulti(((WOLFSSL*)ocspRequest->ssl)->extensions)) {
ocspResponse->pendingCAs = TLSX_CSR2_GetPendingSigners(((WOLFSSL*)ocspRequest->ssl)->extensions);
}
#endif
ret = OcspResponseDecode(ocspResponse, ocsp->cm, ocsp->cm->heap, 0);
if (ret != 0) {
ocsp->error = ret;
@@ -555,7 +560,7 @@ int CheckOcspRequest(WOLFSSL_OCSP* ocsp, OcspRequest* ocspRequest,
#ifndef WOLFSSL_NO_OCSP_ISSUER_CHAIN_CHECK
static int CheckOcspResponderChain(OcspEntry* single, DecodedCert *cert,
void* vp) {
void* vp, Signer* pendingCAs) {
/* Attempt to build a chain up to cert's issuer */
WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp;
Signer* ca = NULL;
@@ -574,8 +579,16 @@ static int CheckOcspResponderChain(OcspEntry* single, DecodedCert *cert,
/* End loop if no more issuers found or if we have found a self
* signed cert (ca == prev) */
for (ca = GetCAByName(cm, single->issuerHash); ca != NULL && ca != prev;
prev = ca, ca = GetCAByName(cm, ca->issuerNameHash)) {
ca = GetCAByName(cm, single->issuerHash);
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
if (ca == NULL && pendingCAs != NULL) {
ca = findSignerByName(pendingCAs, single->issuerHash);
}
#else
(void)pendingCAs;
#endif
for (; ca != NULL && ca != prev;
prev = ca) {
if (XMEMCMP(cert->issuerHash, ca->issuerNameHash,
OCSP_DIGEST_SIZE) == 0) {
WOLFSSL_MSG("\tOCSP Response signed by authorized "
@@ -584,6 +597,12 @@ static int CheckOcspResponderChain(OcspEntry* single, DecodedCert *cert,
passed = 1;
break;
}
ca = GetCAByName(cm, ca->issuerNameHash);
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
if (ca == NULL && pendingCAs != NULL) {
ca = findSignerByName(pendingCAs, single->issuerHash);
}
#endif
}
return passed;
}
@@ -632,7 +651,7 @@ int CheckOcspResponder(OcspResponse *bs, DecodedCert *cert, void* vp)
}
#ifndef WOLFSSL_NO_OCSP_ISSUER_CHAIN_CHECK
else if (vp != NULL) {
passed = CheckOcspResponderChain(single, cert, vp);
passed = CheckOcspResponderChain(single, cert, vp, bs->pendingCAs);
}
#endif
}

105
src/ssl.c
View File

@@ -5283,6 +5283,38 @@ int AddTrustedPeer(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int verify)
}
#endif /* WOLFSSL_TRUST_PEER_CERT */
int AddSigner(WOLFSSL_CERT_MANAGER* cm, Signer *s)
{
byte* subjectHash;
Signer* signers;
word32 row;
if (cm == NULL || s == NULL)
return BAD_FUNC_ARG;
#ifndef NO_SKID
subjectHash = s->subjectKeyIdHash;
#else
subjectHash = s->subjectNameHash;
#endif
if (AlreadySigner(cm, subjectHash)) {
FreeSigner(s, cm->heap);
return 0;
}
row = HashSigner(subjectHash);
if (wc_LockMutex(&cm->caLock) != 0)
return BAD_MUTEX_E;
signers = cm->caTable[row];
s->next = signers;
cm->caTable[row] = s;
wc_UnLockMutex(&cm->caLock);
return 0;
}
/* owns der, internal now uses too */
/* type flag ids from user or from chain received during verify
@@ -5437,76 +5469,8 @@ int AddCA(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int type, int verify)
if (!signer)
ret = MEMORY_ERROR;
}
#ifdef WOLFSSL_DUAL_ALG_CERTS
if (ret == 0 && signer != NULL) {
if (cert->extSapkiSet && cert->sapkiLen > 0) {
/* Allocated space for alternative public key. */
signer->sapkiDer = (byte*)XMALLOC(cert->sapkiLen, cm->heap,
DYNAMIC_TYPE_PUBLIC_KEY);
if (signer->sapkiDer == NULL) {
ret = MEMORY_E;
}
else {
XMEMCPY(signer->sapkiDer, cert->sapkiDer, cert->sapkiLen);
signer->sapkiLen = cert->sapkiLen;
signer->sapkiOID = cert->sapkiOID;
}
}
}
#endif /* WOLFSSL_DUAL_ALG_CERTS */
#if defined(WOLFSSL_AKID_NAME) || defined(HAVE_CRL)
if (ret == 0 && signer != NULL)
ret = CalcHashId(cert->serial, cert->serialSz, signer->serialHash);
#endif
if (ret == 0 && signer != NULL) {
#ifdef WOLFSSL_SIGNER_DER_CERT
ret = AllocDer(&signer->derCert, der->length, der->type, NULL);
}
if (ret == 0 && signer != NULL) {
XMEMCPY(signer->derCert->buffer, der->buffer, der->length);
#endif
signer->keyOID = cert->keyOID;
if (cert->pubKeyStored) {
signer->publicKey = cert->publicKey;
signer->pubKeySize = cert->pubKeySize;
}
if (cert->subjectCNStored) {
signer->nameLen = cert->subjectCNLen;
signer->name = cert->subjectCN;
}
signer->maxPathLen = cert->maxPathLen;
signer->selfSigned = cert->selfSigned;
#ifndef IGNORE_NAME_CONSTRAINTS
signer->permittedNames = cert->permittedNames;
signer->excludedNames = cert->excludedNames;
#endif
#ifndef NO_SKID
XMEMCPY(signer->subjectKeyIdHash, cert->extSubjKeyId,
SIGNER_DIGEST_SIZE);
#endif
XMEMCPY(signer->subjectNameHash, cert->subjectHash,
SIGNER_DIGEST_SIZE);
#if defined(HAVE_OCSP) || defined(HAVE_CRL)
XMEMCPY(signer->issuerNameHash, cert->issuerHash,
SIGNER_DIGEST_SIZE);
#endif
#ifdef HAVE_OCSP
XMEMCPY(signer->subjectKeyHash, cert->subjectKeyHash,
KEYID_SIZE);
#endif
signer->keyUsage = cert->extKeyUsageSet ? cert->extKeyUsage
: 0xFFFF;
signer->next = NULL; /* If Key Usage not set, all uses valid. */
cert->publicKey = 0; /* in case lock fails don't free here. */
cert->subjectCN = 0;
#ifndef IGNORE_NAME_CONSTRAINTS
cert->permittedNames = NULL;
cert->excludedNames = NULL;
#endif
signer->type = (byte)type;
ret = FillSigner(signer, cert, type, der);
#ifndef NO_SKID
row = HashSigner(signer->subjectKeyIdHash);
@@ -5514,7 +5478,8 @@ int AddCA(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int type, int verify)
row = HashSigner(signer->subjectNameHash);
#endif
if (wc_LockMutex(&cm->caLock) == 0) {
if (ret == 0 && wc_LockMutex(&cm->caLock) == 0) {
signer->next = cm->caTable[row];
cm->caTable[row] = signer; /* takes ownership */
wc_UnLockMutex(&cm->caLock);

View File

@@ -3579,10 +3579,20 @@ int TLSX_UseCertificateStatusRequest(TLSX** extensions, byte status_type,
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
static void TLSX_CSR2_FreePendingSigners(Signer *s, void* heap)
{
Signer* next;
while(s) {
next = s->next;
FreeSigner(s, heap);
s = next;
}
}
static void TLSX_CSR2_FreeAll(CertificateStatusRequestItemV2* csr2, void* heap)
{
CertificateStatusRequestItemV2* next;
TLSX_CSR2_FreePendingSigners(csr2->pendingSigners, heap);
for (; csr2; csr2 = next) {
next = csr2->next;
@@ -3853,6 +3863,83 @@ static int TLSX_CSR2_Parse(WOLFSSL* ssl, const byte* input, word16 length,
return 0;
}
static CertificateStatusRequestItemV2* TLSX_CSR2_GetMulti(TLSX *extensions)
{
TLSX* extension = TLSX_Find(extensions, TLSX_STATUS_REQUEST_V2);
CertificateStatusRequestItemV2* csr2 = extension ?
(CertificateStatusRequestItemV2*)extension->data : NULL;
for (; csr2; csr2 = csr2->next) {
if (csr2->status_type == WOLFSSL_CSR2_OCSP_MULTI)
return csr2;
}
return NULL;
}
int TLSX_CSR2_IsMulti(TLSX *extensions)
{
return TLSX_CSR2_GetMulti(extensions) != NULL;
}
int TLSX_CSR2_AddPendingSigner(TLSX *extensions, Signer *s)
{
CertificateStatusRequestItemV2* csr2;
csr2 = TLSX_CSR2_GetMulti(extensions);
if (!csr2)
return -1;
s->next = csr2->pendingSigners;
csr2->pendingSigners = s;
return 0;
}
Signer* TLSX_CSR2_GetPendingSigners(TLSX *extensions)
{
CertificateStatusRequestItemV2* csr2;
csr2 = TLSX_CSR2_GetMulti(extensions);
if (!csr2)
return NULL;
return csr2->pendingSigners;
}
int TLSX_CSR2_ClearPendingCA(WOLFSSL *ssl)
{
CertificateStatusRequestItemV2* csr2;
csr2 = TLSX_CSR2_GetMulti(ssl->extensions);
if (csr2 == NULL)
return 0;
TLSX_CSR2_FreePendingSigners(csr2->pendingSigners, SSL_CM(ssl)->heap);
csr2->pendingSigners = NULL;
return 0;
}
int TLSX_CSR2_MergePendingCA(WOLFSSL* ssl)
{
CertificateStatusRequestItemV2* csr2;
Signer *s, *next;
int r = 0;
csr2 = TLSX_CSR2_GetMulti(ssl->extensions);
if (csr2 == NULL)
return 0;
s = csr2->pendingSigners;
while (s != NULL) {
next = s->next;
r = AddSigner(SSL_CM(ssl), s);
if (r != 0)
FreeSigner(s, SSL_CM(ssl)->heap);
s = next;
}
csr2->pendingSigners = NULL;
return r;
}
int TLSX_CSR2_InitRequests(TLSX* extensions, DecodedCert* cert, byte isPeer,
void* heap)
{