From 183aef241ca8048f438ec3cc9a392686ce10fd83 Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Mon, 23 Sep 2024 11:52:39 -0700 Subject: [PATCH 1/4] CRL improvements, add parsing for CRL number, do not allow CRL duplicates, add callback for when CRL entry is updated. --- src/crl.c | 151 +++++++++++++++++++++++++++++++++++++++++- src/ssl_certman.c | 35 ++++++++++ tests/api.c | 158 +++++++++++++++++++++++++++++++++----------- wolfcrypt/src/asn.c | 44 +++++++++++- wolfssl/crl.h | 5 +- wolfssl/internal.h | 3 + wolfssl/ssl.h | 22 ++++++ 7 files changed, 376 insertions(+), 42 deletions(-) diff --git a/src/crl.c b/src/crl.c index 5e359c7ae9..e0b443ecfc 100644 --- a/src/crl.c +++ b/src/crl.c @@ -311,7 +311,6 @@ static int FindRevokedSerial(RevokedCert* rc, byte* serial, int serialSz, #else (void)totalCerts; /* search in the linked list*/ - while (rc) { if (serialHash == NULL) { if (rc->serialSz == serialSz && @@ -560,12 +559,43 @@ int CheckCertCRL(WOLFSSL_CRL* crl, DecodedCert* cert) NULL, cert->extCrlInfo, cert->extCrlInfoSz, issuerName); } +#ifdef HAVE_CRL_UPDATE_CB +static void SetCrlInfo(CRL_Entry* entry, CrlInfo *info) { + info->issuerHash = (byte *)entry->issuerHash; + info->issuerHashLen = CRL_DIGEST_SIZE; + info->lastDate = (byte *)entry->lastDate; + info->lastDateMaxLen = MAX_DATE_SIZE; + info->lastDateFormat = entry->lastDateFormat; + info->nextDate = (byte *)entry->nextDate; + info->nextDateMaxLen = MAX_DATE_SIZE; + info->nextDateFormat = entry->nextDateFormat; + info->crlNumber = (sword32)entry->crlNumber; +} + +static void SetCrlInfoFromDecoded(DecodedCRL* entry, CrlInfo *info) { + info->issuerHash = (byte *)entry->issuerHash; + info->issuerHashLen = SIGNER_DIGEST_SIZE; + info->lastDate = (byte *)entry->lastDate; + info->lastDateMaxLen = MAX_DATE_SIZE; + info->lastDateFormat = entry->lastDateFormat; + info->nextDate = (byte *)entry->nextDate; + info->nextDateMaxLen = MAX_DATE_SIZE; + info->nextDateFormat = entry->nextDateFormat; + info->crlNumber = (sword32)entry->crlNumber; +} +#endif /* Add Decoded CRL, 0 on success */ static int AddCRL(WOLFSSL_CRL* crl, DecodedCRL* dcrl, const byte* buff, int verified) { CRL_Entry* crle = NULL; + CRL_Entry* curr = NULL; + CRL_Entry* prev = NULL; +#ifdef HAVE_CRL_UPDATE_CB + CrlInfo old; + CrlInfo new; +#endif WOLFSSL_ENTER("AddCRL"); @@ -594,8 +624,43 @@ static int AddCRL(WOLFSSL_CRL* crl, DecodedCRL* dcrl, const byte* buff, return BAD_MUTEX_E; } - crle->next = crl->crlList; - crl->crlList = crle; + for (curr = crl->crlList; curr != NULL; curr = curr->next) { + if (XMEMCMP(curr->issuerHash, crle->issuerHash, CRL_DIGEST_SIZE) == 0) { + if (crle->crlNumber <= curr->crlNumber) { + WOLFSSL_MSG("Same or newer CRL entry already exists"); + CRL_Entry_free(crle, crl->heap); + wc_UnLockRwLock(&crl->crlLock); + return BAD_FUNC_ARG; + } + + crle->next = curr->next; + if (prev != NULL) { + prev->next = crle; + } + else { + crl->crlList = crle; + } + +#ifdef HAVE_CRL_UPDATE_CB + if (crl->cm && crl->cm->cbUpdateCRL != NULL) { + SetCrlInfo(curr, &old); + SetCrlInfo(crle, &new); + crl->cm->cbUpdateCRL(&old, &new); + } +#endif + + break; + } + prev = curr; + } + + if (curr != NULL) { + CRL_Entry_free(curr, crl->heap); + } + else { + crle->next = crl->crlList; + crl->crlList = crle; + } wc_UnLockRwLock(&crl->crlLock); /* Avoid heap-use-after-free after crl->crlList is released */ crl->currentEntry = NULL; @@ -686,6 +751,86 @@ int BufferLoadCRL(WOLFSSL_CRL* crl, const byte* buff, long sz, int type, return ret ? ret : WOLFSSL_SUCCESS; /* convert 0 to WOLFSSL_SUCCESS */ } +#ifdef HAVE_CRL_UPDATE_CB +/* Fill out CRL info structure, WOLFSSL_SUCCESS on ok */ +int GetCRLInfo(WOLFSSL_CRL* crl, CrlInfo* info, const byte* buff, + long sz, int type) +{ + int ret = WOLFSSL_SUCCESS; + const byte* myBuffer = buff; /* if DER ok, otherwise switch */ + DerBuffer* der = NULL; + CRL_Entry* crle = NULL; +#ifdef WOLFSSL_SMALL_STACK + DecodedCRL* dcrl; +#else + DecodedCRL dcrl[1]; +#endif + + WOLFSSL_ENTER("GetCRLInfo"); + + if (crl == NULL || info == NULL || buff == NULL || sz == 0) + return BAD_FUNC_ARG; + + if (type == WOLFSSL_FILETYPE_PEM) { + #ifdef WOLFSSL_PEM_TO_DER + ret = PemToDer(buff, sz, CRL_TYPE, &der, NULL, NULL, NULL); + if (ret == 0) { + myBuffer = der->buffer; + sz = der->length; + } + else { + WOLFSSL_MSG("Pem to Der failed"); + FreeDer(&der); + return -1; + } + #else + ret = NOT_COMPILED_IN; + #endif + } + +#ifdef WOLFSSL_SMALL_STACK + dcrl = (DecodedCRL*)XMALLOC(sizeof(DecodedCRL), NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (dcrl == NULL) { + FreeDer(&der); + return MEMORY_E; + } +#endif + + crle = CRL_Entry_new(crl->heap); + if (crle == NULL) { + WOLFSSL_MSG("alloc CRL Entry failed"); + #ifdef WOLFSSL_SMALL_STACK + XFREE(dcrl, NULL, DYNAMIC_TYPE_TMP_BUFFER); + #endif + FreeDer(&der); + return MEMORY_E; + } + + InitDecodedCRL(dcrl, crl->heap); + ret = ParseCRL(crle->certs, dcrl, myBuffer, (word32)sz, + 0, crl->cm); + if (ret != 0 && !(ret == WC_NO_ERR_TRACE(ASN_CRL_NO_SIGNER_E))) { + WOLFSSL_MSG("ParseCRL error"); + CRL_Entry_free(crle, crl->heap); + crle = NULL; + } + else { + SetCrlInfoFromDecoded((DecodedCRL*)dcrl, info); + } + + FreeDecodedCRL(dcrl); + +#ifdef WOLFSSL_SMALL_STACK + XFREE(dcrl, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + FreeDer(&der); + CRL_Entry_free(crle, crl->heap); + + return ret ? ret : WOLFSSL_SUCCESS; /* convert 0 to WOLFSSL_SUCCESS */ +} +#endif + #if defined(OPENSSL_EXTRA) && defined(HAVE_CRL) /* helper function to create a new dynamic WOLFSSL_X509_CRL structure */ static WOLFSSL_X509_CRL* wolfSSL_X509_crl_new(WOLFSSL_CERT_MANAGER* cm) diff --git a/src/ssl_certman.c b/src/ssl_certman.c index a5b622dede..38573a613b 100644 --- a/src/ssl_certman.c +++ b/src/ssl_certman.c @@ -1878,6 +1878,41 @@ int wolfSSL_CertManagerSetCRL_ErrorCb(WOLFSSL_CERT_MANAGER* cm, crlErrorCb cb, return ret; } +#ifdef HAVE_CRL_UPDATE_CB +int wolfSSL_CertManagerGetCRLInfo(WOLFSSL_CERT_MANAGER* cm, CrlInfo* info, + const byte* buff, long sz, int type) +{ + return GetCRLInfo(cm->crl, info, buff, sz, type); +} + +/* Set the callback to be called when a CRL entry has + * been updated (new entry had the same issuer hash and + * a newer CRL number). + * + * @param [in] cm Certificate manager. + * @param [in] cb CRL update callback. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when cm is NULL. + */ +int wolfSSL_CertManagerSetCRLUpdate_Cb(WOLFSSL_CERT_MANAGER* cm, CbUpdateCRL cb) +{ + int ret = WOLFSSL_SUCCESS; + + WOLFSSL_ENTER("wolfSSL_CertManagerSetCRLUpdate_Cb"); + + /* Validate parameters. */ + if (cm == NULL) { + ret = BAD_FUNC_ARG; + } + if (ret == WOLFSSL_SUCCESS) { + /* Store callback. */ + cm->cbUpdateCRL = cb; + } + + return ret; +} +#endif + #ifdef HAVE_CRL_IO /* Set the CRL I/O callback. * diff --git a/tests/api.c b/tests/api.c index de041f8f6a..78f9b60247 100644 --- a/tests/api.c +++ b/tests/api.c @@ -85769,46 +85769,130 @@ static int test_wolfSSL_CTX_LoadCRL(void) return EXPECT_RESULT(); } -#if defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && defined(HAVE_CRL) && \ - !defined(WOLFSSL_CRL_ALLOW_MISSING_CDP) -static int test_multiple_crls_same_issuer_ctx_ready(WOLFSSL_CTX* ctx) -{ - EXPECT_DECLS; - wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER, NULL); - ExpectIntEQ(wolfSSL_CTX_LoadCRLFile(ctx, "./certs/crl/crl.pem", - WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); - return EXPECT_RESULT(); -} -#endif - -static int test_multiple_crls_same_issuer(void) -{ - EXPECT_DECLS; -#if defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && defined(HAVE_CRL) && \ - !defined(WOLFSSL_CRL_ALLOW_MISSING_CDP) - test_ssl_cbf client_cbs, server_cbs; - struct { - const char* server_cert; - const char* server_key; - } test_params[] = { - { "./certs/server-cert.pem", "./certs/server-key.pem" }, - { "./certs/server-revoked-cert.pem", "./certs/server-revoked-key.pem" } - }; - size_t i; +#if defined(HAVE_CRL) && !defined(NO_RSA) && !defined(NO_FILESYSTEM) && \ + defined(HAVE_CRL_UPDATE_CB) +int crlUpdateTestStatus = 0; +WOLFSSL_CERT_MANAGER* updateCrlTestCm = NULL; +static void updateCrlCb(CrlInfo* old, CrlInfo* new) +{ + const char* crl1 = "./certs/crl/crl.pem"; + const char* crlRevoked = "./certs/crl/crl.revoked"; + byte *crl1Buff = NULL; + word32 crl1Sz; + byte *crlRevBuff = NULL; + word32 crlRevSz; + WOLFSSL_CERT_MANAGER* cm = updateCrlTestCm; + XFILE f; + word32 sz; + CrlInfo crl1Info; + CrlInfo crlRevInfo; + + crlUpdateTestStatus = 0; + if (old == NULL || new == NULL) { + return; + } - for (i = 0; i < (sizeof(test_params)/sizeof(*test_params)); i++) { - XMEMSET(&client_cbs, 0, sizeof(client_cbs)); - XMEMSET(&server_cbs, 0, sizeof(server_cbs)); + AssertTrue((f = XFOPEN(crl1, "rb")) != XBADFILE); + AssertTrue(XFSEEK(f, 0, XSEEK_END) == 0); + AssertIntGE(sz = (size_t) XFTELL(f), 1); + AssertTrue(XFSEEK(f, 0, XSEEK_SET) == 0); + AssertTrue( \ + (crl1Buff = (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_FILE)) != NULL); + AssertTrue(XFREAD(crl1Buff, 1, sz, f) == sz); + XFCLOSE(f); + crl1Sz = sz; + + AssertTrue((f = XFOPEN(crlRevoked, "rb")) != XBADFILE); + AssertTrue(XFSEEK(f, 0, XSEEK_END) == 0); + AssertIntGE(sz = (size_t) XFTELL(f), 1); + AssertTrue(XFSEEK(f, 0, XSEEK_SET) == 0); + AssertTrue( \ + (crlRevBuff = (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_FILE)) != NULL); + AssertTrue(XFREAD(crlRevBuff, 1, sz, f) == sz); + XFCLOSE(f); + crlRevSz = sz; - server_cbs.certPemFile = test_params[i].server_cert; - server_cbs.keyPemFile = test_params[i].server_key; - client_cbs.crlPemFile = "./certs/crl/extra-crls/general-server-crl.pem"; + AssertIntEQ(wolfSSL_CertManagerGetCRLInfo( + cm, &crl1Info, crl1Buff, crl1Sz, WOLFSSL_FILETYPE_PEM), + WOLFSSL_SUCCESS); + AssertIntEQ(wolfSSL_CertManagerGetCRLInfo( + cm, &crlRevInfo, crlRevBuff, crlRevSz, WOLFSSL_FILETYPE_PEM), + WOLFSSL_SUCCESS); - client_cbs.ctx_ready = test_multiple_crls_same_issuer_ctx_ready; + /* Old entry being replaced should match crl1 */ + AssertIntEQ(crl1Info.issuerHashLen, old->issuerHashLen); + AssertIntEQ(crl1Info.lastDateMaxLen, old->lastDateMaxLen); + AssertIntEQ(crl1Info.lastDateFormat, old->lastDateFormat); + AssertIntEQ(crl1Info.nextDateMaxLen, old->nextDateMaxLen); + AssertIntEQ(crl1Info.nextDateFormat, old->nextDateFormat); + AssertIntEQ(crl1Info.crlNumber, old->crlNumber); + AssertIntEQ(XMEMCMP( + crl1Info.issuerHash, old->issuerHash, old->issuerHashLen), 0); + AssertIntEQ(XMEMCMP( + crl1Info.lastDate, old->lastDate, old->lastDateMaxLen), 0); + AssertIntEQ(XMEMCMP( + crl1Info.nextDate, old->nextDate, old->nextDateMaxLen), 0); + + /* Newer entry should match crl revoked */ + AssertIntEQ(crlRevInfo.issuerHashLen, new->issuerHashLen); + AssertIntEQ(crlRevInfo.lastDateMaxLen, new->lastDateMaxLen); + AssertIntEQ(crlRevInfo.lastDateFormat, new->lastDateFormat); + AssertIntEQ(crlRevInfo.nextDateMaxLen, new->nextDateMaxLen); + AssertIntEQ(crlRevInfo.nextDateFormat, new->nextDateFormat); + AssertIntEQ(crlRevInfo.crlNumber, new->crlNumber); + AssertIntEQ(XMEMCMP( + crlRevInfo.issuerHash, new->issuerHash, new->issuerHashLen), 0); + AssertIntEQ(XMEMCMP( + crlRevInfo.lastDate, new->lastDate, new->lastDateMaxLen), 0); + AssertIntEQ(XMEMCMP( + crlRevInfo.nextDate, new->nextDate, new->nextDateMaxLen), 0); + + XFREE(crl1Buff, NULL, DYNAMIC_TYPE_FILE); + XFREE(crlRevBuff, NULL, DYNAMIC_TYPE_FILE); + crlUpdateTestStatus = 1; +} +#endif + +static int test_wolfSSL_crl_update_cb(void) +{ + EXPECT_DECLS; +#if defined(HAVE_CRL) && !defined(NO_RSA) && !defined(NO_FILESYSTEM) && \ + defined(HAVE_CRL_UPDATE_CB) + const char* crl1 = "./certs/crl/crl.pem"; + const char* crlRevoked = "./certs/crl/crl.revoked"; + const char* issuerCert = "./certs/client-cert.pem"; + const char* caCert = "./certs/ca-cert.pem"; + const char* goodCert = "./certs/server-cert.pem"; + const char* revokedCert = "./certs/server-revoked-cert.pem"; + int pemType = WOLFSSL_FILETYPE_PEM; + WOLFSSL_CERT_MANAGER* cm = NULL; - ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cbs, - &server_cbs, NULL), -1001); - } + updateCrlTestCm = wolfSSL_CertManagerNew(); + ExpectNotNull(updateCrlTestCm); + cm = updateCrlTestCm; + ExpectIntEQ(wolfSSL_CertManagerSetCRLUpdate_Cb(cm, updateCrlCb), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CertManagerLoadCA(cm, caCert, NULL), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CertManagerLoadCA(cm, issuerCert, NULL), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CertManagerLoadCRLFile(cm, crl1, pemType), + WOLFSSL_SUCCESS); + /* CRL1 does not have good cert revoked */ + ExpectIntEQ(wolfSSL_CertManagerVerify(cm, goodCert, pemType), + WOLFSSL_SUCCESS); + ExpectIntNE(wolfSSL_CertManagerVerify(cm, revokedCert, pemType), + WOLFSSL_SUCCESS); + /* Load newer CRL from same issuer, callback verifies CRL entry details */ + ExpectIntEQ(wolfSSL_CertManagerLoadCRLFile(cm, crlRevoked, pemType), + WOLFSSL_SUCCESS); + /* CRL callback verified entry info was as expected */ + ExpectIntEQ(crlUpdateTestStatus, 1); + /* Ensure that both certs fail with newer CRL */ + ExpectIntNE(wolfSSL_CertManagerVerify(cm, goodCert, pemType), + WOLFSSL_SUCCESS); + ExpectIntNE(wolfSSL_CertManagerVerify(cm, revokedCert, pemType), + WOLFSSL_SUCCESS); #endif return EXPECT_RESULT(); } @@ -96461,7 +96545,7 @@ TEST_CASE testCases[] = { TEST_DECL(test_wolfSSL_use_certificate_chain_file), TEST_DECL(test_wolfSSL_CTX_trust_peer_cert), TEST_DECL(test_wolfSSL_CTX_LoadCRL), - TEST_DECL(test_multiple_crls_same_issuer), + TEST_DECL(test_wolfSSL_crl_update_cb), TEST_DECL(test_wolfSSL_CTX_SetTmpDH_file), TEST_DECL(test_wolfSSL_CTX_SetTmpDH_buffer), TEST_DECL(test_wolfSSL_CTX_SetMinMaxDhKey_Sz), diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 3f76da8098..be1b95ae30 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -38280,6 +38280,41 @@ static int ParseCRL_AuthKeyIdExt(const byte* input, int sz, DecodedCRL* dcrl) } #endif +#ifdef WOLFSSL_ASN_TEMPLATE + +static const ASNItem crlNumASN[] = { +/* CRL NUM */ {0, ASN_INTEGER, 0, 0, 0 }, +}; +enum { + CRLNUMASN_IDX_CRL_NUM = 0 +}; + +/* Number of items in ASN.1 template for CrlNumber. */ +#define crlNumASN_Length (sizeof(crlNumASN) / sizeof(ASNItem)) + +static int ParseCRL_CrlNumExt(const byte* input, int sz, DecodedCRL* dcrl) +{ + DECL_ASNGETDATA(dataASN, crlNumASN_Length); + int ret = 0; + word32 idx = 0; + + WOLFSSL_ENTER("ParseCRL_CrlNumExt"); + + CALLOC_ASNGETDATA(dataASN, crlNumASN_Length, ret, dcrl->heap); + + if (ret == 0) { + GetASN_Int32Bit(&dataASN[CRLNUMASN_IDX_CRL_NUM], (word32 *)&dcrl->crlNumber); + + /* Parse a CRL number. */ + ret = GetASN_Items(crlNumASN, dataASN, crlNumASN_Length, 0, input, + &idx, (word32)sz); + } + + FREE_ASNGETDATA(dataASN, dcrl->heap); + return ret; +#endif /* WOLFSSL_ASN_TEMPLATE */ +} + #ifndef WOLFSSL_ASN_TEMPLATE static int ParseCRL_Extensions(DecodedCRL* dcrl, const byte* buf, @@ -38472,7 +38507,14 @@ static int ParseCRL_Extensions(DecodedCRL* dcrl, const byte* buf, word32 idx, } #endif } - /* TODO: Parse CRL Number extension */ + else if (oid == CRL_NUMBER_OID) { + /* Parse CRL Number extension. + * idx is at start of OCTET_STRING data. */ + ret = ParseCRL_CrlNumExt(buf + idx, length, dcrl); + if (ret != 0) { + WOLFSSL_MSG("\tcouldn't parse CRL Number extension"); + } + } /* TODO: check criticality */ /* Move index on to next extension. */ idx += (word32)length; diff --git a/wolfssl/crl.h b/wolfssl/crl.h index 5e5205ea2b..cdf52f3739 100644 --- a/wolfssl/crl.h +++ b/wolfssl/crl.h @@ -45,7 +45,10 @@ WOLFSSL_LOCAL int CheckCertCRL(WOLFSSL_CRL* crl, DecodedCert* cert); WOLFSSL_LOCAL int CheckCertCRL_ex(WOLFSSL_CRL* crl, byte* issuerHash, byte* serial, int serialSz, byte* serialHash, const byte* extCrlInfo, int extCrlInfoSz, void* issuerName); - +#ifdef HAVE_CRL_UPDATE_CB +WOLFSSL_LOCAL int GetCRLInfo(WOLFSSL_CRL* crl, CrlInfo* info, const byte* buff, + long sz, int type); +#endif #ifdef __cplusplus } /* extern "C" */ diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 7ce0436355..dd77cc01f2 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -2656,6 +2656,9 @@ struct WOLFSSL_CERT_MANAGER { #ifdef WC_ASN_UNKNOWN_EXT_CB wc_UnknownExtCallback unknownExtCallback; #endif +#ifdef HAVE_CRL_UPDATE_CB + CbUpdateCRL cbUpdateCRL; /* notify thru cb that crl has updated */ +#endif }; WOLFSSL_LOCAL int CM_SaveCertCache(WOLFSSL_CERT_MANAGER* cm, diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 90f711589e..39de05e9e3 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -3324,6 +3324,22 @@ typedef void (*CbOCSPRespFree)(void*,unsigned char*); typedef int (*CbCrlIO)(WOLFSSL_CRL* crl, const char* url, int urlSz); #endif +#ifdef HAVE_CRL_UPDATE_CB +typedef struct CrlInfo { + byte *issuerHash; + word32 issuerHashLen; + byte *lastDate; + word32 lastDateMaxLen; + byte lastDateFormat; + byte *nextDate; + word32 nextDateMaxLen; + byte nextDateFormat; + sword32 crlNumber; +} CrlInfo; + +typedef void (*CbUpdateCRL)(CrlInfo* old, CrlInfo* new); +#endif + /* User Atomic Record Layer CallBacks */ typedef int (*CallbackMacEncrypt)(WOLFSSL* ssl, unsigned char* macOut, const unsigned char* macIn, unsigned int macInSz, int macContent, @@ -3771,6 +3787,12 @@ WOLFSSL_API void wolfSSL_CTX_SetPerformTlsRecordProcessingCb(WOLFSSL_CTX* ctx, WOLFSSL_API int wolfSSL_CertManagerSetCRL_IOCb(WOLFSSL_CERT_MANAGER* cm, CbCrlIO cb); #endif +#ifdef HAVE_CRL_UPDATE_CB + WOLFSSL_API int wolfSSL_CertManagerGetCRLInfo(WOLFSSL_CERT_MANAGER* cm, CrlInfo* info, + const byte* buff, long sz, int type); + WOLFSSL_API int wolfSSL_CertManagerSetCRLUpdate_Cb(WOLFSSL_CERT_MANAGER* cm, + CbUpdateCRL cb); +#endif #if defined(HAVE_OCSP) WOLFSSL_API int wolfSSL_CertManagerCheckOCSPResponse( WOLFSSL_CERT_MANAGER* cm, unsigned char *response, int responseSz, From e5022e3ef0845204d7143beefa831ce6f165d269 Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Mon, 23 Sep 2024 12:11:04 -0700 Subject: [PATCH 2/4] Fix broken endif --- wolfcrypt/src/asn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index be1b95ae30..e342aa61c8 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -38312,8 +38312,8 @@ static int ParseCRL_CrlNumExt(const byte* input, int sz, DecodedCRL* dcrl) FREE_ASNGETDATA(dataASN, dcrl->heap); return ret; -#endif /* WOLFSSL_ASN_TEMPLATE */ } +#endif /* WOLFSSL_ASN_TEMPLATE */ #ifndef WOLFSSL_ASN_TEMPLATE From 720e24209a738535e5f628801511e8345af19429 Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Mon, 23 Sep 2024 13:29:41 -0700 Subject: [PATCH 3/4] Updates for doxygen and review comments --- doc/dox_comments/header_files/ssl.h | 79 +++++++++++++++++++++++++++++ src/crl.c | 6 ++- 2 files changed, 83 insertions(+), 2 deletions(-) diff --git a/doc/dox_comments/header_files/ssl.h b/doc/dox_comments/header_files/ssl.h index bdf1d49f02..c1a9d5f05d 100644 --- a/doc/dox_comments/header_files/ssl.h +++ b/doc/dox_comments/header_files/ssl.h @@ -10012,6 +10012,85 @@ int wolfSSL_CertManagerLoadCRLBuffer(WOLFSSL_CERT_MANAGER* cm, int wolfSSL_CertManagerSetCRL_Cb(WOLFSSL_CERT_MANAGER* cm, CbMissingCRL cb); +/*! + \ingroup CertManager + \brief This function sets the CRL Update callback. If + HAVE_CRL and HAVE_CRL_UPDATE_CB is defined , and an entry with the same + issuer and a lower CRL number exists when a CRL is added, then the + CbUpdateCRL is called with the details of the existing entry and the + new one replacing it. + + \return SSL_SUCCESS returned upon successful execution of the function and + subroutines. + \return BAD_FUNC_ARG returned if the WOLFSSL_CERT_MANAGER structure is NULL. + + \param cm the WOLFSSL_CERT_MANAGER structure holding the information for + the certificate. + \param cb a function pointer to (*CbUpdateCRL) that is set to the + cbUpdateCRL member of the WOLFSSL_CERT_MANAGER. + Signature requirement: + void (*CbUpdateCRL)(CrlInfo *old, CrlInfo *new); + + _Example_ + \code + #include + + WOLFSSL_CTX* ctx = wolfSSL_CTX_new(protocol method); + WOLFSSL* ssl = wolfSSL_new(ctx); + … + void cb(CrlInfo *old, CrlInfo *new){ + Function body. + } + … + CbUpdateCRL cb = CbUpdateCRL; + … + if(ctx){ + return wolfSSL_CertManagerSetCRLUpdate_Cb(SSL_CM(ssl), cb); + } + \endcode + + \sa CbUpdateCRL +*/ +int wolfSSL_CertManagerSetCRLUpdate_Cb(WOLFSSL_CERT_MANAGER* cm, + CbUpdateCRL cb); + +/*! + \ingroup CertManager + \brief This function yields a structure with parsed CRL information from + an encoded CRL buffer. + + \return SSL_SUCCESS returned upon successful execution of the function and + subroutines. + \return BAD_FUNC_ARG returned if the WOLFSSL_CERT_MANAGER structure is NULL. + + \param cm the WOLFSSL_CERT_MANAGER structure.. + \param info pointer to caller managed CrlInfo structure that will receive + the CRL information. + \param buff input buffer containing encoded CRL. + \param sz the length in bytes of the input CRL data in buff. + \param type WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_DER + + _Example_ + \code + #include + + CrlInfo info; + WOLFSSL_CERT_MANAGER* cm = NULL; + + cm = wolfSSL_CertManagerNew(); + + // Read crl data from file into buffer + + wolfSSL_CertManagerGetCRLInfo(cm, &info, crlData, crlDataLen, + WOLFSSL_FILETYPE_PEM); + \endcode + + \sa CbUpdateCRL + \sa wolfSSL_SetCRL_Cb +*/ +int wolfSSL_CertManagerGetCRLInfo(WOLFSSL_CERT_MANAGER* cm, CrlInfo* info, + const byte* buff, long sz, int type) + /*! \ingroup CertManager \brief This function frees the CRL stored in the Cert Manager. An diff --git a/src/crl.c b/src/crl.c index e0b443ecfc..e4ec5585ed 100644 --- a/src/crl.c +++ b/src/crl.c @@ -560,7 +560,8 @@ int CheckCertCRL(WOLFSSL_CRL* crl, DecodedCert* cert) } #ifdef HAVE_CRL_UPDATE_CB -static void SetCrlInfo(CRL_Entry* entry, CrlInfo *info) { +static void SetCrlInfo(CRL_Entry* entry, CrlInfo *info) +{ info->issuerHash = (byte *)entry->issuerHash; info->issuerHashLen = CRL_DIGEST_SIZE; info->lastDate = (byte *)entry->lastDate; @@ -572,7 +573,8 @@ static void SetCrlInfo(CRL_Entry* entry, CrlInfo *info) { info->crlNumber = (sword32)entry->crlNumber; } -static void SetCrlInfoFromDecoded(DecodedCRL* entry, CrlInfo *info) { +static void SetCrlInfoFromDecoded(DecodedCRL* entry, CrlInfo *info) +{ info->issuerHash = (byte *)entry->issuerHash; info->issuerHashLen = SIGNER_DIGEST_SIZE; info->lastDate = (byte *)entry->lastDate; From 3d9a4ccddc25c3c0e0f0d68a0d32662265fc0cc3 Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Thu, 26 Sep 2024 15:43:30 -0700 Subject: [PATCH 4/4] Use GetShortInt instead for CRL number extension parsing --- wolfcrypt/src/asn.c | 42 ++++-------------------------------------- 1 file changed, 4 insertions(+), 38 deletions(-) diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index e342aa61c8..5e59165faf 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -38280,42 +38280,6 @@ static int ParseCRL_AuthKeyIdExt(const byte* input, int sz, DecodedCRL* dcrl) } #endif -#ifdef WOLFSSL_ASN_TEMPLATE - -static const ASNItem crlNumASN[] = { -/* CRL NUM */ {0, ASN_INTEGER, 0, 0, 0 }, -}; -enum { - CRLNUMASN_IDX_CRL_NUM = 0 -}; - -/* Number of items in ASN.1 template for CrlNumber. */ -#define crlNumASN_Length (sizeof(crlNumASN) / sizeof(ASNItem)) - -static int ParseCRL_CrlNumExt(const byte* input, int sz, DecodedCRL* dcrl) -{ - DECL_ASNGETDATA(dataASN, crlNumASN_Length); - int ret = 0; - word32 idx = 0; - - WOLFSSL_ENTER("ParseCRL_CrlNumExt"); - - CALLOC_ASNGETDATA(dataASN, crlNumASN_Length, ret, dcrl->heap); - - if (ret == 0) { - GetASN_Int32Bit(&dataASN[CRLNUMASN_IDX_CRL_NUM], (word32 *)&dcrl->crlNumber); - - /* Parse a CRL number. */ - ret = GetASN_Items(crlNumASN, dataASN, crlNumASN_Length, 0, input, - &idx, (word32)sz); - } - - FREE_ASNGETDATA(dataASN, dcrl->heap); - return ret; -} -#endif /* WOLFSSL_ASN_TEMPLATE */ - - #ifndef WOLFSSL_ASN_TEMPLATE static int ParseCRL_Extensions(DecodedCRL* dcrl, const byte* buf, word32* inOutIdx, word32 sz) @@ -38510,9 +38474,11 @@ static int ParseCRL_Extensions(DecodedCRL* dcrl, const byte* buf, word32 idx, else if (oid == CRL_NUMBER_OID) { /* Parse CRL Number extension. * idx is at start of OCTET_STRING data. */ - ret = ParseCRL_CrlNumExt(buf + idx, length, dcrl); - if (ret != 0) { + if (GetShortInt(buf, + &idx, &dcrl->crlNumber, maxIdx) < 0) { WOLFSSL_MSG("\tcouldn't parse CRL Number extension"); + ret = ASN_PARSE_E; + break; } } /* TODO: check criticality */