diff --git a/src/crl.c b/src/crl.c index ddc39218a..3c0297ce8 100644 --- a/src/crl.c +++ b/src/crl.c @@ -20,8 +20,15 @@ */ - /* Name change compatibility layer no longer needs included here */ - +/* +CRL Options: + * CRL_STATIC_REVOKED_LIST: default: off + * Enables fixed static list of RevokedCerts to allow + * for a binary search. + * CRL_MAX_REVOKED_CERTS: default: 4 + * Specifies the number of buffers to hold RevokedCerts. + * The default value is set to 4. +*/ #ifdef HAVE_CONFIG_H #include #endif @@ -56,7 +63,8 @@ int InitCRL(WOLFSSL_CRL* crl, WOLFSSL_CERT_MANAGER* cm) else crl->heap = NULL; crl->cm = cm; - crl->crlList = NULL; + crl->crlList = NULL; + crl->currentEntry = NULL; crl->monitors[0].path = NULL; crl->monitors[1].path = NULL; #ifdef HAVE_CRL_MONITOR @@ -99,7 +107,12 @@ static int InitCRL_Entry(CRL_Entry* crle, DecodedCRL* dcrl, const byte* buff, return WOLFSSL_FAILURE; } #endif - crle->certs = dcrl->certs; /* take ownsership */ +#ifdef CRL_STATIC_REVOKED_LIST + /* ParseCRL_CertList() has already cached the Revoked certs into + the crle->certs array */ +#else + crle->certs = dcrl->certs; /* take ownership */ +#endif dcrl->certs = NULL; crle->totalCerts = dcrl->totalCerts; crle->crlNumber = dcrl->crlNumber; @@ -141,6 +154,11 @@ static int InitCRL_Entry(CRL_Entry* crle, DecodedCRL* dcrl, const byte* buff, /* Free all CRL Entry resources */ static void FreeCRL_Entry(CRL_Entry* crle, void* heap) { +#ifdef CRL_STATIC_REVOKED_LIST + if (crle != NULL) { + XMEMSET(crle->certs, 0, CRL_MAX_REVOKED_CERTS*sizeof(RevokedCert)); + } +#else RevokedCert* tmp = crle->certs; RevokedCert* next; @@ -151,6 +169,7 @@ static void FreeCRL_Entry(CRL_Entry* crle, void* heap) XFREE(tmp, heap, DYNAMIC_TYPE_REVOKED); tmp = next; } +#endif if (crle->signature != NULL) XFREE(crle->signature, heap, DYNAMIC_TYPE_CRL_ENTRY); if (crle->toBeSigned != NULL) @@ -178,6 +197,10 @@ void FreeCRL(WOLFSSL_CRL* crl, int dynamic) if (crl->monitors[1].path) XFREE(crl->monitors[1].path, crl->heap, DYNAMIC_TYPE_CRL_MONITOR); + if (crl->currentEntry != NULL ) { + XFREE(crl->currentEntry, crl->heap, DYNAMIC_TYPE_CRL_ENTRY); + crl->currentEntry = NULL; + } while(tmp) { CRL_Entry* next = tmp->next; FreeCRL_Entry(tmp, crl->heap); @@ -340,6 +363,30 @@ static int CheckCertCRLList(WOLFSSL_CRL* crl, DecodedCert* cert, int *pFoundEntr if (foundEntry) { RevokedCert* rc = crle->certs; +#ifdef CRL_STATIC_REVOKED_LIST + int low, high, mid; + + low = 0; + high = crle->totalCerts - 1; + + while (low <= high) { + mid = (low + high) / 2; + + if (XMEMCMP(rc[mid].serialNumber, cert->serial, rc->serialSz) < 0) { + low = mid + 1; + } + else if (XMEMCMP(rc[mid].serialNumber, cert->serial, + rc->serialSz) > 0) { + high = mid - 1; + } + else { + WOLFSSL_MSG("Cert revoked"); + ret = CRL_CERT_REVOKED; + break; + } + } +#else + while (rc) { if (rc->serialSz == cert->serialSz && XMEMCMP(rc->serialNumber, cert->serial, rc->serialSz) == 0) { @@ -349,6 +396,7 @@ static int CheckCertCRLList(WOLFSSL_CRL* crl, DecodedCert* cert, int *pFoundEntr } rc = rc->next; } +#endif } wc_UnLockMutex(&crl->crlLock); @@ -444,14 +492,22 @@ int CheckCertCRL(WOLFSSL_CRL* crl, DecodedCert* cert) static int AddCRL(WOLFSSL_CRL* crl, DecodedCRL* dcrl, const byte* buff, int verified) { - CRL_Entry* crle; + CRL_Entry* crle = NULL; WOLFSSL_ENTER("AddCRL"); - crle = (CRL_Entry*)XMALLOC(sizeof(CRL_Entry), crl->heap, DYNAMIC_TYPE_CRL_ENTRY); - if (crle == NULL) { - WOLFSSL_MSG("alloc CRL Entry failed"); + if (crl == NULL) return -1; + + crle = crl->currentEntry; + + if (crle == NULL) { + crle = (CRL_Entry*)XMALLOC(sizeof(CRL_Entry), crl->heap, + DYNAMIC_TYPE_CRL_ENTRY); + if (crle == NULL) { + WOLFSSL_MSG("alloc CRL Entry failed"); + return -1; + } } if (InitCRL_Entry(crle, dcrl, buff, verified, crl->heap) < 0) { @@ -466,9 +522,12 @@ static int AddCRL(WOLFSSL_CRL* crl, DecodedCRL* dcrl, const byte* buff, XFREE(crle, crl->heap, DYNAMIC_TYPE_CRL_ENTRY); return BAD_MUTEX_E; } + crle->next = crl->crlList; crl->crlList = crle; wc_UnLockMutex(&crl->crlLock); + /* Avoid heap-use-after-free after crl->crlList is released */ + crl->currentEntry = NULL; return 0; } @@ -517,10 +576,23 @@ int BufferLoadCRL(WOLFSSL_CRL* crl, const byte* buff, long sz, int type, } #endif + crl->currentEntry = (CRL_Entry*)XMALLOC(sizeof(CRL_Entry), crl->heap, + DYNAMIC_TYPE_CRL_ENTRY); + if (crl->currentEntry == NULL) { + WOLFSSL_MSG("alloc CRL Entry failed"); + return MEMORY_E; + } + XMEMSET(crl->currentEntry, 0, sizeof(CRL_Entry)); + InitDecodedCRL(dcrl, crl->heap); - ret = ParseCRL(dcrl, myBuffer, (word32)sz, verify, crl->cm); + ret = ParseCRL(crl->currentEntry->certs, dcrl, myBuffer, (word32)sz, + verify, crl->cm); if (ret != 0 && !(ret == ASN_CRL_NO_SIGNER_E && verify == NO_VERIFY)) { WOLFSSL_MSG("ParseCRL error"); + if (crl->currentEntry != NULL ) { + XFREE(crl->currentEntry, crl->heap, DYNAMIC_TYPE_CRL_ENTRY); + crl->currentEntry = NULL; + } } else { ret = AddCRL(crl, dcrl, myBuffer, ret != ASN_CRL_NO_SIGNER_E); @@ -558,7 +630,7 @@ static WOLFSSL_X509_CRL* wolfSSL_X509_crl_new(WOLFSSL_CERT_MANAGER* cm) return ret; } - +#ifndef CRL_STATIC_REVOKED_LIST /* returns head of copied list that was alloc'd */ static RevokedCert *DupRevokedCertList(RevokedCert* in, void* heap) { @@ -599,7 +671,7 @@ static RevokedCert *DupRevokedCertList(RevokedCert* in, void* heap) return head; } - +#endif /* CRL_STATIC_REVOKED_LIST */ /* returns a deep copy of ent on success and null on fail */ static CRL_Entry* DupCRL_Entry(const CRL_Entry* ent, void* heap) { @@ -617,8 +689,19 @@ static CRL_Entry* DupCRL_Entry(const CRL_Entry* ent, void* heap) XMEMCPY(dupl->nextDate, ent->nextDate, MAX_DATE_SIZE); dupl->lastDateFormat = ent->lastDateFormat; dupl->nextDateFormat = ent->nextDateFormat; - dupl->certs = DupRevokedCertList(ent->certs, heap); +#ifdef CRL_STATIC_REVOKED_LIST + if (ent->totalCerts > CRL_MAX_REVOKED_CERTS) { + FreeCRL_Entry(dupl, heap); + XFREE(dupl, heap, DYNAMIC_TYPE_CRL_ENTRY); + return NULL; + } + else + XMEMCPY(dupl->certs, ent->certs, + ent->totalCerts*sizeof(RevokedCert)); +#else + dupl->certs = DupRevokedCertList(ent->certs, heap); +#endif dupl->totalCerts = ent->totalCerts; dupl->verified = ent->verified; diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 169510a9f..251904330 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -33475,7 +33475,7 @@ int wc_Curve448PublicKeyToDer(curve448_key* key, byte* output, word32 inLen, #ifndef WOLFSSL_ASN_TEMPLATE -#if defined(HAVE_OCSP) || defined(HAVE_CRL) +#if (defined(HAVE_OCSP) || defined(HAVE_CRL)) && !defined(WOLFCRYPT_ONLY) /* Get raw Date only, no processing, 0 on success */ static int GetBasicDate(const byte* source, word32* idx, byte* date, @@ -33499,7 +33499,7 @@ static int GetBasicDate(const byte* source, word32* idx, byte* date, #endif /* WOLFSSL_ASN_TEMPLATE */ -#ifdef HAVE_OCSP +#if defined(HAVE_OCSP) && !defined(WOLFCRYPT_ONLY) #ifndef WOLFSSL_ASN_TEMPLATE static int GetEnumerated(const byte* input, word32* inOutIdx, int *value, @@ -35391,7 +35391,7 @@ int GetNameHash(const byte* source, word32* idx, byte* hash, int maxIdx) #endif /* WOLFSSL_ASN_TEMPLATE */ } -#ifdef HAVE_CRL +#if defined(HAVE_CRL) && !defined(WOLFCRYPT_ONLY) #ifdef OPENSSL_EXTRA static char* GetNameFromDer(const byte* source, int sz) @@ -35469,8 +35469,8 @@ enum { #endif /* Get Revoked Cert list, 0 on success */ -static int GetRevoked(const byte* buff, word32* idx, DecodedCRL* dcrl, - int maxIdx) +static int GetRevoked(RevokedCert* rcert, const byte* buff, word32* idx, + DecodedCRL* dcrl, int maxIdx) { #ifndef WOLFSSL_ASN_TEMPLATE #ifndef NO_ASN_TIME @@ -35479,7 +35479,9 @@ static int GetRevoked(const byte* buff, word32* idx, DecodedCRL* dcrl, int len; word32 end; RevokedCert* rc; - +#ifdef CRL_STATIC_REVOKED_LIST + int totalCerts = 0; +#endif WOLFSSL_ENTER("GetRevoked"); if (GetSequence(buff, idx, &len, maxIdx) < 0) @@ -35487,6 +35489,21 @@ static int GetRevoked(const byte* buff, word32* idx, DecodedCRL* dcrl, end = *idx + len; +#ifdef CRL_STATIC_REVOKED_LIST + totalCerts = dcrl->totalCerts; + + if (totalCerts >= CRL_MAX_REVOKED_CERTS) { + return MEMORY_E; + } + + rc = &rcert[totalCerts]; + + if (wc_GetSerialNumber(buff, idx, rc->serialNumber, &rc->serialSz, + maxIdx) < 0) { + return ASN_PARSE_E; + } +#else + rc = (RevokedCert*)XMALLOC(sizeof(RevokedCert), dcrl->heap, DYNAMIC_TYPE_REVOKED); if (rc == NULL) { @@ -35503,8 +35520,10 @@ static int GetRevoked(const byte* buff, word32* idx, DecodedCRL* dcrl, /* add to list */ rc->next = dcrl->certs; dcrl->certs = rc; - dcrl->totalCerts++; + (void)rcert; +#endif /* CRL_STATIC_REVOKED_LIST */ + dcrl->totalCerts++; /* get date */ #ifndef NO_ASN_TIME ret = GetBasicDate(buff, idx, rc->revDate, &rc->revDateFormat, maxIdx); @@ -35523,13 +35542,23 @@ static int GetRevoked(const byte* buff, word32* idx, DecodedCRL* dcrl, word32 serialSz = EXTERNAL_SERIAL_SIZE; word32 revDateSz = MAX_DATE_SIZE; RevokedCert* rc; +#ifdef CRL_STATIC_REVOKED_LIST + int totalCerts = dcrl->totalCerts; + if (totalCerts >= CRL_MAX_REVOKED_CERTS) { + return MEMORY_E; + } + + rc = &rcert[totalCerts]; + +#else /* Allocate a new revoked certificate object. */ rc = (RevokedCert*)XMALLOC(sizeof(RevokedCert), dcrl->heap, DYNAMIC_TYPE_CRL); if (rc == NULL) { ret = MEMORY_E; } +#endif /* CRL_STATIC_REVOKED_LIST */ CALLOC_ASNGETDATA(dataASN, revokedASN_Length, ret, dcrl->heap); @@ -35555,15 +35584,20 @@ static int GetRevoked(const byte* buff, word32* idx, DecodedCRL* dcrl, /* TODO: use extensions, only v2 */ /* Add revoked certificate to chain. */ +#ifndef CRL_STATIC_REVOKED_LIST rc->next = dcrl->certs; dcrl->certs = rc; +#endif dcrl->totalCerts++; } FREE_ASNGETDATA(dataASN, dcrl->heap); +#ifndef CRL_STATIC_REVOKED_LIST if ((ret != 0) && (rc != NULL)) { XFREE(rc, dcrl->heap, DYNAMIC_TYPE_CRL); } + (void)rcert; +#endif return ret; #endif /* WOLFSSL_ASN_TEMPLATE */ } @@ -35578,15 +35612,15 @@ static int GetRevoked(const byte* buff, word32* idx, DecodedCRL* dcrl, * @return 0 on success. * @return ASN_PARSE_E on failure. */ -static int ParseCRL_RevokedCerts(DecodedCRL* dcrl, const byte* buff, word32 idx, - word32 maxIdx) +static int ParseCRL_RevokedCerts(RevokedCert* rcert, DecodedCRL* dcrl, + const byte* buff, word32 idx, word32 maxIdx) { int ret = 0; /* Parse each revoked cerificate. */ while ((ret == 0) && (idx < maxIdx)) { /* Parse a revoked certificate. */ - if (GetRevoked(buff, &idx, dcrl, maxIdx) < 0) { + if (GetRevoked(rcert, buff, &idx, dcrl, maxIdx) < 0) { ret = ASN_PARSE_E; } } @@ -35704,8 +35738,8 @@ static int PaseCRL_CheckSignature(DecodedCRL* dcrl, const byte* buff, void* cm) #endif #ifndef WOLFSSL_ASN_TEMPLATE -static int ParseCRL_CertList(DecodedCRL* dcrl, const byte* buf, - word32* inOutIdx, int sz, int verify) +static int ParseCRL_CertList(RevokedCert* rcert, DecodedCRL* dcrl, + const byte* buf,word32* inOutIdx, int sz, int verify) { word32 oid, dateIdx, idx, checkIdx; int length; @@ -35787,7 +35821,7 @@ static int ParseCRL_CertList(DecodedCRL* dcrl, const byte* buf, len += idx; while (idx < (word32)len) { - if (GetRevoked(buf, &idx, dcrl, len) < 0) + if (GetRevoked(rcert, buf, &idx, dcrl, len) < 0) return ASN_PARSE_E; } } @@ -36137,8 +36171,8 @@ enum { #endif /* parse crl buffer into decoded state, 0 on success */ -int ParseCRL(DecodedCRL* dcrl, const byte* buff, word32 sz, int verify, - void* cm) +int ParseCRL(RevokedCert* rcert, DecodedCRL* dcrl, const byte* buff, word32 sz, + int verify, void* cm) { #ifndef WOLFSSL_ASN_TEMPLATE Signer* ca = NULL; @@ -36167,7 +36201,7 @@ int ParseCRL(DecodedCRL* dcrl, const byte* buff, word32 sz, int verify, return ASN_PARSE_E; dcrl->sigIndex = len + idx; - if (ParseCRL_CertList(dcrl, buff, &idx, dcrl->sigIndex, verify) < 0) + if (ParseCRL_CertList(rcert, dcrl, buff, &idx, dcrl->sigIndex, verify) < 0) return ASN_PARSE_E; if (ParseCRL_Extensions(dcrl, buff, &idx, dcrl->sigIndex) < 0) @@ -36303,6 +36337,7 @@ end: } if (ret == 0) { #endif +#if defined(OPENSSL_EXTRA) /* Parse and store the issuer name. */ dcrl->issuerSz = GetASNItem_Length(dataASN[CRLASN_IDX_TBS_ISSUER], buff); @@ -36315,10 +36350,12 @@ end: if (ret < 0) { ret = ASN_PARSE_E; } +#endif } + if ((ret == 0) && (dataASN[CRLASN_IDX_TBS_REVOKEDCERTS].tag != 0)) { /* Parse revoked cerificates - starting after SEQUENCE OF. */ - ret = ParseCRL_RevokedCerts(dcrl, buff, + ret = ParseCRL_RevokedCerts(rcert, dcrl, buff, GetASNItem_DataIdx(dataASN[CRLASN_IDX_TBS_REVOKEDCERTS], buff), GetASNItem_EndIdx(dataASN[CRLASN_IDX_TBS_REVOKEDCERTS], buff)); } diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 0d6f8de42..ab100cefe 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -2198,7 +2198,13 @@ typedef struct CRL_Entry CRL_Entry; #ifdef NO_ASN typedef struct RevokedCert RevokedCert; #endif - +#ifdef CRL_STATIC_REVOKED_LIST + #ifndef CRL_MAX_REVOKED_CERTS + #define CRL_MAX_REVOKED_CERTS 4 + #elif CRL_MAX_REVOKED_CERTS > 22000 + #error CRL_MAX_REVOKED_CERTS too big, max is 22000 + #endif +#endif /* Complete CRL */ struct CRL_Entry { CRL_Entry* next; /* next entry */ @@ -2209,7 +2215,11 @@ struct CRL_Entry { byte nextDate[MAX_DATE_SIZE]; /* next update date */ byte lastDateFormat; /* last date format */ byte nextDateFormat; /* next date format */ +#ifdef CRL_STATIC_REVOKED_LIST + RevokedCert certs[CRL_MAX_REVOKED_CERTS]; +#else RevokedCert* certs; /* revoked cert list */ +#endif int totalCerts; /* number on list */ int version; /* version of certficate */ int verified; @@ -2245,6 +2255,7 @@ struct CRL_Monitor { /* wolfSSL CRL controller */ struct WOLFSSL_CRL { WOLFSSL_CERT_MANAGER* cm; /* pointer back to cert manager */ + CRL_Entry* currentEntry; /* Current CRL entry being processed */ CRL_Entry* crlList; /* our CRL list */ #ifdef HAVE_CRL_IO CbCrlIO crlIOCb; diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index 5f23f89a1..b8baf24cc 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -2472,8 +2472,8 @@ WOLFSSL_LOCAL int VerifyCRL_Signature(SignatureCtx* sigCtx, const byte* signature, word32 sigSz, word32 signatureOID, Signer *ca, void* heap); -WOLFSSL_LOCAL int ParseCRL(DecodedCRL* dcrl, const byte* buff, word32 sz, - int verify, void* cm); +WOLFSSL_LOCAL int ParseCRL(RevokedCert* rcert, DecodedCRL* dcrl, + const byte* buff, word32 sz, int verify, void* cm); WOLFSSL_LOCAL void FreeDecodedCRL(DecodedCRL* dcrl);