/* ssl_certman.c * * Copyright (C) 2006-2023 wolfSSL Inc. * * This file is part of wolfSSL. * * wolfSSL is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * wolfSSL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ #ifdef HAVE_CONFIG_H #include #endif #include #include #if !defined(WOLFSSL_SSL_CERTMAN_INCLUDED) #ifndef WOLFSSL_IGNORE_FILE_WARN #warning ssl_certman.c does not need to be compiled separately from ssl.c #endif #else #ifndef NO_CERTS /* Pick an available TLS method. * * Used when creating temporary WOLFSSL_CTX. * * @return A TLS method on success. * @return NULL when no TLS method built into wolfSSL. */ static WC_INLINE WOLFSSL_METHOD* cm_pick_method(void) { #ifndef NO_WOLFSSL_CLIENT #if !defined(NO_OLD_TLS) && defined(WOLFSSL_ALLOW_SSLV3) return wolfSSLv3_client_method(); #elif !defined(NO_OLD_TLS) && defined(WOLFSSL_ALLOW_TLSV10) return wolfTLSv1_client_method(); #elif !defined(NO_OLD_TLS) return wolfTLSv1_1_client_method(); #elif !defined(WOLFSSL_NO_TLS12) return wolfTLSv1_2_client_method(); #elif defined(WOLFSSL_TLS13) return wolfTLSv1_3_client_method(); #else return NULL; #endif #elif !defined(NO_WOLFSSL_SERVER) #if !defined(NO_OLD_TLS) && defined(WOLFSSL_ALLOW_SSLV3) return wolfSSLv3_server_method(); #elif !defined(NO_OLD_TLS) && defined(WOLFSSL_ALLOW_TLSV10) return wolfTLSv1_server_method(); #elif !defined(NO_OLD_TLS) return wolfTLSv1_1_server_method(); #elif !defined(WOLFSSL_NO_TLS12) return wolfTLSv1_2_server_method(); #elif defined(WOLFSSL_TLS13) return wolfTLSv1_3_server_method(); #else return NULL; #endif #else return NULL; #endif } /* Create a new certificate manager with a heap hint. * * @param [in] heap Heap hint. * @return Certificate manager object on success. * @return NULL on failure. */ WOLFSSL_CERT_MANAGER* wolfSSL_CertManagerNew_ex(void* heap) { int err = 0; WOLFSSL_CERT_MANAGER* cm; WOLFSSL_ENTER("wolfSSL_CertManagerNew"); /* Allocate memory for certificate manager. */ cm = (WOLFSSL_CERT_MANAGER*)XMALLOC(sizeof(WOLFSSL_CERT_MANAGER), heap, DYNAMIC_TYPE_CERT_MANAGER); if (cm == NULL) { err = 1; } if (!err) { /* Reset all fields. */ XMEMSET(cm, 0, sizeof(WOLFSSL_CERT_MANAGER)); /* Create a mutex for use when modify table of stored CAs. */ if (wc_InitMutex(&cm->caLock) != 0) { WOLFSSL_MSG("Bad mutex init"); err = 1; } } if (!err) { /* Initialize reference count. */ 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 /* Create a mutex for use when modify table of trusted peers. */ if ((!err) && (wc_InitMutex(&cm->tpLock) != 0)) { WOLFSSL_MSG("Bad mutex init"); err = 1; } #endif if (!err) { /* Set default minimum key sizes allowed. */ #ifndef NO_RSA cm->minRsaKeySz = MIN_RSAKEY_SZ; #endif #ifdef HAVE_ECC cm->minEccKeySz = MIN_ECCKEY_SZ; #endif #ifdef HAVE_PQC #ifdef HAVE_FALCON cm->minFalconKeySz = MIN_FALCONKEY_SZ; #endif /* HAVE_FALCON */ #ifdef HAVE_DILITHIUM cm->minDilithiumKeySz = MIN_DILITHIUMKEY_SZ; #endif /* HAVE_DILITHIUM */ #endif /* HAVE_PQC */ /* Set heap hint to use in certificate manager operations. */ cm->heap = heap; } /* Dispose of certificate manager on error. */ if (err && (cm != NULL)) { wolfSSL_CertManagerFree(cm); cm = NULL; } return cm; } /* Create a new certificate manager. * * @return Certificate manager object on success. * @return NULL on failure. */ WOLFSSL_CERT_MANAGER* wolfSSL_CertManagerNew(void) { /* No heap hint. */ return wolfSSL_CertManagerNew_ex(NULL); } /* Dispose of certificate manager. * * @param [in, out] cm Certificate manager. */ void wolfSSL_CertManagerFree(WOLFSSL_CERT_MANAGER* cm) { WOLFSSL_ENTER("wolfSSL_CertManagerFree"); /* Validate parameter. */ if (cm != NULL) { int doFree = 0; int ret; /* Decrement reference count and check if value is 0. */ 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 /* Dispose of CRL handler. */ if (cm->crl != NULL) { /* Dispose of CRL object - indicating dynamically allocated. */ FreeCRL(cm->crl, 1); } #endif #ifdef HAVE_OCSP /* Dispose of OCSP handler. */ if (cm->ocsp != NULL) { FreeOCSP(cm->ocsp, 1); } /* Dispose of URL. */ XFREE(cm->ocspOverrideURL, cm->heap, DYNAMIC_TYPE_URL); #if !defined(NO_WOLFSSL_SERVER) && \ (defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \ defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)) /* Dispose of OCSP stapling handler. */ if (cm->ocsp_stapling) { FreeOCSP(cm->ocsp_stapling, 1); } #endif #endif /* HAVE_OCSP */ /* Dispose of CA table and mutex. */ FreeSignerTable(cm->caTable, CA_TABLE_SIZE, cm->heap); wc_FreeMutex(&cm->caLock); #ifdef WOLFSSL_TRUST_PEER_CERT /* Dispose of trusted peer table and mutex. */ FreeTrustedPeerTable(cm->tpTable, TP_TABLE_SIZE, cm->heap); wc_FreeMutex(&cm->tpLock); #endif /* Dispose of reference count. */ wolfSSL_RefFree(&cm->ref); /* Dispose of certificate manager memory. */ XFREE(cm, cm->heap, DYNAMIC_TYPE_CERT_MANAGER); } } } /* Increase reference count on certificate manager. * * @param [in, out] cm Certificate manager. * @return WOLFSSL_SUCCESS on success. * @return 0 when cm is NULL or locking mutex fails. */ int wolfSSL_CertManager_up_ref(WOLFSSL_CERT_MANAGER* cm) { int ret = WOLFSSL_SUCCESS; /* Validate parameter. */ if (cm == NULL) { ret = 0; } if (ret == WOLFSSL_SUCCESS) { int err; /* Increment reference. */ 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; /* Iterate once to get the number of certs, for memory allocation * purposes. */ for (row = 0; row < CA_TABLE_SIZE; row++) { /* Get signer information of CAs in a row. */ signers = cm->caTable[row]; /* Count each signer in row that has a DER certificate buffer. */ while ((signers != NULL) && (signers->derCert != NULL) && (signers->derCert->buffer != NULL)) { ++numCerts; signers = signers->next; } } /* Check we found certificates. */ if (numCerts == 0) { err = 1; } if (!err) { /* Allocate memory for pointers to each DER buffer. */ certBuffers = (DerBuffer**)XMALLOC( sizeof(DerBuffer*) * (size_t)numCerts, cm->heap, DYNAMIC_TYPE_TMP_BUFFER); if (certBuffers == NULL) { err = 1; } } if (!err) { /* Reset pointers. */ XMEMSET(certBuffers, 0, sizeof(DerBuffer*) * (size_t)numCerts); } /* Copy the certs locally so that we can release the caLock. If the lock * is held when wolfSSL_d2i_X509 is called, GetCA will also try to get * the lock, leading to deadlock. */ for (row = 0; (!err) && (row < CA_TABLE_SIZE); row++) { /* Get signer information of CAs in a row. */ signers = cm->caTable[row]; /* Copy each DER certificate buffer of signers in a row. */ while ((signers != NULL) && (signers->derCert != NULL) && (signers->derCert->buffer != NULL)) { /* Allocate memory to hold DER certificate buffer. */ int ret = AllocDer(&certBuffers[i], signers->derCert->length, CA_TYPE, cm->heap); if (ret < 0) { err = 1; break; } /* Copy buffer into array element. */ XMEMCPY(certBuffers[i]->buffer, signers->derCert->buffer, signers->derCert->length); certBuffers[i]->length = signers->derCert->length; /* Store in next index. */ ++i; /* Move on to next signer in row. */ signers = signers->next; } } *buffers = certBuffers; *cnt = numCerts; return err; } /* Retrieve stack of X509 certificates in a certificate manager (CM). * * @param [in] cm Certificate manager. * * @return Stack of X509 certs on success * @return NULL on failure. */ 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"); /* Validate parameter. */ if (cm == NULL) { err = 1; } if (!err) { /* Create an empty certificate stack to return. */ sk = wolfSSL_sk_X509_new_null(); if (sk == NULL) { err = 1; } } /* Lock CA table. */ if ((!err) && (wc_LockMutex(&cm->caLock) != 0)) { err = 1; } if (!err) { err = wolfssl_cm_get_certs_der(cm, &certBuffers, &numCerts); /* Release CA lock. */ wc_UnLockMutex(&cm->caLock); } /* Put each DER certificate buffer into a stack of WOLFSSL_X509 */ for (i = 0; (!err) && (i < numCerts); ++i) { const byte* derBuffer = NULL; WOLFSSL_X509* x509 = NULL; /* Get pointer to DER encoding of certificate. */ derBuffer = certBuffers[i]->buffer; /* Decode certificate. */ wolfSSL_d2i_X509(&x509, &derBuffer, (int)certBuffers[i]->length); if (x509 == NULL) { err = 1; } /* Decode certificate. */ if ((!err) && (wolfSSL_sk_X509_push(sk, x509) != WOLFSSL_SUCCESS)) { wolfSSL_X509_free(x509); err = 1; } } if (certBuffers != NULL) { /* Dispose of temporary cert storage (for access outside of lock). */ for (i = 0; i < numCerts && certBuffers[i] != NULL; ++i) { FreeDer(&certBuffers[i]); } XFREE(certBuffers, cm->heap, DYNAMIC_TYPE_TMP_BUFFER); } /* Dispose of stack of certificates on error. */ if (err && (sk != NULL)) { wolfSSL_sk_X509_pop_free(sk, NULL); sk = NULL; } return sk; } #endif /* WOLFSSL_SIGNER_DER_CERT */ #endif /* OPENSSL_EXTRA && !NO_FILESYSTEM */ /* Unload the CA signer table. * * @param [in] cm Certificate manager. * @return WOLFSSL_SUCCESS on success. * @return BAD_FUNC_ARG when cm is NULL. * @return BAD_MUTEX_E when locking fails. */ int wolfSSL_CertManagerUnloadCAs(WOLFSSL_CERT_MANAGER* cm) { int ret = WOLFSSL_SUCCESS; WOLFSSL_ENTER("wolfSSL_CertManagerUnloadCAs"); /* Validate parameter. */ if (cm == NULL) { ret = BAD_FUNC_ARG; } /* Lock CA table. */ if ((ret == WOLFSSL_SUCCESS) && (wc_LockMutex(&cm->caLock) != 0)) { ret = BAD_MUTEX_E; } if (ret == WOLFSSL_SUCCESS) { /* Dispose of CA table. */ FreeSignerTable(cm->caTable, CA_TABLE_SIZE, cm->heap); /* Unlock CA table. */ wc_UnLockMutex(&cm->caLock); } return ret; } #ifdef WOLFSSL_TRUST_PEER_CERT /* Unload the trusted peers table. * * @param [in] cm Certificate manager. * @return WOLFSSL_SUCCESS on success. * @return BAD_FUNC_ARG when cm is NULL. * @return BAD_MUTEX_E when locking fails. */ int wolfSSL_CertManagerUnload_trust_peers(WOLFSSL_CERT_MANAGER* cm) { int ret = WOLFSSL_SUCCESS; WOLFSSL_ENTER("wolfSSL_CertManagerUnload_trust_peers"); /* Validate parameter. */ if (cm == NULL) { ret = BAD_FUNC_ARG; } /* Lock trusted peers table. */ if ((ret == WOLFSSL_SUCCESS) && (wc_LockMutex(&cm->tpLock) != 0)) { ret = BAD_MUTEX_E; } if (ret == WOLFSSL_SUCCESS) { /* Dispose of trusted peers table. */ FreeTrustedPeerTable(cm->tpTable, TP_TABLE_SIZE, cm->heap); /* Unlock trusted peers table. */ wc_UnLockMutex(&cm->tpLock); } return ret; } #endif /* WOLFSSL_TRUST_PEER_CERT */ /* Load certificate/s from buffer with flags. * * @param [in] cm Certificate manager. * @param [in] buff Buffer holding encoding of certificate. * @param [in] sz Length in bytes of data in buffer. * @param [in] format Format of encoding. Valid values: * WOLFSSL_FILETYPE_ASN1, WOLFSSL_FILETYPE_PEM. * @param [in] userChain Indicates buffer holds chain of certificates. * @param [in] flags Flags to modify behaviour of loading. Valid flags: * WOLFSSL_LOAD_FLAG_IGNORE_ERR, * WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY, * WOLFSSL_LOAD_FLAG_PEM_CA_ONLY, * WOLFSSL_LOAD_FLAG_IGNORE_BAD_PATH_ERR, and * WOLFSSL_LOAD_FLAG_IGNORE_ZEROFILE. * @return WOLFSSL_SUCCESS on success. * @return WOLFSSL_FATAL_ERROR when cm is NULL or failed create WOLFSSL_CTX. * @return Other values on loading failure. */ int wolfSSL_CertManagerLoadCABuffer_ex(WOLFSSL_CERT_MANAGER* cm, const unsigned char* buff, long sz, int format, int userChain, word32 flags) { int ret = WOLFSSL_SUCCESS; WOLFSSL_CTX* tmp = NULL; WOLFSSL_ENTER("wolfSSL_CertManagerLoadCABuffer_ex"); /* Validate parameters. */ if (cm == NULL) { WOLFSSL_MSG("No CertManager error"); ret = WOLFSSL_FATAL_ERROR; } /* Allocate a temporary WOLFSSL_CTX to load with. */ if ((ret == WOLFSSL_SUCCESS) && ((tmp = wolfSSL_CTX_new(cm_pick_method())) == NULL)) { WOLFSSL_MSG("CTX new failed"); ret = WOLFSSL_FATAL_ERROR; } if (ret == WOLFSSL_SUCCESS) { /* Some configurations like OPENSSL_COMPATIBLE_DEFAULTS may turn off * verification by default. Let's restore our desired defaults. */ wolfSSL_CTX_set_verify(tmp, WOLFSSL_VERIFY_DEFAULT, NULL); /* Replace certificate manager with one to load certificate/s into. */ wolfSSL_CertManagerFree(tmp->cm); tmp->cm = cm; /* Load certificate buffer. */ ret = wolfSSL_CTX_load_verify_buffer_ex(tmp, buff, sz, format, userChain, flags); /* Clear certificate manager in WOLFSSL_CTX so it won't be freed. */ tmp->cm = NULL; } /* Dispose of temporary WOLFSSL_CTX. */ wolfSSL_CTX_free(tmp); return ret; } /* Load certificate/s from buffer into table. * * Uses default load verification flags and is not a user chain. * * @param [in] cm Certificate manager. * @param [in] buff Buffer holding encoding of certificate. * @param [in] sz Length in bytes of data in buffer. * @param [in] format Format of encoding. Valid values: * WOLFSSL_FILETYPE_ASN1, WOLFSSL_FILETYPE_PEM. * @return WOLFSSL_SUCCESS on success. * @return WOLFSSL_FATAL_ERROR when cm is NULL or failed create WOLFSSL_CTX. * @return Other values on loading failure. */ 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 /* Set the verification callback into certificate manager. * * @param [in] cm Certificate manager. * @param [in] vc Verification callback. */ void wolfSSL_CertManagerSetVerify(WOLFSSL_CERT_MANAGER* cm, VerifyCallback vc) { WOLFSSL_ENTER("wolfSSL_CertManagerSetVerify"); if (cm != NULL) { cm->verifyCallback = vc; } } #endif /* NO_WOLFSSL_CM_VERIFY */ #if !defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH) /* Verify the certificate. * * Uses the verification callback if available. * * @param [in] cm Certificate manager. * @param [in] buff Buffer holding encoded certificate. * @param [in] sz Size in bytes of data in buffer. * @param [in] format Format of encoding. Valid values: * WOLFSSL_FILETYPE_ASN1, WOLFSSL_FILETYPE_PEM. * @param [in] prev_err Previous error. Passed to callback. * @return WOLFSSL_SUCCESS on success. * @return MEMORY_E when dynamic memory allocation fails. * @return NOT_COMPILED_IN when converting from PEM to DER is not a feature of * the wolfSSL build. */ 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; #ifdef WOLFSSL_SMALL_STACK DecodedCert* cert = NULL; #else DecodedCert cert[1]; #endif WOLFSSL_ENTER("CM_VerifyBuffer_ex"); (void)prev_err; #ifdef WOLFSSL_SMALL_STACK /* Allocate memory for decoded certificate. */ cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), cm->heap, DYNAMIC_TYPE_DCERT); if (cert == NULL) { ret = MEMORY_E; fatal = 1; } if (ret == 0) #endif { /* Reset fields of decoded certificate. */ XMEMSET(cert, 0, sizeof(DecodedCert)); if (format == WOLFSSL_FILETYPE_PEM) { #ifndef WOLFSSL_PEM_TO_DER ret = NOT_COMPILED_IN; fatal = 1; #else /* Convert to DER from PEM. */ ret = PemToDer(buff, sz, CERT_TYPE, &der, cm->heap, NULL, NULL); if (ret != 0) { fatal = 1; } else { /* Replace buffer pointer and size with DER buffer. */ buff = der->buffer; sz = (long)der->length; } #endif } } if (ret == 0) { /* Create a decoded certificate with DER buffer. */ InitDecodedCert(cert, buff, (word32)sz, cm->heap); /* Parse DER into decoded certificate fields and verify signature * against a known CA. */ ret = ParseCertRelative(cert, CERT_TYPE, VERIFY, cm); } #ifdef HAVE_CRL if ((ret == 0) && cm->crlEnabled) { /* Check for a CRL for the CA and check validity of certificate. */ ret = CheckCertCRL(cm->crl, cert); } #endif (void)fatal; #ifndef NO_WOLFSSL_CM_VERIFY /* Use callback to perform verification too if available. */ if ((!fatal) && cm->verifyCallback) { #ifdef WOLFSSL_SMALL_STACK ProcPeerCertArgs* args; #else ProcPeerCertArgs args[1]; #endif buffer certBuf; #ifdef WOLFSSL_SMALL_STACK /* Allocate memory for object to hold arguments for callback. */ 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)); /* DER encoding. */ certBuf.buffer = (byte*)buff; certBuf.length = (unsigned int)sz; /* One certificate available. */ args->totalCerts = 1; args->certs = &certBuf; args->dCert = cert; args->dCertInit = 1; /* Replace value in ret with an error value passed in. */ if (prev_err != 0) { ret = prev_err; } /* Use callback to verify certificate. */ ret = DoVerifyCallback(cm, NULL, ret, args); } #ifdef WOLFSSL_SMALL_STACK /* Dispose of allocated callback args. */ XFREE(args, cm->heap, DYNAMIC_TYPE_TMP_BUFFER); #endif } #endif /* Dispose of allocated memory. */ FreeDecodedCert(cert); FreeDer(&der); #ifdef WOLFSSL_SMALL_STACK XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT); #endif /* Convert the ret value to a return value. */ return (ret == 0) ? WOLFSSL_SUCCESS : ret; } /* Verify the certificate. * * Uses the verification callback if available. * * @param [in] cm Certificate manager. * @param [in] buff Buffer holding encoded certificate. * @param [in] sz Size in bytes of data in buffer. * @param [in] format Format of encoding. Valid values: * WOLFSSL_FILETYPE_ASN1, WOLFSSL_FILETYPE_PEM. * @param [in] prev_err Previous error. Passed to callback. * @return WOLFSSL_SUCCESS on success. * @return BAD_FUNC_ARG when cm or buff is NULL or sz is negative or zero. * @return WOLFSSL_BAD_FILETYPE when format is invalid. * @return MEMORY_E when dynamic memory allocation fails. * @return NOT_COMPILED_IN when converting from PEM to DER is not a feature of * the wolfSSL build. */ int wolfSSL_CertManagerVerifyBuffer(WOLFSSL_CERT_MANAGER* cm, const unsigned char* buff, long sz, int format) { int ret; WOLFSSL_ENTER("wolfSSL_CertManagerVerifyBuffer"); /* Validate parameters. */ 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 { /* No previous error. */ ret = CM_VerifyBuffer_ex(cm, buff, sz, format, 0); } return ret; } #endif /* !NO_WOLFSSL_CLIENT || !WOLFSSL_NO_CLIENT_AUTH */ #ifndef NO_FILESYSTEM #if !defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH) /* Verify the certificate loaded from a file. * * Uses the verification callback if available. * * @param [in] cm Certificate manager. * @param [in] format Format of encoding. Valid values: * WOLFSSL_FILETYPE_ASN1, WOLFSSL_FILETYPE_PEM. * @param [in] prev_err Previous error. Passed to callback. * @return WOLFSSL_SUCCESS on success. * @return BAD_FUNC_ARG when cm or buff is NULL or sz is negative. * @return WOLFSSL_BAD_FILETYPE when format is invalid. * @return WOLFSSL_BAD_FILE when reading the certificate file fails. * @return MEMORY_E when dynamic memory allocation fails. * @return NOT_COMPILED_IN when converting from PEM to DER is not a feature of * the wolfSSL build. */ 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 /* Validate parameters. cm and format validated in: * wolfSSL_CertManagerVerifyBuffer */ if ((cm == NULL) || (fname == NULL)) { ret = BAD_FUNC_ARG; } /* Open the file containing a certificate. */ if ((ret == WOLFSSL_SUCCESS) && ((file = XFOPEN(fname, "rb")) == XBADFILE)) { ret = WOLFSSL_BAD_FILE; } /* Get the length of the file. */ if (ret == WOLFSSL_SUCCESS) { ret = wolfssl_file_len(file, &sz); if (ret == 0) { ret = WOLFSSL_SUCCESS; } } /* Allocate dynamic memory for file contents if no static buffer or too * small. */ #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; } } /* Read all the file into buffer. */ if ((ret == WOLFSSL_SUCCESS) && (XFREAD(buff, 1, (size_t)sz, file) != (size_t)sz)) { ret = WOLFSSL_BAD_FILE; } /* Close file if opened. */ if (file != XBADFILE) { XFCLOSE(file); } if (ret == WOLFSSL_SUCCESS) { /* Verify the certificate read. */ ret = wolfSSL_CertManagerVerifyBuffer(cm, buff, sz, format); } /* Dispose of buffer if it was allocated. */ #ifndef WOLFSSL_SMALL_STACK if (buff != staticBuffer) #endif { if (cm != NULL) { XFREE(buff, cm->heap, DYNAMIC_TYPE_FILE); } } return ret; } #endif /* Load the CA file and/or certificate files in a path. * * @param [in] cm Certificate manager. * @param [in] file Name of CA file. * @param [in] path Path to a directory containing certificates. * @return WOLFSSL_SUCCESS on success. * @return WOLFSSL_FATAL_ERROR when cm is NULL or unable to create WOLFSSL_CTX. * @return Otherwise failure. */ 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"); /* Validate parameters. file and path validated in: * wolfSSL_CTX_load_verify_locations*/ if (cm == NULL) { WOLFSSL_MSG("No CertManager error"); ret = WOLFSSL_FATAL_ERROR; } /* Create temporary WOLFSSL_CTX. */ if ((ret == WOLFSSL_SUCCESS) && ((tmp = wolfSSL_CTX_new(cm_pick_method())) == NULL)) { WOLFSSL_MSG("CTX new failed"); ret = WOLFSSL_FATAL_ERROR; } if (ret == WOLFSSL_SUCCESS) { /* Some configurations like OPENSSL_COMPATIBLE_DEFAULTS may turn off * verification by default. Let's restore our desired defaults. */ wolfSSL_CTX_set_verify(tmp, WOLFSSL_VERIFY_DEFAULT, NULL); /* Replace certificate manager with one to load certificate/s into. */ wolfSSL_CertManagerFree(tmp->cm); tmp->cm = cm; /* Load certificate from file and path. */ ret = wolfSSL_CTX_load_verify_locations(tmp, file, path); /* Clear certificate manager in WOLFSSL_CTX so it won't be freed. */ tmp->cm = NULL; } /* Dispose of temporary WOLFSSL_CTX. */ wolfSSL_CTX_free(tmp); return ret; } #endif /* NO_FILESYSTEM */ #if defined(PERSIST_CERT_CACHE) /* Version of layout of cache of CA certificates. */ #define WOLFSSL_CACHE_CERT_VERSION 1 /* CA certificates cache information. */ typedef struct { /* Cache certificate layout version id. */ int version; /* Number of hash table rows. Maximum of CA_TABLE_SIZE. */ int rows; /* Number of columns per row. */ int columns[CA_TABLE_SIZE]; /* Size of Signer object. */ int signerSz; } CertCacheHeader; /* current cert persistence layout is: 1) CertCacheHeader 2) caTable update WOLFSSL_CERT_CACHE_VERSION if change layout for the following PERSIST_CERT_CACHE functions */ /* Return number of bytes of memory needed to persist this signer. * * Assumes we have locked CA table. * * @param [in] Signer Signer entry in CA table. * @return Number of bytes. */ 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 /* Add dynamic bytes needed. */ sz += (int)signer->pubKeySize; sz += signer->nameLen; return sz; } /* Return number of bytes of memory needed to persist this row. * * Assumes we have locked CA table. * * @param [in] row A row of signers from the CA table. * @return Number of bytes. */ static WC_INLINE int cm_get_cert_cache_row_memory(Signer* row) { int sz = 0; /* Each signer in row. */ while (row != NULL) { /* Add in size of this signer. */ sz += cm_get_signer_memory(row); row = row->next; } return sz; } /* Return the number of bytes of memory to persist cert cache. * * Assumes we have locked CA table. * * @param [in] cm Certificate manager. * @return Number of bytes. */ static WC_INLINE int cm_get_cert_cache_mem_size(WOLFSSL_CERT_MANAGER* cm) { int sz; int i; sz = sizeof(CertCacheHeader); /* Each row in table. */ for (i = 0; i < CA_TABLE_SIZE; i++) { /* Add in size of this row. */ sz += cm_get_cert_cache_row_memory(cm->caTable[i]); } return sz; } /* Get count of columns for each row. * * Assumes we have locked CA table. * * @param [in] cm Certificate manager. * @param [in] columns Array of row counts. */ static WC_INLINE void cm_set_cert_header_Columns(WOLFSSL_CERT_MANAGER* cm, int* columns) { int i; Signer* row; /* Each row in table. */ for (i = 0; i < CA_TABLE_SIZE; i++) { int count = 0; /* Get row from table. */ row = cm->caTable[i]; /* Each entry in row. */ while (row != NULL) { /* Update count. */ ++count; row = row->next; } /* Store row count. */ columns[i] = count; } } /* Restore whole cert row from memory, * * Assumes we have locked CA table. * * @param [in] cm Certificate manager. * @param [in] current Buffer containing rows. * @param [in] row Row number being restored. * @param [in] listSz Number of entries in row. * @param [in] end End of data in buffer. * @return Number of bytes consumed on success. * @return PARSE_ERROR when listSz is less than zero. * @return BUFFER_E when buffer is too small. * @return MEMORY_E when dynamic memory allocation fails. * @return Negative value on error. */ 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; /* Validate parameters. */ if (listSz < 0) { WOLFSSL_MSG("Row header corrupted, negative value"); ret = PARSE_ERROR; } /* Process all entries. */ while ((ret == 0) && (listSz > 0)) { Signer* signer = NULL; byte* publicKey; byte* start = current + idx; /* for end checks on this signer */ int minSz = sizeof(signer->pubKeySize) + sizeof(signer->keyOID) + sizeof(signer->nameLen) + sizeof(signer->subjectNameHash); #ifndef NO_SKID minSz += (int)sizeof(signer->subjectKeyIdHash); #endif /* Check minimal size of bytes available. */ if (start + minSz > end) { WOLFSSL_MSG("Would overread restore buffer"); ret = BUFFER_E; } /* Make a new signer. */ if ((ret == 0) && ((signer = MakeSigner(cm->heap)) == NULL)) { ret = MEMORY_E; } if (ret == 0) { /* Copy in public key size. */ XMEMCPY(&signer->pubKeySize, current + idx, sizeof(signer->pubKeySize)); idx += (int)sizeof(signer->pubKeySize); /* Copy in public key OID. */ XMEMCPY(&signer->keyOID, current + idx, sizeof(signer->keyOID)); idx += (int)sizeof(signer->keyOID); /* Check bytes available for public key. */ if (start + minSz + signer->pubKeySize > end) { WOLFSSL_MSG("Would overread restore buffer"); ret = BUFFER_E; } } if (ret == 0) { /* Allocate memory for public key to be stored in. */ publicKey = (byte*)XMALLOC(signer->pubKeySize, cm->heap, DYNAMIC_TYPE_KEY); if (publicKey == NULL) { ret = MEMORY_E; } } if (ret == 0) { /* Copy in public key. */ XMEMCPY(publicKey, current + idx, signer->pubKeySize); signer->publicKey = publicKey; idx += (int)signer->pubKeySize; /* Copy in certificate name length. */ XMEMCPY(&signer->nameLen, current + idx, sizeof(signer->nameLen)); idx += (int)sizeof(signer->nameLen); /* Check bytes available for certificate name. */ if (start + minSz + signer->pubKeySize + signer->nameLen > end) { WOLFSSL_MSG("Would overread restore buffer"); ret = BUFFER_E; } } if (ret == 0) { /* Allocate memory for public key to be stored in. */ signer->name = (char*)XMALLOC((size_t)signer->nameLen, cm->heap, DYNAMIC_TYPE_SUBJECT_CN); if (signer->name == NULL) { ret = MEMORY_E; } } if (ret == 0) { /* Copy in certificate name. */ XMEMCPY(signer->name, current + idx, (size_t)signer->nameLen); idx += signer->nameLen; /* Copy in hash of subject name. */ XMEMCPY(signer->subjectNameHash, current + idx, SIGNER_DIGEST_SIZE); idx += SIGNER_DIGEST_SIZE; #ifndef NO_SKID /* Copy in hash of subject key. */ XMEMCPY(signer->subjectKeyIdHash, current + idx,SIGNER_DIGEST_SIZE); idx += SIGNER_DIGEST_SIZE; #endif /* Make next Signer the head of the row. */ signer->next = cm->caTable[row]; /* Add Signer to start of row. */ cm->caTable[row] = signer; /* Done one more Signer. */ --listSz; } if ((ret != 0) && (signer != NULL)) { /* Dispose of allocated signer. */ FreeSigner(signer, cm->heap); } } if (ret == 0) { /* Return the number of bytes used on success. */ ret = idx; } return ret; } /* Store whole CA certificate row into memory. * * Assumes we have locked CA table. * * @param [in] cm Certificate manager. * @param [in] current Buffer to write to. * @param [in] row Row number being stored. * @return Number of bytes added. */ static WC_INLINE int cm_store_cert_row(WOLFSSL_CERT_MANAGER* cm, byte* current, int row) { int added = 0; Signer* list; /* Get the row - a linked list. */ list = cm->caTable[row]; /* Each certificate in row. */ while (list != NULL) { /* Public key size. */ XMEMCPY(current + added, &list->pubKeySize, sizeof(list->pubKeySize)); added += (int)sizeof(list->pubKeySize); /* Public key OID. */ XMEMCPY(current + added, &list->keyOID, sizeof(list->keyOID)); added += (int)sizeof(list->keyOID); /* Public key. */ XMEMCPY(current + added, list->publicKey, (size_t)list->pubKeySize); added += (int)list->pubKeySize; /* Certificate name length. */ XMEMCPY(current + added, &list->nameLen, sizeof(list->nameLen)); added += (int)sizeof(list->nameLen); /* Certificate name. */ XMEMCPY(current + added, list->name, (size_t)list->nameLen); added += list->nameLen; /* Hash of subject name. */ XMEMCPY(current + added, list->subjectNameHash, SIGNER_DIGEST_SIZE); added += SIGNER_DIGEST_SIZE; #ifndef NO_SKID /* Hash of public key. */ XMEMCPY(current + added, list->subjectKeyIdHash,SIGNER_DIGEST_SIZE); added += SIGNER_DIGEST_SIZE; #endif /* Next certificate in row. */ list = list->next; } return added; } /* Persist CA certificate cache to memory. * * Assumes we have locked CA table. * * @param [in] cm Certificate manager. * @param [in] mem Memory to persist into. * @param [in] sz Size in bytes of memory. * @return WOLFSSL_SUCCESS on success. * @return BUFFER_E when memory is too small. */ 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"); /* Calculate amount of memory required to store CA certificate table. */ 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; /* Create header for storage. */ hdr.version = WOLFSSL_CACHE_CERT_VERSION; hdr.rows = CA_TABLE_SIZE; cm_set_cert_header_Columns(cm, hdr.columns); hdr.signerSz = (int)sizeof(Signer); /* Copy header into memory. */ XMEMCPY(mem, &hdr, sizeof(CertCacheHeader)); current = (byte*)mem + sizeof(CertCacheHeader); /* Each row of table. */ for (i = 0; i < CA_TABLE_SIZE; ++i) { /* Append row to memory. */ current += cm_store_cert_row(cm, current, i); } } return ret; } #if !defined(NO_FILESYSTEM) /* Persist CA certificate cache to file. * * Locks CA table. * * @param [in] cm Certificate manager. * @param [in] fname File name to write to. * @return WOLFSSL_SUCCESS on success. * @return WOLFSSL_BAD_FILE when opening file fails. * @return BAD_MUTEX_E when locking fails. * @return MEMORY_E when dynamic memory allocation fails. * @return FWRITE_ERROR when writing to file fails. */ int CM_SaveCertCache(WOLFSSL_CERT_MANAGER* cm, const char* fname) { XFILE file; int ret = WOLFSSL_SUCCESS; WOLFSSL_ENTER("CM_SaveCertCache"); /* Open file for writing. */ file = XFOPEN(fname, "w+b"); if (file == XBADFILE) { WOLFSSL_MSG("Couldn't open cert cache save file"); ret = WOLFSSL_BAD_FILE; } /* Lock CA table. */ 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; /* Calculate size of memory required to store CA table. */ size_t memSz = (size_t)cm_get_cert_cache_mem_size(cm); /* Allocate memory to hold CA table. */ 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) { /* Store CA table in memory. */ ret = cm_do_mem_save_cert_cache(cm, mem, (int)memSz); } if (ret == WOLFSSL_SUCCESS) { /* Write memory to file. */ int sz = (int)XFWRITE(mem, memSz, 1, file); if (sz != 1) { WOLFSSL_MSG("Cert cache file write failed"); ret = FWRITE_ERROR; } } if (mem != NULL) { XFREE(mem, cm->heap, DYNAMIC_TYPE_TMP_BUFFER); } /* Unlock CA table. */ wc_UnLockMutex(&cm->caLock); } /* Close file. */ if (file != XBADFILE) { XFCLOSE(file); } return ret; } /* Restore CA certificate cache from file. * * @param [in] cm Certificate manager. * @param [in] fname File name to write to. * @return WOLFSSL_SUCCESS on success. * @return WOLFSSL_BAD_FILE when opening or using file fails. * @return MEMORY_E when dynamic memory allocation fails. * @return FREAD_ERROR when reading from file fails. */ 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"); /* Open file for reading. */ file = XFOPEN(fname, "rb"); if (file == XBADFILE) { WOLFSSL_MSG("Couldn't open cert cache save file"); ret = WOLFSSL_BAD_FILE; } if (ret == WOLFSSL_SUCCESS) { /* Read file into allocated memory. */ ret = wolfssl_read_file(file, (char**)&mem, &memSz); if (ret == 0) { ret = WOLFSSL_SUCCESS; } } if (ret == WOLFSSL_SUCCESS) { /* Create the CA certificate table from memory. */ ret = CM_MemRestoreCertCache(cm, mem, memSz); if (ret != WOLFSSL_SUCCESS) { WOLFSSL_MSG("Mem restore cert cache failed"); } } /* Dispose of dynamic memory read into. */ XFREE(mem, cm->heap, DYNAMIC_TYPE_TMP_BUFFER); /* Close file. */ if (file != XBADFILE) { XFCLOSE(file); } return ret; } #endif /* NO_FILESYSTEM */ /* Persist CA certificate cache to memory. * * Locks CA table. * * @param [in] cm Certificate manager. * @param [in] mem Memory to persist into. * @param [in] sz Size in bytes of memory. * @param [out] used Number of bytes used when persisting cache. * @return WOLFSSL_SUCCESS on success. * @return BAD_MUTEX_E when locking fails. * @return BUFFER_E when memory is too small. */ int CM_MemSaveCertCache(WOLFSSL_CERT_MANAGER* cm, void* mem, int sz, int* used) { int ret = WOLFSSL_SUCCESS; WOLFSSL_ENTER("CM_MemSaveCertCache"); /* Lock CA table. */ if (wc_LockMutex(&cm->caLock) != 0) { WOLFSSL_MSG("wc_LockMutex on caLock failed"); ret = BAD_MUTEX_E; } if (ret == WOLFSSL_SUCCESS) { /* Save CA table into memory. */ ret = cm_do_mem_save_cert_cache(cm, mem, sz); if (ret == WOLFSSL_SUCCESS) { /* Get the number of bytes used. */ *used = cm_get_cert_cache_mem_size(cm); } /* Unlock CA table. */ wc_UnLockMutex(&cm->caLock); } return ret; } /* Restore CA certificate table from memory, * * Locks CA table. * * @param [in] cm Certificate manager. * @param [in] mem Buffer containing rows. * @param [in] sz Size in bytes of data in buffer. * @return WOLFSSL_SUCCESS on success. * @return BUFFER_E when buffer is too small. * @return BAD_MUTEX_E when locking fails. * @return MEMORY_E when dynamic memory allocation fails. */ 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; /* don't go over */ WOLFSSL_ENTER("CM_MemRestoreCertCache"); /* Check memory available is bigger than cache header. */ if (current > end) { WOLFSSL_MSG("Cert Cache Memory buffer too small"); ret = BUFFER_E; } /* Validate the cache header. */ 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; } /* Lock CA table. */ if ((ret == WOLFSSL_SUCCESS) && (wc_LockMutex(&cm->caLock) != 0)) { WOLFSSL_MSG("wc_LockMutex on caLock failed"); ret = BAD_MUTEX_E; } if (ret == WOLFSSL_SUCCESS) { /* Dispose of current CA certificate table. */ FreeSignerTable(cm->caTable, CA_TABLE_SIZE, cm->heap); /* Each row. */ for (i = 0; i < CA_TABLE_SIZE; ++i) { /* Restore a row from memory. */ int added = cm_restore_cert_row(cm, current, i, hdr->columns[i], end); /* Bail on error. */ if (added < 0) { WOLFSSL_MSG("cm_restore_cert_row error"); ret = added; break; } /* Update pointer to data of next row. */ current += added; } /* Unlock CA table. */ wc_UnLockMutex(&cm->caLock); } return ret; } /* Calculate size of CA certificate cache when persisted to memory. * * Locks CA table. * * @param [in] cm Certificate manager. * @return Number of bytes on success. * @return BAD_MUTEX_E when locking fails. */ int CM_GetCertCacheMemSize(WOLFSSL_CERT_MANAGER* cm) { int ret; WOLFSSL_ENTER("CM_GetCertCacheMemSize"); /* Lock CA table. */ if (wc_LockMutex(&cm->caLock) != 0) { WOLFSSL_MSG("wc_LockMutex on caLock failed"); ret = BAD_MUTEX_E; } else { /* Calculate memory size. */ ret = cm_get_cert_cache_mem_size(cm); /* Unlock CA table. */ wc_UnLockMutex(&cm->caLock); } return ret; } #endif /* PERSIST_CERT_CACHE */ /******************************************************************************* * CRL handling ******************************************************************************/ /* Enables/disables the use of CRLs when validating certificates. * * @param [in] cm Certificate manager. * @param [in] options Options for using CRLs. Valid flags: * WOLFSSL_CRL_CHECKALL, WOLFSSL_CRL_CHECK. * @return WOLFSSL_SUCCESS on success. * @return WOLFSSL_FAILURE when initializing the CRL object fails. * @return BAD_FUNC_ARG when cm is NULL. * @return MEMORY_E when dynamic memory allocation fails. * @return NOT_COMPILED_IN when the CRL feature is disabled. */ int wolfSSL_CertManagerEnableCRL(WOLFSSL_CERT_MANAGER* cm, int options) { int ret = WOLFSSL_SUCCESS; WOLFSSL_ENTER("wolfSSL_CertManagerEnableCRL"); (void)options; /* Validate parameters. */ if (cm == NULL) { ret = BAD_FUNC_ARG; } #if defined(OPENSSL_COMPATIBLE_DEFAULTS) /* If disabling then don't worry about whether CRL feature is enabled. */ if ((ret == WOLFSSL_SUCCESS) && (options == 0)) { /* Disable leaf CRL check. */ cm->crlEnabled = 0; /* Disable all CRL checks. */ cm->crlCheckAll = 0; } else #endif if (ret == WOLFSSL_SUCCESS) { #ifndef HAVE_CRL /* CRL feature not enabled. */ ret = NOT_COMPILED_IN; #else /* Create CRL object if not present. */ if (cm->crl == NULL) { /* Allocate memory for CRL object. */ cm->crl = (WOLFSSL_CRL*)XMALLOC(sizeof(WOLFSSL_CRL), cm->heap, DYNAMIC_TYPE_CRL); if (cm->crl == NULL) { ret = MEMORY_E; } if (ret == WOLFSSL_SUCCESS) { /* Reset fields of CRL object. */ XMEMSET(cm->crl, 0, sizeof(WOLFSSL_CRL)); /* Initialize CRL object. */ if (InitCRL(cm->crl, cm) != 0) { WOLFSSL_MSG("Init CRL failed"); /* Dispose of CRL object - indicating dynamically allocated. */ FreeCRL(cm->crl, 1); cm->crl = NULL; ret = WOLFSSL_FAILURE; } } } if (ret == WOLFSSL_SUCCESS) { #if defined(HAVE_CRL_IO) && defined(USE_WOLFSSL_IO) /* Use built-in callback to lookup CRL from URL. */ cm->crl->crlIOCb = EmbedCrlLookup; #endif #if defined(OPENSSL_COMPATIBLE_DEFAULTS) if ((options & WOLFSSL_CRL_CHECKALL) || (options & WOLFSSL_CRL_CHECK)) #endif { /* Enable leaf CRL check. */ cm->crlEnabled = 1; if (options & WOLFSSL_CRL_CHECKALL) { /* Enable all CRL check. */ cm->crlCheckAll = 1; } } } #endif } return ret; } /* Disables the CRL checks. * * @param [in] cm Certificate manager. * @return WOLFSSL_SUCCESS on success. * @return BAD_FUNC_ARG when cm is NULL. */ int wolfSSL_CertManagerDisableCRL(WOLFSSL_CERT_MANAGER* cm) { int ret = WOLFSSL_SUCCESS; WOLFSSL_ENTER("wolfSSL_CertManagerDisableCRL"); /* Validate parameter. */ if (cm == NULL) { ret = BAD_FUNC_ARG; } if (ret == WOLFSSL_SUCCESS) { /* Disable CRL checking. */ cm->crlEnabled = 0; cm->crlCheckAll = 0; } return ret; } #ifdef HAVE_CRL /* Load CRL for use. * * @param [in] cm Certificate manager. * @param [in] buff Buffer holding CRL. * @param [in] sz Size in bytes of CRL in buffer. * @param [in] type Format of encoding. Valid values: * WOLFSSL_FILETYPE_ASN1, WOLFSSL_FILETYPE_PEM. * @return WOLFSSL_SUCCESS on success. * @return BAD_FUNC_ARG when cm or buff is NULL or sz is negative or zero. * @return WOLFSSL_FATAL_ERROR when creating CRL object fails. */ int wolfSSL_CertManagerLoadCRLBuffer(WOLFSSL_CERT_MANAGER* cm, const unsigned char* buff, long sz, int type) { int ret = WOLFSSL_SUCCESS; WOLFSSL_ENTER("wolfSSL_CertManagerLoadCRLBuffer"); /* Validate parameters. */ if ((cm == NULL) || (buff == NULL) || (sz <= 0)) { ret = BAD_FUNC_ARG; } /* Create a CRL object if not available and enable CRL checking. */ 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) { /* Load CRL into CRL object of the certificate manager. */ ret = BufferLoadCRL(cm->crl, buff, sz, type, VERIFY); } return ret; } /* Free the CRL object of the certificate manager. * * @param [in] cm Certificate manager. * @return WOLFSSL_SUCCESS on success. * @return BAD_FUNC_ARG when cm is NULL. */ int wolfSSL_CertManagerFreeCRL(WOLFSSL_CERT_MANAGER* cm) { int ret = WOLFSSL_SUCCESS; WOLFSSL_ENTER("wolfSSL_CertManagerFreeCRL"); /* Validate parameter. */ if (cm == NULL) { ret = BAD_FUNC_ARG; } /* Check whether CRL object exists. */ if ((ret == WOLFSSL_SUCCESS) && (cm->crl != NULL)) { /* Dispose of CRL object - indicating dynamically allocated. */ FreeCRL(cm->crl, 1); cm->crl = NULL; } return ret; } /* Check DER encoded certificate against CRLs if checking enabled. * * @param [in] cm Certificate manager. * @param [in] der DER encode certificate. * @param [in] sz Size in bytes of DER encode certificate. * @return WOLFSSL_SUCCESS on success. * @return BAD_FUNC_ARG when cm or der is NULL or sz is negative or zero. * @return MEMORY_E when dynamic memory allocation fails. */ int wolfSSL_CertManagerCheckCRL(WOLFSSL_CERT_MANAGER* cm, const unsigned char* der, int sz) { int ret = 0; #ifdef WOLFSSL_SMALL_STACK DecodedCert* cert = NULL; #else DecodedCert cert[1]; #endif WOLFSSL_ENTER("wolfSSL_CertManagerCheckCRL"); /* Validate parameters. */ if ((cm == NULL) || (der == NULL) || (sz <= 0)) { ret = BAD_FUNC_ARG; } /* Check if CRL checking enabled. */ if ((ret == 0) && cm->crlEnabled) { #ifdef WOLFSSL_SMALL_STACK /* Allocate memory for decoded certificate. */ cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, DYNAMIC_TYPE_DCERT); if (cert == NULL) ret = MEMORY_E; if (ret == 0) #endif { /* Initialize decoded certificate with buffer. */ InitDecodedCert(cert, der, (word32)sz, NULL); /* Parse certificate and perform CRL checks. */ ret = ParseCertRelative(cert, CERT_TYPE, VERIFY_CRL, cm); if (ret != 0) { WOLFSSL_MSG("ParseCert failed"); } /* Do CRL checks with decoded certificate. */ else if ((ret = CheckCertCRL(cm->crl, cert)) != 0) { WOLFSSL_MSG("CheckCertCRL failed"); } /* Dispose of dynamically allocated memory. */ FreeDecodedCert(cert); #ifdef WOLFSSL_SMALL_STACK XFREE(cert, NULL, DYNAMIC_TYPE_DCERT); #endif } } return (ret == 0) ? WOLFSSL_SUCCESS : ret; } /* Set the missing CRL callback. * * @param [in] cm Certificate manager. * @param [in] cb Missing CRL callback. * @return WOLFSSL_SUCCESS on success. * @return BAD_FUNC_ARG when cm is NULL. */ int wolfSSL_CertManagerSetCRL_Cb(WOLFSSL_CERT_MANAGER* cm, CbMissingCRL cb) { int ret = WOLFSSL_SUCCESS; WOLFSSL_ENTER("wolfSSL_CertManagerSetCRL_Cb"); /* Validate parameters. */ if (cm == NULL) { ret = BAD_FUNC_ARG; } if (ret == WOLFSSL_SUCCESS) { /* Store callback. */ cm->cbMissingCRL = cb; } return ret; } #ifdef HAVE_CRL_IO /* Set the CRL I/O callback. * * @param [in] cm Certificate manager. * @param [in] cb CRL I/O callback. * @return WOLFSSL_SUCCESS on success. * @return BAD_FUNC_ARG when cm is NULL. */ int wolfSSL_CertManagerSetCRL_IOCb(WOLFSSL_CERT_MANAGER* cm, CbCrlIO cb) { int ret = WOLFSSL_SUCCESS; /* Validate parameters. */ if (cm == NULL) { ret = BAD_FUNC_ARG; } if ((ret == WOLFSSL_SUCCESS) && (cm->crl != NULL)) { /* Store callback. */ cm->crl->crlIOCb = cb; } return ret; } #endif #ifndef NO_FILESYSTEM /* Load CRL/s from path with the option of monitoring for changes. * * @param [in] cm Certificate manager. * @param [in] path Path to a directory containing CRLs. * @param [in] type Format of encoding. Valid values: * WOLFSSL_FILETYPE_ASN1, WOLFSSL_FILETYPE_PEM. * @param [in] monitor Whether to monitor path for changes to files. * @return WOLFSSL_SUCCESS on success. * @return BAD_FUNC_ARG when cm or path is NULL. * @return WOLFSSL_FATAL_ERROR when enabling CRLs fails. */ int wolfSSL_CertManagerLoadCRL(WOLFSSL_CERT_MANAGER* cm, const char* path, int type, int monitor) { int ret = WOLFSSL_SUCCESS; WOLFSSL_ENTER("wolfSSL_CertManagerLoadCRL"); /* Validate parameters. */ if ((cm == NULL) || (path == NULL)) { ret = BAD_FUNC_ARG; } /* Create a CRL object if not available. */ 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) { /* Load CRLs from path into CRL object of certificate manager. */ ret = LoadCRL(cm->crl, path, type, monitor); } return ret; } /* Load CRL from file. * * @param [in] cm Certificate manager. * @param [in] file Path to a directory containing CRLs. * @param [in] type Format of encoding. Valid values: * WOLFSSL_FILETYPE_ASN1, WOLFSSL_FILETYPE_PEM. * @return WOLFSSL_SUCCESS on success. * @return BAD_FUNC_ARG when cm or file is NULL. * @return WOLFSSL_FATAL_ERROR when enabling CRLs fails. */ int wolfSSL_CertManagerLoadCRLFile(WOLFSSL_CERT_MANAGER* cm, const char* file, int type) { int ret = WOLFSSL_SUCCESS; WOLFSSL_ENTER("wolfSSL_CertManagerLoadCRLFile"); /* Validate parameters. */ if ((cm == NULL) || (file == NULL)) { ret = BAD_FUNC_ARG; } /* Create a CRL object if not available. */ 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) { /* Load CRL file into CRL object of certificate manager. */ ret = ProcessFile(NULL, file, type, CRL_TYPE, NULL, 0, cm->crl, VERIFY); } return ret; } #endif /* !NO_FILESYSTEM */ #endif /* HAVE_CRL */ /******************************************************************************* * OCSP handling ******************************************************************************/ /* Enables OCSP when validating certificates and sets options. * * @param [in] cm Certificate manager. * @param [in] options Options for using OCSP. Valid flags: * WOLFSSL_OCSP_URL_OVERRIDE, WOLFSSL_OCSP_NO_NONCE, * WOLFSSL_OCSP_CHECKALL. * @return WOLFSSL_SUCCESS on success. * @return 0 when initializing the OCSP object fails. * @return BAD_FUNC_ARG when cm is NULL. * @return MEMORY_E when dynamic memory allocation fails. * @return NOT_COMPILED_IN when the OCSP feature is disabled. */ int wolfSSL_CertManagerEnableOCSP(WOLFSSL_CERT_MANAGER* cm, int options) { int ret = WOLFSSL_SUCCESS; (void)options; WOLFSSL_ENTER("wolfSSL_CertManagerEnableOCSP"); /* Validate parameters. */ if (cm == NULL) { ret = BAD_FUNC_ARG; } #ifndef HAVE_OCSP if (ret == WOLFSSL_SUCCESS) { /* OCSP feature not enabled. */ ret = NOT_COMPILED_IN; } #else if (ret == WOLFSSL_SUCCESS) { /* Check whether OCSP object is available. */ if (cm->ocsp == NULL) { /* Allocate memory for OCSP object. */ cm->ocsp = (WOLFSSL_OCSP*)XMALLOC(sizeof(WOLFSSL_OCSP), cm->heap, DYNAMIC_TYPE_OCSP); if (cm->ocsp == NULL) { ret = MEMORY_E; } if (ret == WOLFSSL_SUCCESS) { /* Reset the fields of the OCSP object. */ XMEMSET(cm->ocsp, 0, sizeof(WOLFSSL_OCSP)); /* Initialize the OCSP object. */ if (InitOCSP(cm->ocsp, cm) != 0) { WOLFSSL_MSG("Init OCSP failed"); /* Dispose of OCSP object - indicating dynamically allocated. */ FreeOCSP(cm->ocsp, 1); cm->ocsp = NULL; ret = 0; } } } } if (ret == WOLFSSL_SUCCESS) { /* Enable OCSP checking. */ cm->ocspEnabled = 1; /* Enable URL override if requested. */ if (options & WOLFSSL_OCSP_URL_OVERRIDE) { cm->ocspUseOverrideURL = 1; } /* Set nonce option for creating OCSP requests. */ cm->ocspSendNonce = (options & WOLFSSL_OCSP_NO_NONCE) != WOLFSSL_OCSP_NO_NONCE; /* Set all OCSP checks on if requested. */ if (options & WOLFSSL_OCSP_CHECKALL) { cm->ocspCheckAll = 1; } #ifndef WOLFSSL_USER_IO /* Set built-in OCSP lookup. */ cm->ocspIOCb = EmbedOcspLookup; cm->ocspRespFreeCb = EmbedOcspRespFree; cm->ocspIOCtx = cm->heap; #endif /* WOLFSSL_USER_IO */ } #endif /* HAVE_OCSP */ return ret; } /* Disables the OCSP checks. * * @param [in] cm Certificate manager. * @return WOLFSSL_SUCCESS on success. * @return BAD_FUNC_ARG when cm is NULL. */ int wolfSSL_CertManagerDisableOCSP(WOLFSSL_CERT_MANAGER* cm) { int ret = WOLFSSL_SUCCESS; WOLFSSL_ENTER("wolfSSL_CertManagerDisableOCSP"); /* Validate parameter. */ if (cm == NULL) { ret = BAD_FUNC_ARG; } if (ret == WOLFSSL_SUCCESS) { /* Disable use of OCSP with certificate validation. */ cm->ocspEnabled = 0; } return ret; } /* Enables OCSP stapling with certificates in manager. * * @param [in] cm Certificate manager. * @param [in] options Options for using OCSP. Valid flags: * WOLFSSL_OCSP_URL_OVERRIDE, WOLFSSL_OCSP_NO_NONCE, * WOLFSSL_OCSP_CHECKALL. * @return WOLFSSL_SUCCESS on success. * @return 0 when initializing the OCSP stapling object fails. * @return BAD_FUNC_ARG when cm is NULL. * @return MEMORY_E when dynamic memory allocation fails. * @return NOT_COMPILED_IN when the OCSP stapling feature is disabled. */ int wolfSSL_CertManagerEnableOCSPStapling(WOLFSSL_CERT_MANAGER* cm) { int ret = WOLFSSL_SUCCESS; WOLFSSL_ENTER("wolfSSL_CertManagerEnableOCSPStapling"); /* Validate parameters. */ if (cm == NULL) { ret = BAD_FUNC_ARG; } #if !defined(HAVE_CERTIFICATE_STATUS_REQUEST) && \ !defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) if (ret == WOLFSSL_SUCCESS) { /* OCSP stapling feature not enabled. */ ret = NOT_COMPILED_IN; } #else #ifndef NO_WOLFSSL_SERVER if (ret == WOLFSSL_SUCCESS) { /* Check whether OCSP object is available. */ if (cm->ocsp_stapling == NULL) { /* Allocate memory for OCSP stapling object. */ 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) { /* Reset the fields of the OCSP object. */ XMEMSET(cm->ocsp_stapling, 0, sizeof(WOLFSSL_OCSP)); /* Initialize the OCSP stapling object. */ if (InitOCSP(cm->ocsp_stapling, cm) != 0) { WOLFSSL_MSG("Init OCSP failed"); /* Dispose of OCSP stapling object - indicating dynamically * allocated. */ FreeOCSP(cm->ocsp_stapling, 1); cm->ocsp_stapling = NULL; ret = 0; } } } } #ifndef WOLFSSL_USER_IO if (ret == WOLFSSL_SUCCESS) { /* Set built-in OCSP lookup. */ cm->ocspIOCb = EmbedOcspLookup; cm->ocspRespFreeCb = EmbedOcspRespFree; cm->ocspIOCtx = cm->heap; } #endif /* WOLFSSL_USER_IO */ #endif /* NO_WOLFSSL_SERVER */ if (ret == WOLFSSL_SUCCESS) { /* Enable OCSP stapling. */ cm->ocspStaplingEnabled = 1; } #endif /* HAVE_CERTIFICATE_STATUS_REQUEST || * HAVE_CERTIFICATE_STATUS_REQUEST_V2 */ return ret; } /* Disables OCSP Stapling. * * @param [in] cm Certificate manager. * @return WOLFSSL_SUCCESS on success. * @return BAD_FUNC_ARG when cm is NULL. */ int wolfSSL_CertManagerDisableOCSPStapling(WOLFSSL_CERT_MANAGER* cm) { int ret = WOLFSSL_SUCCESS; WOLFSSL_ENTER("wolfSSL_CertManagerDisableOCSPStapling"); /* Validate parameter. */ if (cm == NULL) { ret = BAD_FUNC_ARG; } if (ret == WOLFSSL_SUCCESS) { #if defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \ defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) /* Disable use of OCSP Stapling. */ cm->ocspStaplingEnabled = 0; #else /* OCSP stapling feature not enabled. */ ret = NOT_COMPILED_IN; #endif } return ret; } /* Enable the must use OCSP Stapling option. * * @param [in] cm Certificate manager. * @return WOLFSSL_SUCCESS on success. * @return BAD_FUNC_ARG when cm is NULL. */ int wolfSSL_CertManagerEnableOCSPMustStaple(WOLFSSL_CERT_MANAGER* cm) { int ret = WOLFSSL_SUCCESS; WOLFSSL_ENTER("wolfSSL_CertManagerEnableOCSPMustStaple"); /* Validate parameter. */ 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 /* Enable must use OCSP Stapling option. */ cm->ocspMustStaple = 1; #endif #else /* OCSP stapling feature not enabled. */ ret = NOT_COMPILED_IN; #endif } return ret; } /* Disable the must use OCSP Stapling option. * * @param [in] cm Certificate manager. * @return WOLFSSL_SUCCESS on success. * @return BAD_FUNC_ARG when cm is NULL. */ int wolfSSL_CertManagerDisableOCSPMustStaple(WOLFSSL_CERT_MANAGER* cm) { int ret = WOLFSSL_SUCCESS; WOLFSSL_ENTER("wolfSSL_CertManagerDisableOCSPMustStaple"); /* Validate parameter. */ 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 /* Disable must use OCSP Stapling option. */ cm->ocspMustStaple = 0; #endif #else /* OCSP stapling feature not enabled. */ ret = NOT_COMPILED_IN; #endif } return ret; } #ifdef HAVE_OCSP /* Check DER encoded certificate against with OCSP if checking enabled. * * @param [in] cm Certificate manager. * @param [in] der DER encode certificate. * @param [in] sz Size in bytes of DER encode certificate. * @return WOLFSSL_SUCCESS on success. * @return BAD_FUNC_ARG when cm or der is NULL or sz is negative or 0. * @return MEMORY_E when dynamic memory allocation fails. */ int wolfSSL_CertManagerCheckOCSP(WOLFSSL_CERT_MANAGER* cm, const unsigned char* der, int sz) { int ret = 0; #ifdef WOLFSSL_SMALL_STACK DecodedCert* cert = NULL; #else DecodedCert cert[1]; #endif WOLFSSL_ENTER("wolfSSL_CertManagerCheckOCSP"); /* Validate parameters. */ if ((cm == NULL) || (der == NULL) || (sz <= 0)) { ret = BAD_FUNC_ARG; } /* Check if OCSP checking enabled. */ if ((ret == 0) && cm->ocspEnabled) { #ifdef WOLFSSL_SMALL_STACK /* Allocate memory for decoded certificate. */ cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), cm->heap, DYNAMIC_TYPE_DCERT); if (cert == NULL) { ret = MEMORY_E; } if (ret == 0) #endif { /* Initialize decoded certificate with buffer. */ InitDecodedCert(cert, der, (word32)sz, NULL); /* Parse certificate and perform CRL checks. */ ret = ParseCertRelative(cert, CERT_TYPE, VERIFY_OCSP, cm); if (ret != 0) { WOLFSSL_MSG("ParseCert failed"); } /* Do OCSP checks with decoded certificate. */ else if ((ret = CheckCertOCSP(cm->ocsp, cert)) != 0) { WOLFSSL_MSG("CheckCertOCSP failed"); } /* Dispose of dynamically allocated memory. */ FreeDecodedCert(cert); #ifdef WOLFSSL_SMALL_STACK XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT); #endif } } return (ret == 0) ? WOLFSSL_SUCCESS : ret; } /* Check OCSP response. * * @param [in] cm Certificate manager. * @param [in] response Buffer holding OCSP response. * @param [in] responseSz Size in bytes of OCSP response. * @param [in] responseBuffer Buffer to copy response into. * @param [in] status Place to store certificate status. * @param [in] entry Place to store OCSP entry. * @param [in] ocspRequest OCSP request to match with response. * @return WOLFSSL_SUCCESS on success. * @return BAD_FUNC_ARG when cm or response is NULL. */ 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"); /* Validate parameters. */ if ((cm == NULL) || (response == NULL)) { ret = BAD_FUNC_ARG; } if ((ret == 0) && cm->ocspEnabled) { /* Check OCSP response with OCSP object from certificate manager. */ ret = CheckOcspResponse(cm->ocsp, response, responseSz, responseBuffer, status, entry, ocspRequest, NULL); } return (ret == 0) ? WOLFSSL_SUCCESS : ret; } /* Set the OCSP override URL. * * @param [in] cm Certificate manager. * @param [in] url URL to get an OCSP response from. * @return WOLFSSL_SUCCESS on success. * @return BAD_FUNC_ARG when cm is NULL. * @return MEMORY_E when dynamic memory allocation fails. */ int wolfSSL_CertManagerSetOCSPOverrideURL(WOLFSSL_CERT_MANAGER* cm, const char* url) { int ret = WOLFSSL_SUCCESS; WOLFSSL_ENTER("wolfSSL_CertManagerSetOCSPOverrideURL"); /* Validate parameters. */ if (cm == NULL) { ret = BAD_FUNC_ARG; } if (ret == WOLFSSL_SUCCESS) { /* Dispose of old URL. */ XFREE(cm->ocspOverrideURL, cm->heap, DYNAMIC_TYPE_URL); if (url != NULL) { /* Calculate size of URL string. Include terminator character. */ int urlSz = (int)XSTRLEN(url) + 1; /* Allocate memory for URL to be copied into. */ cm->ocspOverrideURL = (char*)XMALLOC((size_t)urlSz, cm->heap, DYNAMIC_TYPE_URL); if (cm->ocspOverrideURL == NULL) { ret = MEMORY_E; } if (ret == WOLFSSL_SUCCESS) { /* Copy URL into certificate manager. */ XMEMCPY(cm->ocspOverrideURL, url, (size_t)urlSz); } } else { /* No URL to set so make it NULL. */ cm->ocspOverrideURL = NULL; } } return ret; } /* Set the OCSP I/O callback, OCSP response free callback and related data. * * @param [in] cm Certificate manager. * @param [in] ioCb OCSP callback. * @param [in] respFreeCb Callback to free OCSP response buffer. * @param [in] ioCbCtx Context data to pass to OCSP callbacks. * @return WOLFSSL_SUCCESS on success. * @return BAD_FUNC_ARG when cm is NULL. */ int wolfSSL_CertManagerSetOCSP_Cb(WOLFSSL_CERT_MANAGER* cm, CbOCSPIO ioCb, CbOCSPRespFree respFreeCb, void* ioCbCtx) { int ret = WOLFSSL_SUCCESS; WOLFSSL_ENTER("wolfSSL_CertManagerSetOCSP_Cb"); /* Validate parameters. */ if (cm == NULL) { ret = BAD_FUNC_ARG; } if (ret == WOLFSSL_SUCCESS) { /* Set callbacks and data into certificate manager. */ cm->ocspIOCb = ioCb; cm->ocspRespFreeCb = respFreeCb; cm->ocspIOCtx = ioCbCtx; } return ret; } #endif /* HAVE_OCSP */ #endif /* NO_CERTS */ #endif /* !WOLFSSL_SSL_CERTMAN_INCLUDED */