#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
#include <wolfssl/internal.h>
#if !defined(WOLFSSL_SSL_CERTMAN_INCLUDED)
#ifndef WOLFSSL_IGNORE_FILE_WARN
#warning ssl_certman.c not to be compiled separately from ssl.c
#endif
#else
#ifndef NO_CERTS
static WC_INLINE WOLFSSL_METHOD* cm_pick_method(void* heap)
{
(void)heap;
#ifndef NO_WOLFSSL_CLIENT
#if !defined(NO_OLD_TLS) && defined(WOLFSSL_ALLOW_SSLV3)
return wolfSSLv3_client_method_ex(heap);
#elif !defined(NO_OLD_TLS) && defined(WOLFSSL_ALLOW_TLSV10)
return wolfTLSv1_client_method_ex(heap);
#elif !defined(NO_OLD_TLS)
return wolfTLSv1_1_client_method_ex(heap);
#elif !defined(WOLFSSL_NO_TLS12)
return wolfTLSv1_2_client_method_ex(heap);
#elif defined(WOLFSSL_TLS13)
return wolfTLSv1_3_client_method_ex(heap);
#else
return NULL;
#endif
#elif !defined(NO_WOLFSSL_SERVER)
#if !defined(NO_OLD_TLS) && defined(WOLFSSL_ALLOW_SSLV3)
return wolfSSLv3_server_method_ex(heap);
#elif !defined(NO_OLD_TLS) && defined(WOLFSSL_ALLOW_TLSV10)
return wolfTLSv1_server_method_ex(heap);
#elif !defined(NO_OLD_TLS)
return wolfTLSv1_1_server_method_ex(heap);
#elif !defined(WOLFSSL_NO_TLS12)
return wolfTLSv1_2_server_method_ex(heap);
#elif defined(WOLFSSL_TLS13)
return wolfTLSv1_3_server_method_ex(heap);
#else
return NULL;
#endif
#else
return NULL;
#endif
}
WOLFSSL_CERT_MANAGER* wolfSSL_CertManagerNew_ex(void* heap)
{
int err = 0;
WOLFSSL_CERT_MANAGER* cm;
WOLFSSL_ENTER("wolfSSL_CertManagerNew");
if (heap == NULL) {
WOLFSSL_MSG("heap param is null");
}
else {
WOLFSSL_MSG_EX("heap param = %p", heap);
}
WOLFSSL_MSG_EX("DYNAMIC_TYPE_CERT_MANAGER Allocating = %d bytes",
(word32)sizeof(WOLFSSL_CERT_MANAGER));
cm = (WOLFSSL_CERT_MANAGER*)XMALLOC(sizeof(WOLFSSL_CERT_MANAGER), heap,
DYNAMIC_TYPE_CERT_MANAGER);
if (cm == NULL) {
WOLFSSL_MSG_EX("XMALLOC failed to allocate WOLFSSL_CERT_MANAGER %d "
"bytes.", (int)sizeof(WOLFSSL_CERT_MANAGER));
err = 1;
}
if (!err) {
XMEMSET(cm, 0, sizeof(WOLFSSL_CERT_MANAGER));
if (wc_InitMutex(&cm->caLock) != 0) {
WOLFSSL_MSG("Bad mutex init");
err = 1;
}
}
if (!err) {
wolfSSL_RefInit(&cm->ref, &err);
#ifdef WOLFSSL_REFCNT_ERROR_RETURN
if (err != 0) {
WOLFSSL_MSG("Bad reference count init");
}
#endif
}
#ifdef WOLFSSL_TRUST_PEER_CERT
if ((!err) && (wc_InitMutex(&cm->tpLock) != 0)) {
WOLFSSL_MSG("Bad mutex init");
err = 1;
}
#endif
if (!err) {
#ifndef NO_RSA
cm->minRsaKeySz = MIN_RSAKEY_SZ;
#endif
#ifdef HAVE_ECC
cm->minEccKeySz = MIN_ECCKEY_SZ;
#endif
#ifdef HAVE_FALCON
cm->minFalconKeySz = MIN_FALCONKEY_SZ;
#endif
#ifdef HAVE_DILITHIUM
cm->minDilithiumKeySz = MIN_DILITHIUMKEY_SZ;
#endif
cm->heap = heap;
}
if (err && (cm != NULL)) {
wolfSSL_CertManagerFree(cm);
cm = NULL;
}
return cm;
}
WOLFSSL_CERT_MANAGER* wolfSSL_CertManagerNew(void)
{
return wolfSSL_CertManagerNew_ex(NULL);
}
void wolfSSL_CertManagerFree(WOLFSSL_CERT_MANAGER* cm)
{
WOLFSSL_ENTER("wolfSSL_CertManagerFree");
if (cm != NULL) {
int doFree = 0;
int ret;
wolfSSL_RefDec(&cm->ref, &doFree, &ret);
#ifdef WOLFSSL_REFCNT_ERROR_RETURN
if (ret != 0) {
WOLFSSL_MSG("Couldn't lock cm mutex");
}
#else
(void)ret;
#endif
if (doFree) {
#ifdef HAVE_CRL
if (cm->crl != NULL) {
FreeCRL(cm->crl, 1);
}
#endif
#ifdef HAVE_OCSP
if (cm->ocsp != NULL) {
FreeOCSP(cm->ocsp, 1);
}
XFREE(cm->ocspOverrideURL, cm->heap, DYNAMIC_TYPE_URL);
#if !defined(NO_WOLFSSL_SERVER) && \
(defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \
defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2))
if (cm->ocsp_stapling) {
FreeOCSP(cm->ocsp_stapling, 1);
}
#endif
#endif
FreeSignerTable(cm->caTable, CA_TABLE_SIZE, cm->heap);
wc_FreeMutex(&cm->caLock);
#ifdef WOLFSSL_TRUST_PEER_CERT
FreeTrustedPeerTable(cm->tpTable, TP_TABLE_SIZE, cm->heap);
wc_FreeMutex(&cm->tpLock);
#endif
wolfSSL_RefFree(&cm->ref);
XFREE(cm, cm->heap, DYNAMIC_TYPE_CERT_MANAGER);
}
}
}
int wolfSSL_CertManager_up_ref(WOLFSSL_CERT_MANAGER* cm)
{
int ret = WOLFSSL_SUCCESS;
if (cm == NULL) {
ret = 0;
}
if (ret == WOLFSSL_SUCCESS) {
int err;
wolfSSL_RefInc(&cm->ref, &err);
#ifdef WOLFSSL_REFCNT_ERROR_RETURN
if (err) {
WOLFSSL_MSG("Failed to lock cm mutex");
ret = 0;
}
#else
(void)err;
#endif
}
return ret;
}
#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM)
#if defined(WOLFSSL_SIGNER_DER_CERT)
static WC_INLINE int wolfssl_cm_get_certs_der(WOLFSSL_CERT_MANAGER* cm,
DerBuffer*** buffers, int* cnt)
{
int err = 0;
Signer* signers = NULL;
DerBuffer** certBuffers = NULL;
int i = 0;
word32 row = 0;
int numCerts = 0;
for (row = 0; row < CA_TABLE_SIZE; row++) {
signers = cm->caTable[row];
while ((signers != NULL) && (signers->derCert != NULL) &&
(signers->derCert->buffer != NULL)) {
++numCerts;
signers = signers->next;
}
}
if (numCerts == 0) {
err = 1;
}
if (!err) {
certBuffers = (DerBuffer**)XMALLOC(
sizeof(DerBuffer*) * (size_t)numCerts, cm->heap,
DYNAMIC_TYPE_TMP_BUFFER);
if (certBuffers == NULL) {
err = 1;
}
}
if (!err) {
XMEMSET(certBuffers, 0, sizeof(DerBuffer*) * (size_t)numCerts);
}
for (row = 0; (!err) && (row < CA_TABLE_SIZE); row++) {
signers = cm->caTable[row];
while ((signers != NULL) && (signers->derCert != NULL) &&
(signers->derCert->buffer != NULL)) {
int ret = AllocDer(&certBuffers[i], signers->derCert->length,
CA_TYPE, cm->heap);
if (ret < 0) {
err = 1;
break;
}
XMEMCPY(certBuffers[i]->buffer, signers->derCert->buffer,
signers->derCert->length);
certBuffers[i]->length = signers->derCert->length;
++i;
signers = signers->next;
}
}
*buffers = certBuffers;
*cnt = numCerts;
return err;
}
WOLFSSL_STACK* wolfSSL_CertManagerGetCerts(WOLFSSL_CERT_MANAGER* cm)
{
WOLFSSL_STACK* sk = NULL;
int numCerts = 0;
DerBuffer** certBuffers = NULL;
int i = 0;
int err = 0;
WOLFSSL_ENTER("wolfSSL_CertManagerGetCerts");
if (cm == NULL) {
err = 1;
}
if (!err) {
sk = wolfSSL_sk_X509_new_null();
if (sk == NULL) {
err = 1;
}
}
if ((!err) && (wc_LockMutex(&cm->caLock) != 0)) {
err = 1;
}
if (!err) {
err = wolfssl_cm_get_certs_der(cm, &certBuffers, &numCerts);
wc_UnLockMutex(&cm->caLock);
}
for (i = 0; (!err) && (i < numCerts); ++i) {
const byte* derBuffer = NULL;
WOLFSSL_X509* x509 = NULL;
derBuffer = certBuffers[i]->buffer;
wolfSSL_d2i_X509(&x509, &derBuffer, (int)certBuffers[i]->length);
if (x509 == NULL) {
err = 1;
}
if ((!err) && (wolfSSL_sk_X509_push(sk, x509) <= 0)) {
wolfSSL_X509_free(x509);
x509 = NULL;
err = 1;
}
}
if (certBuffers != NULL) {
for (i = 0; i < numCerts && certBuffers[i] != NULL; ++i) {
FreeDer(&certBuffers[i]);
}
XFREE(certBuffers, cm->heap, DYNAMIC_TYPE_TMP_BUFFER);
}
if (err && (sk != NULL)) {
wolfSSL_sk_X509_pop_free(sk, NULL);
sk = NULL;
}
return sk;
}
#endif
#endif
int wolfSSL_CertManagerUnloadCAs(WOLFSSL_CERT_MANAGER* cm)
{
int ret = WOLFSSL_SUCCESS;
WOLFSSL_ENTER("wolfSSL_CertManagerUnloadCAs");
if (cm == NULL) {
ret = BAD_FUNC_ARG;
}
if ((ret == WOLFSSL_SUCCESS) && (wc_LockMutex(&cm->caLock) != 0)) {
ret = BAD_MUTEX_E;
}
if (ret == WOLFSSL_SUCCESS) {
FreeSignerTable(cm->caTable, CA_TABLE_SIZE, cm->heap);
wc_UnLockMutex(&cm->caLock);
}
return ret;
}
int wolfSSL_CertManagerUnloadTypeCerts(
WOLFSSL_CERT_MANAGER* cm, byte type)
{
int ret = WOLFSSL_SUCCESS;
WOLFSSL_ENTER("wolfSSL_CertManagerUnloadTypeCerts");
if (cm == NULL) {
ret = BAD_FUNC_ARG;
}
if ((ret == WOLFSSL_SUCCESS) && (wc_LockMutex(&cm->caLock) != 0)) {
ret = BAD_MUTEX_E;
}
if (ret == WOLFSSL_SUCCESS) {
FreeSignerTableType(cm->caTable, CA_TABLE_SIZE, type,
cm->heap);
wc_UnLockMutex(&cm->caLock);
}
return ret;
}
#if defined(OPENSSL_EXTRA)
static int wolfSSL_CertManagerUnloadTempIntermediateCerts(
WOLFSSL_CERT_MANAGER* cm)
{
WOLFSSL_ENTER("wolfSSL_CertManagerUnloadTempIntermediateCerts");
return wolfSSL_CertManagerUnloadTypeCerts(cm, WOLFSSL_TEMP_CA);
}
#endif
int wolfSSL_CertManagerUnloadIntermediateCerts(
WOLFSSL_CERT_MANAGER* cm)
{
WOLFSSL_ENTER("wolfSSL_CertManagerUnloadIntermediateCerts");
return wolfSSL_CertManagerUnloadTypeCerts(cm, WOLFSSL_CHAIN_CA);
}
#ifdef WOLFSSL_TRUST_PEER_CERT
int wolfSSL_CertManagerUnload_trust_peers(WOLFSSL_CERT_MANAGER* cm)
{
int ret = WOLFSSL_SUCCESS;
WOLFSSL_ENTER("wolfSSL_CertManagerUnload_trust_peers");
if (cm == NULL) {
ret = BAD_FUNC_ARG;
}
if ((ret == WOLFSSL_SUCCESS) && (wc_LockMutex(&cm->tpLock) != 0)) {
ret = BAD_MUTEX_E;
}
if (ret == WOLFSSL_SUCCESS) {
FreeTrustedPeerTable(cm->tpTable, TP_TABLE_SIZE, cm->heap);
wc_UnLockMutex(&cm->tpLock);
}
return ret;
}
#endif
int wolfSSL_CertManagerLoadCABufferType(WOLFSSL_CERT_MANAGER* cm,
const unsigned char* buff, long sz, int format, int userChain,
word32 flags, int type)
{
int ret = WOLFSSL_SUCCESS;
WOLFSSL_CTX* tmp = NULL;
DecodedCert* dCert = NULL;
DerBuffer* der = NULL;
WOLFSSL_ENTER("wolfSSL_CertManagerLoadCABufferType");
if (cm == NULL) {
WOLFSSL_MSG("No CertManager error");
ret = WOLFSSL_FATAL_ERROR;
}
if ((ret == WOLFSSL_SUCCESS) && ((tmp =
wolfSSL_CTX_new_ex(cm_pick_method(cm->heap), cm->heap)) == NULL)) {
WOLFSSL_MSG("CTX new failed");
ret = WOLFSSL_FATAL_ERROR;
}
if (ret == WOLFSSL_SUCCESS) {
wolfSSL_CTX_set_verify(tmp, WOLFSSL_VERIFY_DEFAULT, NULL);
wolfSSL_CertManagerFree(tmp->cm);
tmp->cm = cm;
ret = wolfSSL_CTX_load_verify_buffer_ex(tmp, buff, sz, format,
userChain, flags);
tmp->cm = NULL;
}
if (ret == WOLFSSL_SUCCESS && type != WOLFSSL_USER_CA) {
dCert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), cm->heap,
DYNAMIC_TYPE_DCERT);
if (dCert == NULL) {
ret = WOLFSSL_FATAL_ERROR;
} else {
if (format == WOLFSSL_FILETYPE_PEM) {
#ifndef WOLFSSL_PEM_TO_DER
ret = NOT_COMPILED_IN;
#else
ret = PemToDer(buff, sz, CERT_TYPE, &der, cm->heap, NULL, NULL);
if (!ret) {
buff = der->buffer;
sz = (long)der->length;
ret = WOLFSSL_SUCCESS;
} else {
WOLFSSL_ERROR(ret);
ret = WOLFSSL_FATAL_ERROR;
}
#endif
}
if (ret == WOLFSSL_SUCCESS) {
XMEMSET(dCert, 0, sizeof(DecodedCert));
wc_InitDecodedCert(dCert, buff,
(word32)sz, cm->heap);
ret = wc_ParseCert(dCert, CERT_TYPE, NO_VERIFY, NULL);
if (ret) {
ret = WOLFSSL_FATAL_ERROR;
} else {
ret = SetCAType(cm, dCert->extSubjKeyId, type);
}
}
if (dCert) {
wc_FreeDecodedCert(dCert);
XFREE(dCert, cm->heap, DYNAMIC_TYPE_DCERT);
}
if (der) {
FreeDer(&der);
}
}
}
wolfSSL_CTX_free(tmp);
return ret;
}
int wolfSSL_CertManagerLoadCABuffer_ex(WOLFSSL_CERT_MANAGER* cm,
const unsigned char* buff, long sz, int format, int userChain, word32 flags)
{
return wolfSSL_CertManagerLoadCABufferType(cm, buff, sz, format, userChain,
flags, WOLFSSL_USER_CA);
}
int wolfSSL_CertManagerLoadCABuffer(WOLFSSL_CERT_MANAGER* cm,
const unsigned char* buff, long sz, int format)
{
return wolfSSL_CertManagerLoadCABuffer_ex(cm, buff, sz, format, 0,
WOLFSSL_LOAD_VERIFY_DEFAULT_FLAGS);
}
#ifndef NO_WOLFSSL_CM_VERIFY
void wolfSSL_CertManagerSetVerify(WOLFSSL_CERT_MANAGER* cm, VerifyCallback vc)
{
WOLFSSL_ENTER("wolfSSL_CertManagerSetVerify");
if (cm != NULL) {
cm->verifyCallback = vc;
}
}
#endif
#ifdef WC_ASN_UNKNOWN_EXT_CB
void wolfSSL_CertManagerSetUnknownExtCallback(WOLFSSL_CERT_MANAGER* cm,
wc_UnknownExtCallback cb)
{
WOLFSSL_ENTER("wolfSSL_CertManagerSetUnknownExtCallback");
if (cm != NULL) {
cm->unknownExtCallback = cb;
}
}
#endif
#if (!defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH)) || \
defined(OPENSSL_EXTRA)
int CM_VerifyBuffer_ex(WOLFSSL_CERT_MANAGER* cm, const unsigned char* buff,
long sz, int format, int prev_err)
{
int ret = 0;
int fatal = 0;
DerBuffer* der = NULL;
WC_DECLARE_VAR(cert, DecodedCert, 1, 0);
WOLFSSL_ENTER("CM_VerifyBuffer_ex");
(void)prev_err;
WC_ALLOC_VAR_EX(cert, DecodedCert, 1, cm->heap, DYNAMIC_TYPE_DCERT,
{
ret=MEMORY_E;
fatal=1;
});
if (WC_VAR_OK(cert))
{
XMEMSET(cert, 0, sizeof(DecodedCert));
if (format == WOLFSSL_FILETYPE_PEM) {
#ifndef WOLFSSL_PEM_TO_DER
ret = NOT_COMPILED_IN;
fatal = 1;
#else
ret = PemToDer(buff, sz, CERT_TYPE, &der, cm->heap, NULL, NULL);
if (ret != 0) {
fatal = 1;
}
else {
buff = der->buffer;
sz = (long)der->length;
}
#endif
}
}
if (ret == 0) {
InitDecodedCert(cert, buff, (word32)sz, cm->heap);
#ifdef WC_ASN_UNKNOWN_EXT_CB
if (cm->unknownExtCallback != NULL)
wc_SetUnknownExtCallback(cert, cm->unknownExtCallback);
#endif
ret = ParseCertRelative(cert, CERT_TYPE, VERIFY, cm, NULL);
}
#ifdef HAVE_CRL
if ((ret == 0) && cm->crlEnabled) {
ret = CheckCertCRL(cm->crl, cert);
}
#endif
(void)fatal;
#if !defined(NO_WOLFSSL_CM_VERIFY) && \
(!defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH))
if ((!fatal) && cm->verifyCallback) {
WC_DECLARE_VAR(args, ProcPeerCertArgs, 1, 0);
buffer certBuf;
#ifdef WOLFSSL_SMALL_STACK
args = (ProcPeerCertArgs*)XMALLOC(sizeof(ProcPeerCertArgs), cm->heap,
DYNAMIC_TYPE_TMP_BUFFER);
if (args == NULL) {
ret = MEMORY_E;
fatal = 1;
}
if (!fatal)
#endif
{
XMEMSET(args, 0, sizeof(ProcPeerCertArgs));
certBuf.buffer = (byte*)buff;
certBuf.length = (unsigned int)sz;
args->totalCerts = 1;
args->certs = &certBuf;
args->dCert = cert;
args->dCertInit = 1;
if (prev_err != 0) {
ret = prev_err;
}
ret = DoVerifyCallback(cm, NULL, ret, args);
}
WC_FREE_VAR_EX(args, cm->heap, DYNAMIC_TYPE_TMP_BUFFER);
}
#endif
FreeDecodedCert(cert);
FreeDer(&der);
WC_FREE_VAR_EX(cert, cm->heap, DYNAMIC_TYPE_DCERT);
return (ret == 0) ? WOLFSSL_SUCCESS : ret;
}
int wolfSSL_CertManagerVerifyBuffer(WOLFSSL_CERT_MANAGER* cm,
const unsigned char* buff, long sz, int format)
{
int ret;
WOLFSSL_ENTER("wolfSSL_CertManagerVerifyBuffer");
if ((cm == NULL) || (buff == NULL) || (sz <= 0)) {
ret = BAD_FUNC_ARG;
}
else if ((format != WOLFSSL_FILETYPE_ASN1) &&
(format != WOLFSSL_FILETYPE_PEM)) {
ret = WOLFSSL_BAD_FILETYPE;
}
else {
ret = CM_VerifyBuffer_ex(cm, buff, sz, format, 0);
}
return ret;
}
#endif
#ifndef NO_FILESYSTEM
#if (!defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH)) || \
defined(OPENSSL_EXTRA)
int wolfSSL_CertManagerVerify(WOLFSSL_CERT_MANAGER* cm, const char* fname,
int format)
{
int ret = WOLFSSL_SUCCESS;
#ifndef WOLFSSL_SMALL_STACK
byte staticBuffer[FILE_BUFFER_SIZE];
#endif
byte* buff = NULL;
long sz = 0;
XFILE file = XBADFILE;
WOLFSSL_ENTER("wolfSSL_CertManagerVerify");
#ifndef WOLFSSL_SMALL_STACK
buff = staticBuffer;
#endif
if ((cm == NULL) || (fname == NULL)) {
ret = BAD_FUNC_ARG;
}
if ((ret == WOLFSSL_SUCCESS) &&
((file = XFOPEN(fname, "rb")) == XBADFILE)) {
ret = WOLFSSL_BAD_FILE;
}
if (ret == WOLFSSL_SUCCESS) {
ret = wolfssl_file_len(file, &sz);
if (ret == 0) {
ret = WOLFSSL_SUCCESS;
}
}
#ifndef WOLFSSL_SMALL_STACK
if ((ret == WOLFSSL_SUCCESS) && (sz > (long)sizeof(staticBuffer)))
#else
if (ret == WOLFSSL_SUCCESS)
#endif
{
WOLFSSL_MSG("Getting dynamic buffer");
buff = (byte*)XMALLOC((size_t)sz, cm->heap, DYNAMIC_TYPE_FILE);
if (buff == NULL) {
ret = WOLFSSL_BAD_FILE;
}
}
if ((ret == WOLFSSL_SUCCESS) && (XFREAD(buff, 1, (size_t)sz, file) !=
(size_t)sz)) {
ret = WOLFSSL_BAD_FILE;
}
if (file != XBADFILE) {
XFCLOSE(file);
}
if (ret == WOLFSSL_SUCCESS) {
ret = wolfSSL_CertManagerVerifyBuffer(cm, buff, sz, format);
}
#ifndef WOLFSSL_SMALL_STACK
if (buff != staticBuffer)
#endif
{
if (cm != NULL) {
XFREE(buff, cm->heap, DYNAMIC_TYPE_FILE);
}
}
return ret;
}
#endif
int wolfSSL_CertManagerLoadCA(WOLFSSL_CERT_MANAGER* cm, const char* file,
const char* path)
{
int ret = WOLFSSL_SUCCESS;
WOLFSSL_CTX* tmp = NULL;
WOLFSSL_ENTER("wolfSSL_CertManagerLoadCA");
if (cm == NULL) {
WOLFSSL_MSG("No CertManager error");
ret = WOLFSSL_FATAL_ERROR;
}
if ((ret == WOLFSSL_SUCCESS) && ((tmp =
wolfSSL_CTX_new_ex(cm_pick_method(cm->heap), cm->heap)) == NULL)) {
WOLFSSL_MSG("CTX new failed");
ret = WOLFSSL_FATAL_ERROR;
}
if (ret == WOLFSSL_SUCCESS) {
wolfSSL_CTX_set_verify(tmp, WOLFSSL_VERIFY_DEFAULT, NULL);
wolfSSL_CertManagerFree(tmp->cm);
tmp->cm = cm;
ret = wolfSSL_CTX_load_verify_locations(tmp, file, path);
tmp->cm = NULL;
}
wolfSSL_CTX_free(tmp);
return ret;
}
#endif
#if defined(PERSIST_CERT_CACHE)
#define WOLFSSL_CACHE_CERT_VERSION 1
typedef struct {
int version;
int rows;
int columns[CA_TABLE_SIZE];
int signerSz;
} CertCacheHeader;
static WC_INLINE int cm_get_signer_memory(Signer* signer)
{
int sz = sizeof(signer->pubKeySize) + sizeof(signer->keyOID)
+ sizeof(signer->nameLen) + sizeof(signer->subjectNameHash);
#if !defined(NO_SKID)
sz += (int)sizeof(signer->subjectKeyIdHash);
#endif
sz += (int)signer->pubKeySize;
sz += signer->nameLen;
return sz;
}
static WC_INLINE int cm_get_cert_cache_row_memory(Signer* row)
{
int sz = 0;
while (row != NULL) {
sz += cm_get_signer_memory(row);
row = row->next;
}
return sz;
}
static WC_INLINE int cm_get_cert_cache_mem_size(WOLFSSL_CERT_MANAGER* cm)
{
int sz;
int i;
sz = sizeof(CertCacheHeader);
for (i = 0; i < CA_TABLE_SIZE; i++) {
sz += cm_get_cert_cache_row_memory(cm->caTable[i]);
}
return sz;
}
static WC_INLINE void cm_set_cert_header_Columns(WOLFSSL_CERT_MANAGER* cm,
int* columns)
{
int i;
Signer* row;
for (i = 0; i < CA_TABLE_SIZE; i++) {
int count = 0;
row = cm->caTable[i];
while (row != NULL) {
++count;
row = row->next;
}
columns[i] = count;
}
}
static WC_INLINE int cm_restore_cert_row(WOLFSSL_CERT_MANAGER* cm,
byte* current, int row, int listSz, const byte* end)
{
int ret = 0;
int idx = 0;
if (listSz < 0) {
WOLFSSL_MSG("Row header corrupted, negative value");
ret = PARSE_ERROR;
}
while ((ret == 0) && (listSz > 0)) {
Signer* signer = NULL;
byte* publicKey;
byte* start = current + idx;
int minSz = sizeof(signer->pubKeySize) + sizeof(signer->keyOID) +
sizeof(signer->nameLen) + sizeof(signer->subjectNameHash);
#ifndef NO_SKID
minSz += (int)sizeof(signer->subjectKeyIdHash);
#endif
if (start + minSz > end) {
WOLFSSL_MSG("Would overread restore buffer");
ret = BUFFER_E;
}
if ((ret == 0) && ((signer = MakeSigner(cm->heap)) == NULL)) {
ret = MEMORY_E;
}
if (ret == 0) {
XMEMCPY(&signer->pubKeySize, current + idx,
sizeof(signer->pubKeySize));
idx += (int)sizeof(signer->pubKeySize);
XMEMCPY(&signer->keyOID, current + idx, sizeof(signer->keyOID));
idx += (int)sizeof(signer->keyOID);
if (start + minSz + signer->pubKeySize > end) {
WOLFSSL_MSG("Would overread restore buffer");
ret = BUFFER_E;
}
}
if (ret == 0) {
publicKey = (byte*)XMALLOC(signer->pubKeySize, cm->heap,
DYNAMIC_TYPE_KEY);
if (publicKey == NULL) {
ret = MEMORY_E;
}
}
if (ret == 0) {
XMEMCPY(publicKey, current + idx, signer->pubKeySize);
signer->publicKey = publicKey;
idx += (int)signer->pubKeySize;
XMEMCPY(&signer->nameLen, current + idx, sizeof(signer->nameLen));
idx += (int)sizeof(signer->nameLen);
if (start + minSz + signer->pubKeySize + signer->nameLen > end) {
WOLFSSL_MSG("Would overread restore buffer");
ret = BUFFER_E;
}
}
if (ret == 0) {
signer->name = (char*)XMALLOC((size_t)signer->nameLen, cm->heap,
DYNAMIC_TYPE_SUBJECT_CN);
if (signer->name == NULL) {
ret = MEMORY_E;
}
}
if (ret == 0) {
XMEMCPY((void *)(wc_ptr_t)signer->name, current + idx,
(size_t)signer->nameLen);
idx += signer->nameLen;
XMEMCPY(signer->subjectNameHash, current + idx, SIGNER_DIGEST_SIZE);
idx += SIGNER_DIGEST_SIZE;
#ifndef NO_SKID
XMEMCPY(signer->subjectKeyIdHash, current + idx,SIGNER_DIGEST_SIZE);
idx += SIGNER_DIGEST_SIZE;
#endif
signer->next = cm->caTable[row];
cm->caTable[row] = signer;
--listSz;
}
if ((ret != 0) && (signer != NULL)) {
FreeSigner(signer, cm->heap);
}
}
if (ret == 0) {
ret = idx;
}
return ret;
}
static WC_INLINE int cm_store_cert_row(WOLFSSL_CERT_MANAGER* cm, byte* current,
int row)
{
int added = 0;
Signer* list;
list = cm->caTable[row];
while (list != NULL) {
XMEMCPY(current + added, &list->pubKeySize, sizeof(list->pubKeySize));
added += (int)sizeof(list->pubKeySize);
XMEMCPY(current + added, &list->keyOID, sizeof(list->keyOID));
added += (int)sizeof(list->keyOID);
XMEMCPY(current + added, list->publicKey, (size_t)list->pubKeySize);
added += (int)list->pubKeySize;
XMEMCPY(current + added, &list->nameLen, sizeof(list->nameLen));
added += (int)sizeof(list->nameLen);
XMEMCPY(current + added, list->name, (size_t)list->nameLen);
added += list->nameLen;
XMEMCPY(current + added, list->subjectNameHash, SIGNER_DIGEST_SIZE);
added += SIGNER_DIGEST_SIZE;
#ifndef NO_SKID
XMEMCPY(current + added, list->subjectKeyIdHash,SIGNER_DIGEST_SIZE);
added += SIGNER_DIGEST_SIZE;
#endif
list = list->next;
}
return added;
}
static WC_INLINE int cm_do_mem_save_cert_cache(WOLFSSL_CERT_MANAGER* cm,
void* mem, int sz)
{
int ret = WOLFSSL_SUCCESS;
int realSz;
int i;
WOLFSSL_ENTER("cm_do_mem_save_cert_cache");
realSz = cm_get_cert_cache_mem_size(cm);
if (realSz > sz) {
WOLFSSL_MSG("Mem output buffer too small");
ret = BUFFER_E;
}
if (ret == WOLFSSL_SUCCESS) {
byte* current;
CertCacheHeader hdr;
hdr.version = WOLFSSL_CACHE_CERT_VERSION;
hdr.rows = CA_TABLE_SIZE;
cm_set_cert_header_Columns(cm, hdr.columns);
hdr.signerSz = (int)sizeof(Signer);
XMEMCPY(mem, &hdr, sizeof(CertCacheHeader));
current = (byte*)mem + sizeof(CertCacheHeader);
for (i = 0; i < CA_TABLE_SIZE; ++i) {
current += cm_store_cert_row(cm, current, i);
}
}
return ret;
}
#if !defined(NO_FILESYSTEM)
int CM_SaveCertCache(WOLFSSL_CERT_MANAGER* cm, const char* fname)
{
XFILE file;
int ret = WOLFSSL_SUCCESS;
WOLFSSL_ENTER("CM_SaveCertCache");
file = XFOPEN(fname, "w+b");
if (file == XBADFILE) {
WOLFSSL_MSG("Couldn't open cert cache save file");
ret = WOLFSSL_BAD_FILE;
}
if ((ret == WOLFSSL_SUCCESS) && (wc_LockMutex(&cm->caLock) != 0)) {
WOLFSSL_MSG("wc_LockMutex on caLock failed");
ret = BAD_MUTEX_E;
}
if (ret == WOLFSSL_SUCCESS) {
byte* mem;
size_t memSz = (size_t)cm_get_cert_cache_mem_size(cm);
mem = (byte*)XMALLOC(memSz, cm->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (mem == NULL) {
WOLFSSL_MSG("Alloc for tmp buffer failed");
ret = MEMORY_E;
}
if (ret == WOLFSSL_SUCCESS) {
ret = cm_do_mem_save_cert_cache(cm, mem, (int)memSz);
}
if (ret == WOLFSSL_SUCCESS) {
int sz = (int)XFWRITE(mem, memSz, 1, file);
if (sz != 1) {
WOLFSSL_MSG("Cert cache file write failed");
ret = FWRITE_ERROR;
}
}
XFREE(mem, cm->heap, DYNAMIC_TYPE_TMP_BUFFER);
wc_UnLockMutex(&cm->caLock);
}
if (file != XBADFILE) {
XFCLOSE(file);
}
return ret;
}
int CM_RestoreCertCache(WOLFSSL_CERT_MANAGER* cm, const char* fname)
{
XFILE file;
int ret = WOLFSSL_SUCCESS;
int memSz = 0;
byte* mem = NULL;
WOLFSSL_ENTER("CM_RestoreCertCache");
file = XFOPEN(fname, "rb");
if (file == XBADFILE) {
WOLFSSL_MSG("Couldn't open cert cache save file");
ret = WOLFSSL_BAD_FILE;
}
if (ret == WOLFSSL_SUCCESS) {
ret = wolfssl_read_file(file, (char**)&mem, &memSz);
if (ret == 0) {
ret = WOLFSSL_SUCCESS;
}
}
if (ret == WOLFSSL_SUCCESS) {
ret = CM_MemRestoreCertCache(cm, mem, memSz);
if (ret != WOLFSSL_SUCCESS) {
WOLFSSL_MSG("Mem restore cert cache failed");
}
}
XFREE(mem, cm->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (file != XBADFILE) {
XFCLOSE(file);
}
return ret;
}
#endif
int CM_MemSaveCertCache(WOLFSSL_CERT_MANAGER* cm, void* mem, int sz, int* used)
{
int ret = WOLFSSL_SUCCESS;
WOLFSSL_ENTER("CM_MemSaveCertCache");
if (wc_LockMutex(&cm->caLock) != 0) {
WOLFSSL_MSG("wc_LockMutex on caLock failed");
ret = BAD_MUTEX_E;
}
if (ret == WOLFSSL_SUCCESS) {
ret = cm_do_mem_save_cert_cache(cm, mem, sz);
if (ret == WOLFSSL_SUCCESS) {
*used = cm_get_cert_cache_mem_size(cm);
}
wc_UnLockMutex(&cm->caLock);
}
return ret;
}
int CM_MemRestoreCertCache(WOLFSSL_CERT_MANAGER* cm, const void* mem, int sz)
{
int ret = WOLFSSL_SUCCESS;
int i;
CertCacheHeader* hdr = (CertCacheHeader*)mem;
byte* current = (byte*)mem + sizeof(CertCacheHeader);
byte* end = (byte*)mem + sz;
WOLFSSL_ENTER("CM_MemRestoreCertCache");
if ((sz < (int)sizeof(CertCacheHeader)) || (current > end)) {
WOLFSSL_MSG("Cert Cache Memory buffer too small");
ret = BUFFER_E;
}
if ((ret == WOLFSSL_SUCCESS) &&
((hdr->version != WOLFSSL_CACHE_CERT_VERSION) ||
(hdr->rows != CA_TABLE_SIZE) ||
(hdr->signerSz != (int)sizeof(Signer)))) {
WOLFSSL_MSG("Cert Cache Memory header mismatch");
ret = CACHE_MATCH_ERROR;
}
if ((ret == WOLFSSL_SUCCESS) && (wc_LockMutex(&cm->caLock) != 0)) {
WOLFSSL_MSG("wc_LockMutex on caLock failed");
ret = BAD_MUTEX_E;
}
if (ret == WOLFSSL_SUCCESS) {
FreeSignerTable(cm->caTable, CA_TABLE_SIZE, cm->heap);
for (i = 0; i < CA_TABLE_SIZE; ++i) {
int added = cm_restore_cert_row(cm, current, i, hdr->columns[i],
end);
if (added < 0) {
WOLFSSL_MSG("cm_restore_cert_row error");
ret = added;
break;
}
current += added;
}
wc_UnLockMutex(&cm->caLock);
}
return ret;
}
int CM_GetCertCacheMemSize(WOLFSSL_CERT_MANAGER* cm)
{
int ret;
WOLFSSL_ENTER("CM_GetCertCacheMemSize");
if (wc_LockMutex(&cm->caLock) != 0) {
WOLFSSL_MSG("wc_LockMutex on caLock failed");
ret = BAD_MUTEX_E;
}
else {
ret = cm_get_cert_cache_mem_size(cm);
wc_UnLockMutex(&cm->caLock);
}
return ret;
}
#endif
int wolfSSL_CertManagerEnableCRL(WOLFSSL_CERT_MANAGER* cm, int options)
{
int ret = WOLFSSL_SUCCESS;
WOLFSSL_ENTER("wolfSSL_CertManagerEnableCRL");
(void)options;
if (cm == NULL) {
ret = BAD_FUNC_ARG;
}
#if defined(OPENSSL_COMPATIBLE_DEFAULTS)
if ((ret == WOLFSSL_SUCCESS) && (options == 0)) {
cm->crlEnabled = 0;
cm->crlCheckAll = 0;
}
else
#endif
if (ret == WOLFSSL_SUCCESS) {
#ifndef HAVE_CRL
ret = NOT_COMPILED_IN;
#else
if (cm->crl == NULL) {
cm->crl = (WOLFSSL_CRL*)XMALLOC(sizeof(WOLFSSL_CRL), cm->heap,
DYNAMIC_TYPE_CRL);
if (cm->crl == NULL) {
ret = MEMORY_E;
}
if (ret == WOLFSSL_SUCCESS) {
XMEMSET(cm->crl, 0, sizeof(WOLFSSL_CRL));
if (InitCRL(cm->crl, cm) != 0) {
WOLFSSL_MSG("Init CRL failed");
FreeCRL(cm->crl, 1);
cm->crl = NULL;
ret = WOLFSSL_FAILURE;
}
}
}
if (ret == WOLFSSL_SUCCESS) {
#if defined(HAVE_CRL_IO) && defined(USE_WOLFSSL_IO)
cm->crl->crlIOCb = EmbedCrlLookup;
#endif
#if defined(OPENSSL_COMPATIBLE_DEFAULTS)
if ((options & WOLFSSL_CRL_CHECKALL) ||
(options & WOLFSSL_CRL_CHECK))
#endif
{
cm->crlEnabled = 1;
if (options & WOLFSSL_CRL_CHECKALL) {
cm->crlCheckAll = 1;
}
}
}
#endif
}
return ret;
}
int wolfSSL_CertManagerDisableCRL(WOLFSSL_CERT_MANAGER* cm)
{
int ret = WOLFSSL_SUCCESS;
WOLFSSL_ENTER("wolfSSL_CertManagerDisableCRL");
if (cm == NULL) {
ret = BAD_FUNC_ARG;
}
if (ret == WOLFSSL_SUCCESS) {
cm->crlEnabled = 0;
cm->crlCheckAll = 0;
}
return ret;
}
#ifdef HAVE_CRL
int wolfSSL_CertManagerLoadCRLBuffer(WOLFSSL_CERT_MANAGER* cm,
const unsigned char* buff, long sz, int type)
{
int ret = WOLFSSL_SUCCESS;
WOLFSSL_ENTER("wolfSSL_CertManagerLoadCRLBuffer");
if ((cm == NULL) || (buff == NULL) || (sz <= 0)) {
ret = BAD_FUNC_ARG;
}
if ((ret == WOLFSSL_SUCCESS) && (cm->crl == NULL) &&
(wolfSSL_CertManagerEnableCRL(cm, WOLFSSL_CRL_CHECK) !=
WOLFSSL_SUCCESS)) {
WOLFSSL_MSG("Enable CRL failed");
ret = WOLFSSL_FATAL_ERROR;
}
if (ret == WOLFSSL_SUCCESS) {
ret = BufferLoadCRL(cm->crl, buff, sz, type, VERIFY);
}
return ret;
}
int wolfSSL_CertManagerFreeCRL(WOLFSSL_CERT_MANAGER* cm)
{
int ret = WOLFSSL_SUCCESS;
WOLFSSL_ENTER("wolfSSL_CertManagerFreeCRL");
if (cm == NULL) {
ret = BAD_FUNC_ARG;
}
if ((ret == WOLFSSL_SUCCESS) && (cm->crl != NULL)) {
FreeCRL(cm->crl, 1);
cm->crl = NULL;
}
return ret;
}
int wolfSSL_CertManagerCheckCRL(WOLFSSL_CERT_MANAGER* cm,
const unsigned char* der, int sz)
{
int ret = 0;
WC_DECLARE_VAR(cert, DecodedCert, 1, 0);
WOLFSSL_ENTER("wolfSSL_CertManagerCheckCRL");
if ((cm == NULL) || (der == NULL) || (sz <= 0)) {
ret = BAD_FUNC_ARG;
}
if ((ret == 0) && cm->crlEnabled) {
WC_ALLOC_VAR_EX(cert, DecodedCert, 1, NULL, DYNAMIC_TYPE_DCERT,
ret=MEMORY_E);
if (WC_VAR_OK(cert))
{
InitDecodedCert(cert, der, (word32)sz, NULL);
ret = ParseCertRelative(cert, CERT_TYPE, VERIFY_CRL, cm, NULL);
if (ret != 0) {
WOLFSSL_MSG("ParseCert failed");
}
else if ((ret = CheckCertCRL(cm->crl, cert)) != 0) {
WOLFSSL_MSG("CheckCertCRL failed");
}
FreeDecodedCert(cert);
WC_FREE_VAR_EX(cert, NULL, DYNAMIC_TYPE_DCERT);
}
}
return (ret == 0) ? WOLFSSL_SUCCESS : ret;
}
int wolfSSL_CertManagerSetCRL_Cb(WOLFSSL_CERT_MANAGER* cm, CbMissingCRL cb)
{
int ret = WOLFSSL_SUCCESS;
WOLFSSL_ENTER("wolfSSL_CertManagerSetCRL_Cb");
if (cm == NULL) {
ret = BAD_FUNC_ARG;
}
if (ret == WOLFSSL_SUCCESS) {
cm->cbMissingCRL = cb;
}
return ret;
}
int wolfSSL_CertManagerSetCRL_ErrorCb(WOLFSSL_CERT_MANAGER* cm, crlErrorCb cb,
void* ctx)
{
int ret = WOLFSSL_SUCCESS;
WOLFSSL_ENTER("wolfSSL_CertManagerSetCRL_Cb");
if (cm == NULL) {
ret = BAD_FUNC_ARG;
}
if (ret == WOLFSSL_SUCCESS) {
cm->crlCb = cb;
cm->crlCbCtx = ctx;
}
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);
}
int wolfSSL_CertManagerSetCRLUpdate_Cb(WOLFSSL_CERT_MANAGER* cm, CbUpdateCRL cb)
{
int ret = WOLFSSL_SUCCESS;
WOLFSSL_ENTER("wolfSSL_CertManagerSetCRLUpdate_Cb");
if (cm == NULL) {
ret = BAD_FUNC_ARG;
}
if (ret == WOLFSSL_SUCCESS) {
cm->cbUpdateCRL = cb;
}
return ret;
}
#endif
#ifdef HAVE_CRL_IO
int wolfSSL_CertManagerSetCRL_IOCb(WOLFSSL_CERT_MANAGER* cm, CbCrlIO cb)
{
int ret = WOLFSSL_SUCCESS;
if (cm == NULL) {
ret = BAD_FUNC_ARG;
}
if ((ret == WOLFSSL_SUCCESS) && (cm->crl != NULL)) {
cm->crl->crlIOCb = cb;
}
return ret;
}
#endif
#ifndef NO_FILESYSTEM
int wolfSSL_CertManagerLoadCRL(WOLFSSL_CERT_MANAGER* cm, const char* path,
int type, int monitor)
{
int ret = WOLFSSL_SUCCESS;
WOLFSSL_ENTER("wolfSSL_CertManagerLoadCRL");
if ((cm == NULL) || (path == NULL)) {
ret = BAD_FUNC_ARG;
}
if ((ret == WOLFSSL_SUCCESS) && (cm->crl == NULL) &&
(wolfSSL_CertManagerEnableCRL(cm, WOLFSSL_CRL_CHECK) !=
WOLFSSL_SUCCESS)) {
WOLFSSL_MSG("Enable CRL failed");
ret = WOLFSSL_FATAL_ERROR;
}
if (ret == WOLFSSL_SUCCESS) {
ret = LoadCRL(cm->crl, path, type, monitor);
}
return ret;
}
int wolfSSL_CertManagerLoadCRLFile(WOLFSSL_CERT_MANAGER* cm, const char* file,
int type)
{
int ret = WOLFSSL_SUCCESS;
WOLFSSL_ENTER("wolfSSL_CertManagerLoadCRLFile");
if ((cm == NULL) || (file == NULL)) {
ret = BAD_FUNC_ARG;
}
if ((ret == WOLFSSL_SUCCESS) && (cm->crl == NULL) &&
(wolfSSL_CertManagerEnableCRL(cm, WOLFSSL_CRL_CHECK) !=
WOLFSSL_SUCCESS)) {
WOLFSSL_MSG("Enable CRL failed");
ret = WOLFSSL_FATAL_ERROR;
}
if (ret == WOLFSSL_SUCCESS) {
ret = ProcessFile(NULL, file, type, CRL_TYPE, NULL, 0, cm->crl, VERIFY);
}
return ret;
}
#endif
#endif
int wolfSSL_CertManagerEnableOCSP(WOLFSSL_CERT_MANAGER* cm, int options)
{
int ret = WOLFSSL_SUCCESS;
(void)options;
WOLFSSL_ENTER("wolfSSL_CertManagerEnableOCSP");
if (cm == NULL) {
ret = BAD_FUNC_ARG;
}
#ifndef HAVE_OCSP
if (ret == WOLFSSL_SUCCESS) {
ret = NOT_COMPILED_IN;
}
#else
if (ret == WOLFSSL_SUCCESS) {
if (cm->ocsp == NULL) {
cm->ocsp = (WOLFSSL_OCSP*)XMALLOC(sizeof(WOLFSSL_OCSP), cm->heap,
DYNAMIC_TYPE_OCSP);
if (cm->ocsp == NULL) {
ret = MEMORY_E;
}
if (ret == WOLFSSL_SUCCESS) {
XMEMSET(cm->ocsp, 0, sizeof(WOLFSSL_OCSP));
if (InitOCSP(cm->ocsp, cm) != 0) {
WOLFSSL_MSG("Init OCSP failed");
FreeOCSP(cm->ocsp, 1);
cm->ocsp = NULL;
ret = 0;
}
}
}
}
if (ret == WOLFSSL_SUCCESS) {
cm->ocspEnabled = 1;
if (options & WOLFSSL_OCSP_URL_OVERRIDE) {
cm->ocspUseOverrideURL = 1;
}
cm->ocspSendNonce = (options & WOLFSSL_OCSP_NO_NONCE) !=
WOLFSSL_OCSP_NO_NONCE;
if (options & WOLFSSL_OCSP_CHECKALL) {
cm->ocspCheckAll = 1;
}
#ifndef WOLFSSL_USER_IO
cm->ocspIOCb = EmbedOcspLookup;
cm->ocspRespFreeCb = EmbedOcspRespFree;
cm->ocspIOCtx = cm->heap;
#endif
}
#endif
return ret;
}
int wolfSSL_CertManagerDisableOCSP(WOLFSSL_CERT_MANAGER* cm)
{
int ret = WOLFSSL_SUCCESS;
WOLFSSL_ENTER("wolfSSL_CertManagerDisableOCSP");
if (cm == NULL) {
ret = BAD_FUNC_ARG;
}
if (ret == WOLFSSL_SUCCESS) {
cm->ocspEnabled = 0;
}
return ret;
}
int wolfSSL_CertManagerEnableOCSPStapling(WOLFSSL_CERT_MANAGER* cm)
{
int ret = WOLFSSL_SUCCESS;
WOLFSSL_ENTER("wolfSSL_CertManagerEnableOCSPStapling");
if (cm == NULL) {
ret = BAD_FUNC_ARG;
}
#if !defined(HAVE_CERTIFICATE_STATUS_REQUEST) && \
!defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
if (ret == WOLFSSL_SUCCESS) {
ret = NOT_COMPILED_IN;
}
#else
#ifndef NO_WOLFSSL_SERVER
if (ret == WOLFSSL_SUCCESS) {
if (cm->ocsp_stapling == NULL) {
cm->ocsp_stapling = (WOLFSSL_OCSP*)XMALLOC(sizeof(WOLFSSL_OCSP),
cm->heap, DYNAMIC_TYPE_OCSP);
if (cm->ocsp_stapling == NULL) {
ret = MEMORY_E;
}
if (ret == WOLFSSL_SUCCESS) {
XMEMSET(cm->ocsp_stapling, 0, sizeof(WOLFSSL_OCSP));
if (InitOCSP(cm->ocsp_stapling, cm) != 0) {
WOLFSSL_MSG("Init OCSP failed");
FreeOCSP(cm->ocsp_stapling, 1);
cm->ocsp_stapling = NULL;
ret = 0;
}
}
}
}
#ifndef WOLFSSL_USER_IO
if (ret == WOLFSSL_SUCCESS) {
cm->ocspIOCb = EmbedOcspLookup;
cm->ocspRespFreeCb = EmbedOcspRespFree;
cm->ocspIOCtx = cm->heap;
}
#endif
#endif
if (ret == WOLFSSL_SUCCESS) {
cm->ocspStaplingEnabled = 1;
}
#endif
return ret;
}
int wolfSSL_CertManagerDisableOCSPStapling(WOLFSSL_CERT_MANAGER* cm)
{
int ret = WOLFSSL_SUCCESS;
WOLFSSL_ENTER("wolfSSL_CertManagerDisableOCSPStapling");
if (cm == NULL) {
ret = BAD_FUNC_ARG;
}
if (ret == WOLFSSL_SUCCESS) {
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \
defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
cm->ocspStaplingEnabled = 0;
#else
ret = NOT_COMPILED_IN;
#endif
}
return ret;
}
int wolfSSL_CertManagerEnableOCSPMustStaple(WOLFSSL_CERT_MANAGER* cm)
{
int ret = WOLFSSL_SUCCESS;
WOLFSSL_ENTER("wolfSSL_CertManagerEnableOCSPMustStaple");
if (cm == NULL) {
ret = BAD_FUNC_ARG;
}
if (ret == WOLFSSL_SUCCESS) {
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \
defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
#ifndef NO_WOLFSSL_CLIENT
cm->ocspMustStaple = 1;
#endif
#else
ret = NOT_COMPILED_IN;
#endif
}
return ret;
}
int wolfSSL_CertManagerDisableOCSPMustStaple(WOLFSSL_CERT_MANAGER* cm)
{
int ret = WOLFSSL_SUCCESS;
WOLFSSL_ENTER("wolfSSL_CertManagerDisableOCSPMustStaple");
if (cm == NULL) {
ret = BAD_FUNC_ARG;
}
if (ret == WOLFSSL_SUCCESS) {
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \
defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
#ifndef NO_WOLFSSL_CLIENT
cm->ocspMustStaple = 0;
#endif
#else
ret = NOT_COMPILED_IN;
#endif
}
return ret;
}
#ifdef HAVE_OCSP
int wolfSSL_CertManagerCheckOCSP(WOLFSSL_CERT_MANAGER* cm,
const unsigned char* der, int sz)
{
int ret = 0;
WC_DECLARE_VAR(cert, DecodedCert, 1, 0);
WOLFSSL_ENTER("wolfSSL_CertManagerCheckOCSP");
if ((cm == NULL) || (der == NULL) || (sz <= 0)) {
ret = BAD_FUNC_ARG;
}
if ((ret == 0) && cm->ocspEnabled) {
WC_ALLOC_VAR_EX(cert, DecodedCert, 1, cm->heap, DYNAMIC_TYPE_DCERT,
ret=MEMORY_E);
if (WC_VAR_OK(cert))
{
InitDecodedCert(cert, der, (word32)sz, NULL);
ret = ParseCertRelative(cert, CERT_TYPE, VERIFY_OCSP, cm, NULL);
if (ret != 0) {
WOLFSSL_MSG("ParseCert failed");
}
else if ((ret = CheckCertOCSP(cm->ocsp, cert)) != 0) {
WOLFSSL_MSG("CheckCertOCSP failed");
}
FreeDecodedCert(cert);
WC_FREE_VAR_EX(cert, cm->heap, DYNAMIC_TYPE_DCERT);
}
}
return (ret == 0) ? WOLFSSL_SUCCESS : ret;
}
int wolfSSL_CertManagerCheckOCSPResponse(WOLFSSL_CERT_MANAGER *cm,
byte *response, int responseSz, buffer *responseBuffer,
CertStatus *status, OcspEntry *entry, OcspRequest *ocspRequest)
{
int ret = 0;
WOLFSSL_ENTER("wolfSSL_CertManagerCheckOCSPResponse");
if ((cm == NULL) || (response == NULL)) {
ret = BAD_FUNC_ARG;
}
if ((ret == 0) && cm->ocspEnabled) {
ret = CheckOcspResponse(cm->ocsp, response, responseSz, responseBuffer,
status, entry, ocspRequest, NULL);
}
return (ret == 0) ? WOLFSSL_SUCCESS : ret;
}
int wolfSSL_CertManagerSetOCSPOverrideURL(WOLFSSL_CERT_MANAGER* cm,
const char* url)
{
int ret = WOLFSSL_SUCCESS;
WOLFSSL_ENTER("wolfSSL_CertManagerSetOCSPOverrideURL");
if (cm == NULL) {
ret = BAD_FUNC_ARG;
}
if (ret == WOLFSSL_SUCCESS) {
XFREE(cm->ocspOverrideURL, cm->heap, DYNAMIC_TYPE_URL);
if (url != NULL) {
int urlSz = (int)XSTRLEN(url) + 1;
cm->ocspOverrideURL = (char*)XMALLOC((size_t)urlSz, cm->heap,
DYNAMIC_TYPE_URL);
if (cm->ocspOverrideURL == NULL) {
ret = MEMORY_E;
}
if (ret == WOLFSSL_SUCCESS) {
XMEMCPY(cm->ocspOverrideURL, url, (size_t)urlSz);
}
}
else {
cm->ocspOverrideURL = NULL;
}
}
return ret;
}
int wolfSSL_CertManagerSetOCSP_Cb(WOLFSSL_CERT_MANAGER* cm, CbOCSPIO ioCb,
CbOCSPRespFree respFreeCb, void* ioCbCtx)
{
int ret = WOLFSSL_SUCCESS;
WOLFSSL_ENTER("wolfSSL_CertManagerSetOCSP_Cb");
if (cm == NULL) {
ret = BAD_FUNC_ARG;
}
if (ret == WOLFSSL_SUCCESS) {
cm->ocspIOCb = ioCb;
cm->ocspRespFreeCb = respFreeCb;
cm->ocspIOCtx = ioCbCtx;
}
return ret;
}
#endif
static WC_INLINE word32 HashSigner(const byte* hash)
{
return MakeWordFromHash(hash) % CA_TABLE_SIZE;
}
int AlreadySigner(WOLFSSL_CERT_MANAGER* cm, byte* hash)
{
Signer* signers;
int ret = 0;
word32 row;
if (cm == NULL || hash == NULL) {
return ret;
}
row = HashSigner(hash);
if (wc_LockMutex(&cm->caLock) != 0) {
return ret;
}
signers = cm->caTable[row];
while (signers) {
byte* subjectHash;
#ifndef NO_SKID
subjectHash = signers->subjectKeyIdHash;
#else
subjectHash = signers->subjectNameHash;
#endif
if (XMEMCMP(hash, subjectHash, SIGNER_DIGEST_SIZE) == 0) {
ret = 1;
break;
}
signers = signers->next;
}
wc_UnLockMutex(&cm->caLock);
return ret;
}
#ifdef WOLFSSL_TRUST_PEER_CERT
static WC_INLINE word32 TrustedPeerHashSigner(const byte* hash)
{
return MakeWordFromHash(hash) % TP_TABLE_SIZE;
}
int AlreadyTrustedPeer(WOLFSSL_CERT_MANAGER* cm, DecodedCert* cert)
{
TrustedPeerCert* tp;
int ret = 0;
word32 row = TrustedPeerHashSigner(cert->subjectHash);
if (wc_LockMutex(&cm->tpLock) != 0)
return ret;
tp = cm->tpTable[row];
while (tp) {
if ((XMEMCMP(cert->subjectHash, tp->subjectNameHash,
SIGNER_DIGEST_SIZE) == 0)
#ifndef WOLFSSL_NO_ISSUERHASH_TDPEER
&& (XMEMCMP(cert->issuerHash, tp->issuerHash,
SIGNER_DIGEST_SIZE) == 0)
#endif
)
ret = 1;
#ifndef NO_SKID
if (cert->extSubjKeyIdSet) {
if (ret == 1 && XMEMCMP(cert->extSubjKeyId, tp->subjectKeyIdHash,
SIGNER_DIGEST_SIZE) != 0)
ret = 0;
}
#endif
if (ret == 1)
break;
tp = tp->next;
}
wc_UnLockMutex(&cm->tpLock);
return ret;
}
TrustedPeerCert* GetTrustedPeer(void* vp, DecodedCert* cert)
{
WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp;
TrustedPeerCert* ret = NULL;
TrustedPeerCert* tp = NULL;
word32 row;
if (cm == NULL || cert == NULL)
return NULL;
row = TrustedPeerHashSigner(cert->subjectHash);
if (wc_LockMutex(&cm->tpLock) != 0)
return ret;
tp = cm->tpTable[row];
while (tp) {
if ((XMEMCMP(cert->subjectHash, tp->subjectNameHash,
SIGNER_DIGEST_SIZE) == 0)
#ifndef WOLFSSL_NO_ISSUERHASH_TDPEER
&& (XMEMCMP(cert->issuerHash, tp->issuerHash,
SIGNER_DIGEST_SIZE) == 0)
#endif
)
ret = tp;
#ifndef NO_SKID
if (cert->extSubjKeyIdSet) {
if (ret != NULL && XMEMCMP(cert->extSubjKeyId, tp->subjectKeyIdHash,
SIGNER_DIGEST_SIZE) != 0)
ret = NULL;
}
#endif
if (ret != NULL)
break;
tp = tp->next;
}
wc_UnLockMutex(&cm->tpLock);
return ret;
}
int MatchTrustedPeer(TrustedPeerCert* tp, DecodedCert* cert)
{
if (tp == NULL || cert == NULL)
return BAD_FUNC_ARG;
if (tp->sigLen == cert->sigLength) {
if (XMEMCMP(tp->sig, cert->signature, cert->sigLength)) {
return WOLFSSL_FAILURE;
}
}
else {
return WOLFSSL_FAILURE;
}
return WOLFSSL_SUCCESS;
}
#endif
Signer* GetCA(void* vp, byte* hash)
{
WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp;
Signer* ret = NULL;
Signer* signers;
word32 row = 0;
if (cm == NULL || hash == NULL)
return NULL;
row = HashSigner(hash);
if (wc_LockMutex(&cm->caLock) != 0)
return ret;
signers = cm->caTable[row];
while (signers) {
byte* subjectHash;
#ifndef NO_SKID
subjectHash = signers->subjectKeyIdHash;
#else
subjectHash = signers->subjectNameHash;
#endif
if (XMEMCMP(hash, subjectHash, SIGNER_DIGEST_SIZE) == 0) {
ret = signers;
break;
}
signers = signers->next;
}
wc_UnLockMutex(&cm->caLock);
return ret;
}
#if defined(HAVE_OCSP)
Signer* GetCAByKeyHash(void* vp, const byte* keyHash)
{
WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp;
Signer* ret = NULL;
Signer* signers;
int row;
if (cm == NULL || keyHash == NULL)
return NULL;
ret = GetCA(vp, (byte*)keyHash);
if (ret != NULL && XMEMCMP(ret->subjectKeyHash, keyHash, KEYID_SIZE) == 0) {
return ret;
}
if (wc_LockMutex(&cm->caLock) != 0)
return NULL;
for (row = 0; row < CA_TABLE_SIZE && ret == NULL; row++) {
for (signers = cm->caTable[row]; signers != NULL;
signers = signers->next) {
if (XMEMCMP(signers->subjectKeyHash, keyHash, KEYID_SIZE) == 0) {
ret = signers;
break;
}
}
}
wc_UnLockMutex(&cm->caLock);
return ret;
}
#endif
#ifdef WOLFSSL_AKID_NAME
Signer* GetCAByAKID(void* vp, const byte* issuer, word32 issuerSz,
const byte* serial, word32 serialSz)
{
WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp;
Signer* ret = NULL;
Signer* signers;
byte nameHash[SIGNER_DIGEST_SIZE];
byte serialHash[SIGNER_DIGEST_SIZE];
word32 row;
if (cm == NULL || issuer == NULL || issuerSz == 0 ||
serial == NULL || serialSz == 0)
return NULL;
if (CalcHashId(issuer, issuerSz, nameHash) != 0 ||
CalcHashId(serial, serialSz, serialHash) != 0)
return NULL;
if (wc_LockMutex(&cm->caLock) != 0)
return ret;
for (row = 0; row < CA_TABLE_SIZE && ret == NULL; row++) {
for (signers = cm->caTable[row]; signers != NULL;
signers = signers->next) {
if (XMEMCMP(signers->issuerNameHash, nameHash, SIGNER_DIGEST_SIZE)
== 0 && XMEMCMP(signers->serialHash, serialHash,
SIGNER_DIGEST_SIZE) == 0) {
ret = signers;
break;
}
}
}
wc_UnLockMutex(&cm->caLock);
return ret;
}
#endif
#ifndef NO_SKID
Signer* GetCAByName(void* vp, byte* hash)
{
WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp;
Signer* ret = NULL;
Signer* signers;
word32 row;
if (cm == NULL)
return NULL;
if (wc_LockMutex(&cm->caLock) != 0)
return ret;
for (row = 0; row < CA_TABLE_SIZE && ret == NULL; row++) {
signers = cm->caTable[row];
while (signers && ret == NULL) {
if (XMEMCMP(hash, signers->subjectNameHash,
SIGNER_DIGEST_SIZE) == 0) {
ret = signers;
}
signers = signers->next;
}
}
wc_UnLockMutex(&cm->caLock);
return ret;
}
#endif
#ifdef WOLFSSL_TRUST_PEER_CERT
int AddTrustedPeer(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int verify)
{
int ret = 0;
int row = 0;
TrustedPeerCert* peerCert;
DecodedCert* cert;
DerBuffer* der = *pDer;
WOLFSSL_MSG("Adding a Trusted Peer Cert");
cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), cm->heap,
DYNAMIC_TYPE_DCERT);
if (cert == NULL) {
FreeDer(&der);
return MEMORY_E;
}
InitDecodedCert(cert, der->buffer, der->length, cm->heap);
if ((ret = ParseCert(cert, TRUSTED_PEER_TYPE, verify, cm)) != 0) {
FreeDecodedCert(cert);
XFREE(cert, NULL, DYNAMIC_TYPE_DCERT);
FreeDer(&der);
return ret;
}
WOLFSSL_MSG("\tParsed new trusted peer cert");
peerCert = (TrustedPeerCert*)XMALLOC(sizeof(TrustedPeerCert), cm->heap,
DYNAMIC_TYPE_CERT);
if (peerCert == NULL) {
FreeDecodedCert(cert);
XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT);
FreeDer(&der);
return MEMORY_E;
}
XMEMSET(peerCert, 0, sizeof(TrustedPeerCert));
#ifndef IGNORE_NAME_CONSTRAINTS
if (peerCert->permittedNames)
FreeNameSubtrees(peerCert->permittedNames, cm->heap);
if (peerCert->excludedNames)
FreeNameSubtrees(peerCert->excludedNames, cm->heap);
#endif
if (AlreadyTrustedPeer(cm, cert)) {
WOLFSSL_MSG("\tAlready have this CA, not adding again");
FreeTrustedPeer(peerCert, cm->heap);
(void)ret;
}
else {
peerCert->sigLen = cert->sigLength;
peerCert->sig = (byte *)XMALLOC(cert->sigLength, cm->heap,
DYNAMIC_TYPE_SIGNATURE);
if (peerCert->sig == NULL) {
FreeDecodedCert(cert);
XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT);
FreeTrustedPeer(peerCert, cm->heap);
FreeDer(&der);
return MEMORY_E;
}
XMEMCPY(peerCert->sig, cert->signature, cert->sigLength);
peerCert->nameLen = cert->subjectCNLen;
peerCert->name = cert->subjectCN;
#ifndef IGNORE_NAME_CONSTRAINTS
peerCert->permittedNames = cert->permittedNames;
peerCert->excludedNames = cert->excludedNames;
#endif
#ifndef NO_SKID
XMEMCPY(peerCert->subjectKeyIdHash, cert->extSubjKeyId,
SIGNER_DIGEST_SIZE);
#endif
XMEMCPY(peerCert->subjectNameHash, cert->subjectHash,
SIGNER_DIGEST_SIZE);
#ifndef WOLFSSL_NO_ISSUERHASH_TDPEER
XMEMCPY(peerCert->issuerHash, cert->issuerHash,
SIGNER_DIGEST_SIZE);
#endif
peerCert->next = NULL;
cert->subjectCN = 0;
#ifndef IGNORE_NAME_CONSTRAINTS
cert->permittedNames = NULL;
cert->excludedNames = NULL;
#endif
row = (int)TrustedPeerHashSigner(peerCert->subjectNameHash);
if (wc_LockMutex(&cm->tpLock) == 0) {
peerCert->next = cm->tpTable[row];
cm->tpTable[row] = peerCert;
wc_UnLockMutex(&cm->tpLock);
}
else {
WOLFSSL_MSG("\tTrusted Peer Cert Mutex Lock failed");
FreeDecodedCert(cert);
XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT);
FreeTrustedPeer(peerCert, cm->heap);
FreeDer(&der);
return BAD_MUTEX_E;
}
}
WOLFSSL_MSG("\tFreeing parsed trusted peer cert");
FreeDecodedCert(cert);
XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT);
WOLFSSL_MSG("\tFreeing der trusted peer cert");
FreeDer(&der);
WOLFSSL_MSG("\t\tOK Freeing der trusted peer cert");
WOLFSSL_LEAVE("AddTrustedPeer", ret);
return WOLFSSL_SUCCESS;
}
#endif
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;
}
int AddCA(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int type, int verify)
{
int ret = 0;
Signer* signer = NULL;
word32 row = 0;
byte* subjectHash = NULL;
WC_DECLARE_VAR(cert, DecodedCert, 1, 0);
DerBuffer* der = *pDer;
WOLFSSL_MSG_CERT_LOG("Adding a CA");
if (cm == NULL) {
FreeDer(pDer);
return BAD_FUNC_ARG;
}
#ifdef WOLFSSL_SMALL_STACK
cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, DYNAMIC_TYPE_DCERT);
if (cert == NULL) {
FreeDer(pDer);
return MEMORY_E;
}
#endif
InitDecodedCert(cert, der->buffer, der->length, cm->heap);
#ifdef WC_ASN_UNKNOWN_EXT_CB
if (cm->unknownExtCallback != NULL) {
wc_SetUnknownExtCallback(cert, cm->unknownExtCallback);
}
#endif
WOLFSSL_MSG_CERT("\tParsing new CA");
ret = ParseCert(cert, CA_TYPE, verify, cm);
WOLFSSL_MSG("\tParsed new CA");
#ifdef WOLFSSL_DEBUG_CERTS
{
const char* err_msg;
if (ret == 0) {
WOLFSSL_MSG_CERT_EX(WOLFSSL_MSG_CERT_INDENT "issuer: '%s'",
cert->issuer);
WOLFSSL_MSG_CERT_EX(WOLFSSL_MSG_CERT_INDENT "subject: '%s'",
cert->subject);
}
else {
WOLFSSL_MSG_CERT(
WOLFSSL_MSG_CERT_INDENT "Failed during parse of new CA");
err_msg = wc_GetErrorString(ret);
WOLFSSL_MSG_CERT_EX(WOLFSSL_MSG_CERT_INDENT "error ret: %d; %s",
ret, err_msg);
}
}
#endif
#ifndef NO_SKID
subjectHash = cert->extSubjKeyId;
#else
subjectHash = cert->subjectHash;
#endif
if (verify && (ret == 0 )) {
switch (cert->keyOID) {
#ifndef NO_RSA
#ifdef WC_RSA_PSS
case RSAPSSk:
#endif
case RSAk:
if (cm->minRsaKeySz < 0 ||
cert->pubKeySize < (word16)cm->minRsaKeySz) {
ret = RSA_KEY_SIZE_E;
WOLFSSL_MSG_CERT_LOG("\tCA RSA key size error");
WOLFSSL_MSG_CERT_EX("\tCA RSA pubKeySize = %d; "
"minRsaKeySz = %d",
cert->pubKeySize, cm->minRsaKeySz);
}
break;
#endif
#ifdef HAVE_ECC
case ECDSAk:
if (cm->minEccKeySz < 0 ||
cert->pubKeySize < (word16)cm->minEccKeySz) {
ret = ECC_KEY_SIZE_E;
WOLFSSL_MSG_CERT_LOG("\tCA ECC key size error");
WOLFSSL_MSG_CERT_EX("\tCA ECC pubKeySize = %d; "
"minEccKeySz = %d",
cert->pubKeySize, cm->minEccKeySz);
}
break;
#endif
#ifdef HAVE_ED25519
case ED25519k:
if (cm->minEccKeySz < 0 ||
ED25519_KEY_SIZE < (word16)cm->minEccKeySz) {
ret = ECC_KEY_SIZE_E;
WOLFSSL_MSG("\tCA ECC key size error");
}
break;
#endif
#ifdef HAVE_ED448
case ED448k:
if (cm->minEccKeySz < 0 ||
ED448_KEY_SIZE < (word16)cm->minEccKeySz) {
ret = ECC_KEY_SIZE_E;
WOLFSSL_MSG("\tCA ECC key size error");
}
break;
#endif
#if defined(HAVE_FALCON)
case FALCON_LEVEL1k:
if (cm->minFalconKeySz < 0 ||
FALCON_LEVEL1_KEY_SIZE < (word16)cm->minFalconKeySz) {
ret = FALCON_KEY_SIZE_E;
WOLFSSL_MSG("\tCA Falcon level 1 key size error");
}
break;
case FALCON_LEVEL5k:
if (cm->minFalconKeySz < 0 ||
FALCON_LEVEL5_KEY_SIZE < (word16)cm->minFalconKeySz) {
ret = FALCON_KEY_SIZE_E;
WOLFSSL_MSG("\tCA Falcon level 5 key size error");
}
break;
#endif
#if defined(HAVE_DILITHIUM)
#ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT
case DILITHIUM_LEVEL2k:
if (cm->minDilithiumKeySz < 0 ||
DILITHIUM_LEVEL2_KEY_SIZE < (word16)cm->minDilithiumKeySz) {
ret = DILITHIUM_KEY_SIZE_E;
WOLFSSL_MSG("\tCA Dilithium level 2 key size error");
}
break;
case DILITHIUM_LEVEL3k:
if (cm->minDilithiumKeySz < 0 ||
DILITHIUM_LEVEL3_KEY_SIZE < (word16)cm->minDilithiumKeySz) {
ret = DILITHIUM_KEY_SIZE_E;
WOLFSSL_MSG("\tCA Dilithium level 3 key size error");
}
break;
case DILITHIUM_LEVEL5k:
if (cm->minDilithiumKeySz < 0 ||
DILITHIUM_LEVEL5_KEY_SIZE < (word16)cm->minDilithiumKeySz) {
ret = DILITHIUM_KEY_SIZE_E;
WOLFSSL_MSG("\tCA Dilithium level 5 key size error");
}
break;
#endif
case ML_DSA_LEVEL2k:
if (cm->minDilithiumKeySz < 0 ||
ML_DSA_LEVEL2_KEY_SIZE < (word16)cm->minDilithiumKeySz) {
ret = DILITHIUM_KEY_SIZE_E;
WOLFSSL_MSG("\tCA Dilithium level 2 key size error");
}
break;
case ML_DSA_LEVEL3k:
if (cm->minDilithiumKeySz < 0 ||
ML_DSA_LEVEL3_KEY_SIZE < (word16)cm->minDilithiumKeySz) {
ret = DILITHIUM_KEY_SIZE_E;
WOLFSSL_MSG("\tCA Dilithium level 3 key size error");
}
break;
case ML_DSA_LEVEL5k:
if (cm->minDilithiumKeySz < 0 ||
ML_DSA_LEVEL5_KEY_SIZE < (word16)cm->minDilithiumKeySz) {
ret = DILITHIUM_KEY_SIZE_E;
WOLFSSL_MSG("\tCA Dilithium level 5 key size error");
}
break;
#endif
default:
WOLFSSL_MSG("\tNo key size check done on CA");
break;
}
}
if (ret == 0 && cert->isCA == 0 && type != WOLFSSL_USER_CA &&
type != WOLFSSL_TEMP_CA) {
WOLFSSL_MSG("\tCan't add as CA if not actually one");
ret = NOT_CA_ERROR;
}
#ifndef ALLOW_INVALID_CERTSIGN
else if (ret == 0 && cert->isCA == 1 && type != WOLFSSL_USER_CA &&
type != WOLFSSL_TEMP_CA && !cert->selfSigned &&
(cert->extKeyUsage & KEYUSE_KEY_CERT_SIGN) == 0) {
WOLFSSL_MSG("\tDoesn't have key usage certificate signing");
ret = NOT_CA_ERROR;
}
#endif
else if (ret == 0 && AlreadySigner(cm, subjectHash)) {
WOLFSSL_MSG("\tAlready have this CA, not adding again");
(void)ret;
}
else if (ret == 0) {
signer = MakeSigner(cm->heap);
if (!signer)
ret = MEMORY_ERROR;
}
if (ret == 0 && signer != NULL) {
ret = FillSigner(signer, cert, type, der);
if (ret == 0){
#ifndef NO_SKID
row = HashSigner(signer->subjectKeyIdHash);
#else
row = HashSigner(signer->subjectNameHash);
#endif
}
#if defined(WOLFSSL_RENESAS_TSIP_TLS) || defined(WOLFSSL_RENESAS_FSPSM_TLS)
if ( ret == 0 && signer != NULL ) {
signer->cm_idx = row;
if (type == WOLFSSL_USER_CA) {
if ((ret = wc_Renesas_cmn_RootCertVerify(cert->source,
cert->maxIdx,
cert->sigCtx.CertAtt.pubkey_n_start,
cert->sigCtx.CertAtt.pubkey_n_len - 1,
cert->sigCtx.CertAtt.pubkey_e_start,
cert->sigCtx.CertAtt.pubkey_e_len - 1,
row))
< 0)
WOLFSSL_MSG("Renesas_RootCertVerify() failed");
else
WOLFSSL_MSG("Renesas_RootCertVerify() succeed or skipped");
}
}
#endif
if (ret == 0 && wc_LockMutex(&cm->caLock) == 0) {
signer->next = cm->caTable[row];
cm->caTable[row] = signer;
wc_UnLockMutex(&cm->caLock);
if (cm->caCacheCallback)
cm->caCacheCallback(der->buffer, (int)der->length, type);
}
else {
WOLFSSL_MSG("\tCA Mutex Lock failed");
ret = BAD_MUTEX_E;
}
}
WOLFSSL_MSG("\tFreeing Parsed CA");
FreeDecodedCert(cert);
if (ret != 0 && signer != NULL)
FreeSigner(signer, cm->heap);
WC_FREE_VAR_EX(cert, NULL, DYNAMIC_TYPE_DCERT);
WOLFSSL_MSG("\tFreeing der CA");
FreeDer(pDer);
WOLFSSL_MSG("\t\tOK Freeing der CA");
WOLFSSL_LEAVE("AddCA", ret);
return ret == 0 ? WOLFSSL_SUCCESS : ret;
}
int RemoveCA(WOLFSSL_CERT_MANAGER* cm, byte* hash, int type)
{
Signer* current;
Signer** prev;
int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE);
word32 row;
WOLFSSL_MSG("Removing a CA");
if (cm == NULL || hash == NULL) {
return BAD_FUNC_ARG;
}
row = HashSigner(hash);
if (wc_LockMutex(&cm->caLock) != 0) {
return BAD_MUTEX_E;
}
current = cm->caTable[row];
prev = &cm->caTable[row];
while (current) {
byte* subjectHash;
#ifndef NO_SKID
subjectHash = current->subjectKeyIdHash;
#else
subjectHash = current->subjectNameHash;
#endif
if ((current->type == type) &&
(XMEMCMP(hash, subjectHash, SIGNER_DIGEST_SIZE) == 0)) {
*prev = current->next;
FreeSigner(current, cm->heap);
ret = WOLFSSL_SUCCESS;
break;
}
prev = ¤t->next;
current = current->next;
}
wc_UnLockMutex(&cm->caLock);
WOLFSSL_LEAVE("RemoveCA", ret);
return ret;
}
int SetCAType(WOLFSSL_CERT_MANAGER* cm, byte* hash, int type)
{
Signer* current;
int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE);
word32 row;
WOLFSSL_MSG_EX("Setting CA to type %d", type);
if (cm == NULL || hash == NULL ||
type < WOLFSSL_USER_CA || type > WOLFSSL_USER_INTER) {
return ret;
}
row = HashSigner(hash);
if (wc_LockMutex(&cm->caLock) != 0) {
return ret;
}
current = cm->caTable[row];
while (current) {
byte* subjectHash;
#ifndef NO_SKID
subjectHash = current->subjectKeyIdHash;
#else
subjectHash = current->subjectNameHash;
#endif
if (XMEMCMP(hash, subjectHash, SIGNER_DIGEST_SIZE) == 0) {
current->type = (byte)type;
ret = WOLFSSL_SUCCESS;
break;
}
current = current->next;
}
wc_UnLockMutex(&cm->caLock);
WOLFSSL_LEAVE("SetCAType", ret);
return ret;
}
#endif
#endif