diff --git a/src/include.am b/src/include.am index bbee8f9394..7306369941 100644 --- a/src/include.am +++ b/src/include.am @@ -23,13 +23,16 @@ EXTRA_DIST += src/ssl_api_cert.c EXTRA_DIST += src/ssl_api_crl_ocsp.c EXTRA_DIST += src/ssl_api_dtls.c EXTRA_DIST += src/ssl_api_ext.c +EXTRA_DIST += src/ssl_api_hs.c EXTRA_DIST += src/ssl_api_pk.c +EXTRA_DIST += src/ssl_api_rw.c EXTRA_DIST += src/ssl_asn1.c EXTRA_DIST += src/ssl_tsp.c EXTRA_DIST += src/ssl_bn.c EXTRA_DIST += src/ssl_certman.c EXTRA_DIST += src/ssl_crypto.c EXTRA_DIST += src/ssl_ech.c +EXTRA_DIST += src/ssl_err.c EXTRA_DIST += src/ssl_load.c EXTRA_DIST += src/ssl_misc.c EXTRA_DIST += src/ssl_p7p12.c diff --git a/src/ssl.c b/src/ssl.c index f5a309552c..5dc478d807 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -273,57 +273,8 @@ static struct SystemCryptoPolicy crypto_policy; * WOLFSSL_EGD_NBLOCK: Non-blocking EGD entropy support default: off */ -#define WOLFSSL_SSL_MISC_INCLUDED -#include "src/ssl_misc.c" - -#define WOLFSSL_EVP_INCLUDED -#include "wolfcrypt/src/evp.c" - -/* Crypto code uses EVP APIs. */ -#define WOLFSSL_SSL_CRYPTO_INCLUDED -#include "src/ssl_crypto.c" - -#ifndef WOLFCRYPT_ONLY -#define WOLFSSL_SSL_CERTMAN_INCLUDED -#include "src/ssl_certman.c" - -#define WOLFSSL_SSL_SESS_INCLUDED -#include "src/ssl_sess.c" - -#define WOLFSSL_SSL_API_CERT_INCLUDED -#include "src/ssl_api_cert.c" - -#define WOLFSSL_SSL_API_PK_INCLUDED -#include "src/ssl_api_pk.c" -#endif - -#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \ - !defined(WOLFCRYPT_ONLY) -/* Convert shortname to NID. - * - * For OpenSSL compatibility. - * - * @param [in] sn Short name of OID. - * @return NID corresponding to shortname on success. - * @return WC_NID_undef when not recognized. - */ -int wc_OBJ_sn2nid(const char *sn) -{ - const WOLFSSL_ObjectInfo *obj_info = wolfssl_object_info; - size_t i; - WOLFSSL_ENTER("wc_OBJ_sn2nid"); - for (i = 0; i < wolfssl_object_info_sz; i++, obj_info++) { - if (XSTRCMP(sn, obj_info->sName) == 0) - return obj_info->nid; - } - WOLFSSL_MSG("short name not found in table"); - return WC_NID_undef; -} -#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ - #ifndef WOLFCRYPT_ONLY - #if !defined(NO_RSA) || !defined(NO_DH) || defined(HAVE_ECC) || \ (defined(OPENSSL_EXTRA) && defined(WOLFSSL_KEY_GEN) && !defined(NO_DSA)) @@ -447,13 +398,42 @@ WC_RNG* wolfssl_make_rng(WC_RNG* rng, int* local) #endif /* !WOLFSSL_NO_OPENSSL_RAND_CB */ #endif /* OPENSSL_EXTRA */ +#endif /* !WOLFCRYPT_ONLY */ + +#define WOLFSSL_SSL_MISC_INCLUDED +#include "src/ssl_misc.c" + +#define WOLFSSL_EVP_INCLUDED +#include "wolfcrypt/src/evp.c" + +/* Crypto code uses EVP APIs. */ +#define WOLFSSL_SSL_CRYPTO_INCLUDED +#include "src/ssl_crypto.c" + +#ifndef WOLFCRYPT_ONLY +#define WOLFSSL_SSL_CERTMAN_INCLUDED +#include "src/ssl_certman.c" + +#define WOLFSSL_SSL_SESS_INCLUDED +#include "src/ssl_sess.c" + +#define WOLFSSL_SSL_API_CERT_INCLUDED +#include "src/ssl_api_cert.c" + +#define WOLFSSL_SSL_API_PK_INCLUDED +#include "src/ssl_api_pk.c" +#endif + + +#ifndef WOLFCRYPT_ONLY + + + #define WOLFSSL_SSL_BN_INCLUDED #include "src/ssl_bn.c" -#ifndef OPENSSL_EXTRA_NO_ASN1 #define WOLFSSL_SSL_ASN1_INCLUDED #include "src/ssl_asn1.c" -#endif /* OPENSSL_EXTRA_NO_ASN1 */ #define WOLFSSL_SSL_TSP_INCLUDED #include "src/ssl_tsp.c" @@ -1374,46 +1354,6 @@ int wolfSSL_set_ConnectFilter( #endif /* WOLFSSL_WOLFSENTRY_HOOKS */ -#ifndef NO_TLS -/* return underlying connect or accept, WOLFSSL_SUCCESS on ok */ -int wolfSSL_negotiate(WOLFSSL* ssl) -{ - int err = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR); - - WOLFSSL_ENTER("wolfSSL_negotiate"); - - if (ssl == NULL) - return WOLFSSL_FATAL_ERROR; - -#ifndef NO_WOLFSSL_SERVER - if (ssl->options.side == WOLFSSL_SERVER_END) { -#ifdef WOLFSSL_TLS13 - if (IsAtLeastTLSv1_3(ssl->version)) - err = wolfSSL_accept_TLSv13(ssl); - else -#endif - err = wolfSSL_accept(ssl); - } -#endif - -#ifndef NO_WOLFSSL_CLIENT - if (ssl->options.side == WOLFSSL_CLIENT_END) { -#ifdef WOLFSSL_TLS13 - if (IsAtLeastTLSv1_3(ssl->version)) - err = wolfSSL_connect_TLSv13(ssl); - else -#endif - err = wolfSSL_connect(ssl); - } -#endif - - (void)ssl; - - WOLFSSL_LEAVE("wolfSSL_negotiate", err); - - return err; -} -#endif /* !NO_TLS */ WOLFSSL_ABI WC_RNG* wolfSSL_GetRNG(WOLFSSL* ssl) @@ -1632,1372 +1572,655 @@ int wolfSSL_GetOutputSize(WOLFSSL* ssl, int inSz) } -static int wolfSSL_write_internal(WOLFSSL* ssl, const void* data, size_t sz) -{ - int ret = 0; - - WOLFSSL_ENTER("wolfSSL_write"); - - if (ssl == NULL || data == NULL) - return BAD_FUNC_ARG; - -#ifdef WOLFSSL_QUIC - if (WOLFSSL_IS_QUIC(ssl)) { - WOLFSSL_MSG("SSL_write() on QUIC not allowed"); - return BAD_FUNC_ARG; - } -#endif - -#ifdef HAVE_WRITE_DUP - if (ssl->dupSide == READ_DUP_SIDE) { - WOLFSSL_MSG("Read dup side cannot write"); - return WRITE_DUP_WRITE_E; - } - /* Only enter special dupWrite logic when error is cleared. This will help - * with handling async data and other edge case errors. */ - if (ssl->dupWrite != NULL && ssl->error == 0) { - int dupErr = 0; /* local copy */ - /* Lock ssl->dupWrite to gather what needs to be done. */ - if (wc_LockMutex(&ssl->dupWrite->dupMutex) != 0) - return BAD_MUTEX_E; - dupErr = ssl->dupWrite->dupErr; -#ifdef WOLFSSL_TLS13 - if (IsAtLeastTLSv1_3(ssl->version)) { - /* TLS 1.3: if the read side received a KeyUpdate(update_requested) - * it cannot respond; send the response from here. */ - ssl->keys.keyUpdateRespond |= ssl->dupWrite->keyUpdateRespond; - ssl->dupWrite->keyUpdateRespond = 0; -#ifdef WOLFSSL_POST_HANDSHAKE_AUTH - ssl->postHandshakeAuthPending |= - ssl->dupWrite->postHandshakeAuthPending; - ssl->dupWrite->postHandshakeAuthPending = 0; - if (ssl->postHandshakeAuthPending) { - /* Take ownership of the delegated auth state. */ - CertReqCtx** tail = &ssl->dupWrite->postHandshakeCertReqCtx; - while (*tail != NULL) - tail = &(*tail)->next; - *tail = ssl->certReqCtx; - ssl->certReqCtx = ssl->dupWrite->postHandshakeCertReqCtx; - ssl->dupWrite->postHandshakeCertReqCtx = NULL; - FreeHandshakeHashes(ssl); - ssl->hsHashes = ssl->dupWrite->postHandshakeHashState; - ssl->dupWrite->postHandshakeHashState = NULL; - ssl->options.sendVerify = ssl->dupWrite->postHandshakeSendVerify; - ssl->options.sigAlgo = ssl->dupWrite->postHandshakeSigAlgo; - ssl->options.hashAlgo = ssl->dupWrite->postHandshakeHashAlgo; - } -#endif /* WOLFSSL_POST_HANDSHAKE_AUTH */ -#ifdef WOLFSSL_DTLS13 - if (ssl->options.dtls) { - /* Schedule key update to be sent. */ - if (ssl->keys.keyUpdateRespond) - ssl->dtls13DoKeyUpdate = 1; - - /* Copy over ACKs */ - ssl->dtls13Rtx.sendAcks |= ssl->dupWrite->sendAcks; - if (ssl->dupWrite->sendAcks) { - /* Insert each record number so the - * ACK message is properly ordered. */ - struct Dtls13RecordNumber* rn; - for (rn = ssl->dupWrite->sendAckList; rn != NULL; - rn = rn->next) { - ret = Dtls13RtxAddAck(ssl, rn->epoch, rn->seq); - if (ret != 0) - break; - } - /* Clear only on success so no ACKs get dropped */ - if (ret == 0) { - rn = ssl->dupWrite->sendAckList; - ssl->dupWrite->sendAckList = NULL; - ssl->dupWrite->sendAcks = 0; - while (rn != NULL) { - struct Dtls13RecordNumber* next = rn->next; - XFREE(rn, ssl->heap, DYNAMIC_TYPE_DTLS_MSG); - rn = next; - } - } - } - - /* Remove KeyUpdate record from RTX list. */ - if (ssl->dupWrite->keyUpdateAcked) { - Dtls13RtxRemoveRecord(ssl, ssl->dupWrite->keyUpdateEpoch, - ssl->dupWrite->keyUpdateSeq); - } - /* Store if KeyUpdate was ACKed. */ - ssl->dtls13KeyUpdateAcked |= ssl->dupWrite->keyUpdateAcked; - ssl->dupWrite->keyUpdateAcked = 0; - } -#endif /* WOLFSSL_DTLS13 */ - } -#endif /* WOLFSSL_TLS13 */ - wc_UnLockMutex(&ssl->dupWrite->dupMutex); - - if (dupErr != 0) { - WOLFSSL_MSG("Write dup error from other side"); - ssl->error = dupErr; - return WOLFSSL_FATAL_ERROR; - } - if (ret != 0) { - ssl->error = ret; - return WOLFSSL_FATAL_ERROR; - } - - -#ifdef WOLFSSL_TLS13 - if (IsAtLeastTLSv1_3(ssl->version)) { -#ifdef WOLFSSL_POST_HANDSHAKE_AUTH - /* Read side received a CertificateRequest but couldn't write; - * send Certificate+CertificateVerify+Finished from the write side. */ - if (ssl->postHandshakeAuthPending) { - /* reset handshake states */ - ssl->postHandshakeAuthPending = 0; - ssl->options.clientState = CLIENT_HELLO_COMPLETE; - ssl->options.connectState = FIRST_REPLY_DONE; - ssl->options.handShakeState = CLIENT_HELLO_COMPLETE; - ssl->options.processReply = 0; /* doProcessInit */ - if (wolfSSL_connect_TLSv13(ssl) != WOLFSSL_SUCCESS) { - if (ssl->error != WC_NO_ERR_TRACE(WANT_WRITE) && - ssl->error != WC_NO_ERR_TRACE(WC_PENDING_E)) { - WOLFSSL_MSG("Post-handshake auth send failed"); - ssl->error = POST_HAND_AUTH_ERROR; - } - return WOLFSSL_FATAL_ERROR; - } - } -#endif /* WOLFSSL_POST_HANDSHAKE_AUTH */ -#ifdef WOLFSSL_DTLS13 - if (ssl->options.dtls) { - if (ssl->dtls13KeyUpdateAcked) - ret = DoDtls13KeyUpdateAck(ssl); - ssl->dtls13KeyUpdateAcked = 0; - if (ret == 0) - ret = Dtls13DoScheduledWork(ssl); - } - else -#endif /* WOLFSSL_DTLS13 */ - if (ssl->keys.keyUpdateRespond) /* cleared in SendTls13KeyUpdate */ - ret = Tls13UpdateKeys(ssl); - if (ret != 0) { - ssl->error = ret; - return WOLFSSL_FATAL_ERROR; - } - /* WANT_WRITE is safe to clear. Data is buffered in output buffer - * or in DTLS RTX queue */ - ret = 0; - } -#endif /* WOLFSSL_TLS13 */ - } -#endif - -#ifdef HAVE_ERRNO_H - errno = 0; -#endif - #ifdef OPENSSL_EXTRA - if (ssl->CBIS != NULL) { - ssl->CBIS(ssl, WOLFSSL_CB_WRITE, WOLFSSL_SUCCESS); - ssl->cbmode = WOLFSSL_CB_WRITE; - } - #endif - ret = SendData(ssl, data, sz); +#endif /* !NO_TLS */ - WOLFSSL_LEAVE("wolfSSL_write", ret); +#define WOLFSSL_SSL_API_RW_INCLUDED +#include "src/ssl_api_rw.c" - if (ret < 0) - return WOLFSSL_FATAL_ERROR; - else - return ret; -} +#define WOLFSSL_SSL_API_DTLS_INCLUDED +#include "src/ssl_api_dtls.c" +/* helpers to set the device id, WOLFSSL_SUCCESS on ok */ WOLFSSL_ABI -int wolfSSL_write(WOLFSSL* ssl, const void* data, int sz) +int wolfSSL_SetDevId(WOLFSSL* ssl, int devId) { - WOLFSSL_ENTER("wolfSSL_write"); - - if (sz < 0) + if (ssl == NULL) return BAD_FUNC_ARG; - return wolfSSL_write_internal(ssl, data, (size_t)sz); + ssl->devId = devId; + + return WOLFSSL_SUCCESS; } -int wolfSSL_inject(WOLFSSL* ssl, const void* data, int sz) +WOLFSSL_ABI +int wolfSSL_CTX_SetDevId(WOLFSSL_CTX* ctx, int devId) { - int maxLength; - int usedLength; - - WOLFSSL_ENTER("wolfSSL_inject"); - - if (ssl == NULL || data == NULL || sz <= 0) + if (ctx == NULL) return BAD_FUNC_ARG; - usedLength = (int)(ssl->buffers.inputBuffer.length - - ssl->buffers.inputBuffer.idx); - maxLength = (int)(ssl->buffers.inputBuffer.bufferSize - - (word32)usedLength); - - if (sz > maxLength) { - /* Need to make space */ - int ret; - if (ssl->buffers.clearOutputBuffer.length > 0) { - /* clearOutputBuffer points into so reallocating inputBuffer will - * invalidate clearOutputBuffer and lose app data */ - WOLFSSL_MSG("Can't inject while there is application data to read"); - return APP_DATA_READY; - } - ret = GrowInputBuffer(ssl, sz, usedLength); - if (ret < 0) - return ret; - } - - XMEMCPY(ssl->buffers.inputBuffer.buffer + ssl->buffers.inputBuffer.idx, - data, sz); - ssl->buffers.inputBuffer.length += sz; + ctx->devId = devId; return WOLFSSL_SUCCESS; } - -int wolfSSL_write_ex(WOLFSSL* ssl, const void* data, size_t sz, size_t* wr) +/* helpers to get device id and heap */ +WOLFSSL_ABI +int wolfSSL_CTX_GetDevId(WOLFSSL_CTX* ctx, WOLFSSL* ssl) { - int ret; + int devId = INVALID_DEVID; + if (ssl != NULL) + devId = ssl->devId; + if (ctx != NULL && devId == INVALID_DEVID) + devId = ctx->devId; + return devId; +} +void* wolfSSL_CTX_GetHeap(WOLFSSL_CTX* ctx, WOLFSSL* ssl) +{ + void* heap = NULL; + if (ctx != NULL) + heap = ctx->heap; + else if (ssl != NULL) + heap = ssl->heap; + return heap; +} - if (wr != NULL) { - *wr = 0; - } - ret = wolfSSL_write_internal(ssl, data, sz); - if (ret >= 0) { - if (wr != NULL) { - *wr = (size_t)ret; - } - /* handle partial write cases, if not set then a partial write is - * considered a failure case, or if set and ret is 0 then is a fail */ - if (ret == 0 && ssl->options.partialWrite) { - ret = 0; - } - else if ((size_t)ret < sz && !ssl->options.partialWrite) { - ret = 0; - } - else { - /* wrote out all application data, or wrote out 1 byte or more with - * partial write flag set */ - ret = 1; - } - } - else { - ret = 0; +/* get current error state value */ +int wolfSSL_state(WOLFSSL* ssl) +{ + if (ssl == NULL) { + return BAD_FUNC_ARG; } - return ret; + return ssl->error; } -static int wolfSSL_read_internal(WOLFSSL* ssl, void* data, size_t sz, int peek) +WOLFSSL_ABI +int wolfSSL_get_error(WOLFSSL* ssl, int ret) { - int ret; - - WOLFSSL_ENTER("wolfSSL_read_internal"); - - if (ssl == NULL || data == NULL) - return BAD_FUNC_ARG; + WOLFSSL_ENTER("wolfSSL_get_error"); -#ifdef WOLFSSL_QUIC - if (WOLFSSL_IS_QUIC(ssl)) { - WOLFSSL_MSG("SSL_read() on QUIC not allowed"); + if (ret > 0) + return WOLFSSL_ERROR_NONE; + if (ssl == NULL) return BAD_FUNC_ARG; - } -#endif -#if defined(WOLFSSL_ERROR_CODE_OPENSSL) && defined(OPENSSL_EXTRA) - /* This additional logic is meant to simulate following openSSL behavior: - * After bidirectional SSL_shutdown complete, SSL_read returns 0 and - * SSL_get_error_code returns SSL_ERROR_ZERO_RETURN. - * This behavior is used to know the disconnect of the underlying - * transport layer. - * - * In this logic, CBIORecv is called with a read size of 0 to check the - * transport layer status. It also returns WOLFSSL_FAILURE so that - * SSL_read does not return a positive number on failure. - */ - /* make sure bidirectional TLS shutdown completes */ - if (ssl->error == WOLFSSL_ERROR_SYSCALL || ssl->options.shutdownDone) { - /* ask the underlying transport the connection is closed */ - if (ssl->CBIORecv(ssl, (char*)data, 0, ssl->IOCB_ReadCtx) - == WC_NO_ERR_TRACE(WOLFSSL_CBIO_ERR_CONN_CLOSE)) - { - ssl->options.isClosed = 1; - ssl->error = WOLFSSL_ERROR_ZERO_RETURN; - } - return WOLFSSL_FAILURE; - } -#endif + WOLFSSL_LEAVE("wolfSSL_get_error", ssl->error); -#ifdef HAVE_WRITE_DUP - if (ssl->dupWrite && ssl->dupSide == WRITE_DUP_SIDE) { - WOLFSSL_MSG("Write dup side cannot read"); - return WRITE_DUP_READ_E; - } + /* make sure converted types are handled in SetErrorString() too */ + if (ssl->error == WC_NO_ERR_TRACE(WANT_READ)) + return WOLFSSL_ERROR_WANT_READ; /* convert to OpenSSL type */ + else if (ssl->error == WC_NO_ERR_TRACE(WANT_WRITE)) + return WOLFSSL_ERROR_WANT_WRITE; /* convert to OpenSSL type */ + else if (ssl->error == WC_NO_ERR_TRACE(ZERO_RETURN) || + ssl->options.shutdownDone) + return WOLFSSL_ERROR_ZERO_RETURN; /* convert to OpenSSL type */ +#ifdef OPENSSL_EXTRA + else if (ssl->error == WC_NO_ERR_TRACE(MATCH_SUITE_ERROR)) + return WOLFSSL_ERROR_SYSCALL; /* convert to OpenSSL type */ + else if (ssl->error == WC_NO_ERR_TRACE(SOCKET_PEER_CLOSED_E)) + return WOLFSSL_ERROR_SYSCALL; /* convert to OpenSSL type */ #endif - -#ifdef HAVE_ERRNO_H - errno = 0; +#ifdef WOLFSSL_ASYNC_CRYPT + else if (ssl->error == WC_NO_ERR_TRACE(MP_WOULDBLOCK)) + return WC_PENDING_E; /* map non-blocking crypto */ #endif + return ssl->error; +} - ret = ReceiveData(ssl, (byte*)data, sz, peek); -#ifdef HAVE_WRITE_DUP - if (ssl->dupWrite) { - if (ssl->error != 0 && ssl->error != WC_NO_ERR_TRACE(WANT_READ) - #ifdef WOLFSSL_ASYNC_CRYPT - && ssl->error != WC_NO_ERR_TRACE(WC_PENDING_E) - #endif - ) { - int notifyErr; - - WOLFSSL_MSG("Notifying write side of fatal read error"); - notifyErr = NotifyWriteSide(ssl, ssl->error); - if (notifyErr < 0) { - ret = ssl->error = notifyErr; - } - } +/* retrieve alert history, WOLFSSL_SUCCESS on ok */ +int wolfSSL_get_alert_history(WOLFSSL* ssl, WOLFSSL_ALERT_HISTORY *h) +{ + if (ssl && h) { + *h = ssl->alert_history; } -#endif - - WOLFSSL_LEAVE("wolfSSL_read_internal", ret); - - if (ret < 0) - return WOLFSSL_FATAL_ERROR; - else - return ret; + return WOLFSSL_SUCCESS; } -int wolfSSL_peek(WOLFSSL* ssl, void* data, int sz) -{ - WOLFSSL_ENTER("wolfSSL_peek"); +#define WOLFSSL_SSL_ERR_INCLUDED +#include "src/ssl_err.c" - if (sz < 0) - return BAD_FUNC_ARG; - return wolfSSL_read_internal(ssl, data, (size_t)sz, TRUE); +/* don't free temporary arrays at end of handshake */ +void wolfSSL_KeepArrays(WOLFSSL* ssl) +{ + if (ssl) + ssl->options.saveArrays = 1; } -WOLFSSL_ABI -int wolfSSL_read(WOLFSSL* ssl, void* data, int sz) +/* user doesn't need temporary arrays anymore, Free */ +void wolfSSL_FreeArrays(WOLFSSL* ssl) { - WOLFSSL_ENTER("wolfSSL_read"); - - if (sz < 0) - return BAD_FUNC_ARG; - - #ifdef OPENSSL_EXTRA - if (ssl == NULL) { - return BAD_FUNC_ARG; - } - if (ssl->CBIS != NULL) { - ssl->CBIS(ssl, WOLFSSL_CB_READ, WOLFSSL_SUCCESS); - ssl->cbmode = WOLFSSL_CB_READ; + if (ssl && ssl->options.handShakeState == HANDSHAKE_DONE) { + ssl->options.saveArrays = 0; + FreeArrays(ssl, 1); } - #endif - return wolfSSL_read_internal(ssl, data, (size_t)sz, FALSE); } - -/* returns 0 on failure and 1 on read */ -int wolfSSL_read_ex(WOLFSSL* ssl, void* data, size_t sz, size_t* rd) +/* Set option to indicate that the resources are not to be freed after + * handshake. + * + * ssl The SSL/TLS object. + * returns BAD_FUNC_ARG when ssl is NULL and 0 on success. + */ +int wolfSSL_KeepHandshakeResources(WOLFSSL* ssl) { - int ret; - - #ifdef OPENSSL_EXTRA - if (ssl == NULL) { + if (ssl == NULL) return BAD_FUNC_ARG; - } - if (ssl->CBIS != NULL) { - ssl->CBIS(ssl, WOLFSSL_CB_READ, WOLFSSL_SUCCESS); - ssl->cbmode = WOLFSSL_CB_READ; - } - #endif - ret = wolfSSL_read_internal(ssl, data, sz, FALSE); - if (ret > 0 && rd != NULL) { - *rd = (size_t)ret; - } + ssl->options.keepResources = 1; - return ret > 0 ? 1 : 0; + return 0; } -#endif /* !NO_TLS */ - -#define WOLFSSL_SSL_API_DTLS_INCLUDED -#include "src/ssl_api_dtls.c" - -/* helpers to set the device id, WOLFSSL_SUCCESS on ok */ -WOLFSSL_ABI -int wolfSSL_SetDevId(WOLFSSL* ssl, int devId) +/* Free the handshake resources after handshake. + * + * ssl The SSL/TLS object. + * returns BAD_FUNC_ARG when ssl is NULL and 0 on success. + */ +int wolfSSL_FreeHandshakeResources(WOLFSSL* ssl) { if (ssl == NULL) return BAD_FUNC_ARG; - ssl->devId = devId; + FreeHandshakeResources(ssl); - return WOLFSSL_SUCCESS; + return 0; } -WOLFSSL_ABI -int wolfSSL_CTX_SetDevId(WOLFSSL_CTX* ctx, int devId) +/* Use the client's order of preference when matching cipher suites. + * + * ssl The SSL/TLS context object. + * returns BAD_FUNC_ARG when ssl is NULL and 0 on success. + */ +int wolfSSL_CTX_UseClientSuites(WOLFSSL_CTX* ctx) { if (ctx == NULL) return BAD_FUNC_ARG; - ctx->devId = devId; + ctx->useClientOrder = 1; - return WOLFSSL_SUCCESS; + return 0; } -/* helpers to get device id and heap */ -WOLFSSL_ABI -int wolfSSL_CTX_GetDevId(WOLFSSL_CTX* ctx, WOLFSSL* ssl) -{ - int devId = INVALID_DEVID; - if (ssl != NULL) - devId = ssl->devId; - if (ctx != NULL && devId == INVALID_DEVID) - devId = ctx->devId; - return devId; -} -void* wolfSSL_CTX_GetHeap(WOLFSSL_CTX* ctx, WOLFSSL* ssl) +/* Use the client's order of preference when matching cipher suites. + * + * ssl The SSL/TLS object. + * returns BAD_FUNC_ARG when ssl is NULL and 0 on success. + */ +int wolfSSL_UseClientSuites(WOLFSSL* ssl) { - void* heap = NULL; - if (ctx != NULL) - heap = ctx->heap; - else if (ssl != NULL) - heap = ssl->heap; - return heap; -} - + if (ssl == NULL) + return BAD_FUNC_ARG; -#ifndef NO_TLS + ssl->options.useClientOrder = 1; + return 0; +} -#ifndef WOLFSSL_LEANPSK -int wolfSSL_send(WOLFSSL* ssl, const void* data, int sz, int flags) +const byte* wolfSSL_GetMacSecret(WOLFSSL* ssl, int verify) { - int ret; - int oldFlags; +#ifndef WOLFSSL_AEAD_ONLY + if (ssl == NULL) + return NULL; - WOLFSSL_ENTER("wolfSSL_send"); + if ( (ssl->options.side == WOLFSSL_CLIENT_END && !verify) || + (ssl->options.side == WOLFSSL_SERVER_END && verify) ) + return ssl->keys.client_write_MAC_secret; + else + return ssl->keys.server_write_MAC_secret; +#else + (void)ssl; + (void)verify; - if (ssl == NULL || data == NULL || sz < 0) - return BAD_FUNC_ARG; + return NULL; +#endif +} - oldFlags = ssl->wflags; +int wolfSSL_GetSide(WOLFSSL* ssl) +{ + if (ssl) + return ssl->options.side; - ssl->wflags = flags; - ret = wolfSSL_write(ssl, data, sz); - ssl->wflags = oldFlags; + return BAD_FUNC_ARG; +} - WOLFSSL_LEAVE("wolfSSL_send", ret); +#ifdef ATOMIC_USER - return ret; +void wolfSSL_CTX_SetMacEncryptCb(WOLFSSL_CTX* ctx, CallbackMacEncrypt cb) +{ + if (ctx) + ctx->MacEncryptCb = cb; } -int wolfSSL_recv(WOLFSSL* ssl, void* data, int sz, int flags) +void wolfSSL_SetMacEncryptCtx(WOLFSSL* ssl, void *ctx) { - int ret; - int oldFlags; - - WOLFSSL_ENTER("wolfSSL_recv"); + if (ssl) + ssl->MacEncryptCtx = ctx; +} - if (ssl == NULL || data == NULL || sz < 0) - return BAD_FUNC_ARG; - oldFlags = ssl->rflags; +void* wolfSSL_GetMacEncryptCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->MacEncryptCtx; - ssl->rflags = flags; - ret = wolfSSL_read(ssl, data, sz); - ssl->rflags = oldFlags; + return NULL; +} - WOLFSSL_LEAVE("wolfSSL_recv", ret); - return ret; +void wolfSSL_CTX_SetDecryptVerifyCb(WOLFSSL_CTX* ctx, CallbackDecryptVerify cb) +{ + if (ctx) + ctx->DecryptVerifyCb = cb; } -#endif -int wolfSSL_SendUserCanceled(WOLFSSL* ssl) + +void wolfSSL_SetDecryptVerifyCtx(WOLFSSL* ssl, void *ctx) { - int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); - WOLFSSL_ENTER("wolfSSL_recv"); + if (ssl) + ssl->DecryptVerifyCtx = ctx; +} - if (ssl != NULL) { - ssl->error = SendAlert(ssl, alert_warning, user_canceled); - if (ssl->error < 0) { - WOLFSSL_ERROR(ssl->error); - } - else { - ret = wolfSSL_shutdown(ssl); - } - } - WOLFSSL_LEAVE("wolfSSL_SendUserCanceled", ret); +void* wolfSSL_GetDecryptVerifyCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->DecryptVerifyCtx; - return ret; + return NULL; } -/* WOLFSSL_SUCCESS on ok */ -WOLFSSL_ABI -int wolfSSL_shutdown(WOLFSSL* ssl) +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) +/** + * Set the callback, against the context, that encrypts then MACs. + * + * ctx SSL/TLS context. + * cb Callback function to use with Encrypt-Then-MAC. + */ +void wolfSSL_CTX_SetEncryptMacCb(WOLFSSL_CTX* ctx, CallbackEncryptMac cb) { - int ret = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR); - WOLFSSL_ENTER("wolfSSL_shutdown"); - - if (ssl == NULL) - return WOLFSSL_FATAL_ERROR; + if (ctx) + ctx->EncryptMacCb = cb; +} - if (ssl->options.quietShutdown) { - WOLFSSL_MSG("quiet shutdown, no close notify sent"); - ret = WOLFSSL_SUCCESS; - } - else { +/** + * Set the context to use with callback that encrypts then MACs. + * + * ssl SSL/TLS object. + * ctx Callback function's context. + */ +void wolfSSL_SetEncryptMacCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->EncryptMacCtx = ctx; +} - /* Try to flush the buffer first, it might contain the alert */ - if (ssl->error == WC_NO_ERR_TRACE(WANT_WRITE) && - ssl->buffers.outputBuffer.length > 0) { - ret = SendBuffered(ssl); - if (ret != 0) { - ssl->error = ret; - /* for error tracing */ - if (ret != WC_NO_ERR_TRACE(WANT_WRITE)) - WOLFSSL_ERROR(ret); - ret = WOLFSSL_FATAL_ERROR; - WOLFSSL_LEAVE("wolfSSL_shutdown", ret); - return ret; - } +/** + * Get the context being used with callback that encrypts then MACs. + * + * ssl SSL/TLS object. + * returns callback function's context or NULL if SSL/TLS object is NULL. + */ +void* wolfSSL_GetEncryptMacCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->EncryptMacCtx; - ssl->error = WOLFSSL_ERROR_NONE; - /* we succeeded in sending the alert now */ - if (ssl->options.sentNotify) { - /* just after we send the alert, if we didn't receive the alert - * from the other peer yet, return WOLFSSL_STHUDOWN_NOT_DONE */ - if (!ssl->options.closeNotify) { - ret = WOLFSSL_SHUTDOWN_NOT_DONE; - WOLFSSL_LEAVE("wolfSSL_shutdown", ret); - return ret; - } - else { - ssl->options.shutdownDone = 1; - ret = WOLFSSL_SUCCESS; - } - } - } + return NULL; +} - /* try to send close notify, not an error if can't */ - if (!ssl->options.isClosed && !ssl->options.connReset && - !ssl->options.sentNotify) { - ssl->error = SendAlert(ssl, alert_warning, close_notify); - /* the alert is now sent or sitting in the buffer, - * where will be sent eventually */ - if (ssl->error == 0 || ssl->error == WC_NO_ERR_TRACE(WANT_WRITE)) - ssl->options.sentNotify = 1; +/** + * Set the callback, against the context, that MAC verifies then decrypts. + * + * ctx SSL/TLS context. + * cb Callback function to use with Encrypt-Then-MAC. + */ +void wolfSSL_CTX_SetVerifyDecryptCb(WOLFSSL_CTX* ctx, CallbackVerifyDecrypt cb) +{ + if (ctx) + ctx->VerifyDecryptCb = cb; +} - if (ssl->error < 0) { - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } +/** + * Set the context to use with callback that MAC verifies then decrypts. + * + * ssl SSL/TLS object. + * ctx Callback function's context. + */ +void wolfSSL_SetVerifyDecryptCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->VerifyDecryptCtx = ctx; +} - if (ssl->options.closeNotify) { - ret = WOLFSSL_SUCCESS; - ssl->options.shutdownDone = 1; - } - else { - ret = WOLFSSL_SHUTDOWN_NOT_DONE; - WOLFSSL_LEAVE("wolfSSL_shutdown", ret); - return ret; - } - } - -#ifdef WOLFSSL_SHUTDOWNONCE - if (ssl->options.isClosed || ssl->options.connReset) { - /* Shutdown has already occurred. - * Caller is free to ignore this error. */ - return SSL_SHUTDOWN_ALREADY_DONE_E; - } -#endif - - /* wolfSSL_shutdown called again for bidirectional shutdown */ - if (ssl->options.sentNotify && !ssl->options.closeNotify) { - /* If there is still buffered application data waiting to be read, - * do not process incoming records here. clearOutputBuffer.buffer - * points into inputBuffer, and ProcessReply() may call - * GrowInputBuffer(), which frees and reallocates inputBuffer. - * Require the pending data to be drained first. */ - if (ssl->buffers.clearOutputBuffer.length > 0) { - WOLFSSL_MSG("Pending application data, read it before shutdown"); - ret = WOLFSSL_SHUTDOWN_NOT_DONE; - WOLFSSL_LEAVE("wolfSSL_shutdown", ret); - return ret; - } - ret = ProcessReply(ssl); - if ((ret == WC_NO_ERR_TRACE(ZERO_RETURN)) || - (ret == WC_NO_ERR_TRACE(SOCKET_ERROR_E))) { - /* simulate OpenSSL behavior */ - ssl->options.shutdownDone = 1; - /* Clear error */ - ssl->error = WOLFSSL_ERROR_NONE; - ret = WOLFSSL_SUCCESS; - } - else if (ret == WC_NO_ERR_TRACE(MEMORY_E)) { - ret = WOLFSSL_FATAL_ERROR; - } - else if (ret == WC_NO_ERR_TRACE(WANT_READ)) { - ssl->error = ret; - ret = WOLFSSL_FATAL_ERROR; - } - else if (ssl->error == WOLFSSL_ERROR_NONE) { - ret = WOLFSSL_SHUTDOWN_NOT_DONE; - } - else { - WOLFSSL_ERROR(ssl->error); - ret = WOLFSSL_FATAL_ERROR; - } - } - } +/** + * Get the context being used with callback that MAC verifies then decrypts. + * + * ssl SSL/TLS object. + * returns callback function's context or NULL if SSL/TLS object is NULL. + */ +void* wolfSSL_GetVerifyDecryptCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->VerifyDecryptCtx; -#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) - /* reset WOLFSSL structure state for possible reuse */ - if (ret == WOLFSSL_SUCCESS) { - if (wolfSSL_clear(ssl) != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("could not clear WOLFSSL"); - ret = WOLFSSL_FATAL_ERROR; - } - } -#endif + return NULL; +} +#endif /* HAVE_ENCRYPT_THEN_MAC !WOLFSSL_AEAD_ONLY */ - WOLFSSL_LEAVE("wolfSSL_shutdown", ret); - return ret; -} -#endif /* !NO_TLS */ -/* get current error state value */ -int wolfSSL_state(WOLFSSL* ssl) +const byte* wolfSSL_GetClientWriteKey(WOLFSSL* ssl) { - if (ssl == NULL) { - return BAD_FUNC_ARG; - } + if (ssl) + return ssl->keys.client_write_key; - return ssl->error; + return NULL; } -WOLFSSL_ABI -int wolfSSL_get_error(WOLFSSL* ssl, int ret) +const byte* wolfSSL_GetClientWriteIV(WOLFSSL* ssl) { - WOLFSSL_ENTER("wolfSSL_get_error"); - - if (ret > 0) - return WOLFSSL_ERROR_NONE; - if (ssl == NULL) - return BAD_FUNC_ARG; - - WOLFSSL_LEAVE("wolfSSL_get_error", ssl->error); + if (ssl) + return ssl->keys.client_write_IV; - /* make sure converted types are handled in SetErrorString() too */ - if (ssl->error == WC_NO_ERR_TRACE(WANT_READ)) - return WOLFSSL_ERROR_WANT_READ; /* convert to OpenSSL type */ - else if (ssl->error == WC_NO_ERR_TRACE(WANT_WRITE)) - return WOLFSSL_ERROR_WANT_WRITE; /* convert to OpenSSL type */ - else if (ssl->error == WC_NO_ERR_TRACE(ZERO_RETURN) || - ssl->options.shutdownDone) - return WOLFSSL_ERROR_ZERO_RETURN; /* convert to OpenSSL type */ -#ifdef OPENSSL_EXTRA - else if (ssl->error == WC_NO_ERR_TRACE(MATCH_SUITE_ERROR)) - return WOLFSSL_ERROR_SYSCALL; /* convert to OpenSSL type */ - else if (ssl->error == WC_NO_ERR_TRACE(SOCKET_PEER_CLOSED_E)) - return WOLFSSL_ERROR_SYSCALL; /* convert to OpenSSL type */ -#endif -#ifdef WOLFSSL_ASYNC_CRYPT - else if (ssl->error == WC_NO_ERR_TRACE(MP_WOULDBLOCK)) - return WC_PENDING_E; /* map non-blocking crypto */ -#endif - return ssl->error; + return NULL; } -/* retrieve alert history, WOLFSSL_SUCCESS on ok */ -int wolfSSL_get_alert_history(WOLFSSL* ssl, WOLFSSL_ALERT_HISTORY *h) +const byte* wolfSSL_GetServerWriteKey(WOLFSSL* ssl) { - if (ssl && h) { - *h = ssl->alert_history; - } - return WOLFSSL_SUCCESS; -} + if (ssl) + return ssl->keys.server_write_key; -#ifdef OPENSSL_EXTRA -/* returns SSL_WRITING, SSL_READING or SSL_NOTHING */ -int wolfSSL_want(WOLFSSL* ssl) -{ - int rw_state = WOLFSSL_NOTHING; - if (ssl) { - if (ssl->error == WC_NO_ERR_TRACE(WANT_READ)) - rw_state = WOLFSSL_READING; - else if (ssl->error == WC_NO_ERR_TRACE(WANT_WRITE)) - rw_state = WOLFSSL_WRITING; - } - return rw_state; + return NULL; } -#endif - -/* return TRUE if current error is want read */ -int wolfSSL_want_read(WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_want_read"); - if (ssl->error == WC_NO_ERR_TRACE(WANT_READ)) - return 1; - return 0; -} -/* return TRUE if current error is want write */ -int wolfSSL_want_write(WOLFSSL* ssl) +const byte* wolfSSL_GetServerWriteIV(WOLFSSL* ssl) { - WOLFSSL_ENTER("wolfSSL_want_write"); - if (ssl->error == WC_NO_ERR_TRACE(WANT_WRITE)) - return 1; + if (ssl) + return ssl->keys.server_write_IV; - return 0; + return NULL; } -char* wolfSSL_ERR_error_string(unsigned long errNumber, char* data) +int wolfSSL_GetKeySize(WOLFSSL* ssl) { - WOLFSSL_ENTER("wolfSSL_ERR_error_string"); - if (data) { - SetErrorString((int)errNumber, data); - return data; - } - else { - static char tmp[WOLFSSL_MAX_ERROR_SZ] = {0}; - SetErrorString((int)errNumber, tmp); - return tmp; - } -} - + if (ssl) + return ssl->specs.key_size; -void wolfSSL_ERR_error_string_n(unsigned long e, char* buf, unsigned long len) -{ - WOLFSSL_ENTER("wolfSSL_ERR_error_string_n"); - if (len >= WOLFSSL_MAX_ERROR_SZ) - wolfSSL_ERR_error_string(e, buf); - else { - WOLFSSL_MSG("Error buffer too short, truncating"); - if (len) { - char tmp[WOLFSSL_MAX_ERROR_SZ]; - wolfSSL_ERR_error_string(e, tmp); - XMEMCPY(buf, tmp, len-1); - buf[len-1] = '\0'; - } - } + return BAD_FUNC_ARG; } -/* don't free temporary arrays at end of handshake */ -void wolfSSL_KeepArrays(WOLFSSL* ssl) +int wolfSSL_GetIVSize(WOLFSSL* ssl) { if (ssl) - ssl->options.saveArrays = 1; + return ssl->specs.iv_size; + + return BAD_FUNC_ARG; } -/* user doesn't need temporary arrays anymore, Free */ -void wolfSSL_FreeArrays(WOLFSSL* ssl) +int wolfSSL_GetBulkCipher(WOLFSSL* ssl) { - if (ssl && ssl->options.handShakeState == HANDSHAKE_DONE) { - ssl->options.saveArrays = 0; - FreeArrays(ssl, 1); - } + if (ssl) + return ssl->specs.bulk_cipher_algorithm; + + return BAD_FUNC_ARG; } -/* Set option to indicate that the resources are not to be freed after - * handshake. - * - * ssl The SSL/TLS object. - * returns BAD_FUNC_ARG when ssl is NULL and 0 on success. - */ -int wolfSSL_KeepHandshakeResources(WOLFSSL* ssl) + +int wolfSSL_GetCipherType(WOLFSSL* ssl) { if (ssl == NULL) return BAD_FUNC_ARG; - ssl->options.keepResources = 1; +#ifndef WOLFSSL_AEAD_ONLY + if (ssl->specs.cipher_type == block) + return WOLFSSL_BLOCK_TYPE; + if (ssl->specs.cipher_type == stream) + return WOLFSSL_STREAM_TYPE; +#endif + if (ssl->specs.cipher_type == aead) + return WOLFSSL_AEAD_TYPE; - return 0; + return WOLFSSL_FATAL_ERROR; } -/* Free the handshake resources after handshake. - * - * ssl The SSL/TLS object. - * returns BAD_FUNC_ARG when ssl is NULL and 0 on success. - */ -int wolfSSL_FreeHandshakeResources(WOLFSSL* ssl) + +int wolfSSL_GetCipherBlockSize(WOLFSSL* ssl) { if (ssl == NULL) return BAD_FUNC_ARG; - FreeHandshakeResources(ssl); - - return 0; + return ssl->specs.block_size; } -/* Use the client's order of preference when matching cipher suites. - * - * ssl The SSL/TLS context object. - * returns BAD_FUNC_ARG when ssl is NULL and 0 on success. - */ -int wolfSSL_CTX_UseClientSuites(WOLFSSL_CTX* ctx) + +int wolfSSL_GetAeadMacSize(WOLFSSL* ssl) { - if (ctx == NULL) + if (ssl == NULL) return BAD_FUNC_ARG; - ctx->useClientOrder = 1; - - return 0; + return ssl->specs.aead_mac_size; } -/* Use the client's order of preference when matching cipher suites. - * - * ssl The SSL/TLS object. - * returns BAD_FUNC_ARG when ssl is NULL and 0 on success. - */ -int wolfSSL_UseClientSuites(WOLFSSL* ssl) + +int wolfSSL_IsTLSv1_1(WOLFSSL* ssl) { if (ssl == NULL) return BAD_FUNC_ARG; - ssl->options.useClientOrder = 1; + if (ssl->options.tls1_1) + return 1; return 0; } -const byte* wolfSSL_GetMacSecret(WOLFSSL* ssl, int verify) -{ -#ifndef WOLFSSL_AEAD_ONLY - if (ssl == NULL) - return NULL; - - if ( (ssl->options.side == WOLFSSL_CLIENT_END && !verify) || - (ssl->options.side == WOLFSSL_SERVER_END && verify) ) - return ssl->keys.client_write_MAC_secret; - else - return ssl->keys.server_write_MAC_secret; -#else - (void)ssl; - (void)verify; - - return NULL; -#endif -} -int wolfSSL_GetSide(WOLFSSL* ssl) +int wolfSSL_GetHmacSize(WOLFSSL* ssl) { + /* AEAD ciphers don't have HMAC keys */ if (ssl) - return ssl->options.side; + return (ssl->specs.cipher_type != aead) ? ssl->specs.hash_size : 0; return BAD_FUNC_ARG; } -#ifdef ATOMIC_USER - -void wolfSSL_CTX_SetMacEncryptCb(WOLFSSL_CTX* ctx, CallbackMacEncrypt cb) +#ifdef WORD64_AVAILABLE +int wolfSSL_GetPeerSequenceNumber(WOLFSSL* ssl, word64 *seq) { - if (ctx) - ctx->MacEncryptCb = cb; -} - + if ((ssl == NULL) || (seq == NULL)) + return BAD_FUNC_ARG; -void wolfSSL_SetMacEncryptCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->MacEncryptCtx = ctx; + *seq = ((word64)ssl->keys.peer_sequence_number_hi << 32) | + ssl->keys.peer_sequence_number_lo; + return !(*seq); } - -void* wolfSSL_GetMacEncryptCtx(WOLFSSL* ssl) +int wolfSSL_GetSequenceNumber(WOLFSSL* ssl, word64 *seq) { - if (ssl) - return ssl->MacEncryptCtx; + if ((ssl == NULL) || (seq == NULL)) + return BAD_FUNC_ARG; - return NULL; + *seq = ((word64)ssl->keys.sequence_number_hi << 32) | + ssl->keys.sequence_number_lo; + return !(*seq); } +#endif +#endif /* ATOMIC_USER */ -void wolfSSL_CTX_SetDecryptVerifyCb(WOLFSSL_CTX* ctx, CallbackDecryptVerify cb) -{ - if (ctx) - ctx->DecryptVerifyCb = cb; -} +#if !defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM) \ + && defined(XFPRINTF) -void wolfSSL_SetDecryptVerifyCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->DecryptVerifyCtx = ctx; -} +#if defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE) +#endif +#endif /* !NO_FILESYSTEM && !NO_STDIO_FILESYSTEM && XFPRINTF */ -void* wolfSSL_GetDecryptVerifyCtx(WOLFSSL* ssl) +#ifndef WOLFSSL_LEANPSK +/* turn on handshake group messages for context */ +int wolfSSL_CTX_set_group_messages(WOLFSSL_CTX* ctx) { - if (ssl) - return ssl->DecryptVerifyCtx; - - return NULL; -} + if (ctx == NULL) + return BAD_FUNC_ARG; -#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) -/** - * Set the callback, against the context, that encrypts then MACs. - * - * ctx SSL/TLS context. - * cb Callback function to use with Encrypt-Then-MAC. - */ -void wolfSSL_CTX_SetEncryptMacCb(WOLFSSL_CTX* ctx, CallbackEncryptMac cb) -{ - if (ctx) - ctx->EncryptMacCb = cb; -} + ctx->groupMessages = 1; -/** - * Set the context to use with callback that encrypts then MACs. - * - * ssl SSL/TLS object. - * ctx Callback function's context. - */ -void wolfSSL_SetEncryptMacCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->EncryptMacCtx = ctx; + return WOLFSSL_SUCCESS; } -/** - * Get the context being used with callback that encrypts then MACs. - * - * ssl SSL/TLS object. - * returns callback function's context or NULL if SSL/TLS object is NULL. - */ -void* wolfSSL_GetEncryptMacCtx(WOLFSSL* ssl) +int wolfSSL_CTX_clear_group_messages(WOLFSSL_CTX* ctx) { - if (ssl) - return ssl->EncryptMacCtx; - - return NULL; -} + if (ctx == NULL) + return BAD_FUNC_ARG; + ctx->groupMessages = 0; -/** - * Set the callback, against the context, that MAC verifies then decrypts. - * - * ctx SSL/TLS context. - * cb Callback function to use with Encrypt-Then-MAC. - */ -void wolfSSL_CTX_SetVerifyDecryptCb(WOLFSSL_CTX* ctx, CallbackVerifyDecrypt cb) -{ - if (ctx) - ctx->VerifyDecryptCb = cb; + return WOLFSSL_SUCCESS; } +#endif -/** - * Set the context to use with callback that MAC verifies then decrypts. - * - * ssl SSL/TLS object. - * ctx Callback function's context. - */ -void wolfSSL_SetVerifyDecryptCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->VerifyDecryptCtx = ctx; -} -/** - * Get the context being used with callback that MAC verifies then decrypts. - * - * ssl SSL/TLS object. - * returns callback function's context or NULL if SSL/TLS object is NULL. - */ -void* wolfSSL_GetVerifyDecryptCtx(WOLFSSL* ssl) +#ifndef WOLFSSL_LEANPSK +/* turn on handshake group messages for ssl object */ +int wolfSSL_set_group_messages(WOLFSSL* ssl) { - if (ssl) - return ssl->VerifyDecryptCtx; - - return NULL; -} -#endif /* HAVE_ENCRYPT_THEN_MAC !WOLFSSL_AEAD_ONLY */ - - + if (ssl == NULL) + return BAD_FUNC_ARG; -const byte* wolfSSL_GetClientWriteKey(WOLFSSL* ssl) -{ - if (ssl) - return ssl->keys.client_write_key; + ssl->options.groupMessages = 1; - return NULL; + return WOLFSSL_SUCCESS; } - -const byte* wolfSSL_GetClientWriteIV(WOLFSSL* ssl) +int wolfSSL_clear_group_messages(WOLFSSL* ssl) { - if (ssl) - return ssl->keys.client_write_IV; - - return NULL; -} - + if (ssl == NULL) + return BAD_FUNC_ARG; -const byte* wolfSSL_GetServerWriteKey(WOLFSSL* ssl) -{ - if (ssl) - return ssl->keys.server_write_key; + ssl->options.groupMessages = 0; - return NULL; + return WOLFSSL_SUCCESS; } - -const byte* wolfSSL_GetServerWriteIV(WOLFSSL* ssl) +/* make minVersion the internal equivalent SSL version */ +static int SetMinVersionHelper(byte* minVersion, int version) { - if (ssl) - return ssl->keys.server_write_IV; + (void)minVersion; - return NULL; -} + switch (version) { +#if defined(WOLFSSL_ALLOW_SSLV3) && !defined(NO_OLD_TLS) + case WOLFSSL_SSLV3: + *minVersion = SSLv3_MINOR; + break; +#endif -int wolfSSL_GetKeySize(WOLFSSL* ssl) -{ - if (ssl) - return ssl->specs.key_size; +#ifndef NO_TLS + #ifndef NO_OLD_TLS + #ifdef WOLFSSL_ALLOW_TLSV10 + case WOLFSSL_TLSV1: + *minVersion = TLSv1_MINOR; + break; + #endif - return BAD_FUNC_ARG; -} + case WOLFSSL_TLSV1_1: + *minVersion = TLSv1_1_MINOR; + break; + #endif + #ifndef WOLFSSL_NO_TLS12 + case WOLFSSL_TLSV1_2: + *minVersion = TLSv1_2_MINOR; + break; + #endif +#endif + #ifdef WOLFSSL_TLS13 + case WOLFSSL_TLSV1_3: + *minVersion = TLSv1_3_MINOR; + break; + #endif +#ifdef WOLFSSL_DTLS + case WOLFSSL_DTLSV1: + *minVersion = DTLS_MINOR; + break; + case WOLFSSL_DTLSV1_2: + *minVersion = DTLSv1_2_MINOR; + break; +#ifdef WOLFSSL_DTLS13 + case WOLFSSL_DTLSV1_3: + *minVersion = DTLSv1_3_MINOR; + break; +#endif /* WOLFSSL_DTLS13 */ +#endif /* WOLFSSL_DTLS */ -int wolfSSL_GetIVSize(WOLFSSL* ssl) -{ - if (ssl) - return ssl->specs.iv_size; + default: + WOLFSSL_MSG("Bad function argument"); + return BAD_FUNC_ARG; + } - return BAD_FUNC_ARG; + return WOLFSSL_SUCCESS; } -int wolfSSL_GetBulkCipher(WOLFSSL* ssl) +/* Set minimum downgrade version allowed, WOLFSSL_SUCCESS on ok */ +WOLFSSL_ABI +int wolfSSL_CTX_SetMinVersion(WOLFSSL_CTX* ctx, int version) { - if (ssl) - return ssl->specs.bulk_cipher_algorithm; - - return BAD_FUNC_ARG; -} - + WOLFSSL_ENTER("wolfSSL_CTX_SetMinVersion"); -int wolfSSL_GetCipherType(WOLFSSL* ssl) -{ - if (ssl == NULL) + if (ctx == NULL) { + WOLFSSL_MSG("Bad function argument"); return BAD_FUNC_ARG; + } -#ifndef WOLFSSL_AEAD_ONLY - if (ssl->specs.cipher_type == block) - return WOLFSSL_BLOCK_TYPE; - if (ssl->specs.cipher_type == stream) - return WOLFSSL_STREAM_TYPE; -#endif - if (ssl->specs.cipher_type == aead) - return WOLFSSL_AEAD_TYPE; +#if defined(WOLFSSL_SYS_CRYPTO_POLICY) + if (crypto_policy.enabled) { + return CRYPTO_POLICY_FORBIDDEN; + } +#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - return WOLFSSL_FATAL_ERROR; + return SetMinVersionHelper(&ctx->minDowngrade, version); } -int wolfSSL_GetCipherBlockSize(WOLFSSL* ssl) +/* Set minimum downgrade version allowed, WOLFSSL_SUCCESS on ok */ +int wolfSSL_SetMinVersion(WOLFSSL* ssl, int version) { - if (ssl == NULL) - return BAD_FUNC_ARG; - - return ssl->specs.block_size; -} - + WOLFSSL_ENTER("wolfSSL_SetMinVersion"); -int wolfSSL_GetAeadMacSize(WOLFSSL* ssl) -{ - if (ssl == NULL) + if (ssl == NULL) { + WOLFSSL_MSG("Bad function argument"); return BAD_FUNC_ARG; + } - return ssl->specs.aead_mac_size; +#if defined(WOLFSSL_SYS_CRYPTO_POLICY) + if (crypto_policy.enabled) { + return CRYPTO_POLICY_FORBIDDEN; + } +#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ + + return SetMinVersionHelper(&ssl->options.minDowngrade, version); } -int wolfSSL_IsTLSv1_1(WOLFSSL* ssl) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - - if (ssl->options.tls1_1) - return 1; - - return 0; -} - - - -int wolfSSL_GetHmacSize(WOLFSSL* ssl) -{ - /* AEAD ciphers don't have HMAC keys */ - if (ssl) - return (ssl->specs.cipher_type != aead) ? ssl->specs.hash_size : 0; - - return BAD_FUNC_ARG; -} - -#ifdef WORD64_AVAILABLE -int wolfSSL_GetPeerSequenceNumber(WOLFSSL* ssl, word64 *seq) -{ - if ((ssl == NULL) || (seq == NULL)) - return BAD_FUNC_ARG; - - *seq = ((word64)ssl->keys.peer_sequence_number_hi << 32) | - ssl->keys.peer_sequence_number_lo; - return !(*seq); -} - -int wolfSSL_GetSequenceNumber(WOLFSSL* ssl, word64 *seq) -{ - if ((ssl == NULL) || (seq == NULL)) - return BAD_FUNC_ARG; - - *seq = ((word64)ssl->keys.sequence_number_hi << 32) | - ssl->keys.sequence_number_lo; - return !(*seq); -} -#endif - -#endif /* ATOMIC_USER */ - -#if !defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM) \ - && defined(XFPRINTF) - -void wolfSSL_ERR_print_errors_fp(XFILE fp, int err) -{ - char data[WOLFSSL_MAX_ERROR_SZ + 1]; - - WOLFSSL_ENTER("wolfSSL_ERR_print_errors_fp"); - SetErrorString(err, data); - if (XFPRINTF(fp, "%s", data) < 0) - WOLFSSL_MSG("fprintf failed in wolfSSL_ERR_print_errors_fp"); -} - -#if defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE) -void wolfSSL_ERR_dump_errors_fp(XFILE fp) -{ - wc_ERR_print_errors_fp(fp); -} - -void wolfSSL_ERR_print_errors_cb (int (*cb)(const char *str, size_t len, - void *u), void *u) -{ - wc_ERR_print_errors_cb(cb, u); -} -#endif -#endif /* !NO_FILESYSTEM && !NO_STDIO_FILESYSTEM && XFPRINTF */ - -/* - * TODO This ssl parameter needs to be changed to const once our ABI checker - * stops flagging qualifier additions as ABI breaking. - */ -WOLFSSL_ABI -int wolfSSL_pending(WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_pending"); - if (ssl == NULL) - return WOLFSSL_FAILURE; - - return (int)ssl->buffers.clearOutputBuffer.length; -} - -int wolfSSL_has_pending(const WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_has_pending"); - if (ssl == NULL) - return WOLFSSL_FAILURE; - - return ssl->buffers.clearOutputBuffer.length > 0; -} - -#ifndef WOLFSSL_LEANPSK -/* turn on handshake group messages for context */ -int wolfSSL_CTX_set_group_messages(WOLFSSL_CTX* ctx) -{ - if (ctx == NULL) - return BAD_FUNC_ARG; - - ctx->groupMessages = 1; - - return WOLFSSL_SUCCESS; -} - -int wolfSSL_CTX_clear_group_messages(WOLFSSL_CTX* ctx) -{ - if (ctx == NULL) - return BAD_FUNC_ARG; - - ctx->groupMessages = 0; - - return WOLFSSL_SUCCESS; -} -#endif - - -#if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS) -/* connect enough to get peer cert chain */ -int wolfSSL_connect_cert(WOLFSSL* ssl) -{ - int ret; - - if (ssl == NULL) - return WOLFSSL_FAILURE; - - ssl->options.certOnly = 1; - ret = wolfSSL_connect(ssl); - ssl->options.certOnly = 0; - - return ret; -} -#endif - - -#ifndef WOLFSSL_LEANPSK -/* turn on handshake group messages for ssl object */ -int wolfSSL_set_group_messages(WOLFSSL* ssl) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - - ssl->options.groupMessages = 1; - - return WOLFSSL_SUCCESS; -} - -int wolfSSL_clear_group_messages(WOLFSSL* ssl) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - - ssl->options.groupMessages = 0; - - return WOLFSSL_SUCCESS; -} - -/* make minVersion the internal equivalent SSL version */ -static int SetMinVersionHelper(byte* minVersion, int version) -{ - (void)minVersion; - - switch (version) { -#if defined(WOLFSSL_ALLOW_SSLV3) && !defined(NO_OLD_TLS) - case WOLFSSL_SSLV3: - *minVersion = SSLv3_MINOR; - break; -#endif - -#ifndef NO_TLS - #ifndef NO_OLD_TLS - #ifdef WOLFSSL_ALLOW_TLSV10 - case WOLFSSL_TLSV1: - *minVersion = TLSv1_MINOR; - break; - #endif - - case WOLFSSL_TLSV1_1: - *minVersion = TLSv1_1_MINOR; - break; - #endif - #ifndef WOLFSSL_NO_TLS12 - case WOLFSSL_TLSV1_2: - *minVersion = TLSv1_2_MINOR; - break; - #endif -#endif - #ifdef WOLFSSL_TLS13 - case WOLFSSL_TLSV1_3: - *minVersion = TLSv1_3_MINOR; - break; - #endif - -#ifdef WOLFSSL_DTLS - case WOLFSSL_DTLSV1: - *minVersion = DTLS_MINOR; - break; - case WOLFSSL_DTLSV1_2: - *minVersion = DTLSv1_2_MINOR; - break; -#ifdef WOLFSSL_DTLS13 - case WOLFSSL_DTLSV1_3: - *minVersion = DTLSv1_3_MINOR; - break; -#endif /* WOLFSSL_DTLS13 */ -#endif /* WOLFSSL_DTLS */ - - default: - WOLFSSL_MSG("Bad function argument"); - return BAD_FUNC_ARG; - } - - return WOLFSSL_SUCCESS; -} - - -/* Set minimum downgrade version allowed, WOLFSSL_SUCCESS on ok */ -WOLFSSL_ABI -int wolfSSL_CTX_SetMinVersion(WOLFSSL_CTX* ctx, int version) -{ - WOLFSSL_ENTER("wolfSSL_CTX_SetMinVersion"); - - if (ctx == NULL) { - WOLFSSL_MSG("Bad function argument"); - return BAD_FUNC_ARG; - } - -#if defined(WOLFSSL_SYS_CRYPTO_POLICY) - if (crypto_policy.enabled) { - return CRYPTO_POLICY_FORBIDDEN; - } -#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - - return SetMinVersionHelper(&ctx->minDowngrade, version); -} - - -/* Set minimum downgrade version allowed, WOLFSSL_SUCCESS on ok */ -int wolfSSL_SetMinVersion(WOLFSSL* ssl, int version) -{ - WOLFSSL_ENTER("wolfSSL_SetMinVersion"); - - if (ssl == NULL) { - WOLFSSL_MSG("Bad function argument"); - return BAD_FUNC_ARG; - } - -#if defined(WOLFSSL_SYS_CRYPTO_POLICY) - if (crypto_policy.enabled) { - return CRYPTO_POLICY_FORBIDDEN; - } -#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - - return SetMinVersionHelper(&ssl->options.minDowngrade, version); -} - - -/* Function to get version as WOLFSSL_ enum value for wolfSSL_SetVersion */ -int wolfSSL_GetVersion(const WOLFSSL* ssl) +/* Function to get version as WOLFSSL_ enum value for wolfSSL_SetVersion */ +int wolfSSL_GetVersion(const WOLFSSL* ssl) { if (ssl == NULL) return BAD_FUNC_ARG; @@ -3108,10 +2331,6 @@ int wolfSSL_SetVersion(WOLFSSL* ssl, int version) } #endif /* !leanpsk */ -#if defined(OPENSSL_EXTRA) && !defined(WOLFSSL_NO_OPENSSL_RAND_CB) -static int wolfSSL_RAND_InitMutex(void); -#endif - /* If we don't have static mutex initializers, but we do have static atomic * initializers, activate WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS to leverage * the latter. @@ -3230,6 +2449,12 @@ int wolfSSL_Init(void) ret = WC_INIT_E; } +#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \ + !defined(WOLFCRYPT_ONLY) + /* Calculate the index of OID groups in wolfssl_object_info[]. */ + wolfssl_object_info_slice_init(); +#endif + #if defined(HAVE_GLOBAL_RNG) && !defined(WOLFSSL_MUTEX_INITIALIZER) if (ret == WOLFSSL_SUCCESS) { if (wc_InitMutex(&globalRNGMutex) != 0) { @@ -4286,447 +3511,20 @@ int wolfSSL_export_keying_material(WOLFSSL *ssl, return method; } - /* please see note at top of README if you get an error from connect */ - WOLFSSL_ABI - int wolfSSL_connect(WOLFSSL* ssl) - { - #if !(defined(WOLFSSL_NO_TLS12) && defined(NO_OLD_TLS) && \ - defined(WOLFSSL_TLS13)) - int neededState; - byte advanceState; - #endif - int ret = 0; - (void)ret; +#endif /* !NO_WOLFSSL_CLIENT && !NO_TLS */ +/* end client only parts */ - #ifdef HAVE_ERRNO_H - errno = 0; - #endif +/* server only parts */ +#if !defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS) - if (ssl == NULL) - return BAD_FUNC_ARG; - - #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE) - if (ssl->options.side == WOLFSSL_NEITHER_END) { - ssl->error = InitSSL_Side(ssl, WOLFSSL_CLIENT_END); - if (ssl->error != WOLFSSL_SUCCESS) { - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } - ssl->error = 0; /* expected to be zero here */ - } - - #ifdef OPENSSL_EXTRA - if (ssl->CBIS != NULL) { - ssl->CBIS(ssl, WOLFSSL_ST_CONNECT, WOLFSSL_SUCCESS); - ssl->cbmode = WOLFSSL_CB_WRITE; - } - #endif - #endif /* OPENSSL_EXTRA || WOLFSSL_EITHER_SIDE */ - - #if defined(WOLFSSL_NO_TLS12) && defined(NO_OLD_TLS) && \ - defined(WOLFSSL_TLS13) - return wolfSSL_connect_TLSv13(ssl); - #else - #ifdef WOLFSSL_TLS13 - if (ssl->options.tls1_3) { - WOLFSSL_MSG("TLS 1.3"); - return wolfSSL_connect_TLSv13(ssl); - } - #endif - - WOLFSSL_MSG("TLS 1.2 or lower"); - WOLFSSL_ENTER("wolfSSL_connect"); - - /* make sure this wolfSSL object has arrays and rng setup. Protects - * case where the WOLFSSL object is reused via wolfSSL_clear() */ - if ((ret = ReinitSSL(ssl, ssl->ctx, 0)) != 0) { - return ret; - } - -#ifdef WOLFSSL_WOLFSENTRY_HOOKS - if ((ssl->ConnectFilter != NULL) && - (ssl->options.connectState == CONNECT_BEGIN)) { - wolfSSL_netfilter_decision_t res; - if ((ssl->ConnectFilter(ssl, ssl->ConnectFilter_arg, &res) == - WOLFSSL_SUCCESS) && - (res == WOLFSSL_NETFILTER_REJECT)) { - ssl->error = SOCKET_FILTERED_E; - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } - } -#endif /* WOLFSSL_WOLFSENTRY_HOOKS */ - - if (ssl->options.side != WOLFSSL_CLIENT_END) { - ssl->error = SIDE_ERROR; - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } - - #ifdef WOLFSSL_DTLS - if (ssl->version.major == DTLS_MAJOR) { - ssl->options.dtls = 1; - ssl->options.tls = 1; - ssl->options.tls1_1 = 1; - ssl->options.dtlsStateful = 1; - } - #endif - - /* fragOffset is non-zero when sending fragments. On the last - * fragment, fragOffset is zero again, and the state can be - * advanced. */ - advanceState = ssl->fragOffset == 0 && - (ssl->options.connectState == CONNECT_BEGIN || - ssl->options.connectState == HELLO_AGAIN || - (ssl->options.connectState >= FIRST_REPLY_DONE && - ssl->options.connectState <= FIRST_REPLY_FOURTH)); - -#ifdef WOLFSSL_DTLS13 - if (ssl->options.dtls && IsAtLeastTLSv1_3(ssl->version)) - advanceState = advanceState && !ssl->dtls13SendingAckOrRtx; -#endif /* WOLFSSL_DTLS13 */ - - if (ssl->buffers.outputBuffer.length > 0 - #ifdef WOLFSSL_ASYNC_CRYPT - /* do not send buffered or advance state if last error was an - async pending operation */ - && ssl->error != WC_NO_ERR_TRACE(WC_PENDING_E) - #endif - ) { - ret = SendBuffered(ssl); - if (ret == 0) { - if (ssl->fragOffset == 0 && !ssl->options.buildingMsg) { - if (advanceState) { - ssl->options.connectState++; - WOLFSSL_MSG("connect state: Advanced from last " - "buffered fragment send"); - #ifdef WOLFSSL_ASYNC_IO - /* Cleanup async */ - FreeAsyncCtx(ssl, 0); - #endif - } - } - else { - WOLFSSL_MSG("connect state: " - "Not advanced, more fragments to send"); - } - } - else { - ssl->error = ret; - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } -#ifdef WOLFSSL_DTLS13 - if (ssl->options.dtls) - ssl->dtls13SendingAckOrRtx = 0; -#endif /* WOLFSSL_DTLS13 */ - } - - ret = RetrySendAlert(ssl); - if (ret != 0) { - ssl->error = ret; - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } - - switch (ssl->options.connectState) { - - case CONNECT_BEGIN : - /* always send client hello first */ - if ( (ssl->error = SendClientHello(ssl)) != 0) { - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } - ssl->options.connectState = CLIENT_HELLO_SENT; - WOLFSSL_MSG("connect state: CLIENT_HELLO_SENT"); - FALL_THROUGH; - - case CLIENT_HELLO_SENT : - neededState = ssl->options.resuming ? SERVER_FINISHED_COMPLETE : - SERVER_HELLODONE_COMPLETE; - #ifdef WOLFSSL_DTLS - /* In DTLS, when resuming, we can go straight to FINISHED, - * or do a cookie exchange and then skip to FINISHED, assume - * we need the cookie exchange first. */ - if (IsDtlsNotSctpMode(ssl)) - neededState = SERVER_HELLOVERIFYREQUEST_COMPLETE; - #endif - /* get response */ - WOLFSSL_MSG("Server state up to needed state."); - while (ssl->options.serverState < neededState) { - WOLFSSL_MSG("Progressing server state..."); - #ifdef WOLFSSL_TLS13 - if (ssl->options.tls1_3) - return wolfSSL_connect_TLSv13(ssl); - #endif - WOLFSSL_MSG("ProcessReply..."); - if ( (ssl->error = ProcessReply(ssl)) < 0) { - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } - /* if resumption failed, reset needed state */ - else if (neededState == SERVER_FINISHED_COMPLETE) { - if (!ssl->options.resuming) { - #ifdef WOLFSSL_DTLS - if (IsDtlsNotSctpMode(ssl)) - neededState = SERVER_HELLOVERIFYREQUEST_COMPLETE; - else - #endif - neededState = SERVER_HELLODONE_COMPLETE; - } - } - WOLFSSL_MSG("ProcessReply done."); - -#ifdef WOLFSSL_DTLS13 - if (ssl->options.dtls && IsAtLeastTLSv1_3(ssl->version) - && ssl->dtls13Rtx.sendAcks == 1 - && ssl->options.seenUnifiedHdr) { - /* we aren't negotiated the version yet, so we aren't sure - * the other end can speak v1.3. On the other side we have - * received a unified records, assuming that the - * ServerHello got lost, we will send an empty ACK. In case - * the server is a DTLS with version less than 1.3, it - * should just ignore the message */ - ssl->dtls13Rtx.sendAcks = 0; - if ((ssl->error = SendDtls13Ack(ssl)) < 0) { - if (ssl->error == WC_NO_ERR_TRACE(WANT_WRITE)) - ssl->dtls13SendingAckOrRtx = 1; - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } - } -#endif /* WOLFSSL_DTLS13 */ - } - - ssl->options.connectState = HELLO_AGAIN; - WOLFSSL_MSG("connect state: HELLO_AGAIN"); - FALL_THROUGH; - - case HELLO_AGAIN : - - #ifdef WOLFSSL_TLS13 - if (ssl->options.tls1_3) - return wolfSSL_connect_TLSv13(ssl); - #endif - - #ifdef WOLFSSL_DTLS - if (ssl->options.serverState == - SERVER_HELLOVERIFYREQUEST_COMPLETE) { - if (IsDtlsNotSctpMode(ssl)) { - /* re-init hashes, exclude first hello and verify request */ - if ((ssl->error = InitHandshakeHashes(ssl)) != 0) { - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } - if ( (ssl->error = SendClientHello(ssl)) != 0) { - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } - } - } - #endif - - ssl->options.connectState = HELLO_AGAIN_REPLY; - WOLFSSL_MSG("connect state: HELLO_AGAIN_REPLY"); - FALL_THROUGH; - - case HELLO_AGAIN_REPLY : - #ifdef WOLFSSL_DTLS - if (IsDtlsNotSctpMode(ssl)) { - neededState = ssl->options.resuming ? - SERVER_FINISHED_COMPLETE : SERVER_HELLODONE_COMPLETE; - - /* get response */ - while (ssl->options.serverState < neededState) { - if ( (ssl->error = ProcessReply(ssl)) < 0) { - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } - /* if resumption failed, reset needed state */ - if (neededState == SERVER_FINISHED_COMPLETE) { - if (!ssl->options.resuming) - neededState = SERVER_HELLODONE_COMPLETE; - } - } - } - #endif - - ssl->options.connectState = FIRST_REPLY_DONE; - WOLFSSL_MSG("connect state: FIRST_REPLY_DONE"); - FALL_THROUGH; - - case FIRST_REPLY_DONE : - if (ssl->options.certOnly) - return WOLFSSL_SUCCESS; - #if !defined(NO_CERTS) && !defined(WOLFSSL_NO_CLIENT_AUTH) - #ifdef WOLFSSL_TLS13 - if (ssl->options.tls1_3) - return wolfSSL_connect_TLSv13(ssl); - #endif - if (ssl->options.sendVerify) { - if ( (ssl->error = SendCertificate(ssl)) != 0) { - wolfssl_local_MaybeCheckAlertOnErr(ssl, ssl->error); - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } - WOLFSSL_MSG("sent: certificate"); - } - - #endif - ssl->options.connectState = FIRST_REPLY_FIRST; - WOLFSSL_MSG("connect state: FIRST_REPLY_FIRST"); - FALL_THROUGH; - - case FIRST_REPLY_FIRST : - #ifdef WOLFSSL_TLS13 - if (ssl->options.tls1_3) - return wolfSSL_connect_TLSv13(ssl); - #endif - if (!ssl->options.resuming) { - if ( (ssl->error = SendClientKeyExchange(ssl)) != 0) { - wolfssl_local_MaybeCheckAlertOnErr(ssl, ssl->error); -#ifdef WOLFSSL_EXTRA_ALERTS - if (ssl->error == WC_NO_ERR_TRACE(NO_PEER_KEY) || - ssl->error == WC_NO_ERR_TRACE(PSK_KEY_ERROR)) { - SendAlert(ssl, alert_fatal, handshake_failure); - } -#endif - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } - WOLFSSL_MSG("sent: client key exchange"); - } - - ssl->options.connectState = FIRST_REPLY_SECOND; - WOLFSSL_MSG("connect state: FIRST_REPLY_SECOND"); - FALL_THROUGH; - - #if !defined(WOLFSSL_NO_TLS12) || !defined(NO_OLD_TLS) - case FIRST_REPLY_SECOND : - /* CLIENT: Fail-safe for Server Authentication. */ - if (!ssl->options.peerAuthGood) { - WOLFSSL_MSG("Server authentication did not happen"); - ssl->error = NO_PEER_VERIFY; - return WOLFSSL_FATAL_ERROR; - } - - #if !defined(NO_CERTS) && !defined(WOLFSSL_NO_CLIENT_AUTH) - if (ssl->options.sendVerify) { - if ( (ssl->error = SendCertificateVerify(ssl)) != 0) { - wolfssl_local_MaybeCheckAlertOnErr(ssl, ssl->error); - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } - WOLFSSL_MSG("sent: certificate verify"); - } - #endif /* !NO_CERTS && !WOLFSSL_NO_CLIENT_AUTH */ - ssl->options.connectState = FIRST_REPLY_THIRD; - WOLFSSL_MSG("connect state: FIRST_REPLY_THIRD"); - FALL_THROUGH; - - case FIRST_REPLY_THIRD : - if ( (ssl->error = SendChangeCipher(ssl)) != 0) { - wolfssl_local_MaybeCheckAlertOnErr(ssl, ssl->error); - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } - WOLFSSL_MSG("sent: change cipher spec"); - ssl->options.connectState = FIRST_REPLY_FOURTH; - WOLFSSL_MSG("connect state: FIRST_REPLY_FOURTH"); - FALL_THROUGH; - - case FIRST_REPLY_FOURTH : - if ( (ssl->error = SendFinished(ssl)) != 0) { - wolfssl_local_MaybeCheckAlertOnErr(ssl, ssl->error); - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } - WOLFSSL_MSG("sent: finished"); - ssl->options.connectState = FINISHED_DONE; - WOLFSSL_MSG("connect state: FINISHED_DONE"); - FALL_THROUGH; - -#ifdef WOLFSSL_DTLS13 - case WAIT_FINISHED_ACK: - ssl->options.connectState = FINISHED_DONE; - FALL_THROUGH; -#endif /* WOLFSSL_DTLS13 */ - - case FINISHED_DONE : - /* get response */ - while (ssl->options.serverState < SERVER_FINISHED_COMPLETE) - if ( (ssl->error = ProcessReply(ssl)) < 0) { - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } - - ssl->options.connectState = SECOND_REPLY_DONE; - WOLFSSL_MSG("connect state: SECOND_REPLY_DONE"); - FALL_THROUGH; - - case SECOND_REPLY_DONE: - #ifndef NO_HANDSHAKE_DONE_CB - if (ssl->hsDoneCb) { - int cbret = ssl->hsDoneCb(ssl, ssl->hsDoneCtx); - if (cbret < 0) { - ssl->error = cbret; - WOLFSSL_MSG("HandShake Done Cb don't continue error"); - return WOLFSSL_FATAL_ERROR; - } - } - #endif /* NO_HANDSHAKE_DONE_CB */ - - if (!ssl->options.dtls) { - if (!ssl->options.keepResources) { - FreeHandshakeResources(ssl); - } - } - #ifdef WOLFSSL_DTLS - else { - ssl->options.dtlsHsRetain = 1; - } - #endif /* WOLFSSL_DTLS */ - - #if defined(WOLFSSL_ASYNC_CRYPT) && defined(HAVE_SECURE_RENEGOTIATION) - /* This may be necessary in async so that we don't try to - * renegotiate again */ - if (ssl->secure_renegotiation && - ssl->secure_renegotiation->startScr) { - ssl->secure_renegotiation->startScr = 0; - } - #endif /* WOLFSSL_ASYNC_CRYPT && HAVE_SECURE_RENEGOTIATION */ - #if defined(WOLFSSL_ASYNC_IO) && !defined(WOLFSSL_ASYNC_CRYPT) - /* Free the remaining async context if not using it for crypto */ - FreeAsyncCtx(ssl, 1); - #endif - - ssl->error = 0; /* clear the error */ - - WOLFSSL_LEAVE("wolfSSL_connect", WOLFSSL_SUCCESS); - return WOLFSSL_SUCCESS; - #endif /* !WOLFSSL_NO_TLS12 || !NO_OLD_TLS */ - - default: - WOLFSSL_MSG("Unknown connect state ERROR"); - return WOLFSSL_FATAL_ERROR; /* unknown connect state */ - } - #endif /* !WOLFSSL_NO_TLS12 || !NO_OLD_TLS || !WOLFSSL_TLS13 */ - } - -#endif /* !NO_WOLFSSL_CLIENT && !NO_TLS */ -/* end client only parts */ - -/* server only parts */ -#if !defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS) - - #if defined(OPENSSL_EXTRA) && !defined(NO_OLD_TLS) - WOLFSSL_METHOD* wolfSSLv2_server_method(void) - { - WOLFSSL_STUB("wolfSSLv2_server_method"); - return 0; - } - #endif + #if defined(OPENSSL_EXTRA) && !defined(NO_OLD_TLS) + WOLFSSL_METHOD* wolfSSLv2_server_method(void) + { + WOLFSSL_STUB("wolfSSLv2_server_method"); + return 0; + } + #endif #if defined(WOLFSSL_ALLOW_SSLV3) && !defined(NO_OLD_TLS) WOLFSSL_METHOD* wolfSSLv3_server_method(void) @@ -4786,666 +3584,105 @@ int wolfSSL_export_keying_material(WOLFSSL *ssl, } - WOLFSSL_ABI - int wolfSSL_accept(WOLFSSL* ssl) - { -#if !(defined(WOLFSSL_NO_TLS12) && defined(NO_OLD_TLS) && \ - defined(WOLFSSL_TLS13)) - word16 havePSK = 0; - word16 haveAnon = 0; - word16 haveMcast = 0; -#endif - int ret = 0; - (void)ret; - - if (ssl == NULL) - return WOLFSSL_FATAL_ERROR; +#endif /* !NO_WOLFSSL_SERVER && !NO_TLS */ +/* end server only parts */ - #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE) - if (ssl->options.side == WOLFSSL_NEITHER_END) { - WOLFSSL_MSG("Setting WOLFSSL_SSL to be server side"); - ssl->error = InitSSL_Side(ssl, WOLFSSL_SERVER_END); - if (ssl->error != WOLFSSL_SUCCESS) { - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } - ssl->error = 0; /* expected to be zero here */ - } - #endif /* OPENSSL_EXTRA || WOLFSSL_EITHER_SIDE */ +#define WOLFSSL_SSL_API_HS_INCLUDED +#include "src/ssl_api_hs.c" -#if defined(WOLFSSL_NO_TLS12) && defined(NO_OLD_TLS) && defined(WOLFSSL_TLS13) - return wolfSSL_accept_TLSv13(ssl); -#else - #ifdef WOLFSSL_TLS13 - if (ssl->options.tls1_3) - return wolfSSL_accept_TLSv13(ssl); - #endif - WOLFSSL_ENTER("wolfSSL_accept"); - /* make sure this wolfSSL object has arrays and rng setup. Protects - * case where the WOLFSSL object is reused via wolfSSL_clear() */ - if ((ret = ReinitSSL(ssl, ssl->ctx, 0)) != 0) { - return ret; - } -#ifdef WOLFSSL_WOLFSENTRY_HOOKS - if ((ssl->AcceptFilter != NULL) && - ((ssl->options.acceptState == ACCEPT_BEGIN) -#ifdef HAVE_SECURE_RENEGOTIATION - || (ssl->options.acceptState == ACCEPT_BEGIN_RENEG) +WOLFSSL_ABI +int wolfSSL_Cleanup(void) +{ + int ret = WOLFSSL_SUCCESS; /* Only the first error will be returned */ + int release = 0; +#if !defined(NO_SESSION_CACHE) + int i; + int j; #endif - )) - { - wolfSSL_netfilter_decision_t res; - if ((ssl->AcceptFilter(ssl, ssl->AcceptFilter_arg, &res) == - WOLFSSL_SUCCESS) && - (res == WOLFSSL_NETFILTER_REJECT)) { - ssl->error = SOCKET_FILTERED_E; - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } - } -#endif /* WOLFSSL_WOLFSENTRY_HOOKS */ - #ifdef HAVE_ERRNO_H - errno = 0; - #endif + WOLFSSL_ENTER("wolfSSL_Cleanup"); - #ifndef NO_PSK - havePSK = ssl->options.havePSK; - #endif - (void)havePSK; +#ifndef WOLFSSL_MUTEX_INITIALIZER + if (inits_count_mutex_valid == 1) { +#endif + if (wc_LockMutex(&inits_count_mutex) != 0) { + WOLFSSL_MSG("Bad Lock Mutex count"); + return BAD_MUTEX_E; + } +#ifndef WOLFSSL_MUTEX_INITIALIZER + } +#endif - #ifdef HAVE_ANON - haveAnon = ssl->options.useAnon; - #endif - (void)haveAnon; + if (initRefCount > 0) { + initRefCount = initRefCount - 1; + if (initRefCount == 0) + release = 1; + } - #ifdef WOLFSSL_MULTICAST - haveMcast = ssl->options.haveMcast; - #endif - (void)haveMcast; +#ifndef WOLFSSL_MUTEX_INITIALIZER + if (inits_count_mutex_valid == 1) { +#endif + wc_UnLockMutex(&inits_count_mutex); +#ifndef WOLFSSL_MUTEX_INITIALIZER + } +#endif - if (ssl->options.side != WOLFSSL_SERVER_END) { - ssl->error = SIDE_ERROR; - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } + if (!release) + return ret; - #ifndef NO_CERTS - /* in case used set_accept_state after init */ - if (!havePSK && !haveAnon && !haveMcast) { - #ifdef WOLFSSL_CERT_SETUP_CB - if (ssl->ctx->certSetupCb != NULL) { - WOLFSSL_MSG("CertSetupCb set. server cert and " - "key not checked"); - } - else - #endif - { - if (!ssl->buffers.certificate || - !ssl->buffers.certificate->buffer) { +#if defined(WOLFSSL_SYS_CRYPTO_POLICY) + wolfSSL_crypto_policy_disable(); +#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - WOLFSSL_MSG("accept error: server cert required"); - ssl->error = NO_PRIVATE_KEY; - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } +#ifdef OPENSSL_EXTRA + wolfSSL_BN_free_one(); +#endif - if (!ssl->buffers.key || !ssl->buffers.key->buffer) { - /* allow no private key if using existing key */ - #ifdef WOLF_PRIVATE_KEY_ID - if (ssl->devId != INVALID_DEVID - #ifdef HAVE_PK_CALLBACKS - || wolfSSL_CTX_IsPrivatePkSet(ssl->ctx) - #endif - ) { - WOLFSSL_MSG("Allowing no server private key " - "(external)"); - } - else - #endif - { - WOLFSSL_MSG("accept error: server key required"); - ssl->error = NO_PRIVATE_KEY; - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } - } - } +#ifndef NO_SESSION_CACHE + #ifdef ENABLE_SESSION_CACHE_ROW_LOCK + for (i = 0; i < SESSION_ROWS; ++i) { + if ((SessionCache[i].lock_valid == 1) && + (wc_FreeRwLock(&SessionCache[i].row_lock) != 0)) { + if (ret == WOLFSSL_SUCCESS) + ret = BAD_MUTEX_E; } + SessionCache[i].lock_valid = 0; + } + #else + if ((session_lock_valid == 1) && (wc_FreeRwLock(&session_lock) != 0)) { + if (ret == WOLFSSL_SUCCESS) + ret = BAD_MUTEX_E; + } + session_lock_valid = 0; + #endif + for (i = 0; i < SESSION_ROWS; i++) { + for (j = 0; j < SESSIONS_PER_ROW; j++) { + #ifdef SESSION_CACHE_DYNAMIC_MEM + if (SessionCache[i].Sessions[j]) { + EvictSessionFromCache(SessionCache[i].Sessions[j]); + XFREE(SessionCache[i].Sessions[j], SessionCache[i].heap, + DYNAMIC_TYPE_SESSION); + SessionCache[i].Sessions[j] = NULL; + } + #else + EvictSessionFromCache(&SessionCache[i].Sessions[j]); #endif - - #ifdef WOLFSSL_DTLS - if (ssl->version.major == DTLS_MAJOR) { - ssl->options.dtls = 1; - ssl->options.tls = 1; - ssl->options.tls1_1 = 1; - if (!IsDtlsNotSctpMode(ssl) || IsSCR(ssl)) - ssl->options.dtlsStateful = 1; } + } + #ifndef NO_CLIENT_CACHE + #ifndef WOLFSSL_MUTEX_INITIALIZER + if ((clisession_mutex_valid == 1) && + (wc_FreeMutex(&clisession_mutex) != 0)) { + if (ret == WOLFSSL_SUCCESS) + ret = BAD_MUTEX_E; + } + clisession_mutex_valid = 0; + #endif #endif - - if (ssl->buffers.outputBuffer.length > 0 - #ifdef WOLFSSL_ASYNC_CRYPT - /* do not send buffered or advance state if last error was an - async pending operation */ - && ssl->error != WC_NO_ERR_TRACE(WC_PENDING_E) - #endif - ) { - ret = SendBuffered(ssl); - if (ret == 0) { - /* fragOffset is non-zero when sending fragments. On the last - * fragment, fragOffset is zero again, and the state can be - * advanced. */ - if (ssl->fragOffset == 0 && !ssl->options.buildingMsg) { - if (ssl->options.acceptState == ACCEPT_FIRST_REPLY_DONE || - ssl->options.acceptState == SERVER_HELLO_SENT || - ssl->options.acceptState == CERT_SENT || - ssl->options.acceptState == CERT_STATUS_SENT || - ssl->options.acceptState == KEY_EXCHANGE_SENT || - ssl->options.acceptState == CERT_REQ_SENT || - ssl->options.acceptState == ACCEPT_SECOND_REPLY_DONE || - ssl->options.acceptState == TICKET_SENT || - ssl->options.acceptState == CHANGE_CIPHER_SENT) { - ssl->options.acceptState++; - WOLFSSL_MSG("accept state: Advanced from last " - "buffered fragment send"); - #ifdef WOLFSSL_ASYNC_IO - /* Cleanup async */ - FreeAsyncCtx(ssl, 0); - #endif - } - } - else { - WOLFSSL_MSG("accept state: " - "Not advanced, more fragments to send"); - } - } - else { - ssl->error = ret; - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } -#ifdef WOLFSSL_DTLS13 - if (ssl->options.dtls) - ssl->dtls13SendingAckOrRtx = 0; -#endif /* WOLFSSL_DTLS13 */ - } - - ret = RetrySendAlert(ssl); - if (ret != 0) { - ssl->error = ret; - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } - - switch (ssl->options.acceptState) { - - case ACCEPT_BEGIN : -#ifdef HAVE_SECURE_RENEGOTIATION - case ACCEPT_BEGIN_RENEG: -#endif - /* get response */ - while (ssl->options.clientState < CLIENT_HELLO_COMPLETE) - if ( (ssl->error = ProcessReply(ssl)) < 0) { - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } -#ifdef WOLFSSL_TLS13 - ssl->options.acceptState = ACCEPT_CLIENT_HELLO_DONE; - WOLFSSL_MSG("accept state ACCEPT_CLIENT_HELLO_DONE"); - FALL_THROUGH; - - case ACCEPT_CLIENT_HELLO_DONE : - if (ssl->options.tls1_3) { - return wolfSSL_accept_TLSv13(ssl); - } -#endif - - ssl->options.acceptState = ACCEPT_FIRST_REPLY_DONE; - WOLFSSL_MSG("accept state ACCEPT_FIRST_REPLY_DONE"); - FALL_THROUGH; - - case ACCEPT_FIRST_REPLY_DONE : - if (ssl->options.returnOnGoodCh) { - /* Higher level in stack wants us to return. Simulate a - * WANT_WRITE to accomplish this. */ - ssl->error = WANT_WRITE; - return WOLFSSL_FATAL_ERROR; - } - if ( (ssl->error = SendServerHello(ssl)) != 0) { - wolfssl_local_MaybeCheckAlertOnErr(ssl, ssl->error); - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } - ssl->options.acceptState = SERVER_HELLO_SENT; - WOLFSSL_MSG("accept state SERVER_HELLO_SENT"); - FALL_THROUGH; - - case SERVER_HELLO_SENT : - #ifdef WOLFSSL_TLS13 - if (ssl->options.tls1_3) { - return wolfSSL_accept_TLSv13(ssl); - } - #endif - #ifndef NO_CERTS - if (!ssl->options.resuming) - if ( (ssl->error = SendCertificate(ssl)) != 0) { - wolfssl_local_MaybeCheckAlertOnErr(ssl, ssl->error); - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } - #endif - ssl->options.acceptState = CERT_SENT; - WOLFSSL_MSG("accept state CERT_SENT"); - FALL_THROUGH; - - case CERT_SENT : - #ifndef NO_CERTS - if (!ssl->options.resuming) - if ( (ssl->error = SendCertificateStatus(ssl)) != 0) { - wolfssl_local_MaybeCheckAlertOnErr(ssl, ssl->error); - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } - #endif - ssl->options.acceptState = CERT_STATUS_SENT; - WOLFSSL_MSG("accept state CERT_STATUS_SENT"); - FALL_THROUGH; - - case CERT_STATUS_SENT : - #ifdef WOLFSSL_TLS13 - if (ssl->options.tls1_3) { - return wolfSSL_accept_TLSv13(ssl); - } - #endif - if (!ssl->options.resuming) - if ( (ssl->error = SendServerKeyExchange(ssl)) != 0) { - wolfssl_local_MaybeCheckAlertOnErr(ssl, ssl->error); - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } - ssl->options.acceptState = KEY_EXCHANGE_SENT; - WOLFSSL_MSG("accept state KEY_EXCHANGE_SENT"); - FALL_THROUGH; - - case KEY_EXCHANGE_SENT : - #ifndef NO_CERTS - if (!ssl->options.resuming) { - if (ssl->options.verifyPeer) { - if ( (ssl->error = SendCertificateRequest(ssl)) != 0) { - wolfssl_local_MaybeCheckAlertOnErr(ssl, ssl->error); - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } - } - else { - /* SERVER: Peer auth good if not verifying client. */ - ssl->options.peerAuthGood = 1; - } - } - #endif - ssl->options.acceptState = CERT_REQ_SENT; - WOLFSSL_MSG("accept state CERT_REQ_SENT"); - FALL_THROUGH; - - case CERT_REQ_SENT : - if (!ssl->options.resuming) - if ( (ssl->error = SendServerHelloDone(ssl)) != 0) { - wolfssl_local_MaybeCheckAlertOnErr(ssl, ssl->error); - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } - ssl->options.acceptState = SERVER_HELLO_DONE; - WOLFSSL_MSG("accept state SERVER_HELLO_DONE"); - FALL_THROUGH; - - case SERVER_HELLO_DONE : - if (!ssl->options.resuming) { - while (ssl->options.clientState < CLIENT_FINISHED_COMPLETE) - if ( (ssl->error = ProcessReply(ssl)) < 0) { - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } - } - ssl->options.acceptState = ACCEPT_SECOND_REPLY_DONE; - WOLFSSL_MSG("accept state ACCEPT_SECOND_REPLY_DONE"); - FALL_THROUGH; - - case ACCEPT_SECOND_REPLY_DONE : - #ifndef NO_CERTS - /* SERVER: When not resuming and verifying peer but no certificate - * received and not failing when not received then peer auth good. - */ - if (!ssl->options.resuming && ssl->options.verifyPeer && - !ssl->options.havePeerCert && !ssl->options.failNoCert) { - ssl->options.peerAuthGood = 1; - } - #endif /* !NO_CERTS */ - #ifdef WOLFSSL_NO_CLIENT_AUTH - if (!ssl->options.resuming) { - ssl->options.peerAuthGood = 1; - } - #endif - -#ifdef HAVE_SESSION_TICKET - if (ssl->options.createTicket && !ssl->options.noTicketTls12) { - if ( (ssl->error = SendTicket(ssl)) != 0) { - wolfssl_local_MaybeCheckAlertOnErr(ssl, ssl->error); - WOLFSSL_MSG("Thought we need ticket but failed"); - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } - } -#endif /* HAVE_SESSION_TICKET */ - ssl->options.acceptState = TICKET_SENT; - WOLFSSL_MSG("accept state TICKET_SENT"); - FALL_THROUGH; - - case TICKET_SENT: - /* SERVER: Fail-safe for CLient Authentication. */ - if (!ssl->options.peerAuthGood) { - WOLFSSL_MSG("Client authentication did not happen"); - return WOLFSSL_FATAL_ERROR; - } - - if ( (ssl->error = SendChangeCipher(ssl)) != 0) { - wolfssl_local_MaybeCheckAlertOnErr(ssl, ssl->error); - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } - ssl->options.acceptState = CHANGE_CIPHER_SENT; - WOLFSSL_MSG("accept state CHANGE_CIPHER_SENT"); - FALL_THROUGH; - - case CHANGE_CIPHER_SENT : - if ( (ssl->error = SendFinished(ssl)) != 0) { - wolfssl_local_MaybeCheckAlertOnErr(ssl, ssl->error); - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } - - ssl->options.acceptState = ACCEPT_FINISHED_DONE; - WOLFSSL_MSG("accept state ACCEPT_FINISHED_DONE"); - FALL_THROUGH; - - case ACCEPT_FINISHED_DONE : - if (ssl->options.resuming) { - while (ssl->options.clientState < CLIENT_FINISHED_COMPLETE) { - if ( (ssl->error = ProcessReply(ssl)) < 0) { - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } - } - } - ssl->options.acceptState = ACCEPT_THIRD_REPLY_DONE; - WOLFSSL_MSG("accept state ACCEPT_THIRD_REPLY_DONE"); - FALL_THROUGH; - - case ACCEPT_THIRD_REPLY_DONE : -#ifndef NO_HANDSHAKE_DONE_CB - if (ssl->hsDoneCb) { - int cbret = ssl->hsDoneCb(ssl, ssl->hsDoneCtx); - if (cbret < 0) { - ssl->error = cbret; - WOLFSSL_MSG("HandShake Done Cb don't continue error"); - return WOLFSSL_FATAL_ERROR; - } - } -#endif /* NO_HANDSHAKE_DONE_CB */ - - if (!ssl->options.dtls) { - if (!ssl->options.keepResources) { - FreeHandshakeResources(ssl); - } - } -#ifdef WOLFSSL_DTLS - else { - ssl->options.dtlsHsRetain = 1; - } -#endif /* WOLFSSL_DTLS */ - -#if defined(WOLFSSL_ASYNC_CRYPT) && defined(HAVE_SECURE_RENEGOTIATION) - /* This may be necessary in async so that we don't try to - * renegotiate again */ - if (ssl->secure_renegotiation && - ssl->secure_renegotiation->startScr) { - ssl->secure_renegotiation->startScr = 0; - } -#endif /* WOLFSSL_ASYNC_CRYPT && HAVE_SECURE_RENEGOTIATION */ -#if defined(WOLFSSL_ASYNC_IO) && !defined(WOLFSSL_ASYNC_CRYPT) - /* Free the remaining async context if not using it for crypto */ - FreeAsyncCtx(ssl, 1); -#endif - -#if defined(WOLFSSL_SESSION_EXPORT) && defined(WOLFSSL_DTLS) - if (ssl->dtls_export) { - if ((ssl->error = wolfSSL_send_session(ssl)) != 0) { - WOLFSSL_MSG("Export DTLS session error"); - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } - } -#endif - ssl->error = 0; /* clear the error */ - - WOLFSSL_LEAVE("wolfSSL_accept", WOLFSSL_SUCCESS); - return WOLFSSL_SUCCESS; - - default: - WOLFSSL_MSG("Unknown accept state ERROR"); - return WOLFSSL_FATAL_ERROR; - } -#endif /* !WOLFSSL_NO_TLS12 */ - } - -#endif /* !NO_WOLFSSL_SERVER && !NO_TLS */ -/* end server only parts */ - - -#if defined(WOLFSSL_DTLS) && !defined(NO_WOLFSSL_SERVER) -struct chGoodDisableReadCbCtx { - ClientHelloGoodCb userCb; - void* userCtx; -}; - -static int chGoodDisableReadCB(WOLFSSL* ssl, void* ctx) -{ - struct chGoodDisableReadCbCtx* cb = (struct chGoodDisableReadCbCtx*)ctx; - int ret = 0; - if (cb->userCb != NULL) - ret = cb->userCb(ssl, cb->userCtx); - if (ret >= 0) - wolfSSL_SSLDisableRead(ssl); - return ret; -} - -/** - * Statelessly listen for a connection - * @param ssl The ssl object to use for listening to connections - * @return WOLFSSL_SUCCESS - ClientHello containing a valid cookie was received - * The connection can be continued with wolfSSL_accept - * WOLFSSL_FAILURE - The I/O layer returned WANT_READ. This is either - * because there is no data to read and we are using - * non-blocking sockets or we sent a cookie request - * and we are waiting for a reply. The user should - * call wolfDTLS_accept_stateless again after data - * becomes available in the I/O layer. - * WOLFSSL_FATAL_ERROR - A fatal error occurred. The ssl object should - * be free'd and allocated again to continue. - */ -int wolfDTLS_accept_stateless(WOLFSSL* ssl) -{ - byte disableRead; - int ret = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR); - struct chGoodDisableReadCbCtx cb; - - WOLFSSL_ENTER("wolfDTLS_SetChGoodCb"); - - if (ssl == NULL) - return WOLFSSL_FATAL_ERROR; - - /* Save this to restore it later */ - disableRead = (byte)ssl->options.disableRead; - cb.userCb = ssl->chGoodCb; - cb.userCtx = ssl->chGoodCtx; - - /* Register our own callback so that we can disable reading */ - if (wolfDTLS_SetChGoodCb(ssl, chGoodDisableReadCB, &cb) != WOLFSSL_SUCCESS) - return WOLFSSL_FATAL_ERROR; - - ssl->options.returnOnGoodCh = 1; - ret = wolfSSL_accept(ssl); - ssl->options.returnOnGoodCh = 0; - /* restore user options */ - ssl->options.disableRead = disableRead; - (void)wolfDTLS_SetChGoodCb(ssl, cb.userCb, cb.userCtx); - if (ret == WOLFSSL_SUCCESS) { - WOLFSSL_MSG("should not happen. maybe the user called " - "wolfDTLS_accept_stateless instead of wolfSSL_accept"); - } - else if (ssl->error == WC_NO_ERR_TRACE(WANT_READ) || - ssl->error == WC_NO_ERR_TRACE(WANT_WRITE)) { - ssl->error = 0; - if (ssl->options.dtlsStateful) - ret = WOLFSSL_SUCCESS; - else - ret = WOLFSSL_FAILURE; - } - else { - ret = WOLFSSL_FATAL_ERROR; - } - return ret; -} - -/* WC_NO_INLINE: wolfDTLS_accept_stateless passes the address of a stack-local - * context here; the restore call before return clears it again. Preventing - * inlining hides that cross-frame assignment from GCC's -Wdangling-pointer - * analysis, which otherwise flags a false positive on GCC 14+. */ -WC_NO_INLINE -int wolfDTLS_SetChGoodCb(WOLFSSL* ssl, ClientHelloGoodCb cb, void* user_ctx) -{ - WOLFSSL_ENTER("wolfDTLS_SetChGoodCb"); - - if (ssl == NULL) - return BAD_FUNC_ARG; - - ssl->chGoodCb = cb; - ssl->chGoodCtx = user_ctx; - - return WOLFSSL_SUCCESS; -} -#endif - -#ifndef NO_HANDSHAKE_DONE_CB - -int wolfSSL_SetHsDoneCb(WOLFSSL* ssl, HandShakeDoneCb cb, void* user_ctx) -{ - WOLFSSL_ENTER("wolfSSL_SetHsDoneCb"); - - if (ssl == NULL) - return BAD_FUNC_ARG; - - ssl->hsDoneCb = cb; - ssl->hsDoneCtx = user_ctx; - - return WOLFSSL_SUCCESS; -} - -#endif /* NO_HANDSHAKE_DONE_CB */ - -WOLFSSL_ABI -int wolfSSL_Cleanup(void) -{ - int ret = WOLFSSL_SUCCESS; /* Only the first error will be returned */ - int release = 0; -#if !defined(NO_SESSION_CACHE) - int i; - int j; -#endif - - WOLFSSL_ENTER("wolfSSL_Cleanup"); - -#ifndef WOLFSSL_MUTEX_INITIALIZER - if (inits_count_mutex_valid == 1) { -#endif - if (wc_LockMutex(&inits_count_mutex) != 0) { - WOLFSSL_MSG("Bad Lock Mutex count"); - return BAD_MUTEX_E; - } -#ifndef WOLFSSL_MUTEX_INITIALIZER - } -#endif - - if (initRefCount > 0) { - initRefCount = initRefCount - 1; - if (initRefCount == 0) - release = 1; - } - -#ifndef WOLFSSL_MUTEX_INITIALIZER - if (inits_count_mutex_valid == 1) { -#endif - wc_UnLockMutex(&inits_count_mutex); -#ifndef WOLFSSL_MUTEX_INITIALIZER - } -#endif - - if (!release) - return ret; - -#if defined(WOLFSSL_SYS_CRYPTO_POLICY) - wolfSSL_crypto_policy_disable(); -#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - -#ifdef OPENSSL_EXTRA - wolfSSL_BN_free_one(); -#endif - -#ifndef NO_SESSION_CACHE - #ifdef ENABLE_SESSION_CACHE_ROW_LOCK - for (i = 0; i < SESSION_ROWS; ++i) { - if ((SessionCache[i].lock_valid == 1) && - (wc_FreeRwLock(&SessionCache[i].row_lock) != 0)) { - if (ret == WOLFSSL_SUCCESS) - ret = BAD_MUTEX_E; - } - SessionCache[i].lock_valid = 0; - } - #else - if ((session_lock_valid == 1) && (wc_FreeRwLock(&session_lock) != 0)) { - if (ret == WOLFSSL_SUCCESS) - ret = BAD_MUTEX_E; - } - session_lock_valid = 0; - #endif - for (i = 0; i < SESSION_ROWS; i++) { - for (j = 0; j < SESSIONS_PER_ROW; j++) { - #ifdef SESSION_CACHE_DYNAMIC_MEM - if (SessionCache[i].Sessions[j]) { - EvictSessionFromCache(SessionCache[i].Sessions[j]); - XFREE(SessionCache[i].Sessions[j], SessionCache[i].heap, - DYNAMIC_TYPE_SESSION); - SessionCache[i].Sessions[j] = NULL; - } - #else - EvictSessionFromCache(&SessionCache[i].Sessions[j]); - #endif - } - } - #ifndef NO_CLIENT_CACHE - #ifndef WOLFSSL_MUTEX_INITIALIZER - if ((clisession_mutex_valid == 1) && - (wc_FreeMutex(&clisession_mutex) != 0)) { - if (ret == WOLFSSL_SUCCESS) - ret = BAD_MUTEX_E; - } - clisession_mutex_valid = 0; - #endif - #endif -#endif /* !NO_SESSION_CACHE */ +#endif /* !NO_SESSION_CACHE */ #if !defined(WOLFSSL_MUTEX_INITIALIZER) && \ !WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS @@ -5696,266 +3933,26 @@ int wolfSSL_set_compression(WOLFSSL* ssl) } -#ifndef USE_WINDOWS_API - #if !defined(NO_WRITEV) && !defined(NO_TLS) - - /* simulate writev semantics, doesn't actually do block at a time though - because of SSL_write behavior and because front adds may be small */ - int wolfSSL_writev(WOLFSSL* ssl, const struct iovec* iov, int iovcnt) - { - #ifdef WOLFSSL_SMALL_STACK - byte staticBuffer[1]; /* force heap usage */ - #else - byte staticBuffer[FILE_BUFFER_SIZE]; - #endif - byte* myBuffer = staticBuffer; - int dynamic = 0; - size_t sending = 0; - size_t idx = 0; - int i; - int ret; - - WOLFSSL_ENTER("wolfSSL_writev"); - - for (i = 0; i < iovcnt; i++) - if (! WC_SAFE_SUM_UNSIGNED(size_t, sending, iov[i].iov_len, - sending)) - return BUFFER_E; - - if (sending > sizeof(staticBuffer)) { - myBuffer = (byte*)XMALLOC(sending, ssl->heap, - DYNAMIC_TYPE_WRITEV); - if (!myBuffer) - return MEMORY_ERROR; - - dynamic = 1; - } +#ifndef NO_PSK - for (i = 0; i < iovcnt; i++) { - XMEMCPY(&myBuffer[idx], iov[i].iov_base, iov[i].iov_len); - idx += (int)iov[i].iov_len; - } + void wolfSSL_CTX_set_psk_client_callback(WOLFSSL_CTX* ctx, + wc_psk_client_callback cb) + { + WOLFSSL_ENTER("wolfSSL_CTX_set_psk_client_callback"); - /* myBuffer may not be initialized fully, but the span up to the - * sending length will be. - */ - PRAGMA_GCC_DIAG_PUSH - PRAGMA_GCC("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") - ret = wolfSSL_write_internal(ssl, myBuffer, sending); - PRAGMA_GCC_DIAG_POP + if (ctx == NULL) + return; - if (dynamic) - XFREE(myBuffer, ssl->heap, DYNAMIC_TYPE_WRITEV); + ctx->havePSK = 1; + ctx->client_psk_cb = cb; + } - return ret; - } - #endif -#endif + void wolfSSL_set_psk_client_callback(WOLFSSL* ssl,wc_psk_client_callback cb) + { + byte haveRSA = 1; + int keySz = 0; - -#ifdef WOLFSSL_CALLBACKS - - typedef struct itimerval Itimerval; - - /* don't keep calling simple functions while setting up timer and signals - if no inlining these are the next best */ - - #define AddTimes(a, b, c) \ - do { \ - (c).tv_sec = (a).tv_sec + (b).tv_sec; \ - (c).tv_usec = (a).tv_usec + (b).tv_usec;\ - if ((c).tv_usec >= 1000000) { \ - (c).tv_sec++; \ - (c).tv_usec -= 1000000; \ - } \ - } while (0) - - - #define SubtractTimes(a, b, c) \ - do { \ - (c).tv_sec = (a).tv_sec - (b).tv_sec; \ - (c).tv_usec = (a).tv_usec - (b).tv_usec;\ - if ((c).tv_usec < 0) { \ - (c).tv_sec--; \ - (c).tv_usec += 1000000; \ - } \ - } while (0) - - #define CmpTimes(a, b, cmp) \ - (((a).tv_sec == (b).tv_sec) ? \ - ((a).tv_usec cmp (b).tv_usec) : \ - ((a).tv_sec cmp (b).tv_sec)) \ - - - /* do nothing handler */ - static void myHandler(int signo) - { - (void)signo; - return; - } - - - static int wolfSSL_ex_wrapper(WOLFSSL* ssl, HandShakeCallBack hsCb, - TimeoutCallBack toCb, WOLFSSL_TIMEVAL timeout) - { - int ret = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR); - int oldTimerOn = 0; /* was timer already on */ - WOLFSSL_TIMEVAL startTime; - WOLFSSL_TIMEVAL endTime; - WOLFSSL_TIMEVAL totalTime; - Itimerval myTimeout; - Itimerval oldTimeout; /* if old timer adjust from total time to reset */ - struct sigaction act, oact; - - #define ERR_OUT(x) { ssl->hsInfoOn = 0; ssl->toInfoOn = 0; return x; } - - if (hsCb) { - ssl->hsInfoOn = 1; - InitHandShakeInfo(&ssl->handShakeInfo, ssl); - } - if (toCb) { - ssl->toInfoOn = 1; - InitTimeoutInfo(&ssl->timeoutInfo); - - if (gettimeofday(&startTime, 0) < 0) - ERR_OUT(GETTIME_ERROR); - - /* use setitimer to simulate getitimer, init 0 myTimeout */ - myTimeout.it_interval.tv_sec = 0; - myTimeout.it_interval.tv_usec = 0; - myTimeout.it_value.tv_sec = 0; - myTimeout.it_value.tv_usec = 0; - if (setitimer(ITIMER_REAL, &myTimeout, &oldTimeout) < 0) - ERR_OUT(SETITIMER_ERROR); - - if (oldTimeout.it_value.tv_sec || oldTimeout.it_value.tv_usec) { - oldTimerOn = 1; - - /* is old timer going to expire before ours */ - if (CmpTimes(oldTimeout.it_value, timeout, <)) { - timeout.tv_sec = oldTimeout.it_value.tv_sec; - timeout.tv_usec = oldTimeout.it_value.tv_usec; - } - } - myTimeout.it_value.tv_sec = timeout.tv_sec; - myTimeout.it_value.tv_usec = timeout.tv_usec; - - /* set up signal handler, don't restart socket send/recv */ - act.sa_handler = myHandler; - sigemptyset(&act.sa_mask); - act.sa_flags = 0; -#ifdef SA_INTERRUPT - act.sa_flags |= SA_INTERRUPT; -#endif - if (sigaction(SIGALRM, &act, &oact) < 0) - ERR_OUT(SIGACT_ERROR); - - if (setitimer(ITIMER_REAL, &myTimeout, 0) < 0) - ERR_OUT(SETITIMER_ERROR); - } - - /* do main work */ -#ifndef NO_WOLFSSL_CLIENT - if (ssl->options.side == WOLFSSL_CLIENT_END) - ret = wolfSSL_connect(ssl); -#endif -#ifndef NO_WOLFSSL_SERVER - if (ssl->options.side == WOLFSSL_SERVER_END) - ret = wolfSSL_accept(ssl); -#endif - - /* do callbacks */ - if (toCb) { - if (oldTimerOn) { - if (gettimeofday(&endTime, 0) < 0) - ERR_OUT(SYSLIB_FAILED_E); - SubtractTimes(endTime, startTime, totalTime); - /* adjust old timer for elapsed time */ - if (CmpTimes(totalTime, oldTimeout.it_value, <)) - SubtractTimes(oldTimeout.it_value, totalTime, - oldTimeout.it_value); - else { - /* reset value to interval, may be off */ - oldTimeout.it_value.tv_sec = oldTimeout.it_interval.tv_sec; - oldTimeout.it_value.tv_usec =oldTimeout.it_interval.tv_usec; - } - /* keep iter the same whether there or not */ - } - /* restore old handler */ - if (sigaction(SIGALRM, &oact, 0) < 0) - ret = SIGACT_ERROR; /* more pressing error, stomp */ - else - /* use old settings which may turn off (expired or not there) */ - if (setitimer(ITIMER_REAL, &oldTimeout, 0) < 0) - ret = SETITIMER_ERROR; - - /* if we had a timeout call callback */ - if (ssl->timeoutInfo.timeoutName[0]) { - ssl->timeoutInfo.timeoutValue.tv_sec = timeout.tv_sec; - ssl->timeoutInfo.timeoutValue.tv_usec = timeout.tv_usec; - (toCb)(&ssl->timeoutInfo); - } - ssl->toInfoOn = 0; - } - - /* clean up buffers allocated by AddPacketInfo */ - FreeTimeoutInfo(&ssl->timeoutInfo, ssl->heap); - - if (hsCb) { - FinishHandShakeInfo(&ssl->handShakeInfo); - (hsCb)(&ssl->handShakeInfo); - ssl->hsInfoOn = 0; - } - return ret; - } - - -#ifndef NO_WOLFSSL_CLIENT - - int wolfSSL_connect_ex(WOLFSSL* ssl, HandShakeCallBack hsCb, - TimeoutCallBack toCb, WOLFSSL_TIMEVAL timeout) - { - WOLFSSL_ENTER("wolfSSL_connect_ex"); - return wolfSSL_ex_wrapper(ssl, hsCb, toCb, timeout); - } - -#endif - - -#ifndef NO_WOLFSSL_SERVER - - int wolfSSL_accept_ex(WOLFSSL* ssl, HandShakeCallBack hsCb, - TimeoutCallBack toCb, WOLFSSL_TIMEVAL timeout) - { - WOLFSSL_ENTER("wolfSSL_accept_ex"); - return wolfSSL_ex_wrapper(ssl, hsCb, toCb, timeout); - } - -#endif - -#endif /* WOLFSSL_CALLBACKS */ - - -#ifndef NO_PSK - - void wolfSSL_CTX_set_psk_client_callback(WOLFSSL_CTX* ctx, - wc_psk_client_callback cb) - { - WOLFSSL_ENTER("wolfSSL_CTX_set_psk_client_callback"); - - if (ctx == NULL) - return; - - ctx->havePSK = 1; - ctx->client_psk_cb = cb; - } - - void wolfSSL_set_psk_client_callback(WOLFSSL* ssl,wc_psk_client_callback cb) - { - byte haveRSA = 1; - int keySz = 0; - - WOLFSSL_ENTER("wolfSSL_set_psk_client_callback"); + WOLFSSL_ENTER("wolfSSL_set_psk_client_callback"); if (ssl == NULL) return; @@ -6292,30 +4289,6 @@ int wolfSSL_set_compression(WOLFSSL* ssl) #endif /* OPENSSL_EXTRA */ #ifdef WOLFSSL_CERT_SETUP_CB -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) - /* registers client cert callback, called during handshake if server - requests client auth but user has not loaded client cert/key */ - void wolfSSL_CTX_set_client_cert_cb(WOLFSSL_CTX *ctx, client_cert_cb cb) - { - WOLFSSL_ENTER("wolfSSL_CTX_set_client_cert_cb"); - - if (ctx != NULL) { - ctx->CBClientCert = cb; - } - } -#endif - - void wolfSSL_CTX_set_cert_cb(WOLFSSL_CTX* ctx, - CertSetupCallback cb, void *arg) - { - WOLFSSL_ENTER("wolfSSL_CTX_set_cert_cb"); - if (ctx == NULL) - return; - - ctx->certSetupCb = cb; - ctx->certSetupCbArg = arg; - } - int wolfSSL_get_client_suites_sigalgs(const WOLFSSL* ssl, const byte** suites, word16* suiteSz, const byte** hashSigAlgo, word16* hashSigAlgoSz) @@ -6477,182 +4450,10 @@ int wolfSSL_set_compression(WOLFSSL* ssl) } return 0; } - - /** - * Internal wrapper for calling certSetupCb - * @param ssl The SSL/TLS Object - * @return 0 on success - */ - int CertSetupCbWrapper(WOLFSSL* ssl) - { - int ret = 0; - if (ssl->ctx->certSetupCb != NULL) { - WOLFSSL_MSG("Calling user cert setup callback"); - ret = ssl->ctx->certSetupCb(ssl, ssl->ctx->certSetupCbArg); - if (ret == 1) { - WOLFSSL_MSG("User cert callback returned success"); - ret = 0; - } - else if (ret == 0) { - SendAlert(ssl, alert_fatal, internal_error); - ret = CLIENT_CERT_CB_ERROR; - } - else if (ret < 0) { - ret = WOLFSSL_ERROR_WANT_X509_LOOKUP; - } - else { - WOLFSSL_MSG("Unexpected user callback return"); - ret = CLIENT_CERT_CB_ERROR; - } - } - return ret; - } #endif /* WOLFSSL_CERT_SETUP_CB */ #ifdef OPENSSL_EXTRA - #if defined(WOLFCRYPT_HAVE_SRP) && !defined(NO_SHA256) \ - && !defined(WC_NO_RNG) - static const byte srp_N[] = { - 0xEE, 0xAF, 0x0A, 0xB9, 0xAD, 0xB3, 0x8D, 0xD6, 0x9C, 0x33, 0xF8, - 0x0A, 0xFA, 0x8F, 0xC5, 0xE8, 0x60, 0x72, 0x61, 0x87, 0x75, 0xFF, - 0x3C, 0x0B, 0x9E, 0xA2, 0x31, 0x4C, 0x9C, 0x25, 0x65, 0x76, 0xD6, - 0x74, 0xDF, 0x74, 0x96, 0xEA, 0x81, 0xD3, 0x38, 0x3B, 0x48, 0x13, - 0xD6, 0x92, 0xC6, 0xE0, 0xE0, 0xD5, 0xD8, 0xE2, 0x50, 0xB9, 0x8B, - 0xE4, 0x8E, 0x49, 0x5C, 0x1D, 0x60, 0x89, 0xDA, 0xD1, 0x5D, 0xC7, - 0xD7, 0xB4, 0x61, 0x54, 0xD6, 0xB6, 0xCE, 0x8E, 0xF4, 0xAD, 0x69, - 0xB1, 0x5D, 0x49, 0x82, 0x55, 0x9B, 0x29, 0x7B, 0xCF, 0x18, 0x85, - 0xC5, 0x29, 0xF5, 0x66, 0x66, 0x0E, 0x57, 0xEC, 0x68, 0xED, 0xBC, - 0x3C, 0x05, 0x72, 0x6C, 0xC0, 0x2F, 0xD4, 0xCB, 0xF4, 0x97, 0x6E, - 0xAA, 0x9A, 0xFD, 0x51, 0x38, 0xFE, 0x83, 0x76, 0x43, 0x5B, 0x9F, - 0xC6, 0x1D, 0x2F, 0xC0, 0xEB, 0x06, 0xE3 - }; - static const byte srp_g[] = { - 0x02 - }; - - int wolfSSL_CTX_set_srp_username(WOLFSSL_CTX* ctx, char* username) - { - int r = 0; - SrpSide srp_side = SRP_CLIENT_SIDE; - - WOLFSSL_ENTER("wolfSSL_CTX_set_srp_username"); - if (ctx == NULL || ctx->srp == NULL || username==NULL) - return WOLFSSL_FAILURE; - - if (ctx->method->side == WOLFSSL_SERVER_END){ - srp_side = SRP_SERVER_SIDE; - } else if (ctx->method->side == WOLFSSL_CLIENT_END){ - srp_side = SRP_CLIENT_SIDE; - } else { - WOLFSSL_MSG("Init CTX failed"); - return WOLFSSL_FAILURE; - } - - if (wc_SrpInit(ctx->srp, SRP_TYPE_SHA256, srp_side) < 0) { - WOLFSSL_MSG("Init SRP CTX failed"); - XFREE(ctx->srp, ctx->heap, DYNAMIC_TYPE_SRP); - ctx->srp = NULL; - return WOLFSSL_FAILURE; - } - r = wc_SrpSetUsername(ctx->srp, (const byte*)username, - (word32)XSTRLEN(username)); - if (r < 0) { - WOLFSSL_MSG("fail to set srp username."); - return WOLFSSL_FAILURE; - } - - /* if wolfSSL_CTX_set_srp_password has already been called, */ - /* use saved password here */ - if (ctx->srp_password != NULL) { - if (ctx->srp->user == NULL) - return WOLFSSL_FAILURE; - return wolfSSL_CTX_set_srp_password(ctx, (char*)ctx->srp_password); - } - - return WOLFSSL_SUCCESS; - } - - int wolfSSL_CTX_set_srp_password(WOLFSSL_CTX* ctx, char* password) - { - int r; - byte salt[SRP_SALT_SIZE]; - - WOLFSSL_ENTER("wolfSSL_CTX_set_srp_password"); - if (ctx == NULL || ctx->srp == NULL || password == NULL) - return WOLFSSL_FAILURE; - - if (ctx->srp->user != NULL) { - WC_RNG rng; - if (wc_InitRng(&rng) < 0) { - WOLFSSL_MSG("wc_InitRng failed"); - return WOLFSSL_FAILURE; - } - XMEMSET(salt, 0, sizeof(salt)/sizeof(salt[0])); - r = wc_RNG_GenerateBlock(&rng, salt, sizeof(salt)/sizeof(salt[0])); - wc_FreeRng(&rng); - if (r < 0) { - WOLFSSL_MSG("wc_RNG_GenerateBlock failed"); - return WOLFSSL_FAILURE; - } - if (wc_SrpSetParams(ctx->srp, srp_N, sizeof(srp_N)/sizeof(srp_N[0]), - srp_g, sizeof(srp_g)/sizeof(srp_g[0]), - salt, sizeof(salt)/sizeof(salt[0])) < 0){ - WOLFSSL_MSG("wc_SrpSetParam failed"); - return WOLFSSL_FAILURE; - } - r = wc_SrpSetPassword(ctx->srp, (const byte*)password, - (word32)XSTRLEN(password)); - if (r < 0) { - WOLFSSL_MSG("wc_SrpSetPassword failed."); - return WOLFSSL_FAILURE; - } - XFREE(ctx->srp_password, NULL, DYNAMIC_TYPE_SRP); - ctx->srp_password = NULL; - } else { - /* save password for wolfSSL_set_srp_username */ - XFREE(ctx->srp_password, ctx->heap, DYNAMIC_TYPE_SRP); - - ctx->srp_password = (byte*)XMALLOC(XSTRLEN(password) + 1, ctx->heap, - DYNAMIC_TYPE_SRP); - if (ctx->srp_password == NULL){ - WOLFSSL_MSG("memory allocation error"); - return WOLFSSL_FAILURE; - } - XMEMCPY(ctx->srp_password, password, XSTRLEN(password) + 1); - } - return WOLFSSL_SUCCESS; - } - - /** - * The modulus passed to wc_SrpSetParams in ssl.c is constant so check - * that the requested strength is less than or equal to the size of the - * static modulus size. - * @param ctx Not used - * @param strength Minimum number of bits for the modulus - * @return 1 if strength is less than or equal to static modulus - * 0 if strength is greater than static modulus - */ - int wolfSSL_CTX_set_srp_strength(WOLFSSL_CTX *ctx, int strength) - { - (void)ctx; - WOLFSSL_ENTER("wolfSSL_CTX_set_srp_strength"); - if (strength > (int)(sizeof(srp_N)*8)) { - WOLFSSL_MSG("Bad Parameter"); - return WOLFSSL_FAILURE; - } - return WOLFSSL_SUCCESS; - } - - char* wolfSSL_get_srp_username(WOLFSSL *ssl) - { - if (ssl && ssl->ctx && ssl->ctx->srp) { - return (char*) ssl->ctx->srp->user; - } - return NULL; - } - #endif /* WOLFCRYPT_HAVE_SRP && !NO_SHA256 && !WC_NO_RNG */ - /* keyblock size in bytes or -1 */ int wolfSSL_get_keyblock_size(WOLFSSL* ssl) { @@ -6687,76 +4488,9 @@ int wolfSSL_set_compression(WOLFSSL* ssl) return WOLFSSL_SUCCESS; } - void wolfSSL_set_accept_state(WOLFSSL* ssl) - { - WOLFSSL_ENTER("wolfSSL_set_accept_state"); - - if (ssl == NULL) - return; - - if (ssl->options.side == WOLFSSL_CLIENT_END) { - #ifdef HAVE_ECC - WC_DECLARE_VAR(key, ecc_key, 1, 0); - word32 idx = 0; - - #ifdef WOLFSSL_SMALL_STACK - key = (ecc_key*)XMALLOC(sizeof(ecc_key), ssl->heap, - DYNAMIC_TYPE_ECC); - if (key == NULL) { - WOLFSSL_MSG("Error allocating memory for ecc_key"); - } - #endif - if (ssl->options.haveStaticECC && ssl->buffers.key != NULL) { - if (wc_ecc_init(key) >= 0) { - if (wc_EccPrivateKeyDecode(ssl->buffers.key->buffer, &idx, - key, ssl->buffers.key->length) != 0) { - ssl->options.haveECDSAsig = 0; - ssl->options.haveECC = 0; - ssl->options.haveStaticECC = 0; - } - wc_ecc_free(key); - } - } - WC_FREE_VAR_EX(key, ssl->heap, DYNAMIC_TYPE_ECC); - #endif - - #ifndef NO_DH - if (!ssl->options.haveDH && ssl->ctx->haveDH) { - ssl->buffers.serverDH_P = ssl->ctx->serverDH_P; - ssl->buffers.serverDH_G = ssl->ctx->serverDH_G; - ssl->options.haveDH = 1; - } - #endif - } - - if (InitSSL_Side(ssl, WOLFSSL_SERVER_END) != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("Error initializing server side"); - } - } #endif /* OPENSSL_EXTRA || WOLFSSL_EXTRA || WOLFSSL_WPAS_SMALL */ - /* return true if connection established */ - /* this works for TLS and DTLS */ - int wolfSSL_is_init_finished(const WOLFSSL* ssl) - { - if (ssl == NULL) - return 0; - -#if defined(WOLFSSL_DTLS13) && !defined(NO_WOLFSSL_CLIENT) - if (ssl->options.side == WOLFSSL_CLIENT_END && ssl->options.dtls - && IsAtLeastTLSv1_3(ssl->version)) { - return ssl->options.serverState == SERVER_FINISHED_ACKED; - } -#endif /* WOLFSSL_DTLS13 && !NO_WOLFSSL_CLIENT */ - - /* Can't use ssl->options.connectState and ssl->options.acceptState - * because they differ in meaning for TLS <=1.2 and 1.3 */ - if (ssl->options.handShakeState == HANDSHAKE_DONE) - return 1; - - return 0; - } #ifdef OPENSSL_EXTRA void wolfSSL_CTX_set_tmp_rsa_callback(WOLFSSL_CTX* ctx, @@ -6905,15 +4639,6 @@ int wolfSSL_set_compression(WOLFSSL* ssl) #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) || defined(HAVE_MEMCACHED) - unsigned long wolfSSL_ERR_get_error(void) - { - WOLFSSL_ENTER("wolfSSL_ERR_get_error"); -#ifdef WOLFSSL_HAVE_ERROR_QUEUE - return (unsigned long)wc_GetErrorNodeErr(); -#else - return (unsigned long)(0 - NOT_COMPILED_IN); -#endif - } #endif #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) @@ -6962,41 +4687,6 @@ int wolfSSL_set_compression(WOLFSSL* ssl) #ifdef WOLFSSL_HAVE_ERROR_QUEUE #ifndef NO_BIO /* print out and clear all errors */ - void wolfSSL_ERR_print_errors(WOLFSSL_BIO* bio) - { - const char* file = NULL; - const char* reason = NULL; - int ret; - int line = 0; - char buf[WOLFSSL_MAX_ERROR_SZ * 2]; - - WOLFSSL_ENTER("wolfSSL_ERR_print_errors"); - - if (bio == NULL) { - WOLFSSL_MSG("BIO passed in was null"); - return; - } - - do { - ret = wc_PeekErrorNode(0, &file, &reason, &line); - if (ret >= 0) { - const char* r = wolfSSL_ERR_reason_error_string( - (unsigned long)(0 - ret)); - if (XSNPRINTF(buf, sizeof(buf), - "error:%d:wolfSSL library:%s:%s:%d\n", - ret, r, file, line) - >= (int)sizeof(buf)) - { - WOLFSSL_MSG("Buffer overrun formatting error message"); - } - wolfSSL_BIO_write(bio, buf, (int)XSTRLEN(buf)); - wc_RemoveErrorNode(0); - } - } while (ret >= 0); - if (wolfSSL_BIO_write(bio, "", 1) != 1) { - WOLFSSL_MSG("Issue writing final string terminator"); - } - } #endif /* !NO_BIO */ #endif /* WOLFSSL_HAVE_ERROR_QUEUE */ @@ -7872,10 +5562,6 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out, #endif /* OPENSSL_EXTRA */ #ifdef OPENSSL_EXTRA - void wolfSSL_ERR_free_strings(void) - { - /* handled internally */ - } void wolfSSL_cleanup_all_ex_data(void) { @@ -7886,13 +5572,6 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out, #if defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE) || \ defined(HAVE_CURL) - void wolfSSL_ERR_clear_error(void) - { - WOLFSSL_ENTER("wolfSSL_ERR_clear_error"); - #if defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE) - wc_ClearErrorNodes(); - #endif - } #endif int wolfSSL_clear(WOLFSSL* ssl) @@ -8121,486 +5800,42 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out, * file pointer to file name * line gets set to line number of error when not NULL */ - unsigned long wolfSSL_ERR_get_error_line(const char** file, int* line) - { - #ifdef WOLFSSL_HAVE_ERROR_QUEUE - int ret = wc_PullErrorNode(file, NULL, line); - if (ret < 0) { - if (ret == WC_NO_ERR_TRACE(BAD_STATE_E)) - return 0; /* no errors in queue */ - WOLFSSL_MSG("Issue getting error node"); - WOLFSSL_LEAVE("wolfSSL_ERR_get_error_line", ret); - ret = 0 - ret; /* return absolute value of error */ - - /* panic and try to clear out nodes */ - wc_ClearErrorNodes(); - } - return (unsigned long)ret; - #else - (void)file; - (void)line; - return 0; - #endif - } -#if (defined(DEBUG_WOLFSSL) || defined(OPENSSL_EXTRA)) && \ - (!defined(_WIN32) && !defined(NO_ERROR_QUEUE)) - static const char WOLFSSL_SYS_ACCEPT_T[] = "accept"; - static const char WOLFSSL_SYS_BIND_T[] = "bind"; - static const char WOLFSSL_SYS_CONNECT_T[] = "connect"; - static const char WOLFSSL_SYS_FOPEN_T[] = "fopen"; - static const char WOLFSSL_SYS_FREAD_T[] = "fread"; - static const char WOLFSSL_SYS_GETADDRINFO_T[] = "getaddrinfo"; - static const char WOLFSSL_SYS_GETSOCKOPT_T[] = "getsockopt"; - static const char WOLFSSL_SYS_GETSOCKNAME_T[] = "getsockname"; - static const char WOLFSSL_SYS_GETHOSTBYNAME_T[] = "gethostbyname"; - static const char WOLFSSL_SYS_GETNAMEINFO_T[] = "getnameinfo"; - static const char WOLFSSL_SYS_GETSERVBYNAME_T[] = "getservbyname"; - static const char WOLFSSL_SYS_IOCTLSOCKET_T[] = "ioctlsocket"; - static const char WOLFSSL_SYS_LISTEN_T[] = "listen"; - static const char WOLFSSL_SYS_OPENDIR_T[] = "opendir"; - static const char WOLFSSL_SYS_SETSOCKOPT_T[] = "setsockopt"; - static const char WOLFSSL_SYS_SOCKET_T[] = "socket"; - - /* switch with int mapped to function name for compatibility */ - static const char* wolfSSL_ERR_sys_func(int fun) - { - switch (fun) { - case WOLFSSL_SYS_ACCEPT: return WOLFSSL_SYS_ACCEPT_T; - case WOLFSSL_SYS_BIND: return WOLFSSL_SYS_BIND_T; - case WOLFSSL_SYS_CONNECT: return WOLFSSL_SYS_CONNECT_T; - case WOLFSSL_SYS_FOPEN: return WOLFSSL_SYS_FOPEN_T; - case WOLFSSL_SYS_FREAD: return WOLFSSL_SYS_FREAD_T; - case WOLFSSL_SYS_GETADDRINFO: return WOLFSSL_SYS_GETADDRINFO_T; - case WOLFSSL_SYS_GETSOCKOPT: return WOLFSSL_SYS_GETSOCKOPT_T; - case WOLFSSL_SYS_GETSOCKNAME: return WOLFSSL_SYS_GETSOCKNAME_T; - case WOLFSSL_SYS_GETHOSTBYNAME: return WOLFSSL_SYS_GETHOSTBYNAME_T; - case WOLFSSL_SYS_GETNAMEINFO: return WOLFSSL_SYS_GETNAMEINFO_T; - case WOLFSSL_SYS_GETSERVBYNAME: return WOLFSSL_SYS_GETSERVBYNAME_T; - case WOLFSSL_SYS_IOCTLSOCKET: return WOLFSSL_SYS_IOCTLSOCKET_T; - case WOLFSSL_SYS_LISTEN: return WOLFSSL_SYS_LISTEN_T; - case WOLFSSL_SYS_OPENDIR: return WOLFSSL_SYS_OPENDIR_T; - case WOLFSSL_SYS_SETSOCKOPT: return WOLFSSL_SYS_SETSOCKOPT_T; - case WOLFSSL_SYS_SOCKET: return WOLFSSL_SYS_SOCKET_T; - default: - return "NULL"; - } - } -#endif /* DEBUG_WOLFSSL */ - void wolfSSL_ERR_put_error(int lib, int fun, int err, const char* file, - int line) - { - WOLFSSL_ENTER("wolfSSL_ERR_put_error"); - - #if !defined(DEBUG_WOLFSSL) && !defined(OPENSSL_EXTRA) - (void)fun; - (void)err; - (void)file; - (void)line; - WOLFSSL_MSG("Not compiled in debug mode"); - #elif defined(OPENSSL_EXTRA) && \ - (defined(_WIN32) || defined(NO_ERROR_QUEUE)) - (void)fun; - (void)file; - (void)line; - WOLFSSL_ERROR(err); - #else - WOLFSSL_ERROR_LINE(err, wolfSSL_ERR_sys_func(fun), (unsigned int)line, - file, NULL); - #endif - (void)lib; - } +#endif /* OPENSSL_EXTRA */ + - /* Similar to wolfSSL_ERR_get_error_line but takes in a flags argument for - * more flexibility. - * - * file output pointer to file where error happened - * line output to line number of error - * data output data. Is a string if WOLFSSL_ERR_TXT_STRING flag is used - * flags output format of output - * - * Returns the error value or 0 if no errors are in the queue - */ - unsigned long wolfSSL_ERR_get_error_line_data(const char** file, int* line, - const char** data, int *flags) - { -#ifdef WOLFSSL_HAVE_ERROR_QUEUE - int ret; - WOLFSSL_ENTER("wolfSSL_ERR_get_error_line_data"); - if (flags != NULL) - *flags = WOLFSSL_ERR_TXT_STRING; /* Clear the flags */ - ret = wc_PullErrorNode(file, data, line); - if (ret < 0) { - if (ret == WC_NO_ERR_TRACE(BAD_STATE_E)) - return 0; /* no errors in queue */ - WOLFSSL_MSG("Error with pulling error node!"); - WOLFSSL_LEAVE("wolfSSL_ERR_get_error_line_data", ret); - ret = 0 - ret; /* return absolute value of error */ - - /* panic and try to clear out nodes */ - wc_ClearErrorNodes(); - } - return (unsigned long)ret; +int wolfSSL_session_reused(WOLFSSL* ssl) +{ + int resuming = 0; + WOLFSSL_ENTER("wolfSSL_session_reused"); + if (ssl) { +#ifndef HAVE_SECURE_RENEGOTIATION + resuming = ssl->options.resuming; #else - WOLFSSL_ENTER("wolfSSL_ERR_get_error_line_data"); - WOLFSSL_MSG("Error queue turned off, can not get error line"); - (void)file; - (void)line; - (void)data; - (void)flags; - return 0; + resuming = ssl->options.resuming || ssl->options.resumed; #endif } + WOLFSSL_LEAVE("wolfSSL_session_reused", resuming); + return resuming; +} -#endif /* OPENSSL_EXTRA */ - +/* helper function that takes in a protocol version struct and returns string */ +static const char* wolfSSL_internal_get_version(const ProtocolVersion* version) +{ + WOLFSSL_ENTER("wolfSSL_get_version"); -#ifdef SESSION_CERTS - /* Decode the X509 DER encoded certificate into a WOLFSSL_X509 object. - * - * x509 WOLFSSL_X509 object to decode into. - * in X509 DER data. - * len Length of the X509 DER data. - * returns the new certificate on success, otherwise NULL. - */ - static int DecodeToX509(WOLFSSL_X509* x509, const byte* in, int len) - { - int ret; - WC_DECLARE_VAR(cert, DecodedCert, 1, 0); - if (x509 == NULL || in == NULL || len <= 0) - return BAD_FUNC_ARG; - - WC_ALLOC_VAR_EX(cert, DecodedCert, 1, NULL, DYNAMIC_TYPE_DCERT, - return MEMORY_E); - - /* Create a DecodedCert object and copy fields into WOLFSSL_X509 object. - */ - InitDecodedCert(cert, (byte*)in, (word32)len, NULL); - if ((ret = ParseCertRelative(cert, CERT_TYPE, 0, NULL, NULL)) == 0) { - /* Check if x509 was not previously initialized by wolfSSL_X509_new() */ - if (x509->dynamicMemory != TRUE) - InitX509(x509, 0, NULL); - ret = CopyDecodedToX509(x509, cert); - } - FreeDecodedCert(cert); - WC_FREE_VAR_EX(cert, NULL, DYNAMIC_TYPE_DCERT); - - return ret; - } -#endif /* SESSION_CERTS */ - - -#ifdef KEEP_PEER_CERT - WOLFSSL_ABI - WOLFSSL_X509* wolfSSL_get_peer_certificate(WOLFSSL* ssl) - { - WOLFSSL_X509* ret = NULL; - WOLFSSL_ENTER("wolfSSL_get_peer_certificate"); - if (ssl != NULL) { - if (ssl->peerCert.issuer.sz) - ret = wolfSSL_X509_dup(&ssl->peerCert); -#ifdef SESSION_CERTS - else if (ssl->session->chain.count > 0) { - if (DecodeToX509(&ssl->peerCert, - ssl->session->chain.certs[0].buffer, - ssl->session->chain.certs[0].length) == 0) { - ret = wolfSSL_X509_dup(&ssl->peerCert); - } - } -#endif - } - WOLFSSL_LEAVE("wolfSSL_get_peer_certificate", ret != NULL); - return ret; - } - -#endif /* KEEP_PEER_CERT */ - -#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) -/* Return stack of peer certs. - * Caller does not need to free return. The stack is Free'd when WOLFSSL* ssl - * is. - */ -WOLF_STACK_OF(WOLFSSL_X509)* wolfSSL_get_peer_cert_chain(const WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_get_peer_cert_chain"); - - if (ssl == NULL) - return NULL; - - /* Try to populate if NULL or empty */ - if (ssl->peerCertChain == NULL || - wolfSSL_sk_X509_num(ssl->peerCertChain) == 0) { - wolfSSL_set_peer_cert_chain((WOLFSSL*) ssl); - } - return ssl->peerCertChain; -} - - -static int x509GetIssuerFromCM(WOLFSSL_X509 **issuer, WOLFSSL_CERT_MANAGER* cm, - WOLFSSL_X509 *x); -/** - * Recursively push the issuer CA chain onto the stack - * @param cm The cert manager that is queried for the issuer - * @param x This cert's issuer will be queried in cm - * @param sk The issuer is pushed onto this stack - * @return 0 on success or no issuer found - * WOLFSSL_FATAL_ERROR on a fatal error - */ -static int PushCAx509Chain(WOLFSSL_CERT_MANAGER* cm, - WOLFSSL_X509 *x, WOLFSSL_STACK* sk) -{ - int i; - for (i = 0; i < MAX_CHAIN_DEPTH; i++) { - WOLFSSL_X509* issuer = NULL; - if (x509GetIssuerFromCM(&issuer, cm, x) != WOLFSSL_SUCCESS) - break; - if (wolfSSL_sk_X509_push(sk, issuer) <= 0) { - wolfSSL_X509_free(issuer); - issuer = NULL; - return WOLFSSL_FATAL_ERROR; - } - x = issuer; - } - return 0; -} - - -/* Builds up and creates a stack of peer certificates for ssl->peerCertChain - or ssl->verifiedChain based off of the ssl session chain. Attempts to place - CA certificates at the bottom of the stack for a verified chain. Returns - stack of WOLFSSL_X509 certs or NULL on failure */ -static WOLF_STACK_OF(WOLFSSL_X509)* CreatePeerCertChain(const WOLFSSL* ssl, - int verifiedFlag) -{ - WOLFSSL_STACK* sk; - WOLFSSL_X509* x509; - int i = 0; - int err; - - WOLFSSL_ENTER("wolfSSL_set_peer_cert_chain"); - if ((ssl == NULL) || (ssl->session->chain.count == 0)) - return NULL; - - sk = wolfSSL_sk_X509_new_null(); - for (i = 0; i < ssl->session->chain.count; i++) { - x509 = wolfSSL_X509_new_ex(ssl->heap); - if (x509 == NULL) { - WOLFSSL_MSG("Error Creating X509"); - wolfSSL_sk_X509_pop_free(sk, NULL); - return NULL; - } - err = DecodeToX509(x509, ssl->session->chain.certs[i].buffer, - ssl->session->chain.certs[i].length); - if (err == 0 && wolfSSL_sk_X509_push(sk, x509) <= 0) - err = WOLFSSL_FATAL_ERROR; - if (err == 0 && i == ssl->session->chain.count-1 && verifiedFlag) { - /* On the last element in the verified chain try to add the CA chain - * if we have one for this cert */ - SSL_CM_WARNING(ssl); - err = PushCAx509Chain(SSL_CM(ssl), x509, sk); - } - if (err != 0) { - WOLFSSL_MSG("Error decoding cert"); - wolfSSL_X509_free(x509); - x509 = NULL; - wolfSSL_sk_X509_pop_free(sk, NULL); - return NULL; - } - } - - if (sk == NULL) { - WOLFSSL_MSG("Null session chain"); - } - return sk; -} - - -/* Builds up and creates a stack of peer certificates for ssl->peerCertChain - returns the stack on success and NULL on failure */ -WOLF_STACK_OF(WOLFSSL_X509)* wolfSSL_set_peer_cert_chain(WOLFSSL* ssl) -{ - WOLFSSL_STACK* sk; - - WOLFSSL_ENTER("wolfSSL_set_peer_cert_chain"); - if ((ssl == NULL) || (ssl->session->chain.count == 0)) - return NULL; - - sk = CreatePeerCertChain(ssl, 0); - - if (sk != NULL) { - if (ssl->options.side == WOLFSSL_SERVER_END) { - if (ssl->session->peer) - wolfSSL_X509_free(ssl->session->peer); - - ssl->session->peer = wolfSSL_sk_X509_shift(sk); - ssl->session->peerVerifyRet = ssl->peerVerifyRet; - } - if (ssl->peerCertChain != NULL) - wolfSSL_sk_X509_pop_free(ssl->peerCertChain, NULL); - /* This is Free'd when ssl is Free'd */ - ssl->peerCertChain = sk; - } - return sk; -} - -#ifdef KEEP_PEER_CERT -/** - * Implemented in a similar way that ngx_ssl_ocsp_validate does it when - * SSL_get0_verified_chain is not available. - * @param ssl WOLFSSL object to extract certs from - * @return Stack of verified certs - */ -WOLF_STACK_OF(WOLFSSL_X509) *wolfSSL_get0_verified_chain(const WOLFSSL *ssl) -{ - WOLF_STACK_OF(WOLFSSL_X509)* chain = NULL; - WOLFSSL_X509_STORE_CTX* storeCtx = NULL; - WOLFSSL_X509* peerCert = NULL; - - WOLFSSL_ENTER("wolfSSL_get0_verified_chain"); - - if (ssl == NULL || ssl->ctx == NULL) { - WOLFSSL_MSG("Bad parameter"); - return NULL; - } - - peerCert = wolfSSL_get_peer_certificate((WOLFSSL*)ssl); - if (peerCert == NULL) { - WOLFSSL_MSG("wolfSSL_get_peer_certificate error"); - return NULL; - } - /* wolfSSL_get_peer_certificate returns a copy. We want the internal - * member so that we don't have to worry about free'ing it. We call - * wolfSSL_get_peer_certificate so that we don't have to worry about - * setting up the internal pointer. */ - wolfSSL_X509_free(peerCert); - peerCert = (WOLFSSL_X509*)&ssl->peerCert; - chain = CreatePeerCertChain((WOLFSSL*)ssl, 1); - if (chain == NULL) { - WOLFSSL_MSG("wolfSSL_get_peer_cert_chain error"); - return NULL; - } - - if (ssl->verifiedChain != NULL) { - wolfSSL_sk_X509_pop_free(ssl->verifiedChain, NULL); - } - ((WOLFSSL*)ssl)->verifiedChain = chain; - - storeCtx = wolfSSL_X509_STORE_CTX_new(); - if (storeCtx == NULL) { - WOLFSSL_MSG("wolfSSL_X509_STORE_CTX_new error"); - return NULL; - } - if (wolfSSL_X509_STORE_CTX_init(storeCtx, SSL_STORE(ssl), - peerCert, chain) != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("wolfSSL_X509_STORE_CTX_init error"); - wolfSSL_X509_STORE_CTX_free(storeCtx); - return NULL; - } - if (wolfSSL_X509_verify_cert(storeCtx) <= 0) { - WOLFSSL_MSG("wolfSSL_X509_verify_cert error"); - wolfSSL_X509_STORE_CTX_free(storeCtx); - return NULL; - } - wolfSSL_X509_STORE_CTX_free(storeCtx); - return chain; -} -#endif /* KEEP_PEER_CERT */ -#endif /* SESSION_CERTS && OPENSSL_EXTRA */ - -#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) -void wolfSSL_set_connect_state(WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_set_connect_state"); - if (ssl == NULL) { - WOLFSSL_MSG("WOLFSSL struct pointer passed in was null"); - return; - } - - #ifndef NO_DH - /* client creates its own DH parameters on handshake */ - if (ssl->buffers.serverDH_P.buffer && ssl->buffers.weOwnDH) { - XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap, - DYNAMIC_TYPE_PUBLIC_KEY); - } - ssl->buffers.serverDH_P.buffer = NULL; - if (ssl->buffers.serverDH_G.buffer && ssl->buffers.weOwnDH) { - XFREE(ssl->buffers.serverDH_G.buffer, ssl->heap, - DYNAMIC_TYPE_PUBLIC_KEY); - } - ssl->buffers.serverDH_G.buffer = NULL; - #endif - - if (InitSSL_Side(ssl, WOLFSSL_CLIENT_END) != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("Error initializing client side"); - } -} -#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */ - - -int wolfSSL_get_shutdown(const WOLFSSL* ssl) -{ - int isShutdown = 0; - - WOLFSSL_ENTER("wolfSSL_get_shutdown"); - - if (ssl) { -#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) - if (ssl->options.shutdownDone) { - /* The SSL object was possibly cleared with wolfSSL_clear after - * a successful shutdown. Simulate a response for a full - * bidirectional shutdown. */ - isShutdown = WOLFSSL_SENT_SHUTDOWN | WOLFSSL_RECEIVED_SHUTDOWN; - } - else -#endif - { - /* in OpenSSL, WOLFSSL_SENT_SHUTDOWN = 1, when closeNotifySent * - * WOLFSSL_RECEIVED_SHUTDOWN = 2, from close notify or fatal err */ - if (ssl->options.sentNotify) - isShutdown |= WOLFSSL_SENT_SHUTDOWN; - if (ssl->options.closeNotify||ssl->options.connReset) - isShutdown |= WOLFSSL_RECEIVED_SHUTDOWN; - } - - } - - WOLFSSL_LEAVE("wolfSSL_get_shutdown", isShutdown); - return isShutdown; -} - - -int wolfSSL_session_reused(WOLFSSL* ssl) -{ - int resuming = 0; - WOLFSSL_ENTER("wolfSSL_session_reused"); - if (ssl) { -#ifndef HAVE_SECURE_RENEGOTIATION - resuming = ssl->options.resuming; -#else - resuming = ssl->options.resuming || ssl->options.resumed; -#endif - } - WOLFSSL_LEAVE("wolfSSL_session_reused", resuming); - return resuming; -} - -/* helper function that takes in a protocol version struct and returns string */ -static const char* wolfSSL_internal_get_version(const ProtocolVersion* version) -{ - WOLFSSL_ENTER("wolfSSL_get_version"); - - if (version == NULL) { - return "Bad arg"; - } + if (version == NULL) { + return "Bad arg"; + } if (version->major == SSLv3_MAJOR) { switch (version->minor) { @@ -9572,93 +6807,6 @@ char* wolfSSL_CIPHER_description(const WOLFSSL_CIPHER* cipher, char* in, return ret; } -int wolfSSL_OCSP_parse_url(const char* url, char** host, char** port, - char** path, int* ssl) -{ - const char* u; - const char* upath; /* path in u */ - const char* uport; /* port in u */ - const char* hostEnd; - - WOLFSSL_ENTER("OCSP_parse_url"); - - if (url == NULL || host == NULL || port == NULL || path == NULL || - ssl == NULL) { - return WOLFSSL_FAILURE; - } - - u = url; - *host = NULL; - *port = NULL; - *path = NULL; - *ssl = 0; - - if (*(u++) != 'h') goto err; - if (*(u++) != 't') goto err; - if (*(u++) != 't') goto err; - if (*(u++) != 'p') goto err; - if (*u == 's') { - *ssl = 1; - u++; - *port = CopyString("443", -1, NULL, DYNAMIC_TYPE_OPENSSL); - } - else if (*u == ':') { - *ssl = 0; - *port = CopyString("80", -1, NULL, DYNAMIC_TYPE_OPENSSL); - } - else - goto err; - if (*port == NULL) - goto err; - if (*(u++) != ':') goto err; - if (*(u++) != '/') goto err; - if (*(u++) != '/') goto err; - - /* Look for path */ - upath = XSTRSTR(u, "/"); - *path = CopyString(upath == NULL ? "/" : upath, -1, NULL, - DYNAMIC_TYPE_OPENSSL); - - /* Look for port */ - uport = XSTRSTR(u, ":"); - if (uport != NULL) { - if (*(++uport) == '\0') - goto err; - /* port must be before path */ - if (upath != NULL && uport >= upath) - goto err; - XFREE(*port, NULL, DYNAMIC_TYPE_OPENSSL); - if (upath) - *port = CopyString(uport, (int)(upath - uport), NULL, - DYNAMIC_TYPE_OPENSSL); - else - *port = CopyString(uport, -1, NULL, DYNAMIC_TYPE_OPENSSL); - if (*port == NULL) - goto err; - hostEnd = uport - 1; - } - else - hostEnd = upath; - - if (hostEnd) - *host = CopyString(u, (int)(hostEnd - u), NULL, DYNAMIC_TYPE_OPENSSL); - else - *host = CopyString(u, -1, NULL, DYNAMIC_TYPE_OPENSSL); - - if (*host == NULL) - goto err; - - return WOLFSSL_SUCCESS; -err: - XFREE(*host, NULL, DYNAMIC_TYPE_OPENSSL); - *host = NULL; - XFREE(*port, NULL, DYNAMIC_TYPE_OPENSSL); - *port = NULL; - XFREE(*path, NULL, DYNAMIC_TYPE_OPENSSL); - *path = NULL; - return WOLFSSL_FAILURE; -} - #ifndef NO_WOLFSSL_STUB WOLFSSL_COMP_METHOD* wolfSSL_COMP_zlib(void) { @@ -9821,91 +6969,6 @@ void wolfSSL_set_info_callback(WOLFSSL* ssl, } -unsigned long wolfSSL_ERR_peek_error(void) -{ - WOLFSSL_ENTER("wolfSSL_ERR_peek_error"); - - return wolfSSL_ERR_peek_error_line_data(NULL, NULL, NULL, NULL); -} - -#ifdef WOLFSSL_DEBUG_TRACE_ERROR_CODES_H -#include -#endif - -int wolfSSL_ERR_GET_LIB(unsigned long err) -{ - unsigned long value; - - value = (err & 0xFFFFFFL); - switch (value) { - case -PARSE_ERROR: - return WOLFSSL_ERR_LIB_SSL; - case -ASN_NO_PEM_HEADER: - case -WOLFSSL_PEM_R_NO_START_LINE_E: - case -WOLFSSL_PEM_R_PROBLEMS_GETTING_PASSWORD_E: - case -WOLFSSL_PEM_R_BAD_PASSWORD_READ_E: - case -WOLFSSL_PEM_R_BAD_DECRYPT_E: - return WOLFSSL_ERR_LIB_PEM; - case -WOLFSSL_EVP_R_BAD_DECRYPT_E: - case -WOLFSSL_EVP_R_BN_DECODE_ERROR: - case -WOLFSSL_EVP_R_DECODE_ERROR: - case -WOLFSSL_EVP_R_PRIVATE_KEY_DECODE_ERROR: - return WOLFSSL_ERR_LIB_EVP; - case -WOLFSSL_ASN1_R_HEADER_TOO_LONG_E: - return WOLFSSL_ERR_LIB_ASN1; - default: - return 0; - } -} - -#ifdef WOLFSSL_DEBUG_TRACE_ERROR_CODES -#include -#endif - -/* This function is to find global error values that are the same through out - * all library version. With wolfSSL having only one set of error codes the - * return value is pretty straight forward. The only thing needed is all wolfSSL - * error values are typically negative. - * - * Returns the error reason - */ -int wolfSSL_ERR_GET_REASON(unsigned long err) -{ - int ret = (int)err; - - WOLFSSL_ENTER("wolfSSL_ERR_GET_REASON"); - -#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) - /* Nginx looks for this error to know to stop parsing certificates. - * Same for HAProxy. */ - if ((err == (unsigned long)((ERR_LIB_PEM << 24) | PEM_R_NO_START_LINE)) || - ((err & 0xFFFFFFL) == (unsigned long)(-WC_NO_ERR_TRACE(ASN_NO_PEM_HEADER))) || - ((err & 0xFFFL) == (unsigned long)PEM_R_NO_START_LINE)) - return PEM_R_NO_START_LINE; - if (err == (unsigned long)((ERR_LIB_SSL << 24) | -SSL_R_HTTP_REQUEST)) - return SSL_R_HTTP_REQUEST; -#endif -#if defined(OPENSSL_ALL) && defined(WOLFSSL_PYTHON) - if (err == (unsigned long)((ERR_LIB_ASN1 << 24) | ASN1_R_HEADER_TOO_LONG)) - return ASN1_R_HEADER_TOO_LONG; -#endif - - /* check if error value is in range of wolfCrypt or wolfSSL errors */ - ret = 0 - ret; /* setting as negative value */ - - if ((ret <= WC_SPAN1_FIRST_E && ret >= WC_SPAN1_LAST_E) || - (ret <= WC_SPAN2_FIRST_E && ret >= WC_SPAN2_LAST_E) || - (ret <= WOLFSSL_FIRST_E && ret >= WOLFSSL_LAST_E)) - { - return ret; - } - else { - WOLFSSL_MSG("Not in range of typical error values"); - ret = (int)err; - } - - return ret; -} #ifndef NO_TLS /* returns a string that describes the alert @@ -10011,396 +7074,41 @@ const char* wolfSSL_alert_desc_string(int alertID) } #endif /* !NO_TLS */ -#define STATE_STRINGS_PROTO(s) \ - { \ - {"SSLv3 " s, \ - "SSLv3 " s, \ - "SSLv3 " s}, \ - {"TLSv1 " s, \ - "TLSv1 " s, \ - "TLSv1 " s}, \ - {"TLSv1_1 " s, \ - "TLSv1_1 " s, \ - "TLSv1_1 " s}, \ - {"TLSv1_2 " s, \ - "TLSv1_2 " s, \ - "TLSv1_2 " s}, \ - {"TLSv1_3 " s, \ - "TLSv1_3 " s, \ - "TLSv1_3 " s}, \ - {"DTLSv1 " s, \ - "DTLSv1 " s, \ - "DTLSv1 " s}, \ - {"DTLSv1_2 " s, \ - "DTLSv1_2 " s, \ - "DTLSv1_2 " s}, \ - {"DTLSv1_3 " s, \ - "DTLSv1_3 " s, \ - "DTLSv1_3 " s}, \ - } - -#define STATE_STRINGS_PROTO_RW(s) \ - { \ - {"SSLv3 read " s, \ - "SSLv3 write " s, \ - "SSLv3 " s}, \ - {"TLSv1 read " s, \ - "TLSv1 write " s, \ - "TLSv1 " s}, \ - {"TLSv1_1 read " s, \ - "TLSv1_1 write " s, \ - "TLSv1_1 " s}, \ - {"TLSv1_2 read " s, \ - "TLSv1_2 write " s, \ - "TLSv1_2 " s}, \ - {"TLSv1_3 read " s, \ - "TLSv1_3 write " s, \ - "TLSv1_3 " s}, \ - {"DTLSv1 read " s, \ - "DTLSv1 write " s, \ - "DTLSv1 " s}, \ - {"DTLSv1_2 read " s, \ - "DTLSv1_2 write " s, \ - "DTLSv1_2 " s}, \ - {"DTLSv1_3 read " s, \ - "DTLSv1_3 write " s, \ - "DTLSv1_3 " s}, \ - } - -/* Gets the current state of the WOLFSSL structure - * - * ssl WOLFSSL structure to get state of - * - * Returns a human readable string of the WOLFSSL structure state - */ -const char* wolfSSL_state_string_long(const WOLFSSL* ssl) -{ - - static const char* OUTPUT_STR[24][8][3] = { - STATE_STRINGS_PROTO("Initialization"), - STATE_STRINGS_PROTO_RW("Server Hello Request"), - STATE_STRINGS_PROTO_RW("Server Hello Verify Request"), - STATE_STRINGS_PROTO_RW("Server Hello Retry Request"), - STATE_STRINGS_PROTO_RW("Server Hello"), - STATE_STRINGS_PROTO_RW("Server Certificate Status"), - STATE_STRINGS_PROTO_RW("Server Encrypted Extensions"), - STATE_STRINGS_PROTO_RW("Server Session Ticket"), - STATE_STRINGS_PROTO_RW("Server Certificate Request"), - STATE_STRINGS_PROTO_RW("Server Cert"), - STATE_STRINGS_PROTO_RW("Server Key Exchange"), - STATE_STRINGS_PROTO_RW("Server Hello Done"), - STATE_STRINGS_PROTO_RW("Server Change CipherSpec"), - STATE_STRINGS_PROTO_RW("Server Finished"), - STATE_STRINGS_PROTO_RW("server Key Update"), - STATE_STRINGS_PROTO_RW("Client Hello"), - STATE_STRINGS_PROTO_RW("Client Key Exchange"), - STATE_STRINGS_PROTO_RW("Client Cert"), - STATE_STRINGS_PROTO_RW("Client Change CipherSpec"), - STATE_STRINGS_PROTO_RW("Client Certificate Verify"), - STATE_STRINGS_PROTO_RW("Client End Of Early Data"), - STATE_STRINGS_PROTO_RW("Client Finished"), - STATE_STRINGS_PROTO_RW("Client Key Update"), - STATE_STRINGS_PROTO("Handshake Done"), - }; - enum ProtocolVer { - SSL_V3 = 0, - TLS_V1, - TLS_V1_1, - TLS_V1_2, - TLS_V1_3, - DTLS_V1, - DTLS_V1_2, - DTLS_V1_3, - UNKNOWN = 100 - }; - enum IOMode { - SS_READ = 0, - SS_WRITE, - SS_NEITHER - }; +#endif /* OPENSSL_EXTRA */ - enum SslState { - ss_null_state = 0, - ss_server_hellorequest, - ss_server_helloverify, - ss_server_helloretryrequest, - ss_server_hello, - ss_server_certificatestatus, - ss_server_encryptedextensions, - ss_server_sessionticket, - ss_server_certrequest, - ss_server_cert, - ss_server_keyexchange, - ss_server_hellodone, - ss_server_changecipherspec, - ss_server_finished, - ss_server_keyupdate, - ss_client_hello, - ss_client_keyexchange, - ss_client_cert, - ss_client_changecipherspec, - ss_client_certverify, - ss_client_endofearlydata, - ss_client_finished, - ss_client_keyupdate, - ss_handshake_done - }; +static long wolf_set_options(long old_op, long op) +{ + /* if SSL_OP_ALL then turn all bug workarounds on */ + if ((op & WOLFSSL_OP_ALL) == WOLFSSL_OP_ALL) { + WOLFSSL_MSG("\tSSL_OP_ALL"); + } - int protocol = 0; - int cbmode = 0; - int state = 0; + /* by default cookie exchange is on with DTLS */ + if ((op & WOLFSSL_OP_COOKIE_EXCHANGE) == WOLFSSL_OP_COOKIE_EXCHANGE) { + WOLFSSL_MSG("\tSSL_OP_COOKIE_EXCHANGE : on by default"); + } - WOLFSSL_ENTER("wolfSSL_state_string_long"); - if (ssl == NULL) { - WOLFSSL_MSG("Null argument passed in"); - return NULL; + if ((op & WOLFSSL_OP_NO_SSLv2) == WOLFSSL_OP_NO_SSLv2) { + WOLFSSL_MSG("\tWOLFSSL_OP_NO_SSLv2 : wolfSSL does not support SSLv2"); } - /* Get state of callback */ - if (ssl->cbmode == WOLFSSL_CB_MODE_WRITE) { - cbmode = SS_WRITE; +#ifdef SSL_OP_NO_TLSv1_3 + if ((op & WOLFSSL_OP_NO_TLSv1_3) == WOLFSSL_OP_NO_TLSv1_3) { + WOLFSSL_MSG("\tSSL_OP_NO_TLSv1_3"); } - else if (ssl->cbmode == WOLFSSL_CB_MODE_READ) { - cbmode = SS_READ; +#endif + + if ((op & WOLFSSL_OP_NO_TLSv1_2) == WOLFSSL_OP_NO_TLSv1_2) { + WOLFSSL_MSG("\tSSL_OP_NO_TLSv1_2"); } - else { - cbmode = SS_NEITHER; + + if ((op & WOLFSSL_OP_NO_TLSv1_1) == WOLFSSL_OP_NO_TLSv1_1) { + WOLFSSL_MSG("\tSSL_OP_NO_TLSv1_1"); } - /* Get protocol version */ - switch (ssl->version.major) { - case SSLv3_MAJOR: - switch (ssl->version.minor) { - case SSLv3_MINOR: - protocol = SSL_V3; - break; - case TLSv1_MINOR: - protocol = TLS_V1; - break; - case TLSv1_1_MINOR: - protocol = TLS_V1_1; - break; - case TLSv1_2_MINOR: - protocol = TLS_V1_2; - break; - case TLSv1_3_MINOR: - protocol = TLS_V1_3; - break; - default: - protocol = UNKNOWN; - } - break; - case DTLS_MAJOR: - switch (ssl->version.minor) { - case DTLS_MINOR: - protocol = DTLS_V1; - break; - case DTLSv1_2_MINOR: - protocol = DTLS_V1_2; - break; - case DTLSv1_3_MINOR: - protocol = DTLS_V1_3; - break; - default: - protocol = UNKNOWN; - } - break; - default: - protocol = UNKNOWN; - } - - /* accept process */ - if (ssl->cbmode == WOLFSSL_CB_MODE_READ) { - state = ssl->cbtype; - switch (state) { - case hello_request: - state = ss_server_hellorequest; - break; - case client_hello: - state = ss_client_hello; - break; - case server_hello: - state = ss_server_hello; - break; - case hello_verify_request: - state = ss_server_helloverify; - break; - case session_ticket: - state = ss_server_sessionticket; - break; - case end_of_early_data: - state = ss_client_endofearlydata; - break; - case hello_retry_request: - state = ss_server_helloretryrequest; - break; - case encrypted_extensions: - state = ss_server_encryptedextensions; - break; - case certificate: - if (ssl->options.side == WOLFSSL_SERVER_END) - state = ss_client_cert; - else if (ssl->options.side == WOLFSSL_CLIENT_END) - state = ss_server_cert; - else { - WOLFSSL_MSG("Unknown State"); - state = ss_null_state; - } - break; - case server_key_exchange: - state = ss_server_keyexchange; - break; - case certificate_request: - state = ss_server_certrequest; - break; - case server_hello_done: - state = ss_server_hellodone; - break; - case certificate_verify: - state = ss_client_certverify; - break; - case client_key_exchange: - state = ss_client_keyexchange; - break; - case finished: - if (ssl->options.side == WOLFSSL_SERVER_END) - state = ss_client_finished; - else if (ssl->options.side == WOLFSSL_CLIENT_END) - state = ss_server_finished; - else { - WOLFSSL_MSG("Unknown State"); - state = ss_null_state; - } - break; - case certificate_status: - state = ss_server_certificatestatus; - break; - case key_update: - if (ssl->options.side == WOLFSSL_SERVER_END) - state = ss_client_keyupdate; - else if (ssl->options.side == WOLFSSL_CLIENT_END) - state = ss_server_keyupdate; - else { - WOLFSSL_MSG("Unknown State"); - state = ss_null_state; - } - break; - case change_cipher_hs: - if (ssl->options.side == WOLFSSL_SERVER_END) - state = ss_client_changecipherspec; - else if (ssl->options.side == WOLFSSL_CLIENT_END) - state = ss_server_changecipherspec; - else { - WOLFSSL_MSG("Unknown State"); - state = ss_null_state; - } - break; - default: - WOLFSSL_MSG("Unknown State"); - state = ss_null_state; - } - } - else { - /* Send process */ - if (ssl->options.side == WOLFSSL_SERVER_END) - state = ssl->options.serverState; - else - state = ssl->options.clientState; - - switch (state) { - case SERVER_HELLOVERIFYREQUEST_COMPLETE: - state = ss_server_helloverify; - break; - case SERVER_HELLO_RETRY_REQUEST_COMPLETE: - state = ss_server_helloretryrequest; - break; - case SERVER_HELLO_COMPLETE: - state = ss_server_hello; - break; - case SERVER_ENCRYPTED_EXTENSIONS_COMPLETE: - state = ss_server_encryptedextensions; - break; - case SERVER_CERT_COMPLETE: - state = ss_server_cert; - break; - case SERVER_KEYEXCHANGE_COMPLETE: - state = ss_server_keyexchange; - break; - case SERVER_HELLODONE_COMPLETE: - state = ss_server_hellodone; - break; - case SERVER_CHANGECIPHERSPEC_COMPLETE: - state = ss_server_changecipherspec; - break; - case SERVER_FINISHED_COMPLETE: - state = ss_server_finished; - break; - case CLIENT_HELLO_RETRY: - case CLIENT_HELLO_COMPLETE: - state = ss_client_hello; - break; - case CLIENT_KEYEXCHANGE_COMPLETE: - state = ss_client_keyexchange; - break; - case CLIENT_CHANGECIPHERSPEC_COMPLETE: - state = ss_client_changecipherspec; - break; - case CLIENT_FINISHED_COMPLETE: - state = ss_client_finished; - break; - case HANDSHAKE_DONE: - state = ss_handshake_done; - break; - default: - WOLFSSL_MSG("Unknown State"); - state = ss_null_state; - } - } - - if (protocol == UNKNOWN) { - WOLFSSL_MSG("Unknown protocol"); - return ""; - } - else { - return OUTPUT_STR[state][protocol][cbmode]; - } -} - -#endif /* OPENSSL_EXTRA */ - -static long wolf_set_options(long old_op, long op) -{ - /* if SSL_OP_ALL then turn all bug workarounds on */ - if ((op & WOLFSSL_OP_ALL) == WOLFSSL_OP_ALL) { - WOLFSSL_MSG("\tSSL_OP_ALL"); - } - - /* by default cookie exchange is on with DTLS */ - if ((op & WOLFSSL_OP_COOKIE_EXCHANGE) == WOLFSSL_OP_COOKIE_EXCHANGE) { - WOLFSSL_MSG("\tSSL_OP_COOKIE_EXCHANGE : on by default"); - } - - if ((op & WOLFSSL_OP_NO_SSLv2) == WOLFSSL_OP_NO_SSLv2) { - WOLFSSL_MSG("\tWOLFSSL_OP_NO_SSLv2 : wolfSSL does not support SSLv2"); - } - -#ifdef SSL_OP_NO_TLSv1_3 - if ((op & WOLFSSL_OP_NO_TLSv1_3) == WOLFSSL_OP_NO_TLSv1_3) { - WOLFSSL_MSG("\tSSL_OP_NO_TLSv1_3"); - } -#endif - - if ((op & WOLFSSL_OP_NO_TLSv1_2) == WOLFSSL_OP_NO_TLSv1_2) { - WOLFSSL_MSG("\tSSL_OP_NO_TLSv1_2"); - } - - if ((op & WOLFSSL_OP_NO_TLSv1_1) == WOLFSSL_OP_NO_TLSv1_1) { - WOLFSSL_MSG("\tSSL_OP_NO_TLSv1_1"); - } - - if ((op & WOLFSSL_OP_NO_TLSv1) == WOLFSSL_OP_NO_TLSv1) { - WOLFSSL_MSG("\tSSL_OP_NO_TLSv1"); + if ((op & WOLFSSL_OP_NO_TLSv1) == WOLFSSL_OP_NO_TLSv1) { + WOLFSSL_MSG("\tSSL_OP_NO_TLSv1"); } if ((op & WOLFSSL_OP_NO_SSLv3) == WOLFSSL_OP_NO_SSLv3) { @@ -10657,10 +7365,6 @@ WOLF_STACK_OF(WOLFSSL_COMP) *WOLFSSL_COMP_get_compression_methods(void) #if !defined(NETOS) -void wolfSSL_ERR_load_SSL_strings(void) -{ - -} #endif @@ -10905,497 +7609,6 @@ long wolfSSL_CTX_set_tlsext_opaque_prf_input_callback_arg(WOLFSSL_CTX* ctx, #endif /* OPENSSL_EXTRA */ -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) -const WOLFSSL_ObjectInfo wolfssl_object_info[] = { -#ifndef NO_CERTS - /* oidCertExtType */ - { WC_NID_basic_constraints, BASIC_CA_OID, oidCertExtType, - "basicConstraints", "X509v3 Basic Constraints"}, - { WC_NID_subject_alt_name, ALT_NAMES_OID, oidCertExtType, "subjectAltName", - "X509v3 Subject Alternative Name"}, - { WC_NID_crl_distribution_points, CRL_DIST_OID, oidCertExtType, - "crlDistributionPoints", "X509v3 CRL Distribution Points"}, - { WC_NID_info_access, AUTH_INFO_OID, oidCertExtType, "authorityInfoAccess", - "Authority Information Access"}, - { WC_NID_authority_key_identifier, AUTH_KEY_OID, oidCertExtType, - "authorityKeyIdentifier", "X509v3 Authority Key Identifier"}, - { WC_NID_subject_key_identifier, SUBJ_KEY_OID, oidCertExtType, - "subjectKeyIdentifier", "X509v3 Subject Key Identifier"}, - { WC_NID_key_usage, KEY_USAGE_OID, oidCertExtType, "keyUsage", - "X509v3 Key Usage"}, - { WC_NID_inhibit_any_policy, INHIBIT_ANY_OID, oidCertExtType, - "inhibitAnyPolicy", "X509v3 Inhibit Any Policy"}, - { WC_NID_ext_key_usage, EXT_KEY_USAGE_OID, oidCertExtType, - "extendedKeyUsage", "X509v3 Extended Key Usage"}, - { WC_NID_name_constraints, NAME_CONS_OID, oidCertExtType, - "nameConstraints", "X509v3 Name Constraints"}, - { WC_NID_certificate_policies, CERT_POLICY_OID, oidCertExtType, - "certificatePolicies", "X509v3 Certificate Policies"}, - - /* oidCertAuthInfoType */ - { WC_NID_ad_OCSP, AIA_OCSP_OID, oidCertAuthInfoType, "OCSP", - "OCSP"}, - { WC_NID_ad_ca_issuers, AIA_CA_ISSUER_OID, oidCertAuthInfoType, - "caIssuers", "CA Issuers"}, - - /* oidCertPolicyType */ - { WC_NID_any_policy, CP_ANY_OID, oidCertPolicyType, "anyPolicy", - "X509v3 Any Policy"}, - - /* oidCertAltNameType */ - { WC_NID_hw_name_oid, HW_NAME_OID, oidCertAltNameType, "Hardware name",""}, - - /* oidCertKeyUseType */ - { WC_NID_anyExtendedKeyUsage, EKU_ANY_OID, oidCertKeyUseType, - "anyExtendedKeyUsage", "Any Extended Key Usage"}, - { EKU_SERVER_AUTH_OID, EKU_SERVER_AUTH_OID, oidCertKeyUseType, - "serverAuth", "TLS Web Server Authentication"}, - { EKU_CLIENT_AUTH_OID, EKU_CLIENT_AUTH_OID, oidCertKeyUseType, - "clientAuth", "TLS Web Client Authentication"}, - { EKU_OCSP_SIGN_OID, EKU_OCSP_SIGN_OID, oidCertKeyUseType, - "OCSPSigning", "OCSP Signing"}, - - /* oidCertNameType */ - { WC_NID_commonName, WC_NAME_COMMON_NAME_OID, oidCertNameType, - "CN", "commonName"}, -#if !defined(WOLFSSL_CERT_REQ) - { WC_NID_surname, WC_NAME_SURNAME_OID, oidCertNameType, "SN", "surname"}, -#endif - { WC_NID_serialNumber, WC_NAME_SERIAL_NUMBER_OID, oidCertNameType, - "serialNumber", "serialNumber"}, - { WC_NID_userId, WC_NID_userId, oidCertNameType, "UID", "userid"}, - { WC_NID_countryName, WC_NAME_COUNTRY_NAME_OID, oidCertNameType, - "C", "countryName"}, - { WC_NID_localityName, WC_NAME_LOCALITY_NAME_OID, oidCertNameType, - "L", "localityName"}, - { WC_NID_stateOrProvinceName, WC_NAME_STATE_NAME_OID, oidCertNameType, - "ST", "stateOrProvinceName"}, - { WC_NID_streetAddress, WC_NAME_STREET_ADDRESS_OID, oidCertNameType, - "street", "streetAddress"}, - { WC_NID_organizationName, WC_NAME_ORGANIZATION_NAME_OID, oidCertNameType, - "O", "organizationName"}, - { WC_NID_organizationalUnitName, WC_NAME_ORGANIZATION_UNIT_NAME_OID, - oidCertNameType, "OU", "organizationalUnitName"}, - { WC_NID_title, WC_NAME_TITLE_OID, oidCertNameType, "title", "title"}, - { WC_NID_description, WC_NAME_DESCRIPTION_OID, oidCertNameType, - "description", "description"}, - { WC_NID_emailAddress, WC_NAME_EMAIL_ADDRESS_OID, oidCertNameType, - "emailAddress", "emailAddress"}, - { WC_NID_domainComponent, WC_NAME_DOMAIN_COMPONENT_OID, oidCertNameType, - "DC", "domainComponent"}, - { WC_NID_rfc822Mailbox, WC_NAME_RFC822_MAILBOX_OID, oidCertNameType, - "rfc822Mailbox", "rfc822Mailbox"}, - { WC_NID_favouriteDrink, WC_NAME_FAVOURITE_DRINK_OID, oidCertNameType, - "favouriteDrink", "favouriteDrink"}, - { WC_NID_businessCategory, WC_NAME_BUSINESS_CATEGORY_OID, oidCertNameType, - "businessCategory", "businessCategory"}, - { WC_NID_jurisdictionCountryName, WC_NAME_JURIS_COUNTRY_OID, - oidCertNameType, "jurisdictionC", "jurisdictionCountryName"}, - { WC_NID_jurisdictionStateOrProvinceName, WC_NAME_JURIS_STATE_PROV_OID, - oidCertNameType, "jurisdictionST", "jurisdictionStateOrProvinceName"}, - { WC_NID_postalCode, WC_NAME_POSTAL_CODE_OID, oidCertNameType, "postalCode", - "postalCode"}, - { WC_NID_userId, WC_NAME_USER_ID_OID, oidCertNameType, "UID", "userId"}, - { WC_NID_netscape_cert_type, NETSCAPE_CT_OID, oidCertNameType, - "nsCertType", "Netscape Cert Type"}, - -#if defined(WOLFSSL_CERT_REQ) || defined(WOLFSSL_CERT_NAME_ALL) - { WC_NID_pkcs9_challengePassword, CHALLENGE_PASSWORD_OID, - oidCsrAttrType, "challengePassword", "challengePassword"}, - { WC_NID_pkcs9_contentType, PKCS9_CONTENT_TYPE_OID, - oidCsrAttrType, "contentType", "contentType" }, - { WC_NID_pkcs9_unstructuredName, UNSTRUCTURED_NAME_OID, - oidCsrAttrType, "unstructuredName", "unstructuredName" }, - { WC_NID_name, WC_NAME_NAME_OID, oidCsrAttrType, "name", "name" }, - { WC_NID_surname, SURNAME_OID, - oidCsrAttrType, "surname", "surname" }, - { WC_NID_givenName, WC_NAME_GIVEN_NAME_OID, - oidCsrAttrType, "givenName", "givenName" }, - { WC_NID_initials, WC_NAME_INITIALIS_OID, - oidCsrAttrType, "initials", "initials" }, - { WC_NID_dnQualifier, DNQUALIFIER_OID, - oidCsrAttrType, "dnQualifer", "dnQualifier" }, -#endif -#endif -#ifdef OPENSSL_EXTRA /* OPENSSL_EXTRA_X509_SMALL only needs the above */ - /* oidHashType */ - #ifdef WOLFSSL_MD2 - { WC_NID_md2, MD2h, oidHashType, "MD2", "md2"}, - #endif - #ifndef NO_MD4 - { WC_NID_md4, MD4h, oidHashType, "MD4", "md4"}, - #endif - #ifndef NO_MD5 - { WC_NID_md5, MD5h, oidHashType, "MD5", "md5"}, - #endif - #ifndef NO_SHA - { WC_NID_sha1, SHAh, oidHashType, "SHA1", "sha1"}, - #endif - #ifdef WOLFSSL_SHA224 - { WC_NID_sha224, SHA224h, oidHashType, "SHA224", "sha224"}, - #endif - #ifndef NO_SHA256 - { WC_NID_sha256, SHA256h, oidHashType, "SHA256", "sha256"}, - #endif - #ifdef WOLFSSL_SHA384 - { WC_NID_sha384, SHA384h, oidHashType, "SHA384", "sha384"}, - #endif - #ifdef WOLFSSL_SHA512 - { WC_NID_sha512, SHA512h, oidHashType, "SHA512", "sha512"}, - #endif - #ifdef WOLFSSL_SHA3 - #ifndef WOLFSSL_NOSHA3_224 - { WC_NID_sha3_224, SHA3_224h, oidHashType, "SHA3-224", "sha3-224"}, - #endif - #ifndef WOLFSSL_NOSHA3_256 - { WC_NID_sha3_256, SHA3_256h, oidHashType, "SHA3-256", "sha3-256"}, - #endif - #ifndef WOLFSSL_NOSHA3_384 - { WC_NID_sha3_384, SHA3_384h, oidHashType, "SHA3-384", "sha3-384"}, - #endif - #ifndef WOLFSSL_NOSHA3_512 - { WC_NID_sha3_512, SHA3_512h, oidHashType, "SHA3-512", "sha3-512"}, - #endif - #endif /* WOLFSSL_SHA3 */ - #ifdef WOLFSSL_SM3 - { WC_NID_sm3, SM3h, oidHashType, "SM3", "sm3"}, - #endif - #ifdef WOLFSSL_SHAKE128 - { WC_NID_shake128, SHAKE128h, oidHashType, "SHAKE128", "shake128"}, - #endif - #ifdef WOLFSSL_SHAKE256 - { WC_NID_shake256, SHAKE256h, oidHashType, "SHAKE256", "shake256"}, - #endif - /* oidSigType */ - #ifndef NO_DSA - #ifndef NO_SHA - { WC_NID_dsaWithSHA1, CTC_SHAwDSA, oidSigType, - "DSA-SHA1", "dsaWithSHA1"}, - { WC_NID_dsa_with_SHA256, CTC_SHA256wDSA, oidSigType, "dsa_with_SHA256", - "dsa_with_SHA256"}, - #endif - #endif /* NO_DSA */ - #ifndef NO_RSA - #ifdef WOLFSSL_MD2 - { WC_NID_md2WithRSAEncryption, CTC_MD2wRSA, oidSigType, "RSA-MD2", - "md2WithRSAEncryption"}, - #endif - #ifndef NO_MD5 - { WC_NID_md5WithRSAEncryption, CTC_MD5wRSA, oidSigType, "RSA-MD5", - "md5WithRSAEncryption"}, - #endif - #ifndef NO_SHA - { WC_NID_sha1WithRSAEncryption, CTC_SHAwRSA, oidSigType, "RSA-SHA1", - "sha1WithRSAEncryption"}, - #endif - #ifdef WOLFSSL_SHA224 - { WC_NID_sha224WithRSAEncryption, CTC_SHA224wRSA, oidSigType, - "RSA-SHA224", "sha224WithRSAEncryption"}, - #endif - #ifndef NO_SHA256 - { WC_NID_sha256WithRSAEncryption, CTC_SHA256wRSA, oidSigType, - "RSA-SHA256", "sha256WithRSAEncryption"}, - #endif - #ifdef WOLFSSL_SHA384 - { WC_NID_sha384WithRSAEncryption, CTC_SHA384wRSA, oidSigType, - "RSA-SHA384", "sha384WithRSAEncryption"}, - #endif - #ifdef WOLFSSL_SHA512 - { WC_NID_sha512WithRSAEncryption, CTC_SHA512wRSA, oidSigType, - "RSA-SHA512", "sha512WithRSAEncryption"}, - #endif - #ifdef WOLFSSL_SHA3 - #ifndef WOLFSSL_NOSHA3_224 - { WC_NID_RSA_SHA3_224, CTC_SHA3_224wRSA, oidSigType, "RSA-SHA3-224", - "sha3-224WithRSAEncryption"}, - #endif - #ifndef WOLFSSL_NOSHA3_256 - { WC_NID_RSA_SHA3_256, CTC_SHA3_256wRSA, oidSigType, "RSA-SHA3-256", - "sha3-256WithRSAEncryption"}, - #endif - #ifndef WOLFSSL_NOSHA3_384 - { WC_NID_RSA_SHA3_384, CTC_SHA3_384wRSA, oidSigType, "RSA-SHA3-384", - "sha3-384WithRSAEncryption"}, - #endif - #ifndef WOLFSSL_NOSHA3_512 - { WC_NID_RSA_SHA3_512, CTC_SHA3_512wRSA, oidSigType, "RSA-SHA3-512", - "sha3-512WithRSAEncryption"}, - #endif - #endif - #ifdef WC_RSA_PSS - { WC_NID_rsassaPss, CTC_RSASSAPSS, oidSigType, - "RSASSA-PSS", "rsassaPss" }, - #endif - #endif /* NO_RSA */ - #ifdef HAVE_ECC - #ifndef NO_SHA - { WC_NID_ecdsa_with_SHA1, CTC_SHAwECDSA, oidSigType, "ecdsa-with-SHA1", - "shaWithECDSA"}, - #endif - #ifdef WOLFSSL_SHA224 - { WC_NID_ecdsa_with_SHA224, CTC_SHA224wECDSA, oidSigType, - "ecdsa-with-SHA224","sha224WithECDSA"}, - #endif - #ifndef NO_SHA256 - { WC_NID_ecdsa_with_SHA256, CTC_SHA256wECDSA, oidSigType, - "ecdsa-with-SHA256","sha256WithECDSA"}, - #endif - #ifdef WOLFSSL_SHA384 - { WC_NID_ecdsa_with_SHA384, CTC_SHA384wECDSA, oidSigType, - "ecdsa-with-SHA384","sha384WithECDSA"}, - #endif - #ifdef WOLFSSL_SHA512 - { WC_NID_ecdsa_with_SHA512, CTC_SHA512wECDSA, oidSigType, - "ecdsa-with-SHA512","sha512WithECDSA"}, - #endif - #ifdef WOLFSSL_SHA3 - #ifndef WOLFSSL_NOSHA3_224 - { WC_NID_ecdsa_with_SHA3_224, CTC_SHA3_224wECDSA, oidSigType, - "id-ecdsa-with-SHA3-224", "ecdsa_with_SHA3-224"}, - #endif - #ifndef WOLFSSL_NOSHA3_256 - { WC_NID_ecdsa_with_SHA3_256, CTC_SHA3_256wECDSA, oidSigType, - "id-ecdsa-with-SHA3-256", "ecdsa_with_SHA3-256"}, - #endif - #ifndef WOLFSSL_NOSHA3_384 - { WC_NID_ecdsa_with_SHA3_384, CTC_SHA3_384wECDSA, oidSigType, - "id-ecdsa-with-SHA3-384", "ecdsa_with_SHA3-384"}, - #endif - #ifndef WOLFSSL_NOSHA3_512 - { WC_NID_ecdsa_with_SHA3_512, CTC_SHA3_512wECDSA, oidSigType, - "id-ecdsa-with-SHA3-512", "ecdsa_with_SHA3-512"}, - #endif - #endif - #endif /* HAVE_ECC */ - - /* oidKeyType */ - #ifndef NO_DSA - { WC_NID_dsa, DSAk, oidKeyType, "DSA", "dsaEncryption"}, - #endif /* NO_DSA */ - #ifndef NO_RSA - { WC_NID_rsaEncryption, RSAk, oidKeyType, "rsaEncryption", - "rsaEncryption"}, - #ifdef WC_RSA_PSS - { WC_NID_rsassaPss, RSAPSSk, oidKeyType, "RSASSA-PSS", "rsassaPss"}, - #endif - #endif /* NO_RSA */ - #ifdef HAVE_ECC - { WC_NID_X9_62_id_ecPublicKey, ECDSAk, oidKeyType, "id-ecPublicKey", - "id-ecPublicKey"}, - #endif /* HAVE_ECC */ - #ifndef NO_DH - { WC_NID_dhKeyAgreement, DHk, oidKeyType, "dhKeyAgreement", - "dhKeyAgreement"}, - #endif - #ifdef HAVE_ED448 - { WC_NID_ED448, ED448k, oidKeyType, "ED448", "ED448"}, - #endif - #ifdef HAVE_ED25519 - { WC_NID_ED25519, ED25519k, oidKeyType, "ED25519", "ED25519"}, - #endif - #ifdef HAVE_FALCON - { CTC_FALCON_LEVEL1, FALCON_LEVEL1k, oidKeyType, "Falcon Level 1", - "Falcon Level 1"}, - { CTC_FALCON_LEVEL5, FALCON_LEVEL5k, oidKeyType, "Falcon Level 5", - "Falcon Level 5"}, - #endif /* HAVE_FALCON */ - #ifdef WOLFSSL_HAVE_MLDSA - #ifdef WOLFSSL_MLDSA_FIPS204_DRAFT - /* Pre-standardization (NIST PQC round 3) Dilithium OID labels. - * These coexist with the FIPS 204 "ML-DSA 44/65/87" entries below - * and are intentionally kept under the Dilithium name. */ - { CTC_DILITHIUM_LEVEL2, DILITHIUM_LEVEL2k, oidKeyType, - "Dilithium Level 2", "Dilithium Level 2"}, - { CTC_DILITHIUM_LEVEL3, DILITHIUM_LEVEL3k, oidKeyType, - "Dilithium Level 3", "Dilithium Level 3"}, - { CTC_DILITHIUM_LEVEL5, DILITHIUM_LEVEL5k, oidKeyType, - "Dilithium Level 5", "Dilithium Level 5"}, - #endif /* WOLFSSL_MLDSA_FIPS204_DRAFT */ - { CTC_ML_DSA_44, ML_DSA_44k, oidKeyType, - "ML-DSA 44", "ML-DSA 44"}, - { CTC_ML_DSA_65, ML_DSA_65k, oidKeyType, - "ML-DSA 65", "ML-DSA 65"}, - { CTC_ML_DSA_87, ML_DSA_87k, oidKeyType, - "ML-DSA 87", "ML-DSA 87"}, - #endif /* WOLFSSL_HAVE_MLDSA */ - - /* oidCurveType */ - #ifdef HAVE_ECC - { WC_NID_X9_62_prime192v1, ECC_SECP192R1_OID, oidCurveType, - "prime192v1", "prime192v1"}, - { WC_NID_X9_62_prime192v2, ECC_PRIME192V2_OID, oidCurveType, - "prime192v2", "prime192v2"}, - { WC_NID_X9_62_prime192v3, ECC_PRIME192V3_OID, oidCurveType, - "prime192v3", "prime192v3"}, - - { WC_NID_X9_62_prime239v1, ECC_PRIME239V1_OID, oidCurveType, - "prime239v1", "prime239v1"}, - { WC_NID_X9_62_prime239v2, ECC_PRIME239V2_OID, oidCurveType, - "prime239v2", "prime239v2"}, - { WC_NID_X9_62_prime239v3, ECC_PRIME239V3_OID, oidCurveType, - "prime239v3", "prime239v3"}, - - { WC_NID_X9_62_prime256v1, ECC_SECP256R1_OID, oidCurveType, - "prime256v1", "prime256v1"}, - - { WC_NID_secp112r1, ECC_SECP112R1_OID, oidCurveType, "secp112r1", - "secp112r1"}, - { WC_NID_secp112r2, ECC_SECP112R2_OID, oidCurveType, "secp112r2", - "secp112r2"}, - - { WC_NID_secp128r1, ECC_SECP128R1_OID, oidCurveType, "secp128r1", - "secp128r1"}, - { WC_NID_secp128r2, ECC_SECP128R2_OID, oidCurveType, "secp128r2", - "secp128r2"}, - - { WC_NID_secp160r1, ECC_SECP160R1_OID, oidCurveType, "secp160r1", - "secp160r1"}, - { WC_NID_secp160r2, ECC_SECP160R2_OID, oidCurveType, "secp160r2", - "secp160r2"}, - - { WC_NID_secp224r1, ECC_SECP224R1_OID, oidCurveType, "secp224r1", - "secp224r1"}, - { WC_NID_secp384r1, ECC_SECP384R1_OID, oidCurveType, "secp384r1", - "secp384r1"}, - { WC_NID_secp521r1, ECC_SECP521R1_OID, oidCurveType, "secp521r1", - "secp521r1"}, - - { WC_NID_secp160k1, ECC_SECP160K1_OID, oidCurveType, "secp160k1", - "secp160k1"}, - { WC_NID_secp192k1, ECC_SECP192K1_OID, oidCurveType, "secp192k1", - "secp192k1"}, - { WC_NID_secp224k1, ECC_SECP224K1_OID, oidCurveType, "secp224k1", - "secp224k1"}, - { WC_NID_secp256k1, ECC_SECP256K1_OID, oidCurveType, "secp256k1", - "secp256k1"}, - - { WC_NID_brainpoolP160r1, ECC_BRAINPOOLP160R1_OID, oidCurveType, - "brainpoolP160r1", "brainpoolP160r1"}, - { WC_NID_brainpoolP192r1, ECC_BRAINPOOLP192R1_OID, oidCurveType, - "brainpoolP192r1", "brainpoolP192r1"}, - { WC_NID_brainpoolP224r1, ECC_BRAINPOOLP224R1_OID, oidCurveType, - "brainpoolP224r1", "brainpoolP224r1"}, - { WC_NID_brainpoolP256r1, ECC_BRAINPOOLP256R1_OID, oidCurveType, - "brainpoolP256r1", "brainpoolP256r1"}, - { WC_NID_brainpoolP320r1, ECC_BRAINPOOLP320R1_OID, oidCurveType, - "brainpoolP320r1", "brainpoolP320r1"}, - { WC_NID_brainpoolP384r1, ECC_BRAINPOOLP384R1_OID, oidCurveType, - "brainpoolP384r1", "brainpoolP384r1"}, - { WC_NID_brainpoolP512r1, ECC_BRAINPOOLP512R1_OID, oidCurveType, - "brainpoolP512r1", "brainpoolP512r1"}, - - #ifdef WOLFSSL_SM2 - { WC_NID_sm2, ECC_SM2P256V1_OID, oidCurveType, "sm2", "sm2"}, - #endif - #endif /* HAVE_ECC */ - - /* oidBlkType */ - #ifdef WOLFSSL_AES_128 - { AES128CBCb, AES128CBCb, oidBlkType, "AES-128-CBC", "aes-128-cbc"}, - #endif - #ifdef WOLFSSL_AES_192 - { AES192CBCb, AES192CBCb, oidBlkType, "AES-192-CBC", "aes-192-cbc"}, - #endif - #ifdef WOLFSSL_AES_256 - { AES256CBCb, AES256CBCb, oidBlkType, "AES-256-CBC", "aes-256-cbc"}, - #endif - #ifndef NO_DES3 - { WC_NID_des, DESb, oidBlkType, "DES-CBC", "des-cbc"}, - { WC_NID_des3, DES3b, oidBlkType, "DES-EDE3-CBC", "des-ede3-cbc"}, - #endif /* !NO_DES3 */ - #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) - { WC_NID_chacha20_poly1305, WC_NID_chacha20_poly1305, oidBlkType, - "ChaCha20-Poly1305", "chacha20-poly1305"}, - #endif - - /* oidOcspType */ - #ifdef HAVE_OCSP - { WC_NID_id_pkix_OCSP_basic, OCSP_BASIC_OID, oidOcspType, - "basicOCSPResponse", "Basic OCSP Response"}, - { OCSP_NONCE_OID, OCSP_NONCE_OID, oidOcspType, "Nonce", "OCSP Nonce"}, - #endif /* HAVE_OCSP */ - - #ifndef NO_PWDBASED - /* oidKdfType */ - { PBKDF2_OID, PBKDF2_OID, oidKdfType, "PBKDFv2", "PBKDF2"}, - - /* oidPBEType */ - { PBE_SHA1_RC4_128, PBE_SHA1_RC4_128, oidPBEType, - "PBE-SHA1-RC4-128", "pbeWithSHA1And128BitRC4"}, - { PBE_SHA1_DES, PBE_SHA1_DES, oidPBEType, "PBE-SHA1-DES", - "pbeWithSHA1AndDES-CBC"}, - { PBE_SHA1_DES3, PBE_SHA1_DES3, oidPBEType, "PBE-SHA1-3DES", - "pbeWithSHA1And3-KeyTripleDES-CBC"}, - #endif - - /* oidKeyWrapType */ - #ifdef WOLFSSL_AES_128 - { AES128_WRAP, AES128_WRAP, oidKeyWrapType, "AES-128 wrap", - "aes128-wrap"}, - #endif - #ifdef WOLFSSL_AES_192 - { AES192_WRAP, AES192_WRAP, oidKeyWrapType, "AES-192 wrap", - "aes192-wrap"}, - #endif - #ifdef WOLFSSL_AES_256 - { AES256_WRAP, AES256_WRAP, oidKeyWrapType, "AES-256 wrap", - "aes256-wrap"}, - #endif - - #ifndef NO_PKCS7 - #ifndef NO_DH - /* oidCmsKeyAgreeType */ - #ifndef NO_SHA - { dhSinglePass_stdDH_sha1kdf_scheme, dhSinglePass_stdDH_sha1kdf_scheme, - oidCmsKeyAgreeType, "dhSinglePass-stdDH-sha1kdf-scheme", - "dhSinglePass-stdDH-sha1kdf-scheme"}, - #endif - #ifdef WOLFSSL_SHA224 - { dhSinglePass_stdDH_sha224kdf_scheme, - dhSinglePass_stdDH_sha224kdf_scheme, oidCmsKeyAgreeType, - "dhSinglePass-stdDH-sha224kdf-scheme", - "dhSinglePass-stdDH-sha224kdf-scheme"}, - #endif - #ifndef NO_SHA256 - { dhSinglePass_stdDH_sha256kdf_scheme, - dhSinglePass_stdDH_sha256kdf_scheme, oidCmsKeyAgreeType, - "dhSinglePass-stdDH-sha256kdf-scheme", - "dhSinglePass-stdDH-sha256kdf-scheme"}, - #endif - #ifdef WOLFSSL_SHA384 - { dhSinglePass_stdDH_sha384kdf_scheme, - dhSinglePass_stdDH_sha384kdf_scheme, oidCmsKeyAgreeType, - "dhSinglePass-stdDH-sha384kdf-scheme", - "dhSinglePass-stdDH-sha384kdf-scheme"}, - #endif - #ifdef WOLFSSL_SHA512 - { dhSinglePass_stdDH_sha512kdf_scheme, - dhSinglePass_stdDH_sha512kdf_scheme, oidCmsKeyAgreeType, - "dhSinglePass-stdDH-sha512kdf-scheme", - "dhSinglePass-stdDH-sha512kdf-scheme"}, - #endif - #endif - #endif - #if defined(WOLFSSL_APACHE_HTTPD) - /* "1.3.6.1.5.5.7.8.7" */ - { WC_NID_id_on_dnsSRV, WOLFSSL_DNS_SRV_SUM, oidCertNameType, - WOLFSSL_SN_DNS_SRV, WOLFSSL_LN_DNS_SRV }, - - /* "1.3.6.1.4.1.311.20.2.3" */ - { WC_NID_ms_upn, WOLFSSL_MS_UPN_SUM, oidCertExtType, WOLFSSL_SN_MS_UPN, - WOLFSSL_LN_MS_UPN }, - - /* "1.3.6.1.5.5.7.1.24" */ - { WC_NID_tlsfeature, WOLFSSL_TLS_FEATURE_SUM, oidTlsExtType, - WOLFSSL_SN_TLS_FEATURE, WOLFSSL_LN_TLS_FEATURE }, - #endif -#endif /* OPENSSL_EXTRA */ -}; - -#define WOLFSSL_OBJECT_INFO_SZ \ - (sizeof(wolfssl_object_info) / sizeof(*wolfssl_object_info)) -const size_t wolfssl_object_info_sz = WOLFSSL_OBJECT_INFO_SZ; -#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) /* Free the dynamically allocated data. @@ -11490,4948 +7703,2243 @@ void wolfSSL_SetFuzzerCb(WOLFSSL* ssl, CallbackFuzzer cbf, void* fCtx) } #endif -#ifndef NO_CERTS -#ifdef HAVE_PK_CALLBACKS - -/* callback for premaster secret generation */ -void wolfSSL_CTX_SetGenPreMasterCb(WOLFSSL_CTX* ctx, CallbackGenPreMaster cb) -{ - if (ctx) - ctx->GenPreMasterCb = cb; -} -/* Set premaster secret generation callback context */ -void wolfSSL_SetGenPreMasterCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->GenPreMasterCtx = ctx; -} -/* Get premaster secret generation callback context */ -void* wolfSSL_GetGenPreMasterCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->GenPreMasterCtx; - return NULL; -} +#ifdef WOLFSSL_HAVE_WOLFSCEP + /* Used by autoconf to see if wolfSCEP is available */ + void wolfSSL_wolfSCEP(void) {} +#endif -/* callback for master secret generation */ -void wolfSSL_CTX_SetGenMasterSecretCb(WOLFSSL_CTX* ctx, - CallbackGenMasterSecret cb) -{ - if (ctx) - ctx->GenMasterCb = cb; -} -/* Set master secret generation callback context */ -void wolfSSL_SetGenMasterSecretCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->GenMasterCtx = ctx; -} -/* Get master secret generation callback context */ -void* wolfSSL_GetGenMasterSecretCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->GenMasterCtx; - return NULL; -} +#ifdef WOLFSSL_HAVE_CERT_SERVICE + /* Used by autoconf to see if cert service is available */ + void wolfSSL_cert_service(void) {} +#endif -/* callback for extended master secret generation */ -void wolfSSL_CTX_SetGenExtMasterSecretCb(WOLFSSL_CTX* ctx, - CallbackGenExtMasterSecret cb) -{ - if (ctx) - ctx->GenExtMasterCb = cb; -} -/* Set extended master secret generation callback context */ -void wolfSSL_SetGenExtMasterSecretCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->GenExtMasterCtx = ctx; -} -/* Get extended master secret generation callback context */ -void* wolfSSL_GetGenExtMasterSecretCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->GenExtMasterCtx; +#if defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) || \ + defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(HAVE_STUNNEL) || \ + defined(WOLFSSL_NGINX) || defined(HAVE_POCO_LIB) || \ + defined(WOLFSSL_HAPROXY) - return NULL; -} + void wolfSSL_set_verify_depth(WOLFSSL *ssl, int depth) + { + #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + WOLFSSL_ENTER("wolfSSL_set_verify_depth"); + ssl->options.verifyDepth = (byte)depth; + #endif + } +#endif /* OPENSSL_ALL || HAVE_LIGHTY || WOLFSSL_MYSQL_COMPATIBLE || + HAVE_STUNNEL || WOLFSSL_NGINX || HAVE_POCO_LIB || WOLFSSL_HAPROXY */ -/* callback for session key generation */ -void wolfSSL_CTX_SetGenSessionKeyCb(WOLFSSL_CTX* ctx, CallbackGenSessionKey cb) -{ - if (ctx) - ctx->GenSessionKeyCb = cb; -} -/* Set session key generation callback context */ -void wolfSSL_SetGenSessionKeyCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->GenSessionKeyCtx = ctx; -} -/* Get session key generation callback context */ -void* wolfSSL_GetGenSessionKeyCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->GenSessionKeyCtx; +#ifdef OPENSSL_EXTRA - return NULL; -} +/* wolfSSL uses negative values for error states. This function returns an + * unsigned type so the value returned is the absolute value of the error. + */ -/* callback for setting encryption keys */ -void wolfSSL_CTX_SetEncryptKeysCb(WOLFSSL_CTX* ctx, CallbackEncryptKeys cb) -{ - if (ctx) - ctx->EncryptKeysCb = cb; -} -/* Set encryption keys callback context */ -void wolfSSL_SetEncryptKeysCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->EncryptKeysCtx = ctx; -} -/* Get encryption keys callback context */ -void* wolfSSL_GetEncryptKeysCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->EncryptKeysCtx; +#endif /* OPENSSL_EXTRA */ - return NULL; -} +#ifdef HAVE_EX_DATA_CRYPTO +CRYPTO_EX_cb_ctx* crypto_ex_cb_ctx_session = NULL; -/* callback for Tls finished */ -/* the callback can be used to build TLS Finished message if enabled */ -void wolfSSL_CTX_SetTlsFinishedCb(WOLFSSL_CTX* ctx, CallbackTlsFinished cb) -{ - if (ctx) - ctx->TlsFinishedCb = cb; -} -/* Set Tls finished callback context */ -void wolfSSL_SetTlsFinishedCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->TlsFinishedCtx = ctx; -} -/* Get Tls finished callback context */ -void* wolfSSL_GetTlsFinishedCtx(WOLFSSL* ssl) +static int crypto_ex_cb_new(CRYPTO_EX_cb_ctx** dst, long ctx_l, void* ctx_ptr, + WOLFSSL_CRYPTO_EX_new* new_func, WOLFSSL_CRYPTO_EX_dup* dup_func, + WOLFSSL_CRYPTO_EX_free* free_func) { - if (ssl) - return ssl->TlsFinishedCtx; - - return NULL; -} -#if !defined(WOLFSSL_NO_TLS12) && !defined(WOLFSSL_AEAD_ONLY) -/* callback for verify data */ -void wolfSSL_CTX_SetVerifyMacCb(WOLFSSL_CTX* ctx, CallbackVerifyMac cb) -{ - if (ctx) - ctx->VerifyMacCb = cb; + CRYPTO_EX_cb_ctx* new_ctx = (CRYPTO_EX_cb_ctx*)XMALLOC( + sizeof(CRYPTO_EX_cb_ctx), NULL, DYNAMIC_TYPE_OPENSSL); + if (new_ctx == NULL) + return WOLFSSL_FATAL_ERROR; + new_ctx->ctx_l = ctx_l; + new_ctx->ctx_ptr = ctx_ptr; + new_ctx->new_func = new_func; + new_ctx->free_func = free_func; + new_ctx->dup_func = dup_func; + new_ctx->next = NULL; + /* Push to end of list */ + while (*dst != NULL) + dst = &(*dst)->next; + *dst = new_ctx; + return 0; } -/* Set set keys callback context */ -void wolfSSL_SetVerifyMacCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->VerifyMacCtx = ctx; -} -/* Get set keys callback context */ -void* wolfSSL_GetVerifyMacCtx(WOLFSSL* ssl) +void crypto_ex_cb_free(CRYPTO_EX_cb_ctx* cb_ctx) { - if (ssl) - return ssl->VerifyMacCtx; - - return NULL; + while (cb_ctx != NULL) { + CRYPTO_EX_cb_ctx* next = cb_ctx->next; + XFREE(cb_ctx, NULL, DYNAMIC_TYPE_OPENSSL); + cb_ctx = next; + } } -#endif /* !WOLFSSL_NO_TLS12 && !WOLFSSL_AEAD_ONLY */ -void wolfSSL_CTX_SetHKDFExpandLabelCb(WOLFSSL_CTX* ctx, - CallbackHKDFExpandLabel cb) +void crypto_ex_cb_setup_new_data(void *new_obj, CRYPTO_EX_cb_ctx* cb_ctx, + WOLFSSL_CRYPTO_EX_DATA* ex_data) { - if (ctx) - ctx->HKDFExpandLabelCb = cb; + int idx = 0; + for (; cb_ctx != NULL; idx++, cb_ctx = cb_ctx->next) { + if (cb_ctx->new_func != NULL) + cb_ctx->new_func(new_obj, NULL, ex_data, idx, cb_ctx->ctx_l, + cb_ctx->ctx_ptr); + } } -#ifdef WOLFSSL_PUBLIC_ASN -void wolfSSL_CTX_SetProcessPeerCertCb(WOLFSSL_CTX* ctx, - CallbackProcessPeerCert cb) + +int crypto_ex_cb_dup_data(const WOLFSSL_CRYPTO_EX_DATA *in, + WOLFSSL_CRYPTO_EX_DATA *out, CRYPTO_EX_cb_ctx* cb_ctx) { - if (ctx) - ctx->ProcessPeerCertCb = cb; + int idx = 0; + for (; cb_ctx != NULL; idx++, cb_ctx = cb_ctx->next) { + if (cb_ctx->dup_func != NULL) { + void* ptr = wolfSSL_CRYPTO_get_ex_data(in, idx); + if (!cb_ctx->dup_func(out, in, + &ptr, idx, + cb_ctx->ctx_l, cb_ctx->ctx_ptr)) { + return WOLFSSL_FAILURE; + } + wolfSSL_CRYPTO_set_ex_data(out, idx, ptr); + } + } + return WOLFSSL_SUCCESS; } -#endif /* WOLFSSL_PUBLIC_ASN */ -void wolfSSL_CTX_SetProcessServerSigKexCb(WOLFSSL_CTX* ctx, - CallbackProcessServerSigKex cb) + +void crypto_ex_cb_free_data(void *obj, CRYPTO_EX_cb_ctx* cb_ctx, + WOLFSSL_CRYPTO_EX_DATA* ex_data) { - if (ctx) - ctx->ProcessServerSigKexCb = cb; + int idx = 0; + for (; cb_ctx != NULL; idx++, cb_ctx = cb_ctx->next) { + if (cb_ctx->free_func != NULL) + cb_ctx->free_func(obj, NULL, ex_data, idx, cb_ctx->ctx_l, + cb_ctx->ctx_ptr); + } } -void wolfSSL_CTX_SetPerformTlsRecordProcessingCb(WOLFSSL_CTX* ctx, - CallbackPerformTlsRecordProcessing cb) + +/** + * wolfssl_local_get_ex_new_index is a helper function for the following + * xx_get_ex_new_index functions: + * - wolfSSL_CRYPTO_get_ex_new_index + * - wolfSSL_CTX_get_ex_new_index + * - wolfSSL_get_ex_new_index + * Issues a unique index number for the specified class-index. + * Returns an index number greater or equal to zero on success, + * -1 on failure. + */ +int wolfssl_local_get_ex_new_index(int class_index, long ctx_l, void* ctx_ptr, + WOLFSSL_CRYPTO_EX_new* new_func, WOLFSSL_CRYPTO_EX_dup* dup_func, + WOLFSSL_CRYPTO_EX_free* free_func) { - if (ctx) - ctx->PerformTlsRecordProcessingCb = cb; -} -#endif /* HAVE_PK_CALLBACKS */ -#endif /* NO_CERTS */ + /* index counter for each class index*/ + static int ctx_idx = 0; + static int ssl_idx = 0; + static int ssl_session_idx = 0; + static int x509_idx = 0; -#if defined(HAVE_PK_CALLBACKS) && defined(HAVE_HKDF) + int idx = -1; -void wolfSSL_CTX_SetHKDFExtractCb(WOLFSSL_CTX* ctx, CallbackHKDFExtract cb) -{ - if (ctx) - ctx->HkdfExtractCb = cb; + switch(class_index) { + case WOLF_CRYPTO_EX_INDEX_SSL: + WOLFSSL_CRYPTO_EX_DATA_IGNORE_PARAMS(ctx_l, ctx_ptr, new_func, + dup_func, free_func); + idx = ssl_idx++; + break; + case WOLF_CRYPTO_EX_INDEX_SSL_CTX: + WOLFSSL_CRYPTO_EX_DATA_IGNORE_PARAMS(ctx_l, ctx_ptr, new_func, + dup_func, free_func); + idx = ctx_idx++; + break; + case WOLF_CRYPTO_EX_INDEX_X509: + WOLFSSL_CRYPTO_EX_DATA_IGNORE_PARAMS(ctx_l, ctx_ptr, new_func, + dup_func, free_func); + idx = x509_idx++; + break; + case WOLF_CRYPTO_EX_INDEX_SSL_SESSION: + if (crypto_ex_cb_new(&crypto_ex_cb_ctx_session, ctx_l, ctx_ptr, + new_func, dup_func, free_func) != 0) + return WOLFSSL_FATAL_ERROR; + idx = ssl_session_idx++; + break; + + /* following class indexes are not supoprted */ + case WOLF_CRYPTO_EX_INDEX_X509_STORE: + case WOLF_CRYPTO_EX_INDEX_X509_STORE_CTX: + case WOLF_CRYPTO_EX_INDEX_DH: + case WOLF_CRYPTO_EX_INDEX_DSA: + case WOLF_CRYPTO_EX_INDEX_EC_KEY: + case WOLF_CRYPTO_EX_INDEX_RSA: + case WOLF_CRYPTO_EX_INDEX_ENGINE: + case WOLF_CRYPTO_EX_INDEX_UI: + case WOLF_CRYPTO_EX_INDEX_BIO: + case WOLF_CRYPTO_EX_INDEX_APP: + case WOLF_CRYPTO_EX_INDEX_UI_METHOD: + case WOLF_CRYPTO_EX_INDEX_DRBG: + default: + break; + } + if (idx >= MAX_EX_DATA) + return WOLFSSL_FATAL_ERROR; + return idx; } +#endif /* HAVE_EX_DATA_CRYPTO */ -void wolfSSL_SetHKDFExtractCtx(WOLFSSL* ssl, void *ctx) +#ifdef HAVE_EX_DATA_CRYPTO +int wolfSSL_CTX_get_ex_new_index(long idx, void* arg, + WOLFSSL_CRYPTO_EX_new* new_func, + WOLFSSL_CRYPTO_EX_dup* dup_func, + WOLFSSL_CRYPTO_EX_free* free_func) { - if (ssl) - ssl->HkdfExtractCtx = ctx; + + WOLFSSL_ENTER("wolfSSL_CTX_get_ex_new_index"); + + return wolfssl_local_get_ex_new_index(WOLF_CRYPTO_EX_INDEX_SSL_CTX, idx, + arg, new_func, dup_func, free_func); } -void* wolfSSL_GetHKDFExtractCtx(WOLFSSL* ssl) +/* Return the index that can be used for the WOLFSSL structure to store + * application data. + * + */ +int wolfSSL_get_ex_new_index(long argValue, void* arg, + WOLFSSL_CRYPTO_EX_new* cb1, WOLFSSL_CRYPTO_EX_dup* cb2, + WOLFSSL_CRYPTO_EX_free* cb3) { - if (ssl) - return ssl->HkdfExtractCtx; + WOLFSSL_ENTER("wolfSSL_get_ex_new_index"); - return NULL; + return wolfssl_local_get_ex_new_index(WOLF_CRYPTO_EX_INDEX_SSL, argValue, + arg, cb1, cb2, cb3); } -#endif /* HAVE_PK_CALLBACKS && HAVE_HKDF */ +#endif /* HAVE_EX_DATA_CRYPTO */ -#ifdef WOLFSSL_HAVE_WOLFSCEP - /* Used by autoconf to see if wolfSCEP is available */ - void wolfSSL_wolfSCEP(void) {} +#ifdef OPENSSL_EXTRA +void* wolfSSL_CTX_get_ex_data(const WOLFSSL_CTX* ctx, int idx) +{ + WOLFSSL_ENTER("wolfSSL_CTX_get_ex_data"); +#ifdef HAVE_EX_DATA + if (ctx != NULL) { + return wolfSSL_CRYPTO_get_ex_data(&ctx->ex_data, idx); + } +#else + (void)ctx; + (void)idx; #endif + return NULL; +} - -#ifdef WOLFSSL_HAVE_CERT_SERVICE - /* Used by autoconf to see if cert service is available */ - void wolfSSL_cert_service(void) {} +int wolfSSL_CTX_set_ex_data(WOLFSSL_CTX* ctx, int idx, void* data) +{ + WOLFSSL_ENTER("wolfSSL_CTX_set_ex_data"); +#ifdef HAVE_EX_DATA + if (ctx != NULL) { + return wolfSSL_CRYPTO_set_ex_data(&ctx->ex_data, idx, data); + } +#else + (void)ctx; + (void)idx; + (void)data; #endif + return WOLFSSL_FAILURE; +} -#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \ - !defined(WOLFCRYPT_ONLY) - - /* NID variables are dependent on compatibility header files currently - * - * returns a pointer to a new WOLFSSL_ASN1_OBJECT struct on success and NULL - * on fail - */ - - WOLFSSL_ASN1_OBJECT* wolfSSL_OBJ_nid2obj(int id) - { - return wolfSSL_OBJ_nid2obj_ex(id, NULL); +#ifdef HAVE_EX_DATA_CLEANUP_HOOKS +int wolfSSL_CTX_set_ex_data_with_cleanup( + WOLFSSL_CTX* ctx, + int idx, + void* data, + wolfSSL_ex_data_cleanup_routine_t cleanup_routine) +{ + WOLFSSL_ENTER("wolfSSL_CTX_set_ex_data_with_cleanup"); + if (ctx != NULL) { + return wolfSSL_CRYPTO_set_ex_data_with_cleanup(&ctx->ex_data, idx, data, + cleanup_routine); } + return WOLFSSL_FAILURE; +} +#endif /* HAVE_EX_DATA_CLEANUP_HOOKS */ +#endif /* OPENSSL_EXTRA */ +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) - WOLFSSL_LOCAL WOLFSSL_ASN1_OBJECT* wolfSSL_OBJ_nid2obj_ex(int id, - WOLFSSL_ASN1_OBJECT* arg_obj) - { - word32 oidSz = 0; - int nid = 0; - const byte* oid; - word32 type = 0; - WOLFSSL_ASN1_OBJECT* obj = arg_obj; - byte objBuf[MAX_OID_SZ + MAX_LENGTH_SZ + 1]; /* +1 for object tag */ - word32 objSz = 0; - const char* sName = NULL; - int i; +/* Returns char* to app data stored in ex[0]. + * + * ssl WOLFSSL structure to get app data from + */ +void* wolfSSL_get_app_data(const WOLFSSL *ssl) +{ + /* checkout exdata stuff... */ + WOLFSSL_ENTER("wolfSSL_get_app_data"); -#ifdef WOLFSSL_DEBUG_OPENSSL - WOLFSSL_ENTER("wolfSSL_OBJ_nid2obj"); -#endif + return wolfSSL_get_ex_data(ssl, 0); +} - for (i = 0; i < (int)WOLFSSL_OBJECT_INFO_SZ; i++) { - if (wolfssl_object_info[i].nid == id) { - nid = id; - id = wolfssl_object_info[i].id; - sName = wolfssl_object_info[i].sName; - type = wolfssl_object_info[i].type; - break; - } - } - if (i == (int)WOLFSSL_OBJECT_INFO_SZ) { - WOLFSSL_MSG("NID not in table"); - #ifdef WOLFSSL_QT - sName = NULL; - type = (word32)id; - #else - return NULL; - #endif - } - #ifdef HAVE_ECC - if (type == 0 && wc_ecc_get_oid((word32)id, &oid, &oidSz) > 0) { - type = oidCurveType; - } - #endif /* HAVE_ECC */ - - if (sName != NULL) { - if (XSTRLEN(sName) > WOLFSSL_MAX_SNAME - 1) { - WOLFSSL_MSG("Attempted short name is too large"); - return NULL; - } - } +/* Set ex array 0 to have app data + * + * ssl WOLFSSL struct to set app data in + * arg data to be stored + * + * Returns WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on failure + */ +int wolfSSL_set_app_data(WOLFSSL *ssl, void* arg) { + WOLFSSL_ENTER("wolfSSL_set_app_data"); - oid = OidFromId((word32)id, type, &oidSz); + return wolfSSL_set_ex_data(ssl, 0, arg); +} - /* set object ID to buffer */ - if (obj == NULL){ - obj = wolfSSL_ASN1_OBJECT_new(); - if (obj == NULL) { - WOLFSSL_MSG("Issue creating WOLFSSL_ASN1_OBJECT struct"); - return NULL; - } - } - obj->nid = nid; - obj->type = id; - obj->grp = (int)type; +#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ - obj->sName[0] = '\0'; - if (sName != NULL) { - XMEMCPY(obj->sName, (char*)sName, XSTRLEN((char*)sName)); - } - - objBuf[0] = ASN_OBJECT_ID; objSz++; - objSz += SetLength(oidSz, objBuf + 1); - if (oidSz) { - XMEMCPY(objBuf + objSz, oid, oidSz); - objSz += oidSz; - } - - if (obj->objSz == 0 || objSz != obj->objSz) { - obj->objSz = objSz; - if(((obj->dynamic & WOLFSSL_ASN1_DYNAMIC_DATA) != 0) || - (obj->obj == NULL)) { - if (obj->obj != NULL) - XFREE((byte*)obj->obj, NULL, DYNAMIC_TYPE_ASN1); - obj->obj = (byte*)XMALLOC(obj->objSz, NULL, DYNAMIC_TYPE_ASN1); - if (obj->obj == NULL) { - wolfSSL_ASN1_OBJECT_free(obj); - return NULL; - } - obj->dynamic |= WOLFSSL_ASN1_DYNAMIC_DATA; - } - else { - obj->dynamic &= (unsigned char)~WOLFSSL_ASN1_DYNAMIC_DATA; - } - } - XMEMCPY((byte*)obj->obj, objBuf, obj->objSz); - - (void)type; - - return obj; +int wolfSSL_set_ex_data(WOLFSSL* ssl, int idx, void* data) +{ + WOLFSSL_ENTER("wolfSSL_set_ex_data"); +#ifdef HAVE_EX_DATA + if (ssl != NULL) { + return wolfSSL_CRYPTO_set_ex_data(&ssl->ex_data, idx, data); } +#else + WOLFSSL_MSG("HAVE_EX_DATA macro is not defined"); + (void)ssl; + (void)idx; + (void)data; +#endif + return WOLFSSL_FAILURE; +} - static const char* oid_translate_num_to_str(const char* oid) +#ifdef HAVE_EX_DATA_CLEANUP_HOOKS +int wolfSSL_set_ex_data_with_cleanup( + WOLFSSL* ssl, + int idx, + void* data, + wolfSSL_ex_data_cleanup_routine_t cleanup_routine) +{ + WOLFSSL_ENTER("wolfSSL_set_ex_data_with_cleanup"); + if (ssl != NULL) { - const struct oid_dict { - const char* num; - const char* desc; - } oid_dict[] = { - { "2.5.29.37.0", "Any Extended Key Usage" }, - { "1.3.6.1.5.5.7.3.1", "TLS Web Server Authentication" }, - { "1.3.6.1.5.5.7.3.2", "TLS Web Client Authentication" }, - { "1.3.6.1.5.5.7.3.3", "Code Signing" }, - { "1.3.6.1.5.5.7.3.4", "E-mail Protection" }, - { "1.3.6.1.5.5.7.3.8", "Time Stamping" }, - { "1.3.6.1.5.5.7.3.9", "OCSP Signing" }, - { NULL, NULL } - }; - const struct oid_dict* idx; - - for (idx = oid_dict; idx->num != NULL; idx++) { - if (!XSTRCMP(oid, idx->num)) { - return idx->desc; - } - } - return NULL; + return wolfSSL_CRYPTO_set_ex_data_with_cleanup(&ssl->ex_data, idx, data, + cleanup_routine); } + return WOLFSSL_FAILURE; +} +#endif /* HAVE_EX_DATA_CLEANUP_HOOKS */ - static int wolfssl_obj2txt_numeric(char *buf, int bufLen, - const WOLFSSL_ASN1_OBJECT *a) - { - int bufSz; - int length; - word32 idx = 0; - byte tag; - - if (GetASNTag(a->obj, &idx, &tag, a->objSz) != 0) { - return WOLFSSL_FAILURE; - } - - if (tag != ASN_OBJECT_ID) { - WOLFSSL_MSG("Bad ASN1 Object"); - return WOLFSSL_FAILURE; - } - - if (GetLength((const byte*)a->obj, &idx, &length, - a->objSz) < 0 || length < 0) { - return ASN_PARSE_E; - } - - if (bufLen < MAX_OID_STRING_SZ) { - bufSz = bufLen - 1; - } - else { - bufSz = MAX_OID_STRING_SZ; - } - - if ((bufSz = DecodePolicyOID(buf, (word32)bufSz, a->obj + idx, - (word32)length)) <= 0) { - WOLFSSL_MSG("Error decoding OID"); - return WOLFSSL_FAILURE; - } - - buf[bufSz] = '\0'; - - return bufSz; +void* wolfSSL_get_ex_data(const WOLFSSL* ssl, int idx) +{ + WOLFSSL_ENTER("wolfSSL_get_ex_data"); +#ifdef HAVE_EX_DATA + if (ssl != NULL) { + return wolfSSL_CRYPTO_get_ex_data(&ssl->ex_data, idx); } - - /* If no_name is one then use numerical form, otherwise short name. - * - * Returns the buffer size on success, WOLFSSL_FAILURE on error - */ - int wolfSSL_OBJ_obj2txt(char *buf, int bufLen, const WOLFSSL_ASN1_OBJECT *a, - int no_name) - { - int bufSz; - const char* desc; - const char* name; - - WOLFSSL_ENTER("wolfSSL_OBJ_obj2txt"); - - if (buf == NULL || bufLen <= 1 || a == NULL) { - WOLFSSL_MSG("Bad input argument"); - return WOLFSSL_FAILURE; - } - - if (no_name == 1) { - return wolfssl_obj2txt_numeric(buf, bufLen, a); - } - - /* return long name unless using x509small, then return short name */ -#if defined(OPENSSL_EXTRA_X509_SMALL) && !defined(OPENSSL_EXTRA) - name = a->sName; #else - name = wolfSSL_OBJ_nid2ln(wolfSSL_OBJ_obj2nid(a)); + WOLFSSL_MSG("HAVE_EX_DATA macro is not defined"); + (void)ssl; + (void)idx; #endif + return 0; +} - if (name == NULL) { - WOLFSSL_MSG("Name not found"); - bufSz = 0; - } - else if (XSTRLEN(name) + 1 < (word32)bufLen - 1) { - bufSz = (int)XSTRLEN(name); - } - else { - bufSz = bufLen - 1; - } - if (bufSz) { - XMEMCPY(buf, name, (size_t)bufSz); - } - else if (a->type == WOLFSSL_GEN_DNS || a->type == WOLFSSL_GEN_EMAIL || - a->type == WOLFSSL_GEN_URI) { - size_t objLen = XSTRLEN((const char*)a->obj); - if (objLen >= (size_t)bufLen) { - bufSz = bufLen - 1; - } - else { - bufSz = (int)objLen; - } - XMEMCPY(buf, a->obj, (size_t)bufSz); - } - else if ((bufSz = wolfssl_obj2txt_numeric(buf, bufLen, a)) > 0) { - if ((desc = oid_translate_num_to_str(buf))) { - bufSz = (int)XSTRLEN(desc); - bufSz = (int)min((word32)bufSz,(word32) bufLen - 1); - XMEMCPY(buf, desc, (size_t)bufSz); - } - } - else { - bufSz = 0; - } +#if defined(HAVE_LIGHTY) || defined(HAVE_STUNNEL) \ + || defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(OPENSSL_EXTRA) - buf[bufSz] = '\0'; +/* returns the enum value associated with handshake state + * + * ssl the WOLFSSL structure to get state of + */ +int wolfSSL_get_state(const WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_get_state"); - return bufSz; + if (ssl == NULL) { + WOLFSSL_MSG("Null argument passed in"); + return WOLFSSL_FAILURE; } -#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ -#if defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) || \ - defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(HAVE_STUNNEL) || \ - defined(WOLFSSL_NGINX) || defined(HAVE_POCO_LIB) || \ - defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_WPAS_SMALL) - /* Returns the long name that corresponds with an ASN1_OBJECT nid value. - * n : NID value of ASN1_OBJECT to search */ - const char* wolfSSL_OBJ_nid2ln(int n) - { - const WOLFSSL_ObjectInfo *obj_info = wolfssl_object_info; - size_t i; - WOLFSSL_ENTER("wolfSSL_OBJ_nid2ln"); - for (i = 0; i < WOLFSSL_OBJECT_INFO_SZ; i++, obj_info++) { - if (obj_info->nid == n) { - return obj_info->lName; - } - } - WOLFSSL_MSG("NID not found in table"); - return NULL; - } -#endif /* OPENSSL_EXTRA, HAVE_LIGHTY, WOLFSSL_MYSQL_COMPATIBLE, HAVE_STUNNEL, - WOLFSSL_NGINX, HAVE_POCO_LIB, WOLFSSL_HAPROXY, WOLFSSL_WPAS_SMALL */ + return ssl->options.handShakeState; +} +#endif /* HAVE_LIGHTY || HAVE_STUNNEL || WOLFSSL_MYSQL_COMPATIBLE */ -#if defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) || \ - defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(HAVE_STUNNEL) || \ - defined(WOLFSSL_NGINX) || defined(HAVE_POCO_LIB) || \ - defined(WOLFSSL_HAPROXY) - /* Return the corresponding short name for the nid . - * or NULL if short name can't be found. - */ - const char * wolfSSL_OBJ_nid2sn(int n) { - const WOLFSSL_ObjectInfo *obj_info = wolfssl_object_info; - size_t i; - WOLFSSL_ENTER("wolfSSL_OBJ_nid2sn"); - - if (n == WC_NID_md5) { - /* WC_NID_surname == WC_NID_md5 and WC_NID_surname comes before WC_NID_md5 in - * wolfssl_object_info. As a result, the loop below will incorrectly - * return "SN" instead of "MD5." WC_NID_surname isn't the true OpenSSL - * NID, but other functions rely on this table and modifying it to - * conform with OpenSSL's NIDs isn't trivial. */ - return "MD5"; - } - for (i = 0; i < WOLFSSL_OBJECT_INFO_SZ; i++, obj_info++) { - if (obj_info->nid == n) { - return obj_info->sName; - } - } - WOLFSSL_MSG_EX("SN not found (nid:%d)",n); - return NULL; - } +#ifdef OPENSSL_EXTRA +void wolfSSL_certs_clear(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_certs_clear"); -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) - int wolfSSL_OBJ_sn2nid(const char *sn) { - WOLFSSL_ENTER("wolfSSL_OBJ_sn2nid"); - if (sn == NULL) - return WC_NID_undef; - return wc_OBJ_sn2nid(sn); + if (ssl == NULL) + return; + + /* ctx still owns certificate, certChain, key, dh, and cm */ + if (ssl->buffers.weOwnCert) { + FreeDer(&ssl->buffers.certificate); + ssl->buffers.weOwnCert = 0; + } + ssl->buffers.certificate = NULL; + if (ssl->buffers.weOwnCertChain) { + FreeDer(&ssl->buffers.certChain); + ssl->buffers.weOwnCertChain = 0; } + ssl->buffers.certChain = NULL; +#ifdef WOLFSSL_TLS13 + ssl->buffers.certChainCnt = 0; #endif - - size_t wolfSSL_OBJ_length(const WOLFSSL_ASN1_OBJECT* o) - { - size_t ret = 0; - int err = 0; - word32 idx = 0; - int len = 0; - - WOLFSSL_ENTER("wolfSSL_OBJ_length"); - - if (o == NULL || o->obj == NULL) { - WOLFSSL_MSG("Bad argument."); - err = 1; - } - - if (err == 0 && GetASNObjectId(o->obj, &idx, &len, o->objSz)) { - WOLFSSL_MSG("Error parsing ASN.1 header."); - err = 1; - } - if (err == 0) { - ret = (size_t)len; - } - - WOLFSSL_LEAVE("wolfSSL_OBJ_length", (int)ret); - - return ret; + if (ssl->buffers.weOwnKey) { + FreeDer(&ssl->buffers.key); + #ifdef WOLFSSL_BLIND_PRIVATE_KEY + FreeDer(&ssl->buffers.keyMask); + #endif + ssl->buffers.weOwnKey = 0; } - - const unsigned char* wolfSSL_OBJ_get0_data(const WOLFSSL_ASN1_OBJECT* o) - { - const unsigned char* ret = NULL; - int err = 0; - word32 idx = 0; - int len = 0; - - WOLFSSL_ENTER("wolfSSL_OBJ_get0_data"); - - if (o == NULL || o->obj == NULL) { - WOLFSSL_MSG("Bad argument."); - err = 1; - } - - if (err == 0 && GetASNObjectId(o->obj, &idx, &len, o->objSz)) { - WOLFSSL_MSG("Error parsing ASN.1 header."); - err = 1; - } - if (err == 0) { - ret = o->obj + idx; - } - - return ret; + ssl->buffers.key = NULL; +#ifdef WOLFSSL_BLIND_PRIVATE_KEY + ssl->buffers.keyMask = NULL; +#endif + ssl->buffers.keyType = 0; + ssl->buffers.keyId = 0; + ssl->buffers.keyLabel = 0; + ssl->buffers.keySz = 0; + ssl->buffers.keyDevId = 0; +#ifdef WOLFSSL_DUAL_ALG_CERTS + if (ssl->buffers.weOwnAltKey) { + FreeDer(&ssl->buffers.altKey); + #ifdef WOLFSSL_BLIND_PRIVATE_KEY + FreeDer(&ssl->buffers.altKeyMask); + #endif + ssl->buffers.weOwnAltKey = 0; } - - - /* Gets the NID value that corresponds with the ASN1 object. - * - * o ASN1 object to get NID of - * - * Return NID on success and a negative value on failure - */ - int wolfSSL_OBJ_obj2nid(const WOLFSSL_ASN1_OBJECT *o) - { - word32 oid = 0; - word32 idx = 0; - int ret; - -#ifdef WOLFSSL_DEBUG_OPENSSL - WOLFSSL_ENTER("wolfSSL_OBJ_obj2nid"); + ssl->buffers.altKey = NULL; +#ifdef WOLFSSL_BLIND_PRIVATE_KEY + ssl->buffers.altKeyMask = NULL; +#endif +#endif /* WOLFSSL_DUAL_ALG_CERTS */ +} #endif - if (o == NULL) { - return WOLFSSL_FATAL_ERROR; - } +#if defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || defined(WOLFSSL_HAPROXY) \ + || defined(WOLFSSL_NGINX) || defined(WOLFSSL_QT) - #ifdef WOLFSSL_QT - if (o->grp == oidCertExtType) { - /* If nid is an unknown extension, return WC_NID_undef */ - if (wolfSSL_OBJ_nid2sn(o->nid) == NULL) - return WC_NID_undef; - } - #endif +long wolfSSL_ctrl(WOLFSSL* ssl, int cmd, long opt, void* pt) +{ + WOLFSSL_ENTER("wolfSSL_ctrl"); + if (ssl == NULL) + return BAD_FUNC_ARG; - if (o->nid > 0) - return o->nid; - if ((ret = GetObjectId(o->obj, &idx, &oid, - (word32)o->grp, o->objSz)) < 0) { - if (ret == WC_NO_ERR_TRACE(ASN_OBJECT_ID_E)) { - /* Put ASN object tag in front and try again */ - int len = SetObjectId((int)o->objSz, NULL) + (int)o->objSz; - byte* buf = (byte*)XMALLOC((size_t)len, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (!buf) { - WOLFSSL_MSG("malloc error"); - return WOLFSSL_FATAL_ERROR; - } - idx = (word32)SetObjectId((int)o->objSz, buf); - XMEMCPY(buf + idx, o->obj, o->objSz); - idx = 0; - ret = GetObjectId(buf, &idx, &oid, (word32)o->grp, (word32)len); - XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (ret < 0) { - WOLFSSL_MSG("Issue getting OID of object"); - return WOLFSSL_FATAL_ERROR; - } - } - else { - WOLFSSL_MSG("Issue getting OID of object"); - return WOLFSSL_FATAL_ERROR; + switch (cmd) { + #if defined(WOLFSSL_NGINX) || defined(WOLFSSL_QT) || \ + defined(OPENSSL_ALL) + #ifdef HAVE_SNI + case SSL_CTRL_SET_TLSEXT_HOSTNAME: + WOLFSSL_MSG("Entering Case: SSL_CTRL_SET_TLSEXT_HOSTNAME."); + if (pt == NULL) { + WOLFSSL_MSG("Passed in NULL Host Name."); + break; } - } - - return oid2nid(oid, o->grp); + return wolfSSL_set_tlsext_host_name(ssl, (const char*) pt); + #endif /* HAVE_SNI */ + #endif /* WOLFSSL_NGINX || WOLFSSL_QT || OPENSSL_ALL */ + default: + WOLFSSL_MSG("Case not implemented."); } + (void)opt; + (void)pt; + return WOLFSSL_FAILURE; +} - /* Return the corresponding NID for the long name - * or WC_NID_undef if NID can't be found. - */ - int wolfSSL_OBJ_ln2nid(const char *ln) - { - const WOLFSSL_ObjectInfo *obj_info = wolfssl_object_info; - size_t lnlen; - WOLFSSL_ENTER("wolfSSL_OBJ_ln2nid"); - if (ln && (lnlen = XSTRLEN(ln)) > 0) { - /* Accept input like "/commonName=" */ - if (ln[0] == '/') { - ln++; - lnlen--; - } - if (lnlen) { - size_t i; +long wolfSSL_CTX_ctrl(WOLFSSL_CTX* ctx, int cmd, long opt, void* pt) +{ +#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) + long ctrl_opt; +#endif + long ret = WOLFSSL_SUCCESS; - if (ln[lnlen-1] == '=') { - lnlen--; - } - for (i = 0; i < WOLFSSL_OBJECT_INFO_SZ; i++, obj_info++) { - if (lnlen == XSTRLEN(obj_info->lName) && - XSTRNCMP(ln, obj_info->lName, lnlen) == 0) { - return obj_info->nid; - } - } - } - } - return WC_NID_undef; - } + WOLFSSL_ENTER("wolfSSL_CTX_ctrl"); + if (ctx == NULL) + return WOLFSSL_FAILURE; - /* compares two objects, return 0 if equal */ - int wolfSSL_OBJ_cmp(const WOLFSSL_ASN1_OBJECT* a, - const WOLFSSL_ASN1_OBJECT* b) + switch (cmd) { + case SSL_CTRL_CHAIN: +#ifdef SESSION_CERTS { - WOLFSSL_ENTER("wolfSSL_OBJ_cmp"); - - if (a && b && a->obj && b->obj) { - if (a->objSz == b->objSz) { - return XMEMCMP(a->obj, b->obj, a->objSz); - } - else if (a->type == EXT_KEY_USAGE_OID || - b->type == EXT_KEY_USAGE_OID) { - /* Special case for EXT_KEY_USAGE_OID so that - * cmp will be treated as a substring search */ - /* Used in libest to check for id-kp-cmcRA in - * EXT_KEY_USAGE extension */ - unsigned int idx; - const byte* s; /* shorter */ - unsigned int sLen; - const byte* l; /* longer */ - unsigned int lLen; - if (a->objSz > b->objSz) { - s = b->obj; sLen = b->objSz; - l = a->obj; lLen = a->objSz; + /* + * We don't care about opt here because a copy of the certificate is + * stored anyway so increasing the reference counter is not necessary. + * Just check to make sure that it is set to one of the correct values. + */ + WOLF_STACK_OF(WOLFSSL_X509)* sk = (WOLF_STACK_OF(WOLFSSL_X509)*) pt; + WOLFSSL_X509* x509; + int i; + if (opt != 0 && opt != 1) { + ret = WOLFSSL_FAILURE; + break; + } + /* Clear certificate chain */ + FreeDer(&ctx->certChain); + if (sk) { + for (i = 0; i < wolfSSL_sk_X509_num(sk); i++) { + x509 = wolfSSL_sk_X509_value(sk, i); + /* Prevent wolfSSL_CTX_add_extra_chain_cert from freeing cert */ + if (wolfSSL_X509_up_ref(x509) != 1) { + WOLFSSL_MSG("Error increasing reference count"); + continue; } - else { - s = a->obj; sLen = a->objSz; - l = b->obj; lLen = b->objSz; + if (wolfSSL_CTX_add_extra_chain_cert(ctx, x509) != + WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Error adding certificate to context"); + /* Decrease reference count on failure */ + wolfSSL_X509_free(x509); + x509 = NULL; } - for (idx = 0; idx <= lLen - sLen; idx++) { - if (XMEMCMP(l + idx, s, sLen) == 0) { - /* Found substring */ - return 0; - } + } + } + /* Free previous chain */ + wolfSSL_sk_X509_pop_free(ctx->x509Chain, NULL); + ctx->x509Chain = sk; + if (sk && opt == 1) { + /* up all refs when opt == 1 */ + for (i = 0; i < wolfSSL_sk_X509_num(sk); i++) { + x509 = wolfSSL_sk_X509_value(sk, i); + if (wolfSSL_X509_up_ref(x509) != 1) { + WOLFSSL_MSG("Error increasing reference count"); + continue; } } } - - return WOLFSSL_FATAL_ERROR; } -#endif /* OPENSSL_EXTRA, HAVE_LIGHTY, WOLFSSL_MYSQL_COMPATIBLE, HAVE_STUNNEL, - WOLFSSL_NGINX, HAVE_POCO_LIB, WOLFSSL_HAPROXY */ -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) || \ - defined(HAVE_LIGHTY) || defined(WOLFSSL_MYSQL_COMPATIBLE) || \ - defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \ - defined(HAVE_POCO_LIB) || defined(WOLFSSL_HAPROXY) - /* Gets the NID value that is related to the OID string passed in. Example - * string would be "2.5.29.14" for subject key ID. - * - * returns NID value on success and WC_NID_undef on error - */ - int wolfSSL_OBJ_txt2nid(const char* s) - { - unsigned int i; - #ifdef WOLFSSL_CERT_EXT - int ret; - unsigned int sum = 0; - unsigned int outSz = MAX_OID_SZ; - unsigned char out[MAX_OID_SZ]; - - XMEMSET(out, 0, sizeof(out)); - #endif +#else + WOLFSSL_MSG("Session certificates not compiled in"); + ret = WOLFSSL_FAILURE; +#endif + break; - WOLFSSL_ENTER("wolfSSL_OBJ_txt2nid"); +#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) + case SSL_CTRL_OPTIONS: + WOLFSSL_MSG("Entering Case: SSL_CTRL_OPTIONS."); + ctrl_opt = wolfSSL_CTX_set_options(ctx, opt); - if (s == NULL) { - return WC_NID_undef; + #ifdef WOLFSSL_QT + /* Set whether to use client or server cipher preference */ + if ((ctrl_opt & WOLFSSL_OP_CIPHER_SERVER_PREFERENCE) + == WOLFSSL_OP_CIPHER_SERVER_PREFERENCE) { + WOLFSSL_MSG("Using Server's Cipher Preference."); + ctx->useClientOrder = 0; + } else { + WOLFSSL_MSG("Using Client's Cipher Preference."); + ctx->useClientOrder = 1; } + #endif /* WOLFSSL_QT */ - #ifdef WOLFSSL_CERT_EXT - ret = EncodePolicyOID(out, &outSz, s, NULL); - if (ret == 0) { - /* sum OID */ - sum = wc_oid_sum(out, outSz); + return ctrl_opt; +#endif /* OPENSSL_EXTRA || HAVE_WEBSERVER */ + case SSL_CTRL_EXTRA_CHAIN_CERT: + WOLFSSL_MSG("Entering Case: SSL_CTRL_EXTRA_CHAIN_CERT."); + if (pt == NULL) { + WOLFSSL_MSG("Passed in x509 pointer NULL."); + ret = WOLFSSL_FAILURE; + break; } - #endif /* WOLFSSL_CERT_EXT */ - - /* get the group that the OID's sum is in - * @TODO possible conflict with multiples */ - for (i = 0; i < WOLFSSL_OBJECT_INFO_SZ; i++) { - int len; - #ifdef WOLFSSL_CERT_EXT - if (ret == 0) { - if (wolfssl_object_info[i].id == (int)sum) { - return wolfssl_object_info[i].nid; - } - } - #endif - - /* try as a short name */ - len = (int)XSTRLEN(s); - if ((int)XSTRLEN(wolfssl_object_info[i].sName) == len && - XSTRNCMP(wolfssl_object_info[i].sName, s, (word32)len) == 0) { - return wolfssl_object_info[i].nid; - } + return wolfSSL_CTX_add_extra_chain_cert(ctx, (WOLFSSL_X509*)pt); - /* try as a long name */ - if ((int)XSTRLEN(wolfssl_object_info[i].lName) == len && - XSTRNCMP(wolfssl_object_info[i].lName, s, (word32)len) == 0) { - return wolfssl_object_info[i].nid; - } +#ifndef NO_DH + case SSL_CTRL_SET_TMP_DH: + WOLFSSL_MSG("Entering Case: SSL_CTRL_SET_TMP_DH."); + if (pt == NULL) { + WOLFSSL_MSG("Passed in DH pointer NULL."); + ret = WOLFSSL_FAILURE; + break; } - - return WC_NID_undef; - } + return wolfSSL_CTX_set_tmp_dh(ctx, (WOLFSSL_DH*)pt); #endif -#if defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) || \ - defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(HAVE_STUNNEL) || \ - defined(WOLFSSL_NGINX) || defined(HAVE_POCO_LIB) || \ - defined(WOLFSSL_HAPROXY) - /* Creates new ASN1_OBJECT from short name, long name, or text - * representation of oid. If no_name is 0, then short name, long name, and - * numerical value of oid are interpreted. If no_name is 1, then only the - * numerical value of the oid is interpreted. - * - * Returns pointer to ASN1_OBJECT on success, or NULL on error. - */ -#if defined(WOLFSSL_CERT_EXT) && defined(WOLFSSL_CERT_GEN) - WOLFSSL_ASN1_OBJECT* wolfSSL_OBJ_txt2obj(const char* s, int no_name) - { - int i, ret; - int nid = WC_NID_undef; - unsigned int outSz = MAX_OID_SZ; - unsigned char out[MAX_OID_SZ]; - WOLFSSL_ASN1_OBJECT* obj; +#ifdef HAVE_ECC + case SSL_CTRL_SET_TMP_ECDH: + WOLFSSL_MSG("Entering Case: SSL_CTRL_SET_TMP_ECDH."); + if (pt == NULL) { + WOLFSSL_MSG("Passed in ECDH pointer NULL."); + ret = WOLFSSL_FAILURE; + break; + } + return wolfSSL_SSL_CTX_set_tmp_ecdh(ctx, (WOLFSSL_EC_KEY*)pt); +#endif + case SSL_CTRL_MODE: + wolfSSL_CTX_set_mode(ctx,opt); + break; + case SSL_CTRL_SET_MIN_PROTO_VERSION: + WOLFSSL_MSG("set min proto version"); + return wolfSSL_CTX_set_min_proto_version(ctx, (int)opt); + case SSL_CTRL_SET_MAX_PROTO_VERSION: + WOLFSSL_MSG("set max proto version"); + return wolfSSL_CTX_set_max_proto_version(ctx, (int)opt); + case SSL_CTRL_GET_MIN_PROTO_VERSION: + WOLFSSL_MSG("get min proto version"); + return wolfSSL_CTX_get_min_proto_version(ctx); + case SSL_CTRL_GET_MAX_PROTO_VERSION: + WOLFSSL_MSG("get max proto version"); + return wolfSSL_CTX_get_max_proto_version(ctx); + default: + WOLFSSL_MSG("CTX_ctrl cmd not implemented"); + ret = WOLFSSL_FAILURE; + break; + } - WOLFSSL_ENTER("wolfSSL_OBJ_txt2obj"); + (void)ctx; + (void)cmd; + (void)opt; + (void)pt; + WOLFSSL_LEAVE("wolfSSL_CTX_ctrl", (int)ret); + return ret; +} - if (s == NULL) - return NULL; +#ifndef NO_WOLFSSL_STUB +long wolfSSL_CTX_callback_ctrl(WOLFSSL_CTX* ctx, int cmd, void (*fp)(void)) +{ + (void) ctx; + (void) cmd; + (void) fp; + WOLFSSL_STUB("wolfSSL_CTX_callback_ctrl"); + return WOLFSSL_FAILURE; - /* If s is numerical value, try to sum oid */ - ret = EncodePolicyOID(out, &outSz, s, NULL); - if (ret == 0 && outSz > 0) { - /* If numerical encode succeeded then just - * create object from that because sums are - * not unique and can cause confusion. */ - obj = wolfSSL_ASN1_OBJECT_new(); - if (obj == NULL) { - WOLFSSL_MSG("Issue creating WOLFSSL_ASN1_OBJECT struct"); - return NULL; - } - obj->dynamic |= WOLFSSL_ASN1_DYNAMIC; - obj->obj = (byte*)XMALLOC(1 + MAX_LENGTH_SZ + outSz, NULL, - DYNAMIC_TYPE_ASN1); - if (obj->obj == NULL) { - wolfSSL_ASN1_OBJECT_free(obj); - return NULL; - } - obj->dynamic |= WOLFSSL_ASN1_DYNAMIC_DATA; - i = SetObjectId((int)outSz, (byte*)obj->obj); - XMEMCPY((byte*)obj->obj + i, out, outSz); - obj->objSz = (word32)i + outSz; - return obj; - } +} +#endif /* NO_WOLFSSL_STUB */ - /* TODO: update short names in wolfssl_object_info and check OID sums - are correct */ - for (i = 0; i < (int)WOLFSSL_OBJECT_INFO_SZ; i++) { - /* Short name, long name, and numerical value are interpreted */ - if (no_name == 0 && - ((XSTRCMP(s, wolfssl_object_info[i].sName) == 0) || - (XSTRCMP(s, wolfssl_object_info[i].lName) == 0))) - { - nid = wolfssl_object_info[i].nid; - } - } - if (nid != WC_NID_undef) - return wolfSSL_OBJ_nid2obj(nid); +#endif /* OPENSSL_ALL || WOLFSSL_ASIO || WOLFSSL_HAPROXY || WOLFSSL_QT */ - return NULL; - } -#endif - /* compatibility function. Its intended use is to remove OID's from an - * internal table that have been added with OBJ_create. wolfSSL manages its - * own internal OID values and does not currently support OBJ_create. */ - void wolfSSL_OBJ_cleanup(void) - { - WOLFSSL_ENTER("wolfSSL_OBJ_cleanup"); - } +/* stunnel compatibility functions*/ +#if defined(OPENSSL_ALL) || (defined(OPENSSL_EXTRA) && \ + (defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \ + defined(HAVE_LIGHTY) || defined(WOLFSSL_HAPROXY) || \ + defined(WOLFSSL_OPENSSH))) - #ifndef NO_WOLFSSL_STUB - int wolfSSL_OBJ_create(const char *oid, const char *sn, const char *ln) - { - (void)oid; - (void)sn; - (void)ln; - WOLFSSL_STUB("wolfSSL_OBJ_create"); - return WOLFSSL_FAILURE; - } - #endif +#ifndef NO_FILESYSTEM +/***TBD ***/ +void wolfSSL_print_all_errors_fp(XFILE fp) +{ + (void)fp; +} +#endif /* !NO_FILESYSTEM */ - void wolfSSL_set_verify_depth(WOLFSSL *ssl, int depth) - { - #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) - WOLFSSL_ENTER("wolfSSL_set_verify_depth"); - ssl->options.verifyDepth = (byte)depth; - #endif - } +#endif /* OPENSSL_ALL || OPENSSL_EXTRA || HAVE_STUNNEL || WOLFSSL_NGINX || + HAVE_LIGHTY || WOLFSSL_HAPROXY || WOLFSSL_OPENSSH */ -#endif /* OPENSSL_ALL || HAVE_LIGHTY || WOLFSSL_MYSQL_COMPATIBLE || - HAVE_STUNNEL || WOLFSSL_NGINX || HAVE_POCO_LIB || WOLFSSL_HAPROXY */ +/* Note: This is a huge section of API's - through + * wolfSSL_X509_OBJECT_get0_X509_CRL */ +#if defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) -#ifdef OPENSSL_EXTRA +#if defined(USE_WOLFSSL_MEMORY) && !defined(WOLFSSL_DEBUG_MEMORY) && \ + !defined(WOLFSSL_STATIC_MEMORY) +static wolfSSL_OSSL_Malloc_cb ossl_malloc = NULL; +static wolfSSL_OSSL_Free_cb ossl_free = NULL; +static wolfSSL_OSSL_Realloc_cb ossl_realloc = NULL; -/* wolfSSL uses negative values for error states. This function returns an - * unsigned type so the value returned is the absolute value of the error. - */ -unsigned long wolfSSL_ERR_peek_last_error_line(const char **file, int *line) +static void* OSSL_Malloc(size_t size) { - WOLFSSL_ENTER("wolfSSL_ERR_peek_last_error"); - - (void)line; - (void)file; -#ifdef WOLFSSL_HAVE_ERROR_QUEUE - { - int ret; - - if ((ret = wc_PeekErrorNode(-1, file, NULL, line)) < 0) { - WOLFSSL_MSG("Issue peeking at error node in queue"); - return 0; - } - #if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) \ - || defined(WOLFSSL_HAPROXY) - if (ret == -WC_NO_ERR_TRACE(ASN_NO_PEM_HEADER)) - return (ERR_LIB_PEM << 24) | PEM_R_NO_START_LINE; - #endif - #if defined(OPENSSL_ALL) && defined(WOLFSSL_PYTHON) - if (ret == ASN1_R_HEADER_TOO_LONG) { - return (ERR_LIB_ASN1 << 24) | ASN1_R_HEADER_TOO_LONG; - } - #endif - return (unsigned long)ret; - } -#else - return (unsigned long)(0 - NOT_COMPILED_IN); -#endif + if (ossl_malloc != NULL) + return ossl_malloc(size, NULL, 0); + else + return NULL; } -#endif /* OPENSSL_EXTRA */ - -#ifdef HAVE_EX_DATA_CRYPTO -CRYPTO_EX_cb_ctx* crypto_ex_cb_ctx_session = NULL; +static void OSSL_Free(void *ptr) +{ + if (ossl_free != NULL) + ossl_free(ptr, NULL, 0); +} -static int crypto_ex_cb_new(CRYPTO_EX_cb_ctx** dst, long ctx_l, void* ctx_ptr, - WOLFSSL_CRYPTO_EX_new* new_func, WOLFSSL_CRYPTO_EX_dup* dup_func, - WOLFSSL_CRYPTO_EX_free* free_func) +static void* OSSL_Realloc(void *ptr, size_t size) { - CRYPTO_EX_cb_ctx* new_ctx = (CRYPTO_EX_cb_ctx*)XMALLOC( - sizeof(CRYPTO_EX_cb_ctx), NULL, DYNAMIC_TYPE_OPENSSL); - if (new_ctx == NULL) - return WOLFSSL_FATAL_ERROR; - new_ctx->ctx_l = ctx_l; - new_ctx->ctx_ptr = ctx_ptr; - new_ctx->new_func = new_func; - new_ctx->free_func = free_func; - new_ctx->dup_func = dup_func; - new_ctx->next = NULL; - /* Push to end of list */ - while (*dst != NULL) - dst = &(*dst)->next; - *dst = new_ctx; - return 0; + if (ossl_realloc != NULL) + return ossl_realloc(ptr, size, NULL, 0); + else + return NULL; } +#endif /* USE_WOLFSSL_MEMORY && !WOLFSSL_DEBUG_MEMORY && + * !WOLFSSL_STATIC_MEMORY */ -void crypto_ex_cb_free(CRYPTO_EX_cb_ctx* cb_ctx) +int wolfSSL_CRYPTO_set_mem_functions( + wolfSSL_OSSL_Malloc_cb m, + wolfSSL_OSSL_Realloc_cb r, + wolfSSL_OSSL_Free_cb f) { - while (cb_ctx != NULL) { - CRYPTO_EX_cb_ctx* next = cb_ctx->next; - XFREE(cb_ctx, NULL, DYNAMIC_TYPE_OPENSSL); - cb_ctx = next; +#if defined(USE_WOLFSSL_MEMORY) && !defined(WOLFSSL_STATIC_MEMORY) +#ifdef WOLFSSL_DEBUG_MEMORY + WOLFSSL_MSG("mem functions will receive function name instead of " + "file name"); + if (wolfSSL_SetAllocators((wolfSSL_Malloc_cb)m, (wolfSSL_Free_cb)f, + (wolfSSL_Realloc_cb)r) == 0) + return WOLFSSL_SUCCESS; +#else + WOLFSSL_MSG("wolfSSL was compiled without WOLFSSL_DEBUG_MEMORY mem " + "functions will receive a NULL file name and 0 for the " + "line number."); + if (wolfSSL_SetAllocators((wolfSSL_Malloc_cb)OSSL_Malloc, + (wolfSSL_Free_cb)OSSL_Free, (wolfSSL_Realloc_cb)OSSL_Realloc) == 0) { + ossl_malloc = m; + ossl_free = f; + ossl_realloc = r; + return WOLFSSL_SUCCESS; } +#endif + else + return WOLFSSL_FAILURE; +#else + (void)m; + (void)r; + (void)f; + WOLFSSL_MSG("wolfSSL allocator callback functions not compiled in"); + return WOLFSSL_FAILURE; +#endif } -void crypto_ex_cb_setup_new_data(void *new_obj, CRYPTO_EX_cb_ctx* cb_ctx, - WOLFSSL_CRYPTO_EX_DATA* ex_data) + +int wolfSSL_FIPS_mode(void) { - int idx = 0; - for (; cb_ctx != NULL; idx++, cb_ctx = cb_ctx->next) { - if (cb_ctx->new_func != NULL) - cb_ctx->new_func(new_obj, NULL, ex_data, idx, cb_ctx->ctx_l, - cb_ctx->ctx_ptr); - } +#ifdef HAVE_FIPS + return 1; +#else + return 0; +#endif } -int crypto_ex_cb_dup_data(const WOLFSSL_CRYPTO_EX_DATA *in, - WOLFSSL_CRYPTO_EX_DATA *out, CRYPTO_EX_cb_ctx* cb_ctx) +int wolfSSL_FIPS_mode_set(int r) { - int idx = 0; - for (; cb_ctx != NULL; idx++, cb_ctx = cb_ctx->next) { - if (cb_ctx->dup_func != NULL) { - void* ptr = wolfSSL_CRYPTO_get_ex_data(in, idx); - if (!cb_ctx->dup_func(out, in, - &ptr, idx, - cb_ctx->ctx_l, cb_ctx->ctx_ptr)) { - return WOLFSSL_FAILURE; - } - wolfSSL_CRYPTO_set_ex_data(out, idx, ptr); - } +#ifdef HAVE_FIPS + if (r == 0) { + WOLFSSL_MSG("Cannot disable FIPS at runtime."); + return WOLFSSL_FAILURE; } return WOLFSSL_SUCCESS; -} - -void crypto_ex_cb_free_data(void *obj, CRYPTO_EX_cb_ctx* cb_ctx, - WOLFSSL_CRYPTO_EX_DATA* ex_data) -{ - int idx = 0; - for (; cb_ctx != NULL; idx++, cb_ctx = cb_ctx->next) { - if (cb_ctx->free_func != NULL) - cb_ctx->free_func(obj, NULL, ex_data, idx, cb_ctx->ctx_l, - cb_ctx->ctx_ptr); +#else + if (r == 0) { + return WOLFSSL_SUCCESS; } + WOLFSSL_MSG("Cannot enable FIPS. This isn't the wolfSSL FIPS code."); + return WOLFSSL_FAILURE; +#endif } -/** - * wolfssl_local_get_ex_new_index is a helper function for the following - * xx_get_ex_new_index functions: - * - wolfSSL_CRYPTO_get_ex_new_index - * - wolfSSL_CTX_get_ex_new_index - * - wolfSSL_get_ex_new_index - * Issues a unique index number for the specified class-index. - * Returns an index number greater or equal to zero on success, - * -1 on failure. - */ -int wolfssl_local_get_ex_new_index(int class_index, long ctx_l, void* ctx_ptr, - WOLFSSL_CRYPTO_EX_new* new_func, WOLFSSL_CRYPTO_EX_dup* dup_func, - WOLFSSL_CRYPTO_EX_free* free_func) +int wolfSSL_CIPHER_get_bits(const WOLFSSL_CIPHER *c, int *alg_bits) { - /* index counter for each class index*/ - static int ctx_idx = 0; - static int ssl_idx = 0; - static int ssl_session_idx = 0; - static int x509_idx = 0; - - int idx = -1; - - switch(class_index) { - case WOLF_CRYPTO_EX_INDEX_SSL: - WOLFSSL_CRYPTO_EX_DATA_IGNORE_PARAMS(ctx_l, ctx_ptr, new_func, - dup_func, free_func); - idx = ssl_idx++; - break; - case WOLF_CRYPTO_EX_INDEX_SSL_CTX: - WOLFSSL_CRYPTO_EX_DATA_IGNORE_PARAMS(ctx_l, ctx_ptr, new_func, - dup_func, free_func); - idx = ctx_idx++; - break; - case WOLF_CRYPTO_EX_INDEX_X509: - WOLFSSL_CRYPTO_EX_DATA_IGNORE_PARAMS(ctx_l, ctx_ptr, new_func, - dup_func, free_func); - idx = x509_idx++; - break; - case WOLF_CRYPTO_EX_INDEX_SSL_SESSION: - if (crypto_ex_cb_new(&crypto_ex_cb_ctx_session, ctx_l, ctx_ptr, - new_func, dup_func, free_func) != 0) - return WOLFSSL_FATAL_ERROR; - idx = ssl_session_idx++; - break; + int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); + WOLFSSL_ENTER("wolfSSL_CIPHER_get_bits"); - /* following class indexes are not supoprted */ - case WOLF_CRYPTO_EX_INDEX_X509_STORE: - case WOLF_CRYPTO_EX_INDEX_X509_STORE_CTX: - case WOLF_CRYPTO_EX_INDEX_DH: - case WOLF_CRYPTO_EX_INDEX_DSA: - case WOLF_CRYPTO_EX_INDEX_EC_KEY: - case WOLF_CRYPTO_EX_INDEX_RSA: - case WOLF_CRYPTO_EX_INDEX_ENGINE: - case WOLF_CRYPTO_EX_INDEX_UI: - case WOLF_CRYPTO_EX_INDEX_BIO: - case WOLF_CRYPTO_EX_INDEX_APP: - case WOLF_CRYPTO_EX_INDEX_UI_METHOD: - case WOLF_CRYPTO_EX_INDEX_DRBG: - default: - break; + #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) + (void)alg_bits; + if (c!= NULL) + ret = c->bits; + #else + if (c != NULL && c->ssl != NULL) { + ret = 8 * c->ssl->specs.key_size; + if (alg_bits != NULL) { + *alg_bits = ret; + } } - if (idx >= MAX_EX_DATA) - return WOLFSSL_FATAL_ERROR; - return idx; + #endif + return ret; } -#endif /* HAVE_EX_DATA_CRYPTO */ - -#ifdef HAVE_EX_DATA_CRYPTO -int wolfSSL_CTX_get_ex_new_index(long idx, void* arg, - WOLFSSL_CRYPTO_EX_new* new_func, - WOLFSSL_CRYPTO_EX_dup* dup_func, - WOLFSSL_CRYPTO_EX_free* free_func) -{ - WOLFSSL_ENTER("wolfSSL_CTX_get_ex_new_index"); - - return wolfssl_local_get_ex_new_index(WOLF_CRYPTO_EX_INDEX_SSL_CTX, idx, - arg, new_func, dup_func, free_func); -} -/* Return the index that can be used for the WOLFSSL structure to store - * application data. - * - */ -int wolfSSL_get_ex_new_index(long argValue, void* arg, - WOLFSSL_CRYPTO_EX_new* cb1, WOLFSSL_CRYPTO_EX_dup* cb2, - WOLFSSL_CRYPTO_EX_free* cb3) +WOLFSSL_CTX* wolfSSL_set_SSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx) { - WOLFSSL_ENTER("wolfSSL_get_ex_new_index"); + int ret; + /* This method requires some explanation. Its sibling is + * int SetSSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup) + * which re-inits the WOLFSSL* with all settings in the new CTX. + * That one is the right one to use *before* a handshake is started. + * + * This method was added by OpenSSL to be used *during* the handshake, e.g. + * when a server inspects the SNI in a ClientHello callback and + * decides which set of certificates to use. + * + * Since, at the time the SNI callback is run, some decisions on + * Extensions or the ServerHello might already have been taken, this + * method is very restricted in what it does: + * - changing the server certificate(s) + * - changing the server id for session handling + * and everything else in WOLFSSL* needs to remain untouched. + * + * SECURITY: swapping ssl->ctx switches cm-resolved settings (CA store, + * CRL, OCSP) to the new CTX but leaves ssl-cached ones (verify mode and + * callback, minDowngrade, key-size minimums, suites, version bounds) + * pinned to the original. SNI callbacks must re-apply those ssl-level + * settings explicitly; CRL/OCSP isolation requires an SSL-local store. + */ + WOLFSSL_ENTER("wolfSSL_set_SSL_CTX"); + if (ssl == NULL || ctx == NULL) + return NULL; + if (ssl->ctx == ctx) + return ssl->ctx; - return wolfssl_local_get_ex_new_index(WOLF_CRYPTO_EX_INDEX_SSL, argValue, - arg, cb1, cb2, cb3); -} -#endif /* HAVE_EX_DATA_CRYPTO */ + if (ctx->suites == NULL) { + /* suites */ + if (AllocateCtxSuites(ctx) != 0) + return NULL; + InitSSL_CTX_Suites(ctx); + } -#ifdef OPENSSL_EXTRA -void* wolfSSL_CTX_get_ex_data(const WOLFSSL_CTX* ctx, int idx) -{ - WOLFSSL_ENTER("wolfSSL_CTX_get_ex_data"); -#ifdef HAVE_EX_DATA - if (ctx != NULL) { - return wolfSSL_CRYPTO_get_ex_data(&ctx->ex_data, idx); + wolfSSL_RefWithMutexInc(&ctx->ref, &ret); +#ifdef WOLFSSL_REFCNT_ERROR_RETURN + if (ret != 0) { + /* can only fail on serious stuff, like mutex not working + * or ctx refcount out of whack. */ + return NULL; } #else - (void)ctx; - (void)idx; + (void)ret; #endif - return NULL; -} - -int wolfSSL_CTX_set_ex_data(WOLFSSL_CTX* ctx, int idx, void* data) -{ - WOLFSSL_ENTER("wolfSSL_CTX_set_ex_data"); -#ifdef HAVE_EX_DATA - if (ctx != NULL) { - return wolfSSL_CRYPTO_set_ex_data(&ctx->ex_data, idx, data); - } -#else - (void)ctx; - (void)idx; - (void)data; -#endif - return WOLFSSL_FAILURE; -} - -#ifdef HAVE_EX_DATA_CLEANUP_HOOKS -int wolfSSL_CTX_set_ex_data_with_cleanup( - WOLFSSL_CTX* ctx, - int idx, - void* data, - wolfSSL_ex_data_cleanup_routine_t cleanup_routine) -{ - WOLFSSL_ENTER("wolfSSL_CTX_set_ex_data_with_cleanup"); - if (ctx != NULL) { - return wolfSSL_CRYPTO_set_ex_data_with_cleanup(&ctx->ex_data, idx, data, - cleanup_routine); - } - return WOLFSSL_FAILURE; -} -#endif /* HAVE_EX_DATA_CLEANUP_HOOKS */ -#endif /* OPENSSL_EXTRA */ - -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) - -/* Returns char* to app data stored in ex[0]. - * - * ssl WOLFSSL structure to get app data from - */ -void* wolfSSL_get_app_data(const WOLFSSL *ssl) -{ - /* checkout exdata stuff... */ - WOLFSSL_ENTER("wolfSSL_get_app_data"); - - return wolfSSL_get_ex_data(ssl, 0); -} - - -/* Set ex array 0 to have app data - * - * ssl WOLFSSL struct to set app data in - * arg data to be stored - * - * Returns WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on failure - */ -int wolfSSL_set_app_data(WOLFSSL *ssl, void* arg) { - WOLFSSL_ENTER("wolfSSL_set_app_data"); - - return wolfSSL_set_ex_data(ssl, 0, arg); -} - -#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ + if (ssl->ctx != NULL) + wolfSSL_CTX_free(ssl->ctx); + ssl->ctx = ctx; -int wolfSSL_set_ex_data(WOLFSSL* ssl, int idx, void* data) -{ - WOLFSSL_ENTER("wolfSSL_set_ex_data"); -#ifdef HAVE_EX_DATA - if (ssl != NULL) { - return wolfSSL_CRYPTO_set_ex_data(&ssl->ex_data, idx, data); - } -#else - WOLFSSL_MSG("HAVE_EX_DATA macro is not defined"); - (void)ssl; - (void)idx; - (void)data; -#endif - return WOLFSSL_FAILURE; -} +#ifndef NO_CERTS +#ifdef WOLFSSL_COPY_CERT + /* If WOLFSSL_COPY_CERT defined, always make new copy of cert from ctx */ + if (ctx->certificate != NULL) { + if (ssl->buffers.certificate != NULL) { + FreeDer(&ssl->buffers.certificate); + ssl->buffers.certificate = NULL; + } + ret = AllocCopyDer(&ssl->buffers.certificate, ctx->certificate->buffer, + ctx->certificate->length, ctx->certificate->type, + ctx->certificate->heap); + if (ret != 0) { + ssl->buffers.weOwnCert = 0; + return NULL; + } -#ifdef HAVE_EX_DATA_CLEANUP_HOOKS -int wolfSSL_set_ex_data_with_cleanup( - WOLFSSL* ssl, - int idx, - void* data, - wolfSSL_ex_data_cleanup_routine_t cleanup_routine) -{ - WOLFSSL_ENTER("wolfSSL_set_ex_data_with_cleanup"); - if (ssl != NULL) - { - return wolfSSL_CRYPTO_set_ex_data_with_cleanup(&ssl->ex_data, idx, data, - cleanup_routine); + ssl->buffers.weOwnCert = 1; } - return WOLFSSL_FAILURE; -} -#endif /* HAVE_EX_DATA_CLEANUP_HOOKS */ + if (ctx->certChain != NULL) { + if (ssl->buffers.certChain != NULL) { + FreeDer(&ssl->buffers.certChain); + ssl->buffers.certChain = NULL; + } + ret = AllocCopyDer(&ssl->buffers.certChain, ctx->certChain->buffer, + ctx->certChain->length, ctx->certChain->type, + ctx->certChain->heap); + if (ret != 0) { + ssl->buffers.weOwnCertChain = 0; + return NULL; + } -void* wolfSSL_get_ex_data(const WOLFSSL* ssl, int idx) -{ - WOLFSSL_ENTER("wolfSSL_get_ex_data"); -#ifdef HAVE_EX_DATA - if (ssl != NULL) { - return wolfSSL_CRYPTO_get_ex_data(&ssl->ex_data, idx); + ssl->buffers.weOwnCertChain = 1; } #else - WOLFSSL_MSG("HAVE_EX_DATA macro is not defined"); - (void)ssl; - (void)idx; + /* ctx owns certificate, certChain and key */ + ssl->buffers.certificate = ctx->certificate; + ssl->buffers.certChain = ctx->certChain; #endif - return 0; -} - -#if defined(HAVE_LIGHTY) || defined(HAVE_STUNNEL) \ - || defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(OPENSSL_EXTRA) - -/* returns the enum value associated with handshake state - * - * ssl the WOLFSSL structure to get state of - */ -int wolfSSL_get_state(const WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_get_state"); - - if (ssl == NULL) { - WOLFSSL_MSG("Null argument passed in"); - return WOLFSSL_FAILURE; - } - - return ssl->options.handShakeState; -} -#endif /* HAVE_LIGHTY || HAVE_STUNNEL || WOLFSSL_MYSQL_COMPATIBLE */ - -#ifdef OPENSSL_EXTRA -void wolfSSL_certs_clear(WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_certs_clear"); - - if (ssl == NULL) - return; - - /* ctx still owns certificate, certChain, key, dh, and cm */ - if (ssl->buffers.weOwnCert) { - FreeDer(&ssl->buffers.certificate); - ssl->buffers.weOwnCert = 0; - } - ssl->buffers.certificate = NULL; - if (ssl->buffers.weOwnCertChain) { - FreeDer(&ssl->buffers.certChain); - ssl->buffers.weOwnCertChain = 0; - } - ssl->buffers.certChain = NULL; #ifdef WOLFSSL_TLS13 - ssl->buffers.certChainCnt = 0; + ssl->buffers.certChainCnt = ctx->certChainCnt; #endif - if (ssl->buffers.weOwnKey) { +#ifndef WOLFSSL_BLIND_PRIVATE_KEY +#ifdef WOLFSSL_COPY_KEY + if (ssl->buffers.key != NULL && ssl->buffers.weOwnKey) { FreeDer(&ssl->buffers.key); - #ifdef WOLFSSL_BLIND_PRIVATE_KEY - FreeDer(&ssl->buffers.keyMask); - #endif - ssl->buffers.weOwnKey = 0; - } - ssl->buffers.key = NULL; -#ifdef WOLFSSL_BLIND_PRIVATE_KEY - ssl->buffers.keyMask = NULL; -#endif - ssl->buffers.keyType = 0; - ssl->buffers.keyId = 0; - ssl->buffers.keyLabel = 0; - ssl->buffers.keySz = 0; - ssl->buffers.keyDevId = 0; -#ifdef WOLFSSL_DUAL_ALG_CERTS - if (ssl->buffers.weOwnAltKey) { - FreeDer(&ssl->buffers.altKey); - #ifdef WOLFSSL_BLIND_PRIVATE_KEY - FreeDer(&ssl->buffers.altKeyMask); - #endif - ssl->buffers.weOwnAltKey = 0; - } - ssl->buffers.altKey = NULL; -#ifdef WOLFSSL_BLIND_PRIVATE_KEY - ssl->buffers.altKeyMask = NULL; -#endif -#endif /* WOLFSSL_DUAL_ALG_CERTS */ -} -#endif - -#if defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || defined(WOLFSSL_HAPROXY) \ - || defined(WOLFSSL_NGINX) || defined(WOLFSSL_QT) - -long wolfSSL_ctrl(WOLFSSL* ssl, int cmd, long opt, void* pt) -{ - WOLFSSL_ENTER("wolfSSL_ctrl"); - if (ssl == NULL) - return BAD_FUNC_ARG; - - switch (cmd) { - #if defined(WOLFSSL_NGINX) || defined(WOLFSSL_QT) || \ - defined(OPENSSL_ALL) - #ifdef HAVE_SNI - case SSL_CTRL_SET_TLSEXT_HOSTNAME: - WOLFSSL_MSG("Entering Case: SSL_CTRL_SET_TLSEXT_HOSTNAME."); - if (pt == NULL) { - WOLFSSL_MSG("Passed in NULL Host Name."); - break; - } - return wolfSSL_set_tlsext_host_name(ssl, (const char*) pt); - #endif /* HAVE_SNI */ - #endif /* WOLFSSL_NGINX || WOLFSSL_QT || OPENSSL_ALL */ - default: - WOLFSSL_MSG("Case not implemented."); } - (void)opt; - (void)pt; - return WOLFSSL_FAILURE; -} - -long wolfSSL_CTX_ctrl(WOLFSSL_CTX* ctx, int cmd, long opt, void* pt) -{ -#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) - long ctrl_opt; -#endif - long ret = WOLFSSL_SUCCESS; - - WOLFSSL_ENTER("wolfSSL_CTX_ctrl"); - if (ctx == NULL) - return WOLFSSL_FAILURE; - - switch (cmd) { - case SSL_CTRL_CHAIN: -#ifdef SESSION_CERTS - { - /* - * We don't care about opt here because a copy of the certificate is - * stored anyway so increasing the reference counter is not necessary. - * Just check to make sure that it is set to one of the correct values. - */ - WOLF_STACK_OF(WOLFSSL_X509)* sk = (WOLF_STACK_OF(WOLFSSL_X509)*) pt; - WOLFSSL_X509* x509; - int i; - if (opt != 0 && opt != 1) { - ret = WOLFSSL_FAILURE; - break; - } - /* Clear certificate chain */ - FreeDer(&ctx->certChain); - if (sk) { - for (i = 0; i < wolfSSL_sk_X509_num(sk); i++) { - x509 = wolfSSL_sk_X509_value(sk, i); - /* Prevent wolfSSL_CTX_add_extra_chain_cert from freeing cert */ - if (wolfSSL_X509_up_ref(x509) != 1) { - WOLFSSL_MSG("Error increasing reference count"); - continue; - } - if (wolfSSL_CTX_add_extra_chain_cert(ctx, x509) != - WOLFSSL_SUCCESS) { - WOLFSSL_MSG("Error adding certificate to context"); - /* Decrease reference count on failure */ - wolfSSL_X509_free(x509); - x509 = NULL; - } - } - } - /* Free previous chain */ - wolfSSL_sk_X509_pop_free(ctx->x509Chain, NULL); - ctx->x509Chain = sk; - if (sk && opt == 1) { - /* up all refs when opt == 1 */ - for (i = 0; i < wolfSSL_sk_X509_num(sk); i++) { - x509 = wolfSSL_sk_X509_value(sk, i); - if (wolfSSL_X509_up_ref(x509) != 1) { - WOLFSSL_MSG("Error increasing reference count"); - continue; - } - } - } - } -#else - WOLFSSL_MSG("Session certificates not compiled in"); - ret = WOLFSSL_FAILURE; -#endif - break; - -#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) - case SSL_CTRL_OPTIONS: - WOLFSSL_MSG("Entering Case: SSL_CTRL_OPTIONS."); - ctrl_opt = wolfSSL_CTX_set_options(ctx, opt); - - #ifdef WOLFSSL_QT - /* Set whether to use client or server cipher preference */ - if ((ctrl_opt & WOLFSSL_OP_CIPHER_SERVER_PREFERENCE) - == WOLFSSL_OP_CIPHER_SERVER_PREFERENCE) { - WOLFSSL_MSG("Using Server's Cipher Preference."); - ctx->useClientOrder = 0; - } else { - WOLFSSL_MSG("Using Client's Cipher Preference."); - ctx->useClientOrder = 1; - } - #endif /* WOLFSSL_QT */ - - return ctrl_opt; -#endif /* OPENSSL_EXTRA || HAVE_WEBSERVER */ - case SSL_CTRL_EXTRA_CHAIN_CERT: - WOLFSSL_MSG("Entering Case: SSL_CTRL_EXTRA_CHAIN_CERT."); - if (pt == NULL) { - WOLFSSL_MSG("Passed in x509 pointer NULL."); - ret = WOLFSSL_FAILURE; - break; - } - return wolfSSL_CTX_add_extra_chain_cert(ctx, (WOLFSSL_X509*)pt); - -#ifndef NO_DH - case SSL_CTRL_SET_TMP_DH: - WOLFSSL_MSG("Entering Case: SSL_CTRL_SET_TMP_DH."); - if (pt == NULL) { - WOLFSSL_MSG("Passed in DH pointer NULL."); - ret = WOLFSSL_FAILURE; - break; - } - return wolfSSL_CTX_set_tmp_dh(ctx, (WOLFSSL_DH*)pt); -#endif - -#ifdef HAVE_ECC - case SSL_CTRL_SET_TMP_ECDH: - WOLFSSL_MSG("Entering Case: SSL_CTRL_SET_TMP_ECDH."); - if (pt == NULL) { - WOLFSSL_MSG("Passed in ECDH pointer NULL."); - ret = WOLFSSL_FAILURE; - break; - } - return wolfSSL_SSL_CTX_set_tmp_ecdh(ctx, (WOLFSSL_EC_KEY*)pt); -#endif - case SSL_CTRL_MODE: - wolfSSL_CTX_set_mode(ctx,opt); - break; - case SSL_CTRL_SET_MIN_PROTO_VERSION: - WOLFSSL_MSG("set min proto version"); - return wolfSSL_CTX_set_min_proto_version(ctx, (int)opt); - case SSL_CTRL_SET_MAX_PROTO_VERSION: - WOLFSSL_MSG("set max proto version"); - return wolfSSL_CTX_set_max_proto_version(ctx, (int)opt); - case SSL_CTRL_GET_MIN_PROTO_VERSION: - WOLFSSL_MSG("get min proto version"); - return wolfSSL_CTX_get_min_proto_version(ctx); - case SSL_CTRL_GET_MAX_PROTO_VERSION: - WOLFSSL_MSG("get max proto version"); - return wolfSSL_CTX_get_max_proto_version(ctx); - default: - WOLFSSL_MSG("CTX_ctrl cmd not implemented"); - ret = WOLFSSL_FAILURE; - break; - } - - (void)ctx; - (void)cmd; - (void)opt; - (void)pt; - WOLFSSL_LEAVE("wolfSSL_CTX_ctrl", (int)ret); - return ret; -} - -#ifndef NO_WOLFSSL_STUB -long wolfSSL_CTX_callback_ctrl(WOLFSSL_CTX* ctx, int cmd, void (*fp)(void)) -{ - (void) ctx; - (void) cmd; - (void) fp; - WOLFSSL_STUB("wolfSSL_CTX_callback_ctrl"); - return WOLFSSL_FAILURE; - -} -#endif /* NO_WOLFSSL_STUB */ - - -#endif /* OPENSSL_ALL || WOLFSSL_ASIO || WOLFSSL_HAPROXY || WOLFSSL_QT */ - - -/* stunnel compatibility functions*/ -#if defined(OPENSSL_ALL) || (defined(OPENSSL_EXTRA) && \ - (defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \ - defined(HAVE_LIGHTY) || defined(WOLFSSL_HAPROXY) || \ - defined(WOLFSSL_OPENSSH))) -void wolfSSL_ERR_remove_thread_state(void* pid) -{ - (void) pid; - return; -} - -#ifndef NO_FILESYSTEM -/***TBD ***/ -void wolfSSL_print_all_errors_fp(XFILE fp) -{ - (void)fp; -} -#endif /* !NO_FILESYSTEM */ - -#endif /* OPENSSL_ALL || OPENSSL_EXTRA || HAVE_STUNNEL || WOLFSSL_NGINX || - HAVE_LIGHTY || WOLFSSL_HAPROXY || WOLFSSL_OPENSSH */ - -/* Note: This is a huge section of API's - through - * wolfSSL_X509_OBJECT_get0_X509_CRL */ -#if defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) - -#if defined(USE_WOLFSSL_MEMORY) && !defined(WOLFSSL_DEBUG_MEMORY) && \ - !defined(WOLFSSL_STATIC_MEMORY) -static wolfSSL_OSSL_Malloc_cb ossl_malloc = NULL; -static wolfSSL_OSSL_Free_cb ossl_free = NULL; -static wolfSSL_OSSL_Realloc_cb ossl_realloc = NULL; - -static void* OSSL_Malloc(size_t size) -{ - if (ossl_malloc != NULL) - return ossl_malloc(size, NULL, 0); - else - return NULL; -} - -static void OSSL_Free(void *ptr) -{ - if (ossl_free != NULL) - ossl_free(ptr, NULL, 0); -} - -static void* OSSL_Realloc(void *ptr, size_t size) -{ - if (ossl_realloc != NULL) - return ossl_realloc(ptr, size, NULL, 0); - else - return NULL; -} -#endif /* USE_WOLFSSL_MEMORY && !WOLFSSL_DEBUG_MEMORY && - * !WOLFSSL_STATIC_MEMORY */ - -int wolfSSL_CRYPTO_set_mem_functions( - wolfSSL_OSSL_Malloc_cb m, - wolfSSL_OSSL_Realloc_cb r, - wolfSSL_OSSL_Free_cb f) -{ -#if defined(USE_WOLFSSL_MEMORY) && !defined(WOLFSSL_STATIC_MEMORY) -#ifdef WOLFSSL_DEBUG_MEMORY - WOLFSSL_MSG("mem functions will receive function name instead of " - "file name"); - if (wolfSSL_SetAllocators((wolfSSL_Malloc_cb)m, (wolfSSL_Free_cb)f, - (wolfSSL_Realloc_cb)r) == 0) - return WOLFSSL_SUCCESS; -#else - WOLFSSL_MSG("wolfSSL was compiled without WOLFSSL_DEBUG_MEMORY mem " - "functions will receive a NULL file name and 0 for the " - "line number."); - if (wolfSSL_SetAllocators((wolfSSL_Malloc_cb)OSSL_Malloc, - (wolfSSL_Free_cb)OSSL_Free, (wolfSSL_Realloc_cb)OSSL_Realloc) == 0) { - ossl_malloc = m; - ossl_free = f; - ossl_realloc = r; - return WOLFSSL_SUCCESS; - } -#endif - else - return WOLFSSL_FAILURE; -#else - (void)m; - (void)r; - (void)f; - WOLFSSL_MSG("wolfSSL allocator callback functions not compiled in"); - return WOLFSSL_FAILURE; -#endif -} - -int wolfSSL_ERR_load_ERR_strings(void) -{ - return WOLFSSL_SUCCESS; -} - -void wolfSSL_ERR_load_crypto_strings(void) -{ - WOLFSSL_ENTER("wolfSSL_ERR_load_crypto_strings"); - /* Do nothing */ - return; -} - -int wolfSSL_FIPS_mode(void) -{ -#ifdef HAVE_FIPS - return 1; -#else - return 0; -#endif -} - -int wolfSSL_FIPS_mode_set(int r) -{ -#ifdef HAVE_FIPS - if (r == 0) { - WOLFSSL_MSG("Cannot disable FIPS at runtime."); - return WOLFSSL_FAILURE; - } - return WOLFSSL_SUCCESS; -#else - if (r == 0) { - return WOLFSSL_SUCCESS; - } - WOLFSSL_MSG("Cannot enable FIPS. This isn't the wolfSSL FIPS code."); - return WOLFSSL_FAILURE; -#endif -} - -int wolfSSL_CIPHER_get_bits(const WOLFSSL_CIPHER *c, int *alg_bits) -{ - int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); - WOLFSSL_ENTER("wolfSSL_CIPHER_get_bits"); - - #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) - (void)alg_bits; - if (c!= NULL) - ret = c->bits; - #else - if (c != NULL && c->ssl != NULL) { - ret = 8 * c->ssl->specs.key_size; - if (alg_bits != NULL) { - *alg_bits = ret; - } - } - #endif - return ret; -} - - -WOLFSSL_CTX* wolfSSL_set_SSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx) -{ - int ret; - /* This method requires some explanation. Its sibling is - * int SetSSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup) - * which re-inits the WOLFSSL* with all settings in the new CTX. - * That one is the right one to use *before* a handshake is started. - * - * This method was added by OpenSSL to be used *during* the handshake, e.g. - * when a server inspects the SNI in a ClientHello callback and - * decides which set of certificates to use. - * - * Since, at the time the SNI callback is run, some decisions on - * Extensions or the ServerHello might already have been taken, this - * method is very restricted in what it does: - * - changing the server certificate(s) - * - changing the server id for session handling - * and everything else in WOLFSSL* needs to remain untouched. - * - * SECURITY: swapping ssl->ctx switches cm-resolved settings (CA store, - * CRL, OCSP) to the new CTX but leaves ssl-cached ones (verify mode and - * callback, minDowngrade, key-size minimums, suites, version bounds) - * pinned to the original. SNI callbacks must re-apply those ssl-level - * settings explicitly; CRL/OCSP isolation requires an SSL-local store. - */ - WOLFSSL_ENTER("wolfSSL_set_SSL_CTX"); - if (ssl == NULL || ctx == NULL) - return NULL; - if (ssl->ctx == ctx) - return ssl->ctx; - - if (ctx->suites == NULL) { - /* suites */ - if (AllocateCtxSuites(ctx) != 0) - return NULL; - InitSSL_CTX_Suites(ctx); - } - - wolfSSL_RefWithMutexInc(&ctx->ref, &ret); -#ifdef WOLFSSL_REFCNT_ERROR_RETURN - if (ret != 0) { - /* can only fail on serious stuff, like mutex not working - * or ctx refcount out of whack. */ - return NULL; - } -#else - (void)ret; -#endif - if (ssl->ctx != NULL) - wolfSSL_CTX_free(ssl->ctx); - ssl->ctx = ctx; - -#ifndef NO_CERTS -#ifdef WOLFSSL_COPY_CERT - /* If WOLFSSL_COPY_CERT defined, always make new copy of cert from ctx */ - if (ctx->certificate != NULL) { - if (ssl->buffers.certificate != NULL) { - FreeDer(&ssl->buffers.certificate); - ssl->buffers.certificate = NULL; - } - ret = AllocCopyDer(&ssl->buffers.certificate, ctx->certificate->buffer, - ctx->certificate->length, ctx->certificate->type, - ctx->certificate->heap); - if (ret != 0) { - ssl->buffers.weOwnCert = 0; - return NULL; - } - - ssl->buffers.weOwnCert = 1; - } - if (ctx->certChain != NULL) { - if (ssl->buffers.certChain != NULL) { - FreeDer(&ssl->buffers.certChain); - ssl->buffers.certChain = NULL; - } - ret = AllocCopyDer(&ssl->buffers.certChain, ctx->certChain->buffer, - ctx->certChain->length, ctx->certChain->type, - ctx->certChain->heap); - if (ret != 0) { - ssl->buffers.weOwnCertChain = 0; - return NULL; - } - - ssl->buffers.weOwnCertChain = 1; - } -#else - /* ctx owns certificate, certChain and key */ - ssl->buffers.certificate = ctx->certificate; - ssl->buffers.certChain = ctx->certChain; -#endif -#ifdef WOLFSSL_TLS13 - ssl->buffers.certChainCnt = ctx->certChainCnt; -#endif -#ifndef WOLFSSL_BLIND_PRIVATE_KEY -#ifdef WOLFSSL_COPY_KEY - if (ssl->buffers.key != NULL && ssl->buffers.weOwnKey) { - FreeDer(&ssl->buffers.key); - } - if (ctx->privateKey != NULL) { - ret = AllocCopyDer(&ssl->buffers.key, ctx->privateKey->buffer, - ctx->privateKey->length, ctx->privateKey->type, - ctx->privateKey->heap); - if (ret != 0) { - ssl->buffers.weOwnKey = 0; - return NULL; - } - ssl->buffers.weOwnKey = 1; - } - else { - ssl->buffers.key = ctx->privateKey; - } -#else - ssl->buffers.key = ctx->privateKey; -#endif -#else - if (ctx->privateKey != NULL) { - if (ssl->buffers.key != NULL && ssl->buffers.weOwnKey) { - FreeDer(&ssl->buffers.key); - } - ret = AllocCopyDer(&ssl->buffers.key, ctx->privateKey->buffer, - ctx->privateKey->length, ctx->privateKey->type, - ctx->privateKey->heap); - if (ret != 0) { - return NULL; - } - /* Blind the private key for the SSL with new random mask. */ - wolfssl_priv_der_blind_toggle(ssl->buffers.key, ctx->privateKeyMask); - ret = wolfssl_priv_der_blind(ssl->rng, ssl->buffers.key, - &ssl->buffers.keyMask); - if (ret != 0) { - return NULL; - } - } -#endif - ssl->buffers.keyType = ctx->privateKeyType; - ssl->buffers.keyId = ctx->privateKeyId; - ssl->buffers.keyLabel = ctx->privateKeyLabel; - ssl->buffers.keySz = ctx->privateKeySz; - ssl->buffers.keyDevId = ctx->privateKeyDevId; - /* flags indicating what certs/keys are available */ - ssl->options.haveRSA = ctx->haveRSA; - ssl->options.haveDH = ctx->haveDH; - ssl->options.haveECDSAsig = ctx->haveECDSAsig; - ssl->options.haveECC = ctx->haveECC; - ssl->options.haveStaticECC = ctx->haveStaticECC; - ssl->options.haveFalconSig = ctx->haveFalconSig; - ssl->options.haveMlDsaSig = ctx->haveMlDsaSig; -#ifdef WOLFSSL_DUAL_ALG_CERTS -#ifndef WOLFSSL_BLIND_PRIVATE_KEY - ssl->buffers.altKey = ctx->altPrivateKey; -#else - if (ctx->altPrivateKey != NULL) { - ret = AllocCopyDer(&ssl->buffers.altKey, ctx->altPrivateKey->buffer, - ctx->altPrivateKey->length, ctx->altPrivateKey->type, - ctx->altPrivateKey->heap); - if (ret != 0) { - return NULL; - } - /* Blind the private key for the SSL with new random mask. */ - wolfssl_priv_der_blind_toggle(ssl->buffers.altKey, - ctx->altPrivateKeyMask); - ret = wolfssl_priv_der_blind(ssl->rng, ssl->buffers.altKey, - &ssl->buffers.altKeyMask); - if (ret != 0) { - return NULL; - } - } -#endif - ssl->buffers.altKeySz = ctx->altPrivateKeySz; - ssl->buffers.altKeyType = ctx->altPrivateKeyType; -#endif /* WOLFSSL_DUAL_ALG_CERTS */ -#endif - -#ifdef WOLFSSL_SESSION_ID_CTX - /* copy over application session context ID */ - ssl->sessionCtxSz = ctx->sessionCtxSz; - XMEMCPY(ssl->sessionCtx, ctx->sessionCtx, ctx->sessionCtxSz); -#endif - - return ssl->ctx; -} - - -#ifndef NO_BIO -void wolfSSL_ERR_load_BIO_strings(void) { - WOLFSSL_ENTER("wolfSSL_ERR_load_BIO_strings"); - /* do nothing */ -} -#endif - -#ifndef NO_WOLFSSL_STUB -/* Set THREADID callback, return 1 on success, 0 on error */ -int wolfSSL_THREADID_set_callback( - void(*threadid_func)(WOLFSSL_CRYPTO_THREADID*)) -{ - WOLFSSL_ENTER("wolfSSL_THREADID_set_callback"); - WOLFSSL_STUB("CRYPTO_THREADID_set_callback"); - (void)threadid_func; - return 1; -} -#endif - -#ifndef NO_WOLFSSL_STUB -void wolfSSL_THREADID_set_numeric(void* id, unsigned long val) -{ - WOLFSSL_ENTER("wolfSSL_THREADID_set_numeric"); - WOLFSSL_STUB("CRYPTO_THREADID_set_numeric"); - (void)id; - (void)val; - return; -} -#endif - -#endif /* OPENSSL_ALL || OPENSSL_EXTRA */ - - -#if defined(OPENSSL_EXTRA) - -int wolfSSL_CRYPTO_memcmp(const void *a, const void *b, size_t size) -{ - int ret = 0; - int chunk; - const byte* pa = (const byte*)a; - const byte* pb = (const byte*)b; - - if (!a || !b) - return -1; - /* ConstantCompare takes an int length. Compare in chunks of at most - * INT_MAX so a size that does not fit in an int is not narrowed into a - * negative or truncated length, which could wrongly report equality. */ - while (size > 0) { - chunk = (size > (size_t)INT_MAX) ? INT_MAX : (int)size; - ret |= ConstantCompare(pa, pb, chunk); - pa += chunk; - pb += chunk; - size -= (size_t)chunk; - } - return ret; -} - -unsigned long wolfSSL_ERR_peek_last_error(void) -{ - WOLFSSL_ENTER("wolfSSL_ERR_peek_last_error"); - -#ifdef WOLFSSL_HAVE_ERROR_QUEUE - { - int ret; - - if ((ret = wc_PeekErrorNode(-1, NULL, NULL, NULL)) < 0) { - WOLFSSL_MSG("Issue peeking at error node in queue"); - return 0; - } - if (ret == -WC_NO_ERR_TRACE(ASN_NO_PEM_HEADER)) - return (WOLFSSL_ERR_LIB_PEM << 24) | -WC_NO_ERR_TRACE(WOLFSSL_PEM_R_NO_START_LINE_E); - #if defined(WOLFSSL_PYTHON) - if (ret == ASN1_R_HEADER_TOO_LONG) - return (WOLFSSL_ERR_LIB_ASN1 << 24) | -WC_NO_ERR_TRACE(WOLFSSL_ASN1_R_HEADER_TOO_LONG_E); - #endif - return (unsigned long)ret; - } -#else - return (unsigned long)(0 - NOT_COMPILED_IN); -#endif -} - -#endif /* OPENSSL_EXTRA */ - -int wolfSSL_version(WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_version"); - if (ssl->version.major == SSLv3_MAJOR) { - switch (ssl->version.minor) { - case SSLv3_MINOR : - return SSL3_VERSION; - case TLSv1_MINOR : - return TLS1_VERSION; - case TLSv1_1_MINOR : - return TLS1_1_VERSION; - case TLSv1_2_MINOR : - return TLS1_2_VERSION; - case TLSv1_3_MINOR : - return TLS1_3_VERSION; - default: - return WOLFSSL_FAILURE; - } - } - else if (ssl->version.major == DTLS_MAJOR) { - switch (ssl->version.minor) { - case DTLS_MINOR : - return DTLS1_VERSION; - case DTLSv1_2_MINOR : - return DTLS1_2_VERSION; - case DTLSv1_3_MINOR: - return DTLS1_3_VERSION; - default: - return WOLFSSL_FAILURE; - } - } - return WOLFSSL_FAILURE; -} - -WOLFSSL_CTX* wolfSSL_get_SSL_CTX(const WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_get_SSL_CTX"); - return ssl->ctx; -} - - -#ifdef WOLFSSL_JNI - -int wolfSSL_set_jobject(WOLFSSL* ssl, void* objPtr) -{ - WOLFSSL_ENTER("wolfSSL_set_jobject"); - if (ssl != NULL) - { - ssl->jObjectRef = objPtr; - return WOLFSSL_SUCCESS; - } - return WOLFSSL_FAILURE; -} - -void* wolfSSL_get_jobject(WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_get_jobject"); - if (ssl != NULL) - return ssl->jObjectRef; - return NULL; -} - -#endif /* WOLFSSL_JNI */ - - -#ifdef WOLFSSL_ASYNC_CRYPT -int wolfSSL_CTX_AsyncPoll(WOLFSSL_CTX* ctx, WOLF_EVENT** events, int maxEvents, - WOLF_EVENT_FLAG flags, int* eventCount) -{ - if (ctx == NULL) { - return BAD_FUNC_ARG; - } - - return wolfAsync_EventQueuePoll(&ctx->event_queue, NULL, - events, maxEvents, flags, eventCount); -} - -int wolfSSL_AsyncPoll(WOLFSSL* ssl, WOLF_EVENT_FLAG flags) -{ - int ret, eventCount = 0; - WOLF_EVENT* events[1]; - - if (ssl == NULL) { - return BAD_FUNC_ARG; - } - - ret = wolfAsync_EventQueuePoll(&ssl->ctx->event_queue, ssl, - events, sizeof(events)/sizeof(events[0]), flags, &eventCount); - if (ret == 0) { - ret = eventCount; - } - - return ret; -} -#endif /* WOLFSSL_ASYNC_CRYPT */ - -#ifdef OPENSSL_EXTRA - -static int peek_ignore_err(int err) -{ - switch(err) { - case -WC_NO_ERR_TRACE(WANT_READ): - case -WC_NO_ERR_TRACE(WANT_WRITE): - case -WC_NO_ERR_TRACE(ZERO_RETURN): - case -WOLFSSL_ERROR_ZERO_RETURN: - case -WC_NO_ERR_TRACE(SOCKET_PEER_CLOSED_E): - case -WC_NO_ERR_TRACE(SOCKET_ERROR_E): - return 1; - default: - return 0; - } -} - -unsigned long wolfSSL_ERR_peek_error_line_data(const char **file, int *line, - const char **data, int *flags) -{ - unsigned long err; - - WOLFSSL_ENTER("wolfSSL_ERR_peek_error_line_data"); - err = wc_PeekErrorNodeLineData(file, line, data, flags, peek_ignore_err); - - if (err == -WC_NO_ERR_TRACE(ASN_NO_PEM_HEADER)) - return (WOLFSSL_ERR_LIB_PEM << 24) | -WC_NO_ERR_TRACE(WOLFSSL_PEM_R_NO_START_LINE_E); -#ifdef OPENSSL_ALL - /* PARSE_ERROR is returned if an HTTP request is detected. */ - else if (err == -WC_NO_ERR_TRACE(PARSE_ERROR)) - return (WOLFSSL_ERR_LIB_SSL << 24) | -WC_NO_ERR_TRACE(PARSE_ERROR) /* SSL_R_HTTP_REQUEST */; -#endif -#if defined(OPENSSL_ALL) && defined(WOLFSSL_PYTHON) - else if (err == ASN1_R_HEADER_TOO_LONG) - return (WOLFSSL_ERR_LIB_ASN1 << 24) | -WC_NO_ERR_TRACE(WOLFSSL_ASN1_R_HEADER_TOO_LONG_E); -#endif - return err; -} -#endif - -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) || \ - defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) - -#if !defined(WOLFSSL_USER_IO) -/* converts an IPv6 or IPv4 address into an octet string for use with rfc3280 - * example input would be "127.0.0.1" and the returned value would be 7F000001 - */ -WOLFSSL_ASN1_STRING* wolfSSL_a2i_IPADDRESS(const char* ipa) -{ - int ipaSz = WOLFSSL_IP4_ADDR_LEN; - char buf[WOLFSSL_IP6_ADDR_LEN + 1]; /* plus 1 for terminator */ - int af = WOLFSSL_IP4; - WOLFSSL_ASN1_STRING *ret = NULL; - - if (ipa == NULL) - return NULL; - - if (XSTRSTR(ipa, ":") != NULL) { - af = WOLFSSL_IP6; - ipaSz = WOLFSSL_IP6_ADDR_LEN; - } - - buf[WOLFSSL_IP6_ADDR_LEN] = '\0'; -#ifdef FREESCALE_MQX - if (XINET_PTON(af, ipa, (void*)buf, sizeof(buf)) != RTCS_OK) { -#else - if (XINET_PTON(af, ipa, (void*)buf) != 1) { -#endif - WOLFSSL_MSG("Error parsing IP address"); - return NULL; - } - - ret = wolfSSL_ASN1_STRING_new(); - if (ret != NULL) { - if (wolfSSL_ASN1_STRING_set(ret, buf, ipaSz) != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("Error setting the string"); - wolfSSL_ASN1_STRING_free(ret); - ret = NULL; - } - } - - return ret; -} -#endif /* !WOLFSSL_USER_IO */ - -/* Is the specified cipher suite a fake one used an an extension proxy? */ -static WC_INLINE int SCSV_Check(byte suite0, byte suite) -{ - (void)suite0; - (void)suite; -#ifdef HAVE_RENEGOTIATION_INDICATION - if (suite0 == CIPHER_BYTE && suite == TLS_EMPTY_RENEGOTIATION_INFO_SCSV) - return 1; -#endif - return 0; -} - -static WC_INLINE int sslCipherMinMaxCheck(const WOLFSSL *ssl, byte suite0, - byte suite) -{ - const CipherSuiteInfo* cipher_names = GetCipherNames(); - int cipherSz = GetCipherNamesSize(); - int i; - for (i = 0; i < cipherSz; i++) - if (cipher_names[i].cipherSuite0 == suite0 && - cipher_names[i].cipherSuite == suite) - break; - if (i == cipherSz) - return 1; - /* Check min version */ - if (cipher_names[i].minor < ssl->options.minDowngrade) { - if (ssl->options.minDowngrade <= TLSv1_2_MINOR && - cipher_names[i].minor >= TLSv1_MINOR) - /* 1.0 ciphersuites are in general available in 1.1 and - * 1.1 ciphersuites are in general available in 1.2 */ - return 0; - return 1; - } - /* Check max version */ - switch (cipher_names[i].minor) { - case SSLv3_MINOR : - return ssl->options.mask & WOLFSSL_OP_NO_SSLv3; - case TLSv1_MINOR : - return ssl->options.mask & WOLFSSL_OP_NO_TLSv1; - case TLSv1_1_MINOR : - return ssl->options.mask & WOLFSSL_OP_NO_TLSv1_1; - case TLSv1_2_MINOR : - return ssl->options.mask & WOLFSSL_OP_NO_TLSv1_2; - case TLSv1_3_MINOR : - return ssl->options.mask & WOLFSSL_OP_NO_TLSv1_3; - default: - WOLFSSL_MSG("Unrecognized minor version"); - return 1; - } -} - -/* returns a pointer to internal cipher suite list. Should not be free'd by - * caller. - */ -WOLF_STACK_OF(WOLFSSL_CIPHER) *wolfSSL_get_ciphers_compat(const WOLFSSL *ssl) -{ - const Suites* suites; -#if defined(OPENSSL_ALL) - const CipherSuiteInfo* cipher_names = GetCipherNames(); - int cipherSz = GetCipherNamesSize(); -#endif - - WOLFSSL_ENTER("wolfSSL_get_ciphers_compat"); - if (ssl == NULL) - return NULL; - - suites = WOLFSSL_SUITES(ssl); - if (suites == NULL) - return NULL; - - /* check if stack needs populated */ - if (ssl->suitesStack == NULL) { - int i; - - ((WOLFSSL*)ssl)->suitesStack = - wolfssl_sk_new_type_ex(STACK_TYPE_CIPHER, ssl->heap); - if (ssl->suitesStack == NULL) - return NULL; - - /* higher priority of cipher suite will be on top of stack */ -#if defined(OPENSSL_ALL) - for (i = suites->suiteSz - 2; i >=0; i-=2) -#else - for (i = 0; i < suites->suiteSz; i+=2) -#endif - { - struct WOLFSSL_CIPHER cipher; - - /* A couple of suites are placeholders for special options, - * skip those. */ - if (SCSV_Check(suites->suites[i], suites->suites[i+1]) - || sslCipherMinMaxCheck(ssl, suites->suites[i], - suites->suites[i+1])) { - continue; - } - - XMEMSET(&cipher, 0, sizeof(cipher)); - cipher.cipherSuite0 = suites->suites[i]; - cipher.cipherSuite = suites->suites[i+1]; - cipher.ssl = ssl; -#if defined(OPENSSL_ALL) - cipher.in_stack = 1; - { - int j; - for (j = 0; j < cipherSz; j++) { - if (cipher_names[j].cipherSuite0 == cipher.cipherSuite0 && - cipher_names[j].cipherSuite == cipher.cipherSuite) { - cipher.offset = (unsigned long)j; - break; - } - } - } -#endif - if (wolfSSL_sk_insert(ssl->suitesStack, &cipher, 0) <= 0) { - WOLFSSL_MSG("Error inserting cipher onto stack"); - wolfSSL_sk_CIPHER_free(ssl->suitesStack); - ((WOLFSSL*)ssl)->suitesStack = NULL; - break; - } - } - - /* If no ciphers were added, free empty stack and return NULL */ - if (ssl->suitesStack != NULL && wolfSSL_sk_num(ssl->suitesStack) == 0) { - wolfSSL_sk_CIPHER_free(ssl->suitesStack); - ((WOLFSSL*)ssl)->suitesStack = NULL; - } - } - return ssl->suitesStack; -} -#endif /* OPENSSL_EXTRA || OPENSSL_ALL || WOLFSSL_NGINX || WOLFSSL_HAPROXY */ -#ifdef OPENSSL_ALL -/* returned pointer is to an internal element in WOLFSSL struct and should not - * be free'd. It gets free'd when the WOLFSSL struct is free'd. */ -WOLF_STACK_OF(WOLFSSL_CIPHER)* wolfSSL_get_client_ciphers(WOLFSSL* ssl) -{ - WOLF_STACK_OF(WOLFSSL_CIPHER)* ret = NULL; - const CipherSuiteInfo* cipher_names = GetCipherNames(); - int cipherSz = GetCipherNamesSize(); - const Suites* suites; - - WOLFSSL_ENTER("wolfSSL_get_client_ciphers"); - - if (ssl == NULL) { - return NULL; - } - - /* return NULL if is client side */ - if (wolfSSL_is_server(ssl) == 0) { - return NULL; - } - - suites = ssl->clSuites; - if (suites == NULL) { - WOLFSSL_MSG("No client suites stored"); - } - else if (ssl->clSuitesStack != NULL) { - ret = ssl->clSuitesStack; - } - else { /* generate cipher suites stack if not already done */ - int i; - int j; - - ret = wolfSSL_sk_new_node(ssl->heap); - if (ret != NULL) { - ret->type = STACK_TYPE_CIPHER; - - /* higher priority of cipher suite will be on top of stack */ - for (i = suites->suiteSz - 2; i >= 0; i -= 2) { - WOLFSSL_CIPHER cipher; - - /* A couple of suites are placeholders for special options, - * skip those. */ - if (SCSV_Check(suites->suites[i], suites->suites[i+1]) - || sslCipherMinMaxCheck(ssl, suites->suites[i], - suites->suites[i+1])) { - continue; - } - - cipher.cipherSuite0 = suites->suites[i]; - cipher.cipherSuite = suites->suites[i+1]; - cipher.ssl = ssl; - for (j = 0; j < cipherSz; j++) { - if (cipher_names[j].cipherSuite0 == - cipher.cipherSuite0 && - cipher_names[j].cipherSuite == - cipher.cipherSuite) { - cipher.offset = (unsigned long)j; - break; - } - } - - /* in_stack is checked in wolfSSL_CIPHER_description */ - cipher.in_stack = 1; - - if (wolfSSL_sk_CIPHER_push(ret, &cipher) <= 0) { - WOLFSSL_MSG("Error pushing client cipher onto stack"); - wolfSSL_sk_CIPHER_free(ret); - ret = NULL; - break; - } - } - } - ssl->clSuitesStack = ret; - } - return ret; -} -#endif /* OPENSSL_ALL */ - -#if defined(OPENSSL_EXTRA) || defined(HAVE_SECRET_CALLBACK) -long wolfSSL_SSL_CTX_get_timeout(const WOLFSSL_CTX *ctx) -{ - WOLFSSL_ENTER("wolfSSL_SSL_CTX_get_timeout"); - - if (ctx == NULL) - return 0; - - return ctx->timeout; -} - - -/* returns the time in seconds of the current timeout */ -long wolfSSL_get_timeout(WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_get_timeout"); - - if (ssl == NULL) - return 0; - return ssl->timeout; -} -#endif - -#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) \ - || defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) - -#ifndef NO_BIO -WOLFSSL_BIO *wolfSSL_SSL_get_rbio(const WOLFSSL *s) -{ - WOLFSSL_ENTER("wolfSSL_SSL_get_rbio"); - /* Nginx sets the buffer size if the read BIO is different to write BIO. - * The setting buffer size doesn't do anything so return NULL for both. - */ - if (s == NULL) - return NULL; - - return s->biord; -} -WOLFSSL_BIO *wolfSSL_SSL_get_wbio(const WOLFSSL *s) -{ - WOLFSSL_ENTER("wolfSSL_SSL_get_wbio"); - (void)s; - /* Nginx sets the buffer size if the read BIO is different to write BIO. - * The setting buffer size doesn't do anything so return NULL for both. - */ - if (s == NULL) - return NULL; - - return s->biowr; -} -#endif /* !NO_BIO */ - -#ifndef NO_TLS -int wolfSSL_SSL_do_handshake_internal(WOLFSSL *s) -{ - WOLFSSL_ENTER("wolfSSL_SSL_do_handshake_internal"); - if (s == NULL) - return WOLFSSL_FAILURE; - - if (s->options.side == WOLFSSL_CLIENT_END) { - #ifndef NO_WOLFSSL_CLIENT - return wolfSSL_connect(s); - #else - WOLFSSL_MSG("Client not compiled in"); - return WOLFSSL_FAILURE; - #endif - } - -#ifndef NO_WOLFSSL_SERVER - return wolfSSL_accept(s); -#else - WOLFSSL_MSG("Server not compiled in"); - return WOLFSSL_FAILURE; -#endif -} - -int wolfSSL_SSL_do_handshake(WOLFSSL *s) -{ - WOLFSSL_ENTER("wolfSSL_SSL_do_handshake"); -#ifdef WOLFSSL_QUIC - if (WOLFSSL_IS_QUIC(s)) { - return wolfSSL_quic_do_handshake(s); - } -#endif - return wolfSSL_SSL_do_handshake_internal(s); -} -#endif /* !NO_TLS */ - -#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L -int wolfSSL_SSL_in_init(const WOLFSSL *ssl) -#else -int wolfSSL_SSL_in_init(WOLFSSL *ssl) -#endif -{ - WOLFSSL_ENTER("wolfSSL_SSL_in_init"); - - return !wolfSSL_is_init_finished(ssl); -} - -int wolfSSL_SSL_in_before(const WOLFSSL *ssl) -{ - WOLFSSL_ENTER("wolfSSL_SSL_in_before"); - - if (ssl == NULL) - return WOLFSSL_FAILURE; - - return ssl->options.handShakeState == NULL_STATE; -} - -int wolfSSL_SSL_in_connect_init(WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_SSL_in_connect_init"); - - if (ssl == NULL) - return WOLFSSL_FAILURE; - - if (ssl->options.side == WOLFSSL_CLIENT_END) { - return ssl->options.connectState > CONNECT_BEGIN && - ssl->options.connectState < SECOND_REPLY_DONE; - } - - return ssl->options.acceptState > ACCEPT_BEGIN && - ssl->options.acceptState < ACCEPT_THIRD_REPLY_DONE; -} - - -#endif /* OPENSSL_ALL || WOLFSSL_NGINX || WOLFSSL_HAPROXY || - OPENSSL_EXTRA || HAVE_LIGHTY */ - - -#if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || \ - defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) - - -void wolfSSL_WOLFSSL_STRING_free(WOLFSSL_STRING s) -{ - WOLFSSL_ENTER("wolfSSL_WOLFSSL_STRING_free"); - - XFREE(s, NULL, DYNAMIC_TYPE_OPENSSL); -} - -#endif /* WOLFSSL_NGINX || WOLFSSL_HAPROXY || OPENSSL_EXTRA || OPENSSL_ALL */ - - -#if defined(OPENSSL_EXTRA) || defined(HAVE_CURL) - -#if (defined(HAVE_ECC) || \ - defined(HAVE_CURVE25519) || defined(HAVE_CURVE448)) -#define CURVE_NAME(c) XSTR_SIZEOF((c)), (c) - -const WOLF_EC_NIST_NAME kNistCurves[] = { -#ifdef HAVE_ECC - {CURVE_NAME("P-160"), WC_NID_secp160r1, WOLFSSL_ECC_SECP160R1}, - {CURVE_NAME("P-160-2"), WC_NID_secp160r2, WOLFSSL_ECC_SECP160R2}, - {CURVE_NAME("P-192"), WC_NID_X9_62_prime192v1, WOLFSSL_ECC_SECP192R1}, - {CURVE_NAME("P-224"), WC_NID_secp224r1, WOLFSSL_ECC_SECP224R1}, - {CURVE_NAME("P-256"), WC_NID_X9_62_prime256v1, WOLFSSL_ECC_SECP256R1}, - {CURVE_NAME("P-384"), WC_NID_secp384r1, WOLFSSL_ECC_SECP384R1}, - {CURVE_NAME("P-521"), WC_NID_secp521r1, WOLFSSL_ECC_SECP521R1}, - {CURVE_NAME("K-160"), WC_NID_secp160k1, WOLFSSL_ECC_SECP160K1}, - {CURVE_NAME("K-192"), WC_NID_secp192k1, WOLFSSL_ECC_SECP192K1}, - {CURVE_NAME("K-224"), WC_NID_secp224k1, WOLFSSL_ECC_SECP224K1}, - {CURVE_NAME("K-256"), WC_NID_secp256k1, WOLFSSL_ECC_SECP256K1}, - {CURVE_NAME("B-256"), WC_NID_brainpoolP256r1, - WOLFSSL_ECC_BRAINPOOLP256R1}, - {CURVE_NAME("B-384"), WC_NID_brainpoolP384r1, - WOLFSSL_ECC_BRAINPOOLP384R1}, - {CURVE_NAME("B-512"), WC_NID_brainpoolP512r1, - WOLFSSL_ECC_BRAINPOOLP512R1}, -#endif -#ifdef HAVE_CURVE25519 - {CURVE_NAME("X25519"), WC_NID_X25519, WOLFSSL_ECC_X25519}, -#endif -#ifdef HAVE_CURVE448 - {CURVE_NAME("X448"), WC_NID_X448, WOLFSSL_ECC_X448}, -#endif -#ifdef WOLFSSL_HAVE_MLKEM -#ifndef WOLFSSL_NO_ML_KEM - {CURVE_NAME("ML_KEM_512"), WOLFSSL_ML_KEM_512, WOLFSSL_ML_KEM_512}, - {CURVE_NAME("ML_KEM_768"), WOLFSSL_ML_KEM_768, WOLFSSL_ML_KEM_768}, - {CURVE_NAME("ML_KEM_1024"), WOLFSSL_ML_KEM_1024, WOLFSSL_ML_KEM_1024}, - /* Aliases accepting the OpenSSL/IANA spelling without underscores. */ - {CURVE_NAME("MLKEM512"), WOLFSSL_ML_KEM_512, WOLFSSL_ML_KEM_512}, - {CURVE_NAME("MLKEM768"), WOLFSSL_ML_KEM_768, WOLFSSL_ML_KEM_768}, - {CURVE_NAME("MLKEM1024"), WOLFSSL_ML_KEM_1024, WOLFSSL_ML_KEM_1024}, -#if defined(HAVE_ECC) - #ifdef WOLFSSL_PQC_HYBRIDS - {CURVE_NAME("SecP256r1MLKEM768"), WOLFSSL_SECP256R1MLKEM768, - WOLFSSL_SECP256R1MLKEM768}, - {CURVE_NAME("SecP384r1MLKEM1024"), WOLFSSL_SECP384R1MLKEM1024, - WOLFSSL_SECP384R1MLKEM1024}, - {CURVE_NAME("X25519MLKEM768"), WOLFSSL_X25519MLKEM768, - WOLFSSL_X25519MLKEM768}, - #endif /* WOLFSSL_PQC_HYBRIDS */ - #ifdef WOLFSSL_EXTRA_PQC_HYBRIDS - {CURVE_NAME("SecP256r1MLKEM512"), WOLFSSL_SECP256R1MLKEM512, - WOLFSSL_SECP256R1MLKEM512}, - {CURVE_NAME("SecP384r1MLKEM768"), WOLFSSL_SECP384R1MLKEM768, - WOLFSSL_SECP384R1MLKEM768}, - {CURVE_NAME("SecP521r1MLKEM1024"), WOLFSSL_SECP521R1MLKEM1024, - WOLFSSL_SECP521R1MLKEM1024}, - {CURVE_NAME("X25519MLKEM512"), WOLFSSL_X25519MLKEM512, - WOLFSSL_X25519MLKEM512}, - {CURVE_NAME("X448MLKEM768"), WOLFSSL_X448MLKEM768, - WOLFSSL_X448MLKEM768}, - #endif /* WOLFSSL_EXTRA_PQC_HYBRIDS */ -#endif -#endif /* !WOLFSSL_NO_ML_KEM */ -#ifdef WOLFSSL_MLKEM_KYBER - {CURVE_NAME("KYBER_LEVEL1"), WOLFSSL_KYBER_LEVEL1, WOLFSSL_KYBER_LEVEL1}, - {CURVE_NAME("KYBER_LEVEL3"), WOLFSSL_KYBER_LEVEL3, WOLFSSL_KYBER_LEVEL3}, - {CURVE_NAME("KYBER_LEVEL5"), WOLFSSL_KYBER_LEVEL5, WOLFSSL_KYBER_LEVEL5}, -#if defined(HAVE_ECC) - {CURVE_NAME("P256_KYBER_LEVEL1"), WOLFSSL_P256_KYBER_LEVEL1, - WOLFSSL_P256_KYBER_LEVEL1}, - {CURVE_NAME("P384_KYBER_LEVEL3"), WOLFSSL_P384_KYBER_LEVEL3, - WOLFSSL_P384_KYBER_LEVEL3}, - {CURVE_NAME("P256_KYBER_LEVEL3"), WOLFSSL_P256_KYBER_LEVEL3, - WOLFSSL_P256_KYBER_LEVEL3}, - {CURVE_NAME("P521_KYBER_LEVEL5"), WOLFSSL_P521_KYBER_LEVEL5, - WOLFSSL_P521_KYBER_LEVEL5}, - {CURVE_NAME("X25519_KYBER_LEVEL1"), WOLFSSL_X25519_KYBER_LEVEL1, - WOLFSSL_X25519_KYBER_LEVEL1}, - {CURVE_NAME("X448_KYBER_LEVEL3"), WOLFSSL_X448_KYBER_LEVEL3, - WOLFSSL_X448_KYBER_LEVEL3}, - {CURVE_NAME("X25519_KYBER_LEVEL3"), WOLFSSL_X25519_KYBER_LEVEL3, - WOLFSSL_X25519_KYBER_LEVEL3}, -#endif -#endif /* WOLFSSL_MLKEM_KYBER */ -#endif /* WOLFSSL_HAVE_MLKEM */ -#ifdef WOLFSSL_SM2 - {CURVE_NAME("SM2"), WC_NID_sm2, WOLFSSL_ECC_SM2P256V1}, -#endif -#ifdef HAVE_ECC - /* Alternative curve names */ - {CURVE_NAME("prime256v1"), WC_NID_X9_62_prime256v1, WOLFSSL_ECC_SECP256R1}, - {CURVE_NAME("secp256r1"), WC_NID_X9_62_prime256v1, WOLFSSL_ECC_SECP256R1}, - {CURVE_NAME("secp384r1"), WC_NID_secp384r1, WOLFSSL_ECC_SECP384R1}, - {CURVE_NAME("secp521r1"), WC_NID_secp521r1, WOLFSSL_ECC_SECP521R1}, -#endif -#ifdef WOLFSSL_SM2 - {CURVE_NAME("sm2p256v1"), WC_NID_sm2, WOLFSSL_ECC_SM2P256V1}, -#endif - {0, NULL, 0, 0}, -}; - -int set_curves_list(WOLFSSL* ssl, WOLFSSL_CTX *ctx, const char* names, - byte curves_only) -{ - int idx, start = 0, len, i, ret = WOLFSSL_FAILURE; - word16 curve; - word32 disabled; - char name[MAX_CURVE_NAME_SZ]; - byte groups_len = 0; -#ifdef WOLFSSL_SMALL_STACK - void *heap = ssl? ssl->heap : ctx ? ctx->heap : NULL; - int *groups; -#else - int groups[WOLFSSL_MAX_GROUP_COUNT]; -#endif - const WOLF_EC_NIST_NAME* nist_name; - - WC_ALLOC_VAR_EX(groups, int, WOLFSSL_MAX_GROUP_COUNT, heap, - DYNAMIC_TYPE_TMP_BUFFER, - { - ret=MEMORY_E; - goto leave; - }); - - for (idx = 1; names[idx-1] != '\0'; idx++) { - if (names[idx] != ':' && names[idx] != '\0') - continue; - - len = idx - start; - if (len > MAX_CURVE_NAME_SZ - 1) - goto leave; - - XMEMCPY(name, names + start, (size_t)len); - name[len] = 0; - curve = WOLFSSL_NAMED_GROUP_INVALID; - - for (nist_name = kNistCurves; nist_name->name != NULL; nist_name++) { - if (len == nist_name->name_len && - XSTRNCASECMP(name, nist_name->name, (size_t)len) == 0) { - curve = nist_name->curve; - break; - } - } - - if (curve == WOLFSSL_NAMED_GROUP_INVALID) { - #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && defined(HAVE_ECC) - int nret; - const ecc_set_type *eccSet; - - nret = wc_ecc_get_curve_idx_from_name(name); - if (nret < 0) { - WOLFSSL_MSG("Could not find name in set"); - goto leave; - } - - eccSet = wc_ecc_get_curve_params(nret); - if (eccSet == NULL) { - WOLFSSL_MSG("NULL set returned"); - goto leave; - } - - curve = GetCurveByOID((int)eccSet->oidSum); - #else - WOLFSSL_MSG("API not present to search farther using name"); - goto leave; - #endif - } - - if ((curves_only && curve >= WOLFSSL_ECC_MAX_AVAIL) || - curve == WOLFSSL_NAMED_GROUP_INVALID) { - WOLFSSL_MSG("curve value is not supported"); - goto leave; - } - - for (i = 0; i < groups_len; ++i) { - if (groups[i] == curve) { - /* silently drop duplicates */ - break; - } - } - if (i >= groups_len) { - if (groups_len >= WOLFSSL_MAX_GROUP_COUNT) { - WOLFSSL_MSG_EX("setting %d or more supported " - "curves is not permitted", groups_len); - goto leave; - } - groups[groups_len++] = (int)curve; + if (ctx->privateKey != NULL) { + ret = AllocCopyDer(&ssl->buffers.key, ctx->privateKey->buffer, + ctx->privateKey->length, ctx->privateKey->type, + ctx->privateKey->heap); + if (ret != 0) { + ssl->buffers.weOwnKey = 0; + return NULL; } - - start = idx + 1; + ssl->buffers.weOwnKey = 1; } - - /* Disable all curves so that only the ones the user wants are enabled. */ - disabled = 0xFFFFFFFFUL; - for (i = 0; i < groups_len; ++i) { - /* Switch the bit to off and therefore is enabled. */ - curve = (word16)groups[i]; - if (curve >= 64) { - WC_DO_NOTHING; + else { + ssl->buffers.key = ctx->privateKey; + } +#else + ssl->buffers.key = ctx->privateKey; +#endif +#else + if (ctx->privateKey != NULL) { + if (ssl->buffers.key != NULL && ssl->buffers.weOwnKey) { + FreeDer(&ssl->buffers.key); } - else if (curve >= 32) { - /* 0 is for invalid and 1-14 aren't used otherwise. */ - disabled &= ~(1U << (curve - 32)); + ret = AllocCopyDer(&ssl->buffers.key, ctx->privateKey->buffer, + ctx->privateKey->length, ctx->privateKey->type, + ctx->privateKey->heap); + if (ret != 0) { + return NULL; } - else { - disabled &= ~(1U << curve); + /* Blind the private key for the SSL with new random mask. */ + wolfssl_priv_der_blind_toggle(ssl->buffers.key, ctx->privateKeyMask); + ret = wolfssl_priv_der_blind(ssl->rng, ssl->buffers.key, + &ssl->buffers.keyMask); + if (ret != 0) { + return NULL; } - #if defined(HAVE_SUPPORTED_CURVES) && !defined(NO_TLS) - #if !defined(WOLFSSL_OLD_SET_CURVES_LIST) - /* using the wolfSSL API to set the groups, this will populate - * (ssl|ctx)->groups and reset any TLSX_SUPPORTED_GROUPS. - * The order in (ssl|ctx)->groups will then be respected - * when TLSX_KEY_SHARE needs to be established */ - if ((ssl && wolfSSL_set_groups(ssl, groups, groups_len) - != WOLFSSL_SUCCESS) - || (ctx && wolfSSL_CTX_set_groups(ctx, groups, groups_len) - != WOLFSSL_SUCCESS)) { - WOLFSSL_MSG("Unable to set supported curve"); - goto leave; + } +#endif + ssl->buffers.keyType = ctx->privateKeyType; + ssl->buffers.keyId = ctx->privateKeyId; + ssl->buffers.keyLabel = ctx->privateKeyLabel; + ssl->buffers.keySz = ctx->privateKeySz; + ssl->buffers.keyDevId = ctx->privateKeyDevId; + /* flags indicating what certs/keys are available */ + ssl->options.haveRSA = ctx->haveRSA; + ssl->options.haveDH = ctx->haveDH; + ssl->options.haveECDSAsig = ctx->haveECDSAsig; + ssl->options.haveECC = ctx->haveECC; + ssl->options.haveStaticECC = ctx->haveStaticECC; + ssl->options.haveFalconSig = ctx->haveFalconSig; + ssl->options.haveMlDsaSig = ctx->haveMlDsaSig; +#ifdef WOLFSSL_DUAL_ALG_CERTS +#ifndef WOLFSSL_BLIND_PRIVATE_KEY + ssl->buffers.altKey = ctx->altPrivateKey; +#else + if (ctx->altPrivateKey != NULL) { + ret = AllocCopyDer(&ssl->buffers.altKey, ctx->altPrivateKey->buffer, + ctx->altPrivateKey->length, ctx->altPrivateKey->type, + ctx->altPrivateKey->heap); + if (ret != 0) { + return NULL; } - #elif !defined(NO_WOLFSSL_CLIENT) - /* set the supported curve so client TLS extension contains only the - * desired curves */ - if ((ssl && wolfSSL_UseSupportedCurve(ssl, curve) != WOLFSSL_SUCCESS) - || (ctx && wolfSSL_CTX_UseSupportedCurve(ctx, curve) - != WOLFSSL_SUCCESS)) { - WOLFSSL_MSG("Unable to set supported curve"); - goto leave; + /* Blind the private key for the SSL with new random mask. */ + wolfssl_priv_der_blind_toggle(ssl->buffers.altKey, + ctx->altPrivateKeyMask); + ret = wolfssl_priv_der_blind(ssl->rng, ssl->buffers.altKey, + &ssl->buffers.altKeyMask); + if (ret != 0) { + return NULL; } - #endif - #endif /* HAVE_SUPPORTED_CURVES && !NO_TLS */ } +#endif + ssl->buffers.altKeySz = ctx->altPrivateKeySz; + ssl->buffers.altKeyType = ctx->altPrivateKeyType; +#endif /* WOLFSSL_DUAL_ALG_CERTS */ +#endif - if (ssl != NULL) - ssl->disabledCurves = disabled; - else if (ctx != NULL) - ctx->disabledCurves = disabled; - ret = WOLFSSL_SUCCESS; - -leave: -#ifdef WOLFSSL_SMALL_STACK - if (groups) - XFREE((void*)groups, heap, DYNAMIC_TYPE_TMP_BUFFER); +#ifdef WOLFSSL_SESSION_ID_CTX + /* copy over application session context ID */ + ssl->sessionCtxSz = ctx->sessionCtxSz; + XMEMCPY(ssl->sessionCtx, ctx->sessionCtx, ctx->sessionCtxSz); #endif - return ret; + + return ssl->ctx; } -#endif /* (HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448) */ -#endif /* OPENSSL_EXTRA || HAVE_CURL */ +#ifndef NO_BIO +#endif -#ifdef OPENSSL_EXTRA -/* Sets a callback for when sending and receiving protocol messages. - * This callback is copied to all WOLFSSL objects created from the ctx. - * - * ctx WOLFSSL_CTX structure to set callback in - * cb callback to use - * - * return WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE with error case - */ -int wolfSSL_CTX_set_msg_callback(WOLFSSL_CTX *ctx, SSL_Msg_Cb cb) +#ifndef NO_WOLFSSL_STUB +/* Set THREADID callback, return 1 on success, 0 on error */ +int wolfSSL_THREADID_set_callback( + void(*threadid_func)(WOLFSSL_CRYPTO_THREADID*)) { - WOLFSSL_ENTER("wolfSSL_CTX_set_msg_callback"); - if (ctx == NULL) { - WOLFSSL_MSG("Null ctx passed in"); - return WOLFSSL_FAILURE; - } - - ctx->protoMsgCb = cb; - return WOLFSSL_SUCCESS; + WOLFSSL_ENTER("wolfSSL_THREADID_set_callback"); + WOLFSSL_STUB("CRYPTO_THREADID_set_callback"); + (void)threadid_func; + return 1; } +#endif - -/* Sets a callback for when sending and receiving protocol messages. - * - * ssl WOLFSSL structure to set callback in - * cb callback to use - * - * return WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE with error case - */ -int wolfSSL_set_msg_callback(WOLFSSL *ssl, SSL_Msg_Cb cb) +#ifndef NO_WOLFSSL_STUB +void wolfSSL_THREADID_set_numeric(void* id, unsigned long val) { - WOLFSSL_ENTER("wolfSSL_set_msg_callback"); - - if (ssl == NULL) { - return WOLFSSL_FAILURE; - } - - if (cb != NULL) { - ssl->toInfoOn = 1; - } - - ssl->protoMsgCb = cb; - return WOLFSSL_SUCCESS; + WOLFSSL_ENTER("wolfSSL_THREADID_set_numeric"); + WOLFSSL_STUB("CRYPTO_THREADID_set_numeric"); + (void)id; + (void)val; + return; } +#endif +#endif /* OPENSSL_ALL || OPENSSL_EXTRA */ -/* set the user argument to pass to the msg callback when called - * return WOLFSSL_SUCCESS on success */ -int wolfSSL_CTX_set_msg_callback_arg(WOLFSSL_CTX *ctx, void* arg) -{ - WOLFSSL_ENTER("wolfSSL_CTX_set_msg_callback_arg"); - if (ctx == NULL) { - WOLFSSL_MSG("Null WOLFSSL_CTX passed in"); - return WOLFSSL_FAILURE; - } - - ctx->protoMsgCtx = arg; - return WOLFSSL_SUCCESS; -} +#if defined(OPENSSL_EXTRA) -int wolfSSL_set_msg_callback_arg(WOLFSSL *ssl, void* arg) +int wolfSSL_CRYPTO_memcmp(const void *a, const void *b, size_t size) { - WOLFSSL_ENTER("wolfSSL_set_msg_callback_arg"); - if (ssl == NULL) - return WOLFSSL_FAILURE; + int ret = 0; + int chunk; + const byte* pa = (const byte*)a; + const byte* pb = (const byte*)b; - ssl->protoMsgCtx = arg; - return WOLFSSL_SUCCESS; + if (!a || !b) + return -1; + /* ConstantCompare takes an int length. Compare in chunks of at most + * INT_MAX so a size that does not fit in an int is not narrowed into a + * negative or truncated length, which could wrongly report equality. */ + while (size > 0) { + chunk = (size > (size_t)INT_MAX) ? INT_MAX : (int)size; + ret |= ConstantCompare(pa, pb, chunk); + pa += chunk; + pb += chunk; + size -= (size_t)chunk; + } + return ret; } -void *wolfSSL_OPENSSL_memdup(const void *data, size_t siz, const char* file, - int line) -{ - void *ret; - (void)file; - (void)line; - if (data == NULL || siz >= INT_MAX) - return NULL; +#endif /* OPENSSL_EXTRA */ - ret = wolfSSL_OPENSSL_malloc(siz); - if (ret == NULL) { - return NULL; +int wolfSSL_version(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_version"); + if (ssl->version.major == SSLv3_MAJOR) { + switch (ssl->version.minor) { + case SSLv3_MINOR : + return SSL3_VERSION; + case TLSv1_MINOR : + return TLS1_VERSION; + case TLSv1_1_MINOR : + return TLS1_1_VERSION; + case TLSv1_2_MINOR : + return TLS1_2_VERSION; + case TLSv1_3_MINOR : + return TLS1_3_VERSION; + default: + return WOLFSSL_FAILURE; + } + } + else if (ssl->version.major == DTLS_MAJOR) { + switch (ssl->version.minor) { + case DTLS_MINOR : + return DTLS1_VERSION; + case DTLSv1_2_MINOR : + return DTLS1_2_VERSION; + case DTLSv1_3_MINOR: + return DTLS1_3_VERSION; + default: + return WOLFSSL_FAILURE; + } } - return XMEMCPY(ret, data, siz); + return WOLFSSL_FAILURE; } -void wolfSSL_OPENSSL_cleanse(void *ptr, size_t len) +WOLFSSL_CTX* wolfSSL_get_SSL_CTX(const WOLFSSL* ssl) { - if (ptr) - ForceZero(ptr, (word32)len); + WOLFSSL_ENTER("wolfSSL_get_SSL_CTX"); + return ssl->ctx; } -#endif /* OPENSSL_EXTRA */ - -#define WOLFSSL_SSL_API_EXT_INCLUDED -#include "src/ssl_api_ext.c" - -#if defined(OPENSSL_EXTRA) - -#ifndef NO_BIO -#define WOLFSSL_BIO_INCLUDED -#include "src/bio.c" -#endif -#endif /* OPENSSL_EXTRA */ - -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) +#ifdef WOLFSSL_JNI -word32 nid2oid(int nid, int grp) +int wolfSSL_set_jobject(WOLFSSL* ssl, void* objPtr) { - /* get OID type */ - switch (grp) { - /* oidHashType */ - case oidHashType: - switch (nid) { - #ifdef WOLFSSL_MD2 - case WC_NID_md2: - return MD2h; - #endif - #ifndef NO_MD5 - case WC_NID_md5: - return MD5h; - #endif - #ifndef NO_SHA - case WC_NID_sha1: - return SHAh; - #endif - case WC_NID_sha224: - return SHA224h; - #ifndef NO_SHA256 - case WC_NID_sha256: - return SHA256h; - #endif - #ifdef WOLFSSL_SHA384 - case WC_NID_sha384: - return SHA384h; - #endif - #ifdef WOLFSSL_SHA512 - case WC_NID_sha512: - return SHA512h; - #endif - #ifndef WOLFSSL_NOSHA3_224 - case WC_NID_sha3_224: - return SHA3_224h; - #endif - #ifndef WOLFSSL_NOSHA3_256 - case WC_NID_sha3_256: - return SHA3_256h; - #endif - #ifndef WOLFSSL_NOSHA3_384 - case WC_NID_sha3_384: - return SHA3_384h; - #endif - #ifndef WOLFSSL_NOSHA3_512 - case WC_NID_sha3_512: - return SHA3_512h; - #endif - } - break; - - /* oidSigType */ - case oidSigType: - switch (nid) { - #ifndef NO_DSA - case WC_NID_dsaWithSHA1: - return CTC_SHAwDSA; - case WC_NID_dsa_with_SHA256: - return CTC_SHA256wDSA; - #endif /* NO_DSA */ - #ifndef NO_RSA - case WC_NID_md2WithRSAEncryption: - return CTC_MD2wRSA; - case WC_NID_md5WithRSAEncryption: - return CTC_MD5wRSA; - case WC_NID_sha1WithRSAEncryption: - return CTC_SHAwRSA; - case WC_NID_sha224WithRSAEncryption: - return CTC_SHA224wRSA; - case WC_NID_sha256WithRSAEncryption: - return CTC_SHA256wRSA; - case WC_NID_sha384WithRSAEncryption: - return CTC_SHA384wRSA; - case WC_NID_sha512WithRSAEncryption: - return CTC_SHA512wRSA; - #ifdef WOLFSSL_SHA3 - case WC_NID_RSA_SHA3_224: - return CTC_SHA3_224wRSA; - case WC_NID_RSA_SHA3_256: - return CTC_SHA3_256wRSA; - case WC_NID_RSA_SHA3_384: - return CTC_SHA3_384wRSA; - case WC_NID_RSA_SHA3_512: - return CTC_SHA3_512wRSA; - #endif - #endif /* NO_RSA */ - #ifdef HAVE_ECC - case WC_NID_ecdsa_with_SHA1: - return CTC_SHAwECDSA; - case WC_NID_ecdsa_with_SHA224: - return CTC_SHA224wECDSA; - case WC_NID_ecdsa_with_SHA256: - return CTC_SHA256wECDSA; - case WC_NID_ecdsa_with_SHA384: - return CTC_SHA384wECDSA; - case WC_NID_ecdsa_with_SHA512: - return CTC_SHA512wECDSA; - #ifdef WOLFSSL_SHA3 - case WC_NID_ecdsa_with_SHA3_224: - return CTC_SHA3_224wECDSA; - case WC_NID_ecdsa_with_SHA3_256: - return CTC_SHA3_256wECDSA; - case WC_NID_ecdsa_with_SHA3_384: - return CTC_SHA3_384wECDSA; - case WC_NID_ecdsa_with_SHA3_512: - return CTC_SHA3_512wECDSA; - #endif - #endif /* HAVE_ECC */ - #ifdef HAVE_ED25519 - case WC_NID_ED25519: - return CTC_ED25519; - #endif /* HAVE_ED25519 */ - #ifdef HAVE_ED448 - case WC_NID_ED448: - return CTC_ED448; - #endif /* HAVE_ED448 */ - } - break; - - /* oidKeyType */ - case oidKeyType: - switch (nid) { - #ifndef NO_DSA - case WC_NID_dsa: - return DSAk; - #endif /* NO_DSA */ - #ifndef NO_RSA - case WC_NID_rsaEncryption: - return RSAk; - #endif /* NO_RSA */ - #ifdef HAVE_ECC - case WC_NID_X9_62_id_ecPublicKey: - return ECDSAk; - #endif /* HAVE_ECC */ - #ifdef HAVE_ED25519 - case WC_NID_ED25519: - return ED25519k; - #endif /* HAVE_ED25519 */ - #ifdef HAVE_ED448 - case WC_NID_ED448: - return ED448k; - #endif /* HAVE_ED448 */ - } - break; - - - #ifdef HAVE_ECC - case oidCurveType: - switch (nid) { - case WC_NID_X9_62_prime192v1: - return ECC_SECP192R1_OID; - case WC_NID_X9_62_prime192v2: - return ECC_PRIME192V2_OID; - case WC_NID_X9_62_prime192v3: - return ECC_PRIME192V3_OID; - case WC_NID_X9_62_prime239v1: - return ECC_PRIME239V1_OID; - case WC_NID_X9_62_prime239v2: - return ECC_PRIME239V2_OID; - case WC_NID_X9_62_prime239v3: - return ECC_PRIME239V3_OID; - case WC_NID_X9_62_prime256v1: - return ECC_SECP256R1_OID; - case WC_NID_secp112r1: - return ECC_SECP112R1_OID; - case WC_NID_secp112r2: - return ECC_SECP112R2_OID; - case WC_NID_secp128r1: - return ECC_SECP128R1_OID; - case WC_NID_secp128r2: - return ECC_SECP128R2_OID; - case WC_NID_secp160r1: - return ECC_SECP160R1_OID; - case WC_NID_secp160r2: - return ECC_SECP160R2_OID; - case WC_NID_secp224r1: - return ECC_SECP224R1_OID; - case WC_NID_secp384r1: - return ECC_SECP384R1_OID; - case WC_NID_secp521r1: - return ECC_SECP521R1_OID; - case WC_NID_secp160k1: - return ECC_SECP160K1_OID; - case WC_NID_secp192k1: - return ECC_SECP192K1_OID; - case WC_NID_secp224k1: - return ECC_SECP224K1_OID; - case WC_NID_secp256k1: - return ECC_SECP256K1_OID; - case WC_NID_brainpoolP160r1: - return ECC_BRAINPOOLP160R1_OID; - case WC_NID_brainpoolP192r1: - return ECC_BRAINPOOLP192R1_OID; - case WC_NID_brainpoolP224r1: - return ECC_BRAINPOOLP224R1_OID; - case WC_NID_brainpoolP256r1: - return ECC_BRAINPOOLP256R1_OID; - case WC_NID_brainpoolP320r1: - return ECC_BRAINPOOLP320R1_OID; - case WC_NID_brainpoolP384r1: - return ECC_BRAINPOOLP384R1_OID; - case WC_NID_brainpoolP512r1: - return ECC_BRAINPOOLP512R1_OID; - } - break; - #endif /* HAVE_ECC */ - - /* oidBlkType */ - case oidBlkType: - switch (nid) { - #ifdef WOLFSSL_AES_128 - case AES128CBCb: - return AES128CBCb; - #endif - #ifdef WOLFSSL_AES_192 - case AES192CBCb: - return AES192CBCb; - #endif - #ifdef WOLFSSL_AES_256 - case AES256CBCb: - return AES256CBCb; - #endif - #ifndef NO_DES3 - case WC_NID_des: - return DESb; - case WC_NID_des3: - return DES3b; - #endif - } - break; - - #ifdef HAVE_OCSP - case oidOcspType: - switch (nid) { - case WC_NID_id_pkix_OCSP_basic: - return OCSP_BASIC_OID; - case OCSP_NONCE_OID: - return OCSP_NONCE_OID; - } - break; - #endif /* HAVE_OCSP */ - - /* oidCertExtType */ - case oidCertExtType: - switch (nid) { - case WC_NID_basic_constraints: - return BASIC_CA_OID; - case WC_NID_subject_alt_name: - return ALT_NAMES_OID; - case WC_NID_crl_distribution_points: - return CRL_DIST_OID; - case WC_NID_info_access: - return AUTH_INFO_OID; - case WC_NID_authority_key_identifier: - return AUTH_KEY_OID; - case WC_NID_subject_key_identifier: - return SUBJ_KEY_OID; - case WC_NID_inhibit_any_policy: - return INHIBIT_ANY_OID; - case WC_NID_key_usage: - return KEY_USAGE_OID; - case WC_NID_name_constraints: - return NAME_CONS_OID; - case WC_NID_certificate_policies: - return CERT_POLICY_OID; - case WC_NID_ext_key_usage: - return EXT_KEY_USAGE_OID; - } - break; - - /* oidCertAuthInfoType */ - case oidCertAuthInfoType: - switch (nid) { - case WC_NID_ad_OCSP: - return AIA_OCSP_OID; - case WC_NID_ad_ca_issuers: - return AIA_CA_ISSUER_OID; - } - break; - - /* oidCertPolicyType */ - case oidCertPolicyType: - switch (nid) { - case WC_NID_any_policy: - return CP_ANY_OID; - } - break; - - /* oidCertAltNameType */ - case oidCertAltNameType: - switch (nid) { - case WC_NID_hw_name_oid: - return HW_NAME_OID; - } - break; - - /* oidCertKeyUseType */ - case oidCertKeyUseType: - switch (nid) { - case WC_NID_anyExtendedKeyUsage: - return EKU_ANY_OID; - case EKU_SERVER_AUTH_OID: - return EKU_SERVER_AUTH_OID; - case EKU_CLIENT_AUTH_OID: - return EKU_CLIENT_AUTH_OID; - case EKU_OCSP_SIGN_OID: - return EKU_OCSP_SIGN_OID; - } - break; - - /* oidKdfType */ - case oidKdfType: - switch (nid) { - case PBKDF2_OID: - return PBKDF2_OID; - } - break; - - /* oidPBEType */ - case oidPBEType: - switch (nid) { - case PBE_SHA1_RC4_128: - return PBE_SHA1_RC4_128; - case PBE_SHA1_DES: - return PBE_SHA1_DES; - case PBE_SHA1_DES3: - return PBE_SHA1_DES3; - } - break; + WOLFSSL_ENTER("wolfSSL_set_jobject"); + if (ssl != NULL) + { + ssl->jObjectRef = objPtr; + return WOLFSSL_SUCCESS; + } + return WOLFSSL_FAILURE; +} - /* oidKeyWrapType */ - case oidKeyWrapType: - switch (nid) { - #ifdef WOLFSSL_AES_128 - case AES128_WRAP: - return AES128_WRAP; - #endif - #ifdef WOLFSSL_AES_192 - case AES192_WRAP: - return AES192_WRAP; - #endif - #ifdef WOLFSSL_AES_256 - case AES256_WRAP: - return AES256_WRAP; - #endif - } - break; +void* wolfSSL_get_jobject(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_get_jobject"); + if (ssl != NULL) + return ssl->jObjectRef; + return NULL; +} - /* oidCmsKeyAgreeType */ - case oidCmsKeyAgreeType: - switch (nid) { - #ifndef NO_SHA - case dhSinglePass_stdDH_sha1kdf_scheme: - return dhSinglePass_stdDH_sha1kdf_scheme; - #endif - #ifdef WOLFSSL_SHA224 - case dhSinglePass_stdDH_sha224kdf_scheme: - return dhSinglePass_stdDH_sha224kdf_scheme; - #endif - #ifndef NO_SHA256 - case dhSinglePass_stdDH_sha256kdf_scheme: - return dhSinglePass_stdDH_sha256kdf_scheme; - #endif - #ifdef WOLFSSL_SHA384 - case dhSinglePass_stdDH_sha384kdf_scheme: - return dhSinglePass_stdDH_sha384kdf_scheme; - #endif - #ifdef WOLFSSL_SHA512 - case dhSinglePass_stdDH_sha512kdf_scheme: - return dhSinglePass_stdDH_sha512kdf_scheme; - #endif - } - break; +#endif /* WOLFSSL_JNI */ - /* oidCmsKeyAgreeType */ - #ifdef WOLFSSL_CERT_REQ - case oidCsrAttrType: - switch (nid) { - case WC_NID_pkcs9_contentType: - return PKCS9_CONTENT_TYPE_OID; - case WC_NID_pkcs9_challengePassword: - return CHALLENGE_PASSWORD_OID; - case WC_NID_serialNumber: - return SERIAL_NUMBER_OID; - case WC_NID_userId: - return USER_ID_OID; - case WC_NID_surname: - return SURNAME_OID; - } - break; - #endif - default: - WOLFSSL_MSG("NID not in table"); - /* MSVC warns without the cast */ - return (word32)-1; +#ifdef WOLFSSL_ASYNC_CRYPT +int wolfSSL_CTX_AsyncPoll(WOLFSSL_CTX* ctx, WOLF_EVENT** events, int maxEvents, + WOLF_EVENT_FLAG flags, int* eventCount) +{ + if (ctx == NULL) { + return BAD_FUNC_ARG; } - /* MSVC warns without the cast */ - return (word32)-1; + return wolfAsync_EventQueuePoll(&ctx->event_queue, NULL, + events, maxEvents, flags, eventCount); } -int oid2nid(word32 oid, int grp) +int wolfSSL_AsyncPoll(WOLFSSL* ssl, WOLF_EVENT_FLAG flags) { - size_t i; - /* get OID type */ - switch (grp) { - /* oidHashType */ - case oidHashType: - switch (oid) { - #ifdef WOLFSSL_MD2 - case MD2h: - return WC_NID_md2; - #endif - #ifndef NO_MD5 - case MD5h: - return WC_NID_md5; - #endif - #ifndef NO_SHA - case SHAh: - return WC_NID_sha1; - #endif - case SHA224h: - return WC_NID_sha224; - #ifndef NO_SHA256 - case SHA256h: - return WC_NID_sha256; - #endif - #ifdef WOLFSSL_SHA384 - case SHA384h: - return WC_NID_sha384; - #endif - #ifdef WOLFSSL_SHA512 - case SHA512h: - return WC_NID_sha512; - #endif - } - break; - - /* oidSigType */ - case oidSigType: - switch (oid) { - #ifndef NO_DSA - case CTC_SHAwDSA: - return WC_NID_dsaWithSHA1; - case CTC_SHA256wDSA: - return WC_NID_dsa_with_SHA256; - #endif /* NO_DSA */ - #ifndef NO_RSA - case CTC_MD2wRSA: - return WC_NID_md2WithRSAEncryption; - case CTC_MD5wRSA: - return WC_NID_md5WithRSAEncryption; - case CTC_SHAwRSA: - return WC_NID_sha1WithRSAEncryption; - case CTC_SHA224wRSA: - return WC_NID_sha224WithRSAEncryption; - case CTC_SHA256wRSA: - return WC_NID_sha256WithRSAEncryption; - case CTC_SHA384wRSA: - return WC_NID_sha384WithRSAEncryption; - case CTC_SHA512wRSA: - return WC_NID_sha512WithRSAEncryption; - #ifdef WOLFSSL_SHA3 - case CTC_SHA3_224wRSA: - return WC_NID_RSA_SHA3_224; - case CTC_SHA3_256wRSA: - return WC_NID_RSA_SHA3_256; - case CTC_SHA3_384wRSA: - return WC_NID_RSA_SHA3_384; - case CTC_SHA3_512wRSA: - return WC_NID_RSA_SHA3_512; - #endif - #ifdef WC_RSA_PSS - case CTC_RSASSAPSS: - return WC_NID_rsassaPss; - #endif - #endif /* NO_RSA */ - #ifdef HAVE_ECC - case CTC_SHAwECDSA: - return WC_NID_ecdsa_with_SHA1; - case CTC_SHA224wECDSA: - return WC_NID_ecdsa_with_SHA224; - case CTC_SHA256wECDSA: - return WC_NID_ecdsa_with_SHA256; - case CTC_SHA384wECDSA: - return WC_NID_ecdsa_with_SHA384; - case CTC_SHA512wECDSA: - return WC_NID_ecdsa_with_SHA512; - #ifdef WOLFSSL_SHA3 - case CTC_SHA3_224wECDSA: - return WC_NID_ecdsa_with_SHA3_224; - case CTC_SHA3_256wECDSA: - return WC_NID_ecdsa_with_SHA3_256; - case CTC_SHA3_384wECDSA: - return WC_NID_ecdsa_with_SHA3_384; - case CTC_SHA3_512wECDSA: - return WC_NID_ecdsa_with_SHA3_512; - #endif - #endif /* HAVE_ECC */ - #ifdef HAVE_ED25519 - case CTC_ED25519: - return WC_NID_ED25519; - #endif /* HAVE_ED25519 */ - #ifdef HAVE_ED448 - case CTC_ED448: - return WC_NID_ED448; - #endif /* HAVE_ED448 */ - } - break; + int ret, eventCount = 0; + WOLF_EVENT* events[1]; - /* oidKeyType */ - case oidKeyType: - switch (oid) { - #ifndef NO_DSA - case DSAk: - return WC_NID_dsa; - #endif /* NO_DSA */ - #ifndef NO_RSA - case RSAk: - return WC_NID_rsaEncryption; - #ifdef WC_RSA_PSS - case RSAPSSk: - return WC_NID_rsassaPss; - #endif - #endif /* NO_RSA */ - #ifdef HAVE_ECC - case ECDSAk: - return WC_NID_X9_62_id_ecPublicKey; - #endif /* HAVE_ECC */ - #ifdef HAVE_ED25519 - case ED25519k: - return WC_NID_ED25519; - #endif /* HAVE_ED25519 */ - #ifdef HAVE_ED448 - case ED448k: - return WC_NID_ED448; - #endif /* HAVE_ED448 */ - } - break; + if (ssl == NULL) { + return BAD_FUNC_ARG; + } + ret = wolfAsync_EventQueuePoll(&ssl->ctx->event_queue, ssl, + events, sizeof(events)/sizeof(events[0]), flags, &eventCount); + if (ret == 0) { + ret = eventCount; + } - #ifdef HAVE_ECC - case oidCurveType: - switch (oid) { - case ECC_SECP192R1_OID: - return WC_NID_X9_62_prime192v1; - case ECC_PRIME192V2_OID: - return WC_NID_X9_62_prime192v2; - case ECC_PRIME192V3_OID: - return WC_NID_X9_62_prime192v3; - case ECC_PRIME239V1_OID: - return WC_NID_X9_62_prime239v1; - case ECC_PRIME239V2_OID: - return WC_NID_X9_62_prime239v2; - case ECC_PRIME239V3_OID: - return WC_NID_X9_62_prime239v3; - case ECC_SECP256R1_OID: - return WC_NID_X9_62_prime256v1; - case ECC_SECP112R1_OID: - return WC_NID_secp112r1; - case ECC_SECP112R2_OID: - return WC_NID_secp112r2; - case ECC_SECP128R1_OID: - return WC_NID_secp128r1; - case ECC_SECP128R2_OID: - return WC_NID_secp128r2; - case ECC_SECP160R1_OID: - return WC_NID_secp160r1; - case ECC_SECP160R2_OID: - return WC_NID_secp160r2; - case ECC_SECP224R1_OID: - return WC_NID_secp224r1; - case ECC_SECP384R1_OID: - return WC_NID_secp384r1; - case ECC_SECP521R1_OID: - return WC_NID_secp521r1; - case ECC_SECP160K1_OID: - return WC_NID_secp160k1; - case ECC_SECP192K1_OID: - return WC_NID_secp192k1; - case ECC_SECP224K1_OID: - return WC_NID_secp224k1; - case ECC_SECP256K1_OID: - return WC_NID_secp256k1; - case ECC_BRAINPOOLP160R1_OID: - return WC_NID_brainpoolP160r1; - case ECC_BRAINPOOLP192R1_OID: - return WC_NID_brainpoolP192r1; - case ECC_BRAINPOOLP224R1_OID: - return WC_NID_brainpoolP224r1; - case ECC_BRAINPOOLP256R1_OID: - return WC_NID_brainpoolP256r1; - case ECC_BRAINPOOLP320R1_OID: - return WC_NID_brainpoolP320r1; - case ECC_BRAINPOOLP384R1_OID: - return WC_NID_brainpoolP384r1; - case ECC_BRAINPOOLP512R1_OID: - return WC_NID_brainpoolP512r1; - } - break; - #endif /* HAVE_ECC */ - - /* oidBlkType */ - case oidBlkType: - switch (oid) { - #ifdef WOLFSSL_AES_128 - case AES128CBCb: - return AES128CBCb; - #endif - #ifdef WOLFSSL_AES_192 - case AES192CBCb: - return AES192CBCb; - #endif - #ifdef WOLFSSL_AES_256 - case AES256CBCb: - return AES256CBCb; - #endif - #ifndef NO_DES3 - case DESb: - return WC_NID_des; - case DES3b: - return WC_NID_des3; - #endif - } - break; + return ret; +} +#endif /* WOLFSSL_ASYNC_CRYPT */ - #ifdef HAVE_OCSP - case oidOcspType: - switch (oid) { - case OCSP_BASIC_OID: - return WC_NID_id_pkix_OCSP_basic; - case OCSP_NONCE_OID: - return OCSP_NONCE_OID; - } - break; - #endif /* HAVE_OCSP */ - - /* oidCertExtType */ - case oidCertExtType: - switch (oid) { - case BASIC_CA_OID: - return WC_NID_basic_constraints; - case ALT_NAMES_OID: - return WC_NID_subject_alt_name; - case CRL_DIST_OID: - return WC_NID_crl_distribution_points; - case AUTH_INFO_OID: - return WC_NID_info_access; - case AUTH_KEY_OID: - return WC_NID_authority_key_identifier; - case SUBJ_KEY_OID: - return WC_NID_subject_key_identifier; - case INHIBIT_ANY_OID: - return WC_NID_inhibit_any_policy; - case KEY_USAGE_OID: - return WC_NID_key_usage; - case NAME_CONS_OID: - return WC_NID_name_constraints; - case CERT_POLICY_OID: - return WC_NID_certificate_policies; - case EXT_KEY_USAGE_OID: - return WC_NID_ext_key_usage; - } - break; +#ifdef OPENSSL_EXTRA - /* oidCertAuthInfoType */ - case oidCertAuthInfoType: - switch (oid) { - case AIA_OCSP_OID: - return WC_NID_ad_OCSP; - case AIA_CA_ISSUER_OID: - return WC_NID_ad_ca_issuers; - } - break; +#endif - /* oidCertPolicyType */ - case oidCertPolicyType: - switch (oid) { - case CP_ANY_OID: - return WC_NID_any_policy; - } - break; +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) || \ + defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) - /* oidCertAltNameType */ - case oidCertAltNameType: - switch (oid) { - case HW_NAME_OID: - return WC_NID_hw_name_oid; - } - break; +#if !defined(WOLFSSL_USER_IO) +/* converts an IPv6 or IPv4 address into an octet string for use with rfc3280 + * example input would be "127.0.0.1" and the returned value would be 7F000001 + */ +WOLFSSL_ASN1_STRING* wolfSSL_a2i_IPADDRESS(const char* ipa) +{ + int ipaSz = WOLFSSL_IP4_ADDR_LEN; + char buf[WOLFSSL_IP6_ADDR_LEN + 1]; /* plus 1 for terminator */ + int af = WOLFSSL_IP4; + WOLFSSL_ASN1_STRING *ret = NULL; - /* oidCertKeyUseType */ - case oidCertKeyUseType: - switch (oid) { - case EKU_ANY_OID: - return WC_NID_anyExtendedKeyUsage; - case EKU_SERVER_AUTH_OID: - return EKU_SERVER_AUTH_OID; - case EKU_CLIENT_AUTH_OID: - return EKU_CLIENT_AUTH_OID; - case EKU_OCSP_SIGN_OID: - return EKU_OCSP_SIGN_OID; - } - break; + if (ipa == NULL) + return NULL; - /* oidKdfType */ - case oidKdfType: - switch (oid) { - case PBKDF2_OID: - return PBKDF2_OID; - } - break; + if (XSTRSTR(ipa, ":") != NULL) { + af = WOLFSSL_IP6; + ipaSz = WOLFSSL_IP6_ADDR_LEN; + } - /* oidPBEType */ - case oidPBEType: - switch (oid) { - case PBE_SHA1_RC4_128: - return PBE_SHA1_RC4_128; - case PBE_SHA1_DES: - return PBE_SHA1_DES; - case PBE_SHA1_DES3: - return PBE_SHA1_DES3; - } - break; + buf[WOLFSSL_IP6_ADDR_LEN] = '\0'; +#ifdef FREESCALE_MQX + if (XINET_PTON(af, ipa, (void*)buf, sizeof(buf)) != RTCS_OK) { +#else + if (XINET_PTON(af, ipa, (void*)buf) != 1) { +#endif + WOLFSSL_MSG("Error parsing IP address"); + return NULL; + } - /* oidKeyWrapType */ - case oidKeyWrapType: - switch (oid) { - #ifdef WOLFSSL_AES_128 - case AES128_WRAP: - return AES128_WRAP; - #endif - #ifdef WOLFSSL_AES_192 - case AES192_WRAP: - return AES192_WRAP; - #endif - #ifdef WOLFSSL_AES_256 - case AES256_WRAP: - return AES256_WRAP; - #endif - } - break; + ret = wolfSSL_ASN1_STRING_new(); + if (ret != NULL) { + if (wolfSSL_ASN1_STRING_set(ret, buf, ipaSz) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Error setting the string"); + wolfSSL_ASN1_STRING_free(ret); + ret = NULL; + } + } - /* oidCmsKeyAgreeType */ - case oidCmsKeyAgreeType: - switch (oid) { - #ifndef NO_SHA - case dhSinglePass_stdDH_sha1kdf_scheme: - return dhSinglePass_stdDH_sha1kdf_scheme; - #endif - #ifdef WOLFSSL_SHA224 - case dhSinglePass_stdDH_sha224kdf_scheme: - return dhSinglePass_stdDH_sha224kdf_scheme; - #endif - #ifndef NO_SHA256 - case dhSinglePass_stdDH_sha256kdf_scheme: - return dhSinglePass_stdDH_sha256kdf_scheme; - #endif - #ifdef WOLFSSL_SHA384 - case dhSinglePass_stdDH_sha384kdf_scheme: - return dhSinglePass_stdDH_sha384kdf_scheme; - #endif - #ifdef WOLFSSL_SHA512 - case dhSinglePass_stdDH_sha512kdf_scheme: - return dhSinglePass_stdDH_sha512kdf_scheme; - #endif - } - break; + return ret; +} +#endif /* !WOLFSSL_USER_IO */ -#ifdef WOLFSSL_CERT_REQ - case oidCsrAttrType: - switch (oid) { - case PKCS9_CONTENT_TYPE_OID: - return WC_NID_pkcs9_contentType; - case CHALLENGE_PASSWORD_OID: - return WC_NID_pkcs9_challengePassword; - case SERIAL_NUMBER_OID: - return WC_NID_serialNumber; - case USER_ID_OID: - return WC_NID_userId; - } - break; +/* Is the specified cipher suite a fake one used an an extension proxy? */ +static WC_INLINE int SCSV_Check(byte suite0, byte suite) +{ + (void)suite0; + (void)suite; +#ifdef HAVE_RENEGOTIATION_INDICATION + if (suite0 == CIPHER_BYTE && suite == TLS_EMPTY_RENEGOTIATION_INFO_SCSV) + return 1; #endif + return 0; +} - default: - WOLFSSL_MSG("OID not in table"); +static WC_INLINE int sslCipherMinMaxCheck(const WOLFSSL *ssl, byte suite0, + byte suite) +{ + const CipherSuiteInfo* cipher_names = GetCipherNames(); + int cipherSz = GetCipherNamesSize(); + int i; + for (i = 0; i < cipherSz; i++) + if (cipher_names[i].cipherSuite0 == suite0 && + cipher_names[i].cipherSuite == suite) + break; + if (i == cipherSz) + return 1; + /* Check min version */ + if (cipher_names[i].minor < ssl->options.minDowngrade) { + if (ssl->options.minDowngrade <= TLSv1_2_MINOR && + cipher_names[i].minor >= TLSv1_MINOR) + /* 1.0 ciphersuites are in general available in 1.1 and + * 1.1 ciphersuites are in general available in 1.2 */ + return 0; + return 1; } - /* If not found in above switch then try the table */ - for (i = 0; i < WOLFSSL_OBJECT_INFO_SZ; i++) { - if (wolfssl_object_info[i].id == (int)oid) { - return wolfssl_object_info[i].nid; - } + /* Check max version */ + switch (cipher_names[i].minor) { + case SSLv3_MINOR : + return ssl->options.mask & WOLFSSL_OP_NO_SSLv3; + case TLSv1_MINOR : + return ssl->options.mask & WOLFSSL_OP_NO_TLSv1; + case TLSv1_1_MINOR : + return ssl->options.mask & WOLFSSL_OP_NO_TLSv1_1; + case TLSv1_2_MINOR : + return ssl->options.mask & WOLFSSL_OP_NO_TLSv1_2; + case TLSv1_3_MINOR : + return ssl->options.mask & WOLFSSL_OP_NO_TLSv1_3; + default: + WOLFSSL_MSG("Unrecognized minor version"); + return 1; } - - return WOLFSSL_FATAL_ERROR; } -#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ - -#if defined(OPENSSL_EXTRA) - -/* frees all nodes in the current threads error queue - * - * id thread id. ERR_remove_state is depreciated and id is ignored. The - * current threads queue will be free'd. +/* returns a pointer to internal cipher suite list. Should not be free'd by + * caller. */ -void wolfSSL_ERR_remove_state(unsigned long id) +WOLF_STACK_OF(WOLFSSL_CIPHER) *wolfSSL_get_ciphers_compat(const WOLFSSL *ssl) { - WOLFSSL_ENTER("wolfSSL_ERR_remove_state"); - (void)id; - if (wc_ERR_remove_state() != 0) { - WOLFSSL_MSG("Error with removing the state"); - } -} + const Suites* suites; +#if defined(OPENSSL_ALL) + const CipherSuiteInfo* cipher_names = GetCipherNames(); + int cipherSz = GetCipherNamesSize(); +#endif -#endif /* OPENSSL_EXTRA */ + WOLFSSL_ENTER("wolfSSL_get_ciphers_compat"); + if (ssl == NULL) + return NULL; + suites = WOLFSSL_SUITES(ssl); + if (suites == NULL) + return NULL; -#if defined(OPENSSL_EXTRA) -/* wolfSSL_THREADID_current is provided as a compat API with - * CRYPTO_THREADID_current to register current thread id into given id object. - * However, CRYPTO_THREADID_current API has been deprecated and no longer - * exists in the OpenSSL 1.0.0 or later.This API only works as a stub - * like as existing wolfSSL_THREADID_set_numeric. - */ -void wolfSSL_THREADID_current(WOLFSSL_CRYPTO_THREADID* id) -{ - (void)id; - return; -} -/* wolfSSL_THREADID_hash is provided as a compatible API with - * CRYPTO_THREADID_hash which returns a hash value calculated from the - * specified thread id. However, CRYPTO_THREADID_hash API has been - * deprecated and no longer exists in the OpenSSL 1.0.0 or later. - * This API only works as a stub to returns 0. This behavior is - * equivalent to the latest OpenSSL CRYPTO_THREADID_hash. - */ -unsigned long wolfSSL_THREADID_hash(const WOLFSSL_CRYPTO_THREADID* id) -{ - (void)id; - return 0UL; -} + /* check if stack needs populated */ + if (ssl->suitesStack == NULL) { + int i; -/** - * Set security level (wolfSSL doesn't support setting the security level). - * - * The security level can only be set through a system wide crypto-policy - * with wolfSSL_crypto_policy_enable(). - * - * @param ctx a pointer to WOLFSSL_CTX structure - * @param level security level - */ -void wolfSSL_CTX_set_security_level(WOLFSSL_CTX* ctx, int level) -{ - WOLFSSL_ENTER("wolfSSL_CTX_set_security_level"); - (void)ctx; - (void)level; -} + ((WOLFSSL*)ssl)->suitesStack = + wolfssl_sk_new_type_ex(STACK_TYPE_CIPHER, ssl->heap); + if (ssl->suitesStack == NULL) + return NULL; -int wolfSSL_CTX_get_security_level(const WOLFSSL_CTX * ctx) -{ - WOLFSSL_ENTER("wolfSSL_CTX_get_security_level"); - #if defined(WOLFSSL_SYS_CRYPTO_POLICY) - if (ctx == NULL) { - return BAD_FUNC_ARG; - } + /* higher priority of cipher suite will be on top of stack */ +#if defined(OPENSSL_ALL) + for (i = suites->suiteSz - 2; i >=0; i-=2) +#else + for (i = 0; i < suites->suiteSz; i+=2) +#endif + { + struct WOLFSSL_CIPHER cipher; - return ctx->secLevel; - #else - (void)ctx; - return 0; - #endif /* WOLFSSL_SYS_CRYPTO_POLICY */ -} + /* A couple of suites are placeholders for special options, + * skip those. */ + if (SCSV_Check(suites->suites[i], suites->suites[i+1]) + || sslCipherMinMaxCheck(ssl, suites->suites[i], + suites->suites[i+1])) { + continue; + } -#if defined(OPENSSL_EXTRA) && defined(HAVE_SECRET_CALLBACK) -/* - * This API accepts a user callback which puts key-log records into - * a KEY LOGFILE. The callback is stored into a CTX and propagated to - * each SSL object on its creation timing. - */ -void wolfSSL_CTX_set_keylog_callback(WOLFSSL_CTX* ctx, - wolfSSL_CTX_keylog_cb_func cb) -{ - WOLFSSL_ENTER("wolfSSL_CTX_set_keylog_callback"); - /* stores the callback into WOLFSSL_CTX */ - if (ctx != NULL) { - ctx->keyLogCb = cb; + XMEMSET(&cipher, 0, sizeof(cipher)); + cipher.cipherSuite0 = suites->suites[i]; + cipher.cipherSuite = suites->suites[i+1]; + cipher.ssl = ssl; +#if defined(OPENSSL_ALL) + cipher.in_stack = 1; + { + int j; + for (j = 0; j < cipherSz; j++) { + if (cipher_names[j].cipherSuite0 == cipher.cipherSuite0 && + cipher_names[j].cipherSuite == cipher.cipherSuite) { + cipher.offset = (unsigned long)j; + break; + } + } + } +#endif + if (wolfSSL_sk_insert(ssl->suitesStack, &cipher, 0) <= 0) { + WOLFSSL_MSG("Error inserting cipher onto stack"); + wolfSSL_sk_CIPHER_free(ssl->suitesStack); + ((WOLFSSL*)ssl)->suitesStack = NULL; + break; + } + } + + /* If no ciphers were added, free empty stack and return NULL */ + if (ssl->suitesStack != NULL && wolfSSL_sk_num(ssl->suitesStack) == 0) { + wolfSSL_sk_CIPHER_free(ssl->suitesStack); + ((WOLFSSL*)ssl)->suitesStack = NULL; + } } + return ssl->suitesStack; } -wolfSSL_CTX_keylog_cb_func wolfSSL_CTX_get_keylog_callback( - const WOLFSSL_CTX* ctx) +#endif /* OPENSSL_EXTRA || OPENSSL_ALL || WOLFSSL_NGINX || WOLFSSL_HAPROXY */ +#ifdef OPENSSL_ALL +/* returned pointer is to an internal element in WOLFSSL struct and should not + * be free'd. It gets free'd when the WOLFSSL struct is free'd. */ +WOLF_STACK_OF(WOLFSSL_CIPHER)* wolfSSL_get_client_ciphers(WOLFSSL* ssl) { - WOLFSSL_ENTER("wolfSSL_CTX_get_keylog_callback"); - if (ctx != NULL) - return ctx->keyLogCb; - return NULL; -} -#endif /* OPENSSL_EXTRA && HAVE_SECRET_CALLBACK */ - -#endif /* OPENSSL_EXTRA */ + WOLF_STACK_OF(WOLFSSL_CIPHER)* ret = NULL; + const CipherSuiteInfo* cipher_names = GetCipherNames(); + int cipherSz = GetCipherNamesSize(); + const Suites* suites; -#ifdef WOLFSSL_THREADED_CRYPT -int wolfSSL_AsyncEncryptReady(WOLFSSL* ssl, int idx) -{ - ThreadCrypt* encrypt; + WOLFSSL_ENTER("wolfSSL_get_client_ciphers"); if (ssl == NULL) { - return 0; + return NULL; } - encrypt = &ssl->buffers.encrypt[idx]; - return (encrypt->avail == 0) && (encrypt->done == 0); -} - -int wolfSSL_AsyncEncryptStop(WOLFSSL* ssl, int idx) -{ - ThreadCrypt* encrypt; + /* return NULL if is client side */ + if (wolfSSL_is_server(ssl) == 0) { + return NULL; + } - if (ssl == NULL) { - return 1; + suites = ssl->clSuites; + if (suites == NULL) { + WOLFSSL_MSG("No client suites stored"); } + else if (ssl->clSuitesStack != NULL) { + ret = ssl->clSuitesStack; + } + else { /* generate cipher suites stack if not already done */ + int i; + int j; - encrypt = &ssl->buffers.encrypt[idx]; - return encrypt->stop; -} + ret = wolfSSL_sk_new_node(ssl->heap); + if (ret != NULL) { + ret->type = STACK_TYPE_CIPHER; -int wolfSSL_AsyncEncrypt(WOLFSSL* ssl, int idx) -{ - int ret = WC_NO_ERR_TRACE(NOT_COMPILED_IN); - ThreadCrypt* encrypt = &ssl->buffers.encrypt[idx]; + /* higher priority of cipher suite will be on top of stack */ + for (i = suites->suiteSz - 2; i >= 0; i -= 2) { + WOLFSSL_CIPHER cipher; - if (ssl->specs.bulk_cipher_algorithm == wolfssl_aes_gcm) { - unsigned char* out = encrypt->buffer.buffer + encrypt->offset; - unsigned char* input = encrypt->buffer.buffer + encrypt->offset; - word32 encSz = encrypt->buffer.length - encrypt->offset; + /* A couple of suites are placeholders for special options, + * skip those. */ + if (SCSV_Check(suites->suites[i], suites->suites[i+1]) + || sslCipherMinMaxCheck(ssl, suites->suites[i], + suites->suites[i+1])) { + continue; + } - ret = -#if !defined(NO_GCM_ENCRYPT_EXTRA) && \ - ((!defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)) || \ - (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2))) - wc_AesGcmEncrypt_ex -#else - wc_AesGcmEncrypt -#endif - (encrypt->encrypt.aes, - out + AESGCM_EXP_IV_SZ, input + AESGCM_EXP_IV_SZ, - encSz - AESGCM_EXP_IV_SZ - ssl->specs.aead_mac_size, - encrypt->nonce, AESGCM_NONCE_SZ, - out + encSz - ssl->specs.aead_mac_size, - ssl->specs.aead_mac_size, - encrypt->additional, AEAD_AUTH_DATA_SZ); -#if !defined(NO_PUBLIC_GCM_SET_IV) && \ - ((!defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)) || \ - (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2))) - XMEMCPY(out, encrypt->nonce + AESGCM_IMP_IV_SZ, AESGCM_EXP_IV_SZ); -#endif - encrypt->done = 1; - } + cipher.cipherSuite0 = suites->suites[i]; + cipher.cipherSuite = suites->suites[i+1]; + cipher.ssl = ssl; + for (j = 0; j < cipherSz; j++) { + if (cipher_names[j].cipherSuite0 == + cipher.cipherSuite0 && + cipher_names[j].cipherSuite == + cipher.cipherSuite) { + cipher.offset = (unsigned long)j; + break; + } + } + /* in_stack is checked in wolfSSL_CIPHER_description */ + cipher.in_stack = 1; + + if (wolfSSL_sk_CIPHER_push(ret, &cipher) <= 0) { + WOLFSSL_MSG("Error pushing client cipher onto stack"); + wolfSSL_sk_CIPHER_free(ret); + ret = NULL; + break; + } + } + } + ssl->clSuitesStack = ret; + } return ret; } +#endif /* OPENSSL_ALL */ -int wolfSSL_AsyncEncryptSetSignal(WOLFSSL* ssl, int idx, - WOLFSSL_THREAD_SIGNAL signal, void* ctx) +#if defined(OPENSSL_EXTRA) || defined(HAVE_SECRET_CALLBACK) +long wolfSSL_SSL_CTX_get_timeout(const WOLFSSL_CTX *ctx) { - int ret = 0; + WOLFSSL_ENTER("wolfSSL_SSL_CTX_get_timeout"); - if (ssl == NULL) { - ret = BAD_FUNC_ARG; - } - else { - ssl->buffers.encrypt[idx].signal = signal; - ssl->buffers.encrypt[idx].signalCtx = ctx; - } + if (ctx == NULL) + return 0; - return ret; + return ctx->timeout; } -#endif -#ifndef NO_CERT -#define WOLFSSL_X509_INCLUDED -#include "src/x509.c" -#endif - -/******************************************************************************* - * START OF standard C library wrapping APIs - ******************************************************************************/ -#if defined(OPENSSL_ALL) || (defined(OPENSSL_EXTRA) && \ - (defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \ - defined(HAVE_LIGHTY) || defined(WOLFSSL_HAPROXY) || \ - defined(WOLFSSL_OPENSSH))) -#ifndef NO_WOLFSSL_STUB -int wolfSSL_CRYPTO_set_mem_ex_functions(void *(*m) (size_t, const char *, int), - void *(*r) (void *, size_t, const char *, - int), void (*f) (void *)) +/* returns the time in seconds of the current timeout */ +long wolfSSL_get_timeout(WOLFSSL* ssl) { - (void) m; - (void) r; - (void) f; - WOLFSSL_ENTER("wolfSSL_CRYPTO_set_mem_ex_functions"); - WOLFSSL_STUB("CRYPTO_set_mem_ex_functions"); + WOLFSSL_ENTER("wolfSSL_get_timeout"); - return WOLFSSL_FAILURE; + if (ssl == NULL) + return 0; + return ssl->timeout; } #endif -#endif -#if defined(OPENSSL_EXTRA) +#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) \ + || defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) -/** - * free allocated memory resource - * @param str a pointer to resource to be freed - * @param file dummy argument - * @param line dummy argument - */ -void wolfSSL_CRYPTO_free(void *str, const char *file, int line) +#ifndef NO_BIO +WOLFSSL_BIO *wolfSSL_SSL_get_rbio(const WOLFSSL *s) { - (void)file; - (void)line; - XFREE(str, 0, DYNAMIC_TYPE_TMP_BUFFER); + WOLFSSL_ENTER("wolfSSL_SSL_get_rbio"); + /* Nginx sets the buffer size if the read BIO is different to write BIO. + * The setting buffer size doesn't do anything so return NULL for both. + */ + if (s == NULL) + return NULL; + + return s->biord; } -/** - * allocate memory with size of num - * @param num size of memory allocation to be malloced - * @param file dummy argument - * @param line dummy argument - * @return a pointer to allocated memory on succssesful, otherwise NULL - */ -void *wolfSSL_CRYPTO_malloc(size_t num, const char *file, int line) +WOLFSSL_BIO *wolfSSL_SSL_get_wbio(const WOLFSSL *s) { - (void)file; - (void)line; - return XMALLOC(num, 0, DYNAMIC_TYPE_TMP_BUFFER); + WOLFSSL_ENTER("wolfSSL_SSL_get_wbio"); + (void)s; + /* Nginx sets the buffer size if the read BIO is different to write BIO. + * The setting buffer size doesn't do anything so return NULL for both. + */ + if (s == NULL) + return NULL; + + return s->biowr; } +#endif /* !NO_BIO */ -#endif -/******************************************************************************* - * END OF standard C library wrapping APIs - ******************************************************************************/ -/******************************************************************************* - * START OF EX_DATA APIs - ******************************************************************************/ -#ifdef HAVE_EX_DATA -void wolfSSL_CRYPTO_cleanup_all_ex_data(void) -{ - WOLFSSL_ENTER("wolfSSL_CRYPTO_cleanup_all_ex_data"); -} +#endif /* OPENSSL_ALL || WOLFSSL_NGINX || WOLFSSL_HAPROXY || + OPENSSL_EXTRA || HAVE_LIGHTY */ -void* wolfSSL_CRYPTO_get_ex_data(const WOLFSSL_CRYPTO_EX_DATA* ex_data, int idx) + +#if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || \ + defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) + + +void wolfSSL_WOLFSSL_STRING_free(WOLFSSL_STRING s) { - WOLFSSL_ENTER("wolfSSL_CRYPTO_get_ex_data"); -#ifdef MAX_EX_DATA - if (ex_data && idx < MAX_EX_DATA && idx >= 0) { - return ex_data->ex_data[idx]; - } -#else - (void)ex_data; - (void)idx; -#endif - return NULL; + WOLFSSL_ENTER("wolfSSL_WOLFSSL_STRING_free"); + + XFREE(s, NULL, DYNAMIC_TYPE_OPENSSL); } -int wolfSSL_CRYPTO_set_ex_data(WOLFSSL_CRYPTO_EX_DATA* ex_data, int idx, - void *data) -{ - WOLFSSL_ENTER("wolfSSL_CRYPTO_set_ex_data"); -#ifdef MAX_EX_DATA - if (ex_data && idx < MAX_EX_DATA && idx >= 0) { -#ifdef HAVE_EX_DATA_CLEANUP_HOOKS - if (ex_data->ex_data_cleanup_routines[idx]) { - /* call cleanup then remove cleanup callback, - * since different value is being set */ - if (ex_data->ex_data[idx]) - ex_data->ex_data_cleanup_routines[idx](ex_data->ex_data[idx]); - ex_data->ex_data_cleanup_routines[idx] = NULL; - } +#endif /* WOLFSSL_NGINX || WOLFSSL_HAPROXY || OPENSSL_EXTRA || OPENSSL_ALL */ + + +#if defined(OPENSSL_EXTRA) || defined(HAVE_CURL) + +#if (defined(HAVE_ECC) || \ + defined(HAVE_CURVE25519) || defined(HAVE_CURVE448)) +#define CURVE_NAME(c) XSTR_SIZEOF((c)), (c) + +const WOLF_EC_NIST_NAME kNistCurves[] = { +#ifdef HAVE_ECC + {CURVE_NAME("P-160"), WC_NID_secp160r1, WOLFSSL_ECC_SECP160R1}, + {CURVE_NAME("P-160-2"), WC_NID_secp160r2, WOLFSSL_ECC_SECP160R2}, + {CURVE_NAME("P-192"), WC_NID_X9_62_prime192v1, WOLFSSL_ECC_SECP192R1}, + {CURVE_NAME("P-224"), WC_NID_secp224r1, WOLFSSL_ECC_SECP224R1}, + {CURVE_NAME("P-256"), WC_NID_X9_62_prime256v1, WOLFSSL_ECC_SECP256R1}, + {CURVE_NAME("P-384"), WC_NID_secp384r1, WOLFSSL_ECC_SECP384R1}, + {CURVE_NAME("P-521"), WC_NID_secp521r1, WOLFSSL_ECC_SECP521R1}, + {CURVE_NAME("K-160"), WC_NID_secp160k1, WOLFSSL_ECC_SECP160K1}, + {CURVE_NAME("K-192"), WC_NID_secp192k1, WOLFSSL_ECC_SECP192K1}, + {CURVE_NAME("K-224"), WC_NID_secp224k1, WOLFSSL_ECC_SECP224K1}, + {CURVE_NAME("K-256"), WC_NID_secp256k1, WOLFSSL_ECC_SECP256K1}, + {CURVE_NAME("B-256"), WC_NID_brainpoolP256r1, + WOLFSSL_ECC_BRAINPOOLP256R1}, + {CURVE_NAME("B-384"), WC_NID_brainpoolP384r1, + WOLFSSL_ECC_BRAINPOOLP384R1}, + {CURVE_NAME("B-512"), WC_NID_brainpoolP512r1, + WOLFSSL_ECC_BRAINPOOLP512R1}, #endif - ex_data->ex_data[idx] = data; - return WOLFSSL_SUCCESS; - } -#else - (void)ex_data; - (void)idx; - (void)data; +#ifdef HAVE_CURVE25519 + {CURVE_NAME("X25519"), WC_NID_X25519, WOLFSSL_ECC_X25519}, +#endif +#ifdef HAVE_CURVE448 + {CURVE_NAME("X448"), WC_NID_X448, WOLFSSL_ECC_X448}, +#endif +#ifdef WOLFSSL_HAVE_MLKEM +#ifndef WOLFSSL_NO_ML_KEM + {CURVE_NAME("ML_KEM_512"), WOLFSSL_ML_KEM_512, WOLFSSL_ML_KEM_512}, + {CURVE_NAME("ML_KEM_768"), WOLFSSL_ML_KEM_768, WOLFSSL_ML_KEM_768}, + {CURVE_NAME("ML_KEM_1024"), WOLFSSL_ML_KEM_1024, WOLFSSL_ML_KEM_1024}, + /* Aliases accepting the OpenSSL/IANA spelling without underscores. */ + {CURVE_NAME("MLKEM512"), WOLFSSL_ML_KEM_512, WOLFSSL_ML_KEM_512}, + {CURVE_NAME("MLKEM768"), WOLFSSL_ML_KEM_768, WOLFSSL_ML_KEM_768}, + {CURVE_NAME("MLKEM1024"), WOLFSSL_ML_KEM_1024, WOLFSSL_ML_KEM_1024}, +#if defined(HAVE_ECC) + #ifdef WOLFSSL_PQC_HYBRIDS + {CURVE_NAME("SecP256r1MLKEM768"), WOLFSSL_SECP256R1MLKEM768, + WOLFSSL_SECP256R1MLKEM768}, + {CURVE_NAME("SecP384r1MLKEM1024"), WOLFSSL_SECP384R1MLKEM1024, + WOLFSSL_SECP384R1MLKEM1024}, + {CURVE_NAME("X25519MLKEM768"), WOLFSSL_X25519MLKEM768, + WOLFSSL_X25519MLKEM768}, + #endif /* WOLFSSL_PQC_HYBRIDS */ + #ifdef WOLFSSL_EXTRA_PQC_HYBRIDS + {CURVE_NAME("SecP256r1MLKEM512"), WOLFSSL_SECP256R1MLKEM512, + WOLFSSL_SECP256R1MLKEM512}, + {CURVE_NAME("SecP384r1MLKEM768"), WOLFSSL_SECP384R1MLKEM768, + WOLFSSL_SECP384R1MLKEM768}, + {CURVE_NAME("SecP521r1MLKEM1024"), WOLFSSL_SECP521R1MLKEM1024, + WOLFSSL_SECP521R1MLKEM1024}, + {CURVE_NAME("X25519MLKEM512"), WOLFSSL_X25519MLKEM512, + WOLFSSL_X25519MLKEM512}, + {CURVE_NAME("X448MLKEM768"), WOLFSSL_X448MLKEM768, + WOLFSSL_X448MLKEM768}, + #endif /* WOLFSSL_EXTRA_PQC_HYBRIDS */ +#endif +#endif /* !WOLFSSL_NO_ML_KEM */ +#ifdef WOLFSSL_MLKEM_KYBER + {CURVE_NAME("KYBER_LEVEL1"), WOLFSSL_KYBER_LEVEL1, WOLFSSL_KYBER_LEVEL1}, + {CURVE_NAME("KYBER_LEVEL3"), WOLFSSL_KYBER_LEVEL3, WOLFSSL_KYBER_LEVEL3}, + {CURVE_NAME("KYBER_LEVEL5"), WOLFSSL_KYBER_LEVEL5, WOLFSSL_KYBER_LEVEL5}, +#if defined(HAVE_ECC) + {CURVE_NAME("P256_KYBER_LEVEL1"), WOLFSSL_P256_KYBER_LEVEL1, + WOLFSSL_P256_KYBER_LEVEL1}, + {CURVE_NAME("P384_KYBER_LEVEL3"), WOLFSSL_P384_KYBER_LEVEL3, + WOLFSSL_P384_KYBER_LEVEL3}, + {CURVE_NAME("P256_KYBER_LEVEL3"), WOLFSSL_P256_KYBER_LEVEL3, + WOLFSSL_P256_KYBER_LEVEL3}, + {CURVE_NAME("P521_KYBER_LEVEL5"), WOLFSSL_P521_KYBER_LEVEL5, + WOLFSSL_P521_KYBER_LEVEL5}, + {CURVE_NAME("X25519_KYBER_LEVEL1"), WOLFSSL_X25519_KYBER_LEVEL1, + WOLFSSL_X25519_KYBER_LEVEL1}, + {CURVE_NAME("X448_KYBER_LEVEL3"), WOLFSSL_X448_KYBER_LEVEL3, + WOLFSSL_X448_KYBER_LEVEL3}, + {CURVE_NAME("X25519_KYBER_LEVEL3"), WOLFSSL_X25519_KYBER_LEVEL3, + WOLFSSL_X25519_KYBER_LEVEL3}, +#endif +#endif /* WOLFSSL_MLKEM_KYBER */ +#endif /* WOLFSSL_HAVE_MLKEM */ +#ifdef WOLFSSL_SM2 + {CURVE_NAME("SM2"), WC_NID_sm2, WOLFSSL_ECC_SM2P256V1}, +#endif +#ifdef HAVE_ECC + /* Alternative curve names */ + {CURVE_NAME("prime256v1"), WC_NID_X9_62_prime256v1, WOLFSSL_ECC_SECP256R1}, + {CURVE_NAME("secp256r1"), WC_NID_X9_62_prime256v1, WOLFSSL_ECC_SECP256R1}, + {CURVE_NAME("secp384r1"), WC_NID_secp384r1, WOLFSSL_ECC_SECP384R1}, + {CURVE_NAME("secp521r1"), WC_NID_secp521r1, WOLFSSL_ECC_SECP521R1}, #endif - return WOLFSSL_FAILURE; -} +#ifdef WOLFSSL_SM2 + {CURVE_NAME("sm2p256v1"), WC_NID_sm2, WOLFSSL_ECC_SM2P256V1}, +#endif + {0, NULL, 0, 0}, +}; -#ifdef HAVE_EX_DATA_CLEANUP_HOOKS -int wolfSSL_CRYPTO_set_ex_data_with_cleanup( - WOLFSSL_CRYPTO_EX_DATA* ex_data, - int idx, - void *data, - wolfSSL_ex_data_cleanup_routine_t cleanup_routine) +int set_curves_list(WOLFSSL* ssl, WOLFSSL_CTX *ctx, const char* names, + byte curves_only) { - WOLFSSL_ENTER("wolfSSL_CRYPTO_set_ex_data_with_cleanup"); - if (ex_data && idx < MAX_EX_DATA && idx >= 0) { - if (ex_data->ex_data_cleanup_routines[idx] && ex_data->ex_data[idx]) - ex_data->ex_data_cleanup_routines[idx](ex_data->ex_data[idx]); - ex_data->ex_data[idx] = data; - ex_data->ex_data_cleanup_routines[idx] = cleanup_routine; - return WOLFSSL_SUCCESS; - } - return WOLFSSL_FAILURE; -} -#endif /* HAVE_EX_DATA_CLEANUP_HOOKS */ -#endif /* HAVE_EX_DATA */ + int idx, start = 0, len, i, ret = WOLFSSL_FAILURE; + word16 curve; + word32 disabled; + char name[MAX_CURVE_NAME_SZ]; + byte groups_len = 0; +#ifdef WOLFSSL_SMALL_STACK + void *heap = ssl? ssl->heap : ctx ? ctx->heap : NULL; + int *groups; +#else + int groups[WOLFSSL_MAX_GROUP_COUNT]; +#endif + const WOLF_EC_NIST_NAME* nist_name; -#ifdef HAVE_EX_DATA_CRYPTO -/** - * Issues unique index for the class specified by class_index. - * Other parameter except class_index are ignored. - * Currently, following class_index are accepted: - * - WOLF_CRYPTO_EX_INDEX_SSL - * - WOLF_CRYPTO_EX_INDEX_SSL_CTX - * - WOLF_CRYPTO_EX_INDEX_X509 - * @param class_index index one of CRYPTO_EX_INDEX_xxx - * @param argp parameters to be saved - * @param argl parameters to be saved - * @param new_func a pointer to WOLFSSL_CRYPTO_EX_new - * @param dup_func a pointer to WOLFSSL_CRYPTO_EX_dup - * @param free_func a pointer to WOLFSSL_CRYPTO_EX_free - * @return index value grater or equal to zero on success, -1 on failure. - */ -int wolfSSL_CRYPTO_get_ex_new_index(int class_index, long argl, void *argp, - WOLFSSL_CRYPTO_EX_new* new_func, - WOLFSSL_CRYPTO_EX_dup* dup_func, - WOLFSSL_CRYPTO_EX_free* free_func) -{ - WOLFSSL_ENTER("wolfSSL_CRYPTO_get_ex_new_index"); + WC_ALLOC_VAR_EX(groups, int, WOLFSSL_MAX_GROUP_COUNT, heap, + DYNAMIC_TYPE_TMP_BUFFER, + { + ret=MEMORY_E; + goto leave; + }); - return wolfssl_local_get_ex_new_index(class_index, argl, argp, new_func, - dup_func, free_func); -} -#endif /* HAVE_EX_DATA_CRYPTO */ + for (idx = 1; names[idx-1] != '\0'; idx++) { + if (names[idx] != ':' && names[idx] != '\0') + continue; -/******************************************************************************* - * END OF EX_DATA APIs - ******************************************************************************/ + len = idx - start; + if (len > MAX_CURVE_NAME_SZ - 1) + goto leave; -/******************************************************************************* - * START OF BUF_MEM API - ******************************************************************************/ + XMEMCPY(name, names + start, (size_t)len); + name[len] = 0; + curve = WOLFSSL_NAMED_GROUP_INVALID; -#if defined(OPENSSL_EXTRA) + for (nist_name = kNistCurves; nist_name->name != NULL; nist_name++) { + if (len == nist_name->name_len && + XSTRNCASECMP(name, nist_name->name, (size_t)len) == 0) { + curve = nist_name->curve; + break; + } + } -/* Begin functions for openssl/buffer.h */ -WOLFSSL_BUF_MEM* wolfSSL_BUF_MEM_new(void) -{ - WOLFSSL_BUF_MEM* buf; - buf = (WOLFSSL_BUF_MEM*)XMALLOC(sizeof(WOLFSSL_BUF_MEM), NULL, - DYNAMIC_TYPE_OPENSSL); - if (buf) { - XMEMSET(buf, 0, sizeof(WOLFSSL_BUF_MEM)); - } - return buf; -} + if (curve == WOLFSSL_NAMED_GROUP_INVALID) { + #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && defined(HAVE_ECC) + int nret; + const ecc_set_type *eccSet; -/* non-compat API returns length of buffer on success */ -int wolfSSL_BUF_MEM_grow_ex(WOLFSSL_BUF_MEM* buf, size_t len, - char zeroFill) -{ - size_t mx; - char* tmp; + nret = wc_ecc_get_curve_idx_from_name(name); + if (nret < 0) { + WOLFSSL_MSG("Could not find name in set"); + goto leave; + } - /* verify provided arguments. The return value is an int holding the - * resulting length, so reject any len that cannot be represented as a - * non-negative int. This also prevents truncating size_t to int. */ - if (buf == NULL || len > (size_t)WC_MAX_SINT_OF(int)) { - return 0; /* BAD_FUNC_ARG; */ - } + eccSet = wc_ecc_get_curve_params(nret); + if (eccSet == NULL) { + WOLFSSL_MSG("NULL set returned"); + goto leave; + } - /* check to see if fits in existing length */ - if (buf->length > len) { - buf->length = len; - return (int)len; + curve = GetCurveByOID((int)eccSet->oidSum); + #else + WOLFSSL_MSG("API not present to search farther using name"); + goto leave; + #endif + } + + if ((curves_only && curve >= WOLFSSL_ECC_MAX_AVAIL) || + curve == WOLFSSL_NAMED_GROUP_INVALID) { + WOLFSSL_MSG("curve value is not supported"); + goto leave; + } + + for (i = 0; i < groups_len; ++i) { + if (groups[i] == curve) { + /* silently drop duplicates */ + break; + } + } + if (i >= groups_len) { + if (groups_len >= WOLFSSL_MAX_GROUP_COUNT) { + WOLFSSL_MSG_EX("setting %d or more supported " + "curves is not permitted", groups_len); + goto leave; + } + groups[groups_len++] = (int)curve; + } + + start = idx + 1; } - /* check to see if fits in max buffer */ - if (buf->max >= len) { - if (buf->data != NULL && zeroFill) { - XMEMSET(&buf->data[buf->length], 0, len - buf->length); + /* Disable all curves so that only the ones the user wants are enabled. */ + disabled = 0xFFFFFFFFUL; + for (i = 0; i < groups_len; ++i) { + /* Switch the bit to off and therefore is enabled. */ + curve = (word16)groups[i]; + if (curve >= 64) { + WC_DO_NOTHING; } - buf->length = len; - return (int)len; + else if (curve >= 32) { + /* 0 is for invalid and 1-14 aren't used otherwise. */ + disabled &= ~(1U << (curve - 32)); + } + else { + disabled &= ~(1U << curve); + } + #if defined(HAVE_SUPPORTED_CURVES) && !defined(NO_TLS) + #if !defined(WOLFSSL_OLD_SET_CURVES_LIST) + /* using the wolfSSL API to set the groups, this will populate + * (ssl|ctx)->groups and reset any TLSX_SUPPORTED_GROUPS. + * The order in (ssl|ctx)->groups will then be respected + * when TLSX_KEY_SHARE needs to be established */ + if ((ssl && wolfSSL_set_groups(ssl, groups, groups_len) + != WOLFSSL_SUCCESS) + || (ctx && wolfSSL_CTX_set_groups(ctx, groups, groups_len) + != WOLFSSL_SUCCESS)) { + WOLFSSL_MSG("Unable to set supported curve"); + goto leave; + } + #elif !defined(NO_WOLFSSL_CLIENT) + /* set the supported curve so client TLS extension contains only the + * desired curves */ + if ((ssl && wolfSSL_UseSupportedCurve(ssl, curve) != WOLFSSL_SUCCESS) + || (ctx && wolfSSL_CTX_UseSupportedCurve(ctx, curve) + != WOLFSSL_SUCCESS)) { + WOLFSSL_MSG("Unable to set supported curve"); + goto leave; + } + #endif + #endif /* HAVE_SUPPORTED_CURVES && !NO_TLS */ } - /* expand size, to handle growth */ - mx = (len + 3) / 3 * 4; + if (ssl != NULL) + ssl->disabledCurves = disabled; + else if (ctx != NULL) + ctx->disabledCurves = disabled; + ret = WOLFSSL_SUCCESS; -#ifdef WOLFSSL_NO_REALLOC - tmp = (char*)XMALLOC(mx, NULL, DYNAMIC_TYPE_OPENSSL); - if (tmp != NULL && buf->data != NULL) { - /* only the existing content is valid in the old buffer; copying - * len_int (the new, larger size) would read past buf->max */ - XMEMCPY(tmp, buf->data, buf->length); - XFREE(buf->data, NULL, DYNAMIC_TYPE_OPENSSL); - buf->data = NULL; - } -#else - /* use realloc */ - tmp = (char*)XREALLOC(buf->data, mx, NULL, DYNAMIC_TYPE_OPENSSL); +leave: +#ifdef WOLFSSL_SMALL_STACK + if (groups) + XFREE((void*)groups, heap, DYNAMIC_TYPE_TMP_BUFFER); #endif + return ret; +} - if (tmp == NULL) { - return 0; /* ERR_R_MALLOC_FAILURE; */ - } - buf->data = tmp; +#endif /* (HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448) */ +#endif /* OPENSSL_EXTRA || HAVE_CURL */ - buf->max = mx; - if (zeroFill) - XMEMSET(&buf->data[buf->length], 0, len - buf->length); - buf->length = len; - return (int)len; +#ifdef OPENSSL_EXTRA +/* Sets a callback for when sending and receiving protocol messages. + * This callback is copied to all WOLFSSL objects created from the ctx. + * + * ctx WOLFSSL_CTX structure to set callback in + * cb callback to use + * + * return WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE with error case + */ +int wolfSSL_CTX_set_msg_callback(WOLFSSL_CTX *ctx, SSL_Msg_Cb cb) +{ + WOLFSSL_ENTER("wolfSSL_CTX_set_msg_callback"); + if (ctx == NULL) { + WOLFSSL_MSG("Null ctx passed in"); + return WOLFSSL_FAILURE; + } + ctx->protoMsgCb = cb; + return WOLFSSL_SUCCESS; } -/* returns length of buffer on success */ -int wolfSSL_BUF_MEM_grow(WOLFSSL_BUF_MEM* buf, size_t len) -{ - return wolfSSL_BUF_MEM_grow_ex(buf, len, 1); -} -/* non-compat API returns length of buffer on success */ -int wolfSSL_BUF_MEM_resize(WOLFSSL_BUF_MEM* buf, size_t len) +/* Sets a callback for when sending and receiving protocol messages. + * + * ssl WOLFSSL structure to set callback in + * cb callback to use + * + * return WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE with error case + */ +int wolfSSL_set_msg_callback(WOLFSSL *ssl, SSL_Msg_Cb cb) { - char* tmp; - size_t mx; + WOLFSSL_ENTER("wolfSSL_set_msg_callback"); - /* verify provided arguments. The return value is an int, so reject any - * len that cannot be represented as a positive int. */ - if (buf == NULL || len == 0 || len > (size_t)WC_MAX_SINT_OF(int)) { - return 0; /* BAD_FUNC_ARG; */ + if (ssl == NULL) { + return WOLFSSL_FAILURE; } - if (len == buf->length) - return (int)len; + if (cb != NULL) { + ssl->toInfoOn = 1; + } - if (len > buf->length) - return wolfSSL_BUF_MEM_grow_ex(buf, len, 0); + ssl->protoMsgCb = cb; + return WOLFSSL_SUCCESS; +} - /* expand size, to handle growth */ - mx = (len + 3) / 3 * 4; - /* We want to shrink the internal buffer */ -#ifdef WOLFSSL_NO_REALLOC - tmp = (char*)XMALLOC(mx, NULL, DYNAMIC_TYPE_OPENSSL); - if (tmp != NULL && buf->data != NULL) - { - XMEMCPY(tmp, buf->data, len); - XFREE(buf->data,NULL,DYNAMIC_TYPE_OPENSSL); - buf->data = NULL; +/* set the user argument to pass to the msg callback when called + * return WOLFSSL_SUCCESS on success */ +int wolfSSL_CTX_set_msg_callback_arg(WOLFSSL_CTX *ctx, void* arg) +{ + WOLFSSL_ENTER("wolfSSL_CTX_set_msg_callback_arg"); + if (ctx == NULL) { + WOLFSSL_MSG("Null WOLFSSL_CTX passed in"); + return WOLFSSL_FAILURE; } -#else - tmp = (char*)XREALLOC(buf->data, mx, NULL, DYNAMIC_TYPE_OPENSSL); -#endif - if (tmp == NULL) - return 0; + ctx->protoMsgCtx = arg; + return WOLFSSL_SUCCESS; +} - buf->data = tmp; - buf->length = len; - buf->max = mx; - return (int)len; +int wolfSSL_set_msg_callback_arg(WOLFSSL *ssl, void* arg) +{ + WOLFSSL_ENTER("wolfSSL_set_msg_callback_arg"); + if (ssl == NULL) + return WOLFSSL_FAILURE; + + ssl->protoMsgCtx = arg; + return WOLFSSL_SUCCESS; } -void wolfSSL_BUF_MEM_free(WOLFSSL_BUF_MEM* buf) +void *wolfSSL_OPENSSL_memdup(const void *data, size_t siz, const char* file, + int line) { - if (buf) { - XFREE(buf->data, NULL, DYNAMIC_TYPE_OPENSSL); - buf->data = NULL; - buf->max = 0; - buf->length = 0; - XFREE(buf, NULL, DYNAMIC_TYPE_OPENSSL); + void *ret; + (void)file; + (void)line; + + if (data == NULL || siz >= INT_MAX) + return NULL; + + ret = wolfSSL_OPENSSL_malloc(siz); + if (ret == NULL) { + return NULL; } + return XMEMCPY(ret, data, siz); } -/* End Functions for openssl/buffer.h */ -#endif /* OPENSSL_EXTRA */ +void wolfSSL_OPENSSL_cleanse(void *ptr, size_t len) +{ + if (ptr) + ForceZero(ptr, (word32)len); +} -/******************************************************************************* - * END OF BUF_MEM API - ******************************************************************************/ +#endif /* OPENSSL_EXTRA */ -#define WOLFSSL_CONF_INCLUDED -#include +#define WOLFSSL_SSL_API_EXT_INCLUDED +#include "src/ssl_api_ext.c" -/******************************************************************************* - * START OF RAND API - ******************************************************************************/ +#if defined(OPENSSL_EXTRA) -#if defined(OPENSSL_EXTRA) && !defined(WOLFSSL_NO_OPENSSL_RAND_CB) -static int wolfSSL_RAND_InitMutex(void) -{ -#ifndef WOLFSSL_MUTEX_INITIALIZER - if (gRandMethodsInit == 0) { - if (wc_InitMutex(&gRandMethodMutex) != 0) { - WOLFSSL_MSG("Bad Init Mutex rand methods"); - return BAD_MUTEX_E; - } - gRandMethodsInit = 1; - } -#endif - return 0; -} +#ifndef NO_BIO +#define WOLFSSL_BIO_INCLUDED +#include "src/bio.c" #endif -#ifdef OPENSSL_EXTRA +#endif /* OPENSSL_EXTRA */ -#if defined(HAVE_GETPID) && !defined(WOLFSSL_NO_GETPID) && \ - ((defined(HAVE_FIPS) && FIPS_VERSION3_LE(6,0,0)) || defined(HAVE_SELFTEST)) -/* In older FIPS bundles add check for reseed here since it does not exist in - * the older random.c certified files. */ -static pid_t currentRandPid = 0; -#endif -/* Checks if the global RNG has been created. If not then one is created. +#if defined(OPENSSL_EXTRA) + +/* frees all nodes in the current threads error queue * - * Returns WOLFSSL_SUCCESS when no error is encountered. + * id thread id. ERR_remove_state is depreciated and id is ignored. The + * current threads queue will be free'd. */ -int wolfSSL_RAND_Init(void) -{ - int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); -#ifdef HAVE_GLOBAL_RNG - if (wc_LockMutex(&globalRNGMutex) == 0) { - if (initGlobalRNG == 0) { - ret = wc_InitRng(&globalRNG); - if (ret == 0) { - #if defined(HAVE_GETPID) && !defined(WOLFSSL_NO_GETPID) && \ - ((defined(HAVE_FIPS) && FIPS_VERSION3_LE(6,0,0)) || \ - defined(HAVE_SELFTEST)) - - currentRandPid = getpid(); - #endif - initGlobalRNG = 1; - ret = WOLFSSL_SUCCESS; - } - } - else { - /* GlobalRNG is already initialized */ - ret = WOLFSSL_SUCCESS; - } - wc_UnLockMutex(&globalRNGMutex); - } -#endif - return ret; -} +#endif /* OPENSSL_EXTRA */ -/* WOLFSSL_SUCCESS on ok */ -int wolfSSL_RAND_seed(const void* seed, int len) +#if defined(OPENSSL_EXTRA) +/* wolfSSL_THREADID_current is provided as a compat API with + * CRYPTO_THREADID_current to register current thread id into given id object. + * However, CRYPTO_THREADID_current API has been deprecated and no longer + * exists in the OpenSSL 1.0.0 or later.This API only works as a stub + * like as existing wolfSSL_THREADID_set_numeric. + */ +void wolfSSL_THREADID_current(WOLFSSL_CRYPTO_THREADID* id) { -#ifndef WOLFSSL_NO_OPENSSL_RAND_CB - if (wolfSSL_RAND_InitMutex() == 0 && wc_LockMutex(&gRandMethodMutex) == 0) { - if (gRandMethods && gRandMethods->seed) { - int ret = gRandMethods->seed(seed, len); - wc_UnLockMutex(&gRandMethodMutex); - return ret; - } - wc_UnLockMutex(&gRandMethodMutex); - } -#else - (void)seed; - (void)len; -#endif - - /* Make sure global shared RNG (globalRNG) is initialized */ - return wolfSSL_RAND_Init(); + (void)id; + return; +} +/* wolfSSL_THREADID_hash is provided as a compatible API with + * CRYPTO_THREADID_hash which returns a hash value calculated from the + * specified thread id. However, CRYPTO_THREADID_hash API has been + * deprecated and no longer exists in the OpenSSL 1.0.0 or later. + * This API only works as a stub to returns 0. This behavior is + * equivalent to the latest OpenSSL CRYPTO_THREADID_hash. + */ +unsigned long wolfSSL_THREADID_hash(const WOLFSSL_CRYPTO_THREADID* id) +{ + (void)id; + return 0UL; } - -/* Returns the path for reading seed data from. - * Uses the env variable $RANDFILE first if set, if not then used $HOME/.rnd - * - * Note uses stdlib by default unless XGETENV macro is overwritten +/** + * Set security level (wolfSSL doesn't support setting the security level). * - * fname buffer to hold path - * len length of fname buffer + * The security level can only be set through a system wide crypto-policy + * with wolfSSL_crypto_policy_enable(). * - * Returns a pointer to fname on success and NULL on failure + * @param ctx a pointer to WOLFSSL_CTX structure + * @param level security level */ -const char* wolfSSL_RAND_file_name(char* fname, unsigned long len) +void wolfSSL_CTX_set_security_level(WOLFSSL_CTX* ctx, int level) { -#if !defined(NO_FILESYSTEM) && defined(XGETENV) && !defined(NO_GETENV) - char* rt; - - WOLFSSL_ENTER("wolfSSL_RAND_file_name"); + WOLFSSL_ENTER("wolfSSL_CTX_set_security_level"); + (void)ctx; + (void)level; +} - if (fname == NULL) { - return NULL; +int wolfSSL_CTX_get_security_level(const WOLFSSL_CTX * ctx) +{ + WOLFSSL_ENTER("wolfSSL_CTX_get_security_level"); + #if defined(WOLFSSL_SYS_CRYPTO_POLICY) + if (ctx == NULL) { + return BAD_FUNC_ARG; } - XMEMSET(fname, 0, len); + return ctx->secLevel; + #else + (void)ctx; + return 0; + #endif /* WOLFSSL_SYS_CRYPTO_POLICY */ +} -/* // NOLINTBEGIN(concurrency-mt-unsafe) */ - if ((rt = XGETENV("RANDFILE")) != NULL) { - if (len > XSTRLEN(rt)) { - XMEMCPY(fname, rt, XSTRLEN(rt)); - } - else { - WOLFSSL_MSG("RANDFILE too large for buffer"); - rt = NULL; - } +#if defined(OPENSSL_EXTRA) && defined(HAVE_SECRET_CALLBACK) +/* + * This API accepts a user callback which puts key-log records into + * a KEY LOGFILE. The callback is stored into a CTX and propagated to + * each SSL object on its creation timing. + */ +void wolfSSL_CTX_set_keylog_callback(WOLFSSL_CTX* ctx, + wolfSSL_CTX_keylog_cb_func cb) +{ + WOLFSSL_ENTER("wolfSSL_CTX_set_keylog_callback"); + /* stores the callback into WOLFSSL_CTX */ + if (ctx != NULL) { + ctx->keyLogCb = cb; } -/* // NOLINTEND(concurrency-mt-unsafe) */ - - /* $RANDFILE was not set or is too large, check $HOME */ - if (rt == NULL) { - const char ap[] = "/.rnd"; - - WOLFSSL_MSG("Environment variable RANDFILE not set"); +} +wolfSSL_CTX_keylog_cb_func wolfSSL_CTX_get_keylog_callback( + const WOLFSSL_CTX* ctx) +{ + WOLFSSL_ENTER("wolfSSL_CTX_get_keylog_callback"); + if (ctx != NULL) + return ctx->keyLogCb; + return NULL; +} +#endif /* OPENSSL_EXTRA && HAVE_SECRET_CALLBACK */ -/* // NOLINTBEGIN(concurrency-mt-unsafe) */ - if ((rt = XGETENV("HOME")) == NULL) { - #ifdef XALTHOMEVARNAME - if ((rt = XGETENV(XALTHOMEVARNAME)) == NULL) { - WOLFSSL_MSG("Environment variable HOME and " XALTHOMEVARNAME - " not set"); - return NULL; - } - #else - WOLFSSL_MSG("Environment variable HOME not set"); - return NULL; - #endif - } -/* // NOLINTEND(concurrency-mt-unsafe) */ +#endif /* OPENSSL_EXTRA */ - if (len > XSTRLEN(rt) + XSTRLEN(ap)) { - fname[0] = '\0'; - XSTRNCAT(fname, rt, len); - XSTRNCAT(fname, ap, len - XSTRLEN(rt)); - return fname; - } - else { - WOLFSSL_MSG("Path too large for buffer"); - return NULL; - } - } +#ifdef WOLFSSL_THREADED_CRYPT +int wolfSSL_AsyncEncryptReady(WOLFSSL* ssl, int idx) +{ + ThreadCrypt* encrypt; - return fname; -#else - WOLFSSL_ENTER("wolfSSL_RAND_file_name"); - WOLFSSL_MSG("RAND_file_name requires filesystem and getenv support, " - "not compiled in"); - (void)fname; - (void)len; - return NULL; -#endif -} + if (ssl == NULL) { + return 0; + } + encrypt = &ssl->buffers.encrypt[idx]; + return (encrypt->avail == 0) && (encrypt->done == 0); +} -#ifndef WOLFSSL_RAND_WRITE_FILE_BUF_SZ -#define WOLFSSL_RAND_WRITE_FILE_BUF_SZ 1024 -#endif -/* Writes WOLFSSL_RAND_WRITE_FILE_BUF_SZ bytes (1024 by default) from the RNG - * to the given file name. - * - * fname name of file to write to - * - * Returns the number of bytes written - */ -int wolfSSL_RAND_write_file(const char* fname) +int wolfSSL_AsyncEncryptStop(WOLFSSL* ssl, int idx) { - int bytes = 0; - - WOLFSSL_ENTER("wolfSSL_RAND_write_file"); + ThreadCrypt* encrypt; - if (fname == NULL) { - return WOLFSSL_FAILURE; + if (ssl == NULL) { + return 1; } -#ifndef NO_FILESYSTEM - { - #ifndef WOLFSSL_SMALL_STACK - unsigned char buf[WOLFSSL_RAND_WRITE_FILE_BUF_SZ]; - #else - unsigned char* buf = (unsigned char *)XMALLOC( - WOLFSSL_RAND_WRITE_FILE_BUF_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (buf == NULL) { - WOLFSSL_MSG("malloc failed"); - return WOLFSSL_FAILURE; - } - #endif - bytes = WOLFSSL_RAND_WRITE_FILE_BUF_SZ; + encrypt = &ssl->buffers.encrypt[idx]; + return encrypt->stop; +} - if (initGlobalRNG == 0 && wolfSSL_RAND_Init() != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("No RNG to use"); - WC_FREE_VAR_EX(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return 0; - } +int wolfSSL_AsyncEncrypt(WOLFSSL* ssl, int idx) +{ + int ret = WC_NO_ERR_TRACE(NOT_COMPILED_IN); + ThreadCrypt* encrypt = &ssl->buffers.encrypt[idx]; - if (wc_LockMutex(&globalRNGMutex) != 0) { - WOLFSSL_MSG("Bad Lock Mutex rng"); - WC_FREE_VAR_EX(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return 0; - } + if (ssl->specs.bulk_cipher_algorithm == wolfssl_aes_gcm) { + unsigned char* out = encrypt->buffer.buffer + encrypt->offset; + unsigned char* input = encrypt->buffer.buffer + encrypt->offset; + word32 encSz = encrypt->buffer.length - encrypt->offset; - if (wc_RNG_GenerateBlock(&globalRNG, buf, (word32)bytes) != 0) { - wc_UnLockMutex(&globalRNGMutex); - WOLFSSL_MSG("Error generating random buffer"); - bytes = 0; - } - else { - XFILE f; + ret = +#if !defined(NO_GCM_ENCRYPT_EXTRA) && \ + ((!defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)) || \ + (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2))) + wc_AesGcmEncrypt_ex +#else + wc_AesGcmEncrypt +#endif + (encrypt->encrypt.aes, + out + AESGCM_EXP_IV_SZ, input + AESGCM_EXP_IV_SZ, + encSz - AESGCM_EXP_IV_SZ - ssl->specs.aead_mac_size, + encrypt->nonce, AESGCM_NONCE_SZ, + out + encSz - ssl->specs.aead_mac_size, + ssl->specs.aead_mac_size, + encrypt->additional, AEAD_AUTH_DATA_SZ); +#if !defined(NO_PUBLIC_GCM_SET_IV) && \ + ((!defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)) || \ + (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2))) + XMEMCPY(out, encrypt->nonce + AESGCM_IMP_IV_SZ, AESGCM_EXP_IV_SZ); +#endif + encrypt->done = 1; + } - wc_UnLockMutex(&globalRNGMutex); + return ret; +} - #ifdef WOLFSSL_CHECK_MEM_ZERO - wc_MemZero_Add("wolfSSL_RAND_write_file buf", buf, bytes); - #endif +int wolfSSL_AsyncEncryptSetSignal(WOLFSSL* ssl, int idx, + WOLFSSL_THREAD_SIGNAL signal, void* ctx) +{ + int ret = 0; - f = XFOPEN(fname, "wb"); - if (f == XBADFILE) { - WOLFSSL_MSG("Error opening the file"); - bytes = 0; - } - else { - size_t bytes_written = XFWRITE(buf, 1, (size_t)bytes, f); - bytes = (int)bytes_written; - XFCLOSE(f); - } - } - /* wipe the whole buffer, not just (word32)bytes: error paths set - * bytes = 0 but the buffer may still hold generated random data */ - ForceZero(buf, WOLFSSL_RAND_WRITE_FILE_BUF_SZ); - #ifdef WOLFSSL_SMALL_STACK - XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - #elif defined(WOLFSSL_CHECK_MEM_ZERO) - wc_MemZero_Check(buf, sizeof(buf)); - #endif + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ssl->buffers.encrypt[idx].signal = signal; + ssl->buffers.encrypt[idx].signalCtx = ctx; } -#endif - return bytes; + return ret; } +#endif -#ifndef FREERTOS_TCP -/* These constant values are protocol values made by egd */ -#if defined(USE_WOLFSSL_IO) && !defined(USE_WINDOWS_API) && \ - !defined(HAVE_FIPS) && defined(HAVE_HASHDRBG) && !defined(NETOS) && \ - defined(HAVE_SYS_UN_H) - #define WOLFSSL_EGD_NBLOCK 0x01 - #include +#ifndef NO_CERT +#define WOLFSSL_X509_INCLUDED +#include "src/x509.c" #endif -/* This collects entropy from the path nm and seeds the global PRNG with it. - * - * nm is the file path to the egd server - * - * Returns the number of bytes read. - */ -int wolfSSL_RAND_egd(const char* nm) +/******************************************************************************* + * START OF standard C library wrapping APIs + ******************************************************************************/ +#if defined(OPENSSL_ALL) || (defined(OPENSSL_EXTRA) && \ + (defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \ + defined(HAVE_LIGHTY) || defined(WOLFSSL_HAPROXY) || \ + defined(WOLFSSL_OPENSSH))) +#ifndef NO_WOLFSSL_STUB +int wolfSSL_CRYPTO_set_mem_ex_functions(void *(*m) (size_t, const char *, int), + void *(*r) (void *, size_t, const char *, + int), void (*f) (void *)) { -#ifdef WOLFSSL_EGD_NBLOCK - struct sockaddr_un rem; - int fd; - int ret = WOLFSSL_SUCCESS; - word32 bytes = 0; - word32 idx = 0; -#ifndef WOLFSSL_SMALL_STACK - unsigned char buf[256]; -#else - unsigned char* buf; - buf = (unsigned char*)XMALLOC(256, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (buf == NULL) { - WOLFSSL_MSG("Not enough memory"); - return WOLFSSL_FATAL_ERROR; - } -#endif + (void) m; + (void) r; + (void) f; + WOLFSSL_ENTER("wolfSSL_CRYPTO_set_mem_ex_functions"); + WOLFSSL_STUB("CRYPTO_set_mem_ex_functions"); - XMEMSET(&rem, 0, sizeof(struct sockaddr_un)); - if (nm == NULL) { - WC_FREE_VAR_EX(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return WOLFSSL_FATAL_ERROR; - } + return WOLFSSL_FAILURE; +} +#endif +#endif - fd = wc_socket_cloexec(AF_UNIX, SOCK_STREAM, 0); - if (fd < 0) { - WOLFSSL_MSG("Error creating socket"); - WC_FREE_VAR_EX(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return WOLFSSL_FATAL_ERROR; - } - rem.sun_family = AF_UNIX; - XSTRNCPY(rem.sun_path, nm, sizeof(rem.sun_path) - 1); - rem.sun_path[sizeof(rem.sun_path)-1] = '\0'; +#if defined(OPENSSL_EXTRA) - /* connect to egd server */ - if (connect(fd, (struct sockaddr*)&rem, sizeof(struct sockaddr_un)) == -1) { - WOLFSSL_MSG("error connecting to egd server"); - ret = WOLFSSL_FATAL_ERROR; - } +/** + * free allocated memory resource + * @param str a pointer to resource to be freed + * @param file dummy argument + * @param line dummy argument + */ +void wolfSSL_CRYPTO_free(void *str, const char *file, int line) +{ + (void)file; + (void)line; + XFREE(str, 0, DYNAMIC_TYPE_TMP_BUFFER); +} +/** + * allocate memory with size of num + * @param num size of memory allocation to be malloced + * @param file dummy argument + * @param line dummy argument + * @return a pointer to allocated memory on succssesful, otherwise NULL + */ +void *wolfSSL_CRYPTO_malloc(size_t num, const char *file, int line) +{ + (void)file; + (void)line; + return XMALLOC(num, 0, DYNAMIC_TYPE_TMP_BUFFER); +} -#ifdef WOLFSSL_CHECK_MEM_ZERO - if (ret == WOLFSSL_SUCCESS) { - wc_MemZero_Add("wolfSSL_RAND_egd buf", buf, 256); - } #endif - while (ret == WOLFSSL_SUCCESS && bytes < 255 && idx + 2 < 256) { - buf[idx] = WOLFSSL_EGD_NBLOCK; - buf[idx + 1] = 255 - bytes; /* request 255 bytes from server */ - ret = (int)write(fd, buf + idx, 2); - if (ret != 2) { - if (errno == EAGAIN) { - ret = WOLFSSL_SUCCESS; - continue; - } - WOLFSSL_MSG("error requesting entropy from egd server"); - ret = WOLFSSL_FATAL_ERROR; - break; - } - /* attempting to read */ - buf[idx] = 0; - ret = (int)read(fd, buf + idx, 256 - bytes); - if (ret == 0) { - WOLFSSL_MSG("error reading entropy from egd server"); - ret = WOLFSSL_FATAL_ERROR; - break; - } - if (ret > 0 && buf[idx] > 0) { - bytes += buf[idx]; /* egd stores amount sent in first byte */ - if (bytes + idx > 255 || buf[idx] > ret) { - WOLFSSL_MSG("Buffer error"); - ret = WOLFSSL_FATAL_ERROR; - break; - } - XMEMMOVE(buf + idx, buf + idx + 1, buf[idx]); - idx = bytes; - ret = WOLFSSL_SUCCESS; - if (bytes >= 255) { - break; - } - } - else { - if (errno == EAGAIN || errno == EINTR) { - WOLFSSL_MSG("EGD would read"); - ret = WOLFSSL_SUCCESS; /* try again */ - } - else if (buf[idx] == 0) { - /* if egd returned 0 then there is no more entropy to be had. - Do not try more reads. */ - ret = WOLFSSL_SUCCESS; - break; - } - else { - WOLFSSL_MSG("Error with read"); - ret = WOLFSSL_FATAL_ERROR; - } - } - } +/******************************************************************************* + * END OF standard C library wrapping APIs + ******************************************************************************/ - if (bytes > 0 && ret == WOLFSSL_SUCCESS) { - /* call to check global RNG is created */ - if (wolfSSL_RAND_Init() != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("Error with initializing global RNG structure"); - ret = WOLFSSL_FATAL_ERROR; - } - else if (wc_LockMutex(&globalRNGMutex) != 0) { - WOLFSSL_MSG("Bad Lock Mutex rng"); - ret = WOLFSSL_FATAL_ERROR; - } - else { - if (wc_RNG_DRBG_Reseed(&globalRNG, (const byte*) buf, bytes) - != 0) { - WOLFSSL_MSG("Error with reseeding DRBG structure"); - ret = WOLFSSL_FATAL_ERROR; - } - wc_UnLockMutex(&globalRNGMutex); +/******************************************************************************* + * START OF EX_DATA APIs + ******************************************************************************/ +#ifdef HAVE_EX_DATA +void wolfSSL_CRYPTO_cleanup_all_ex_data(void) +{ + WOLFSSL_ENTER("wolfSSL_CRYPTO_cleanup_all_ex_data"); +} - #ifdef SHOW_SECRETS - /* print out entropy found only when no error occurred */ - if (ret == WOLFSSL_SUCCESS) { - word32 i; - printf("EGD Entropy = "); - for (i = 0; i < bytes; i++) { - printf("%02X", buf[i]); - } - printf("\n"); - } - #endif - } +void* wolfSSL_CRYPTO_get_ex_data(const WOLFSSL_CRYPTO_EX_DATA* ex_data, int idx) +{ + WOLFSSL_ENTER("wolfSSL_CRYPTO_get_ex_data"); +#ifdef MAX_EX_DATA + if (ex_data && idx < MAX_EX_DATA && idx >= 0) { + return ex_data->ex_data[idx]; } - - ForceZero(buf, bytes); -#ifdef WOLFSSL_SMALL_STACK - XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#elif defined(WOLFSSL_CHECK_MEM_ZERO) - wc_MemZero_Check(buf, 256); +#else + (void)ex_data; + (void)idx; #endif - close(fd); + return NULL; +} - if (ret == WOLFSSL_SUCCESS) { - return (int)bytes; - } - else { - return ret; +int wolfSSL_CRYPTO_set_ex_data(WOLFSSL_CRYPTO_EX_DATA* ex_data, int idx, + void *data) +{ + WOLFSSL_ENTER("wolfSSL_CRYPTO_set_ex_data"); +#ifdef MAX_EX_DATA + if (ex_data && idx < MAX_EX_DATA && idx >= 0) { +#ifdef HAVE_EX_DATA_CLEANUP_HOOKS + if (ex_data->ex_data_cleanup_routines[idx]) { + /* call cleanup then remove cleanup callback, + * since different value is being set */ + if (ex_data->ex_data[idx]) + ex_data->ex_data_cleanup_routines[idx](ex_data->ex_data[idx]); + ex_data->ex_data_cleanup_routines[idx] = NULL; + } +#endif + ex_data->ex_data[idx] = data; + return WOLFSSL_SUCCESS; } #else - WOLFSSL_MSG("Type of socket needed is not available"); - WOLFSSL_MSG("\tor using mode where DRBG API is not available"); - (void)nm; - - return WOLFSSL_FATAL_ERROR; -#endif /* WOLFSSL_EGD_NBLOCK */ + (void)ex_data; + (void)idx; + (void)data; +#endif + return WOLFSSL_FAILURE; } -#endif /* !FREERTOS_TCP */ +#ifdef HAVE_EX_DATA_CLEANUP_HOOKS +int wolfSSL_CRYPTO_set_ex_data_with_cleanup( + WOLFSSL_CRYPTO_EX_DATA* ex_data, + int idx, + void *data, + wolfSSL_ex_data_cleanup_routine_t cleanup_routine) +{ + WOLFSSL_ENTER("wolfSSL_CRYPTO_set_ex_data_with_cleanup"); + if (ex_data && idx < MAX_EX_DATA && idx >= 0) { + if (ex_data->ex_data_cleanup_routines[idx] && ex_data->ex_data[idx]) + ex_data->ex_data_cleanup_routines[idx](ex_data->ex_data[idx]); + ex_data->ex_data[idx] = data; + ex_data->ex_data_cleanup_routines[idx] = cleanup_routine; + return WOLFSSL_SUCCESS; + } + return WOLFSSL_FAILURE; +} +#endif /* HAVE_EX_DATA_CLEANUP_HOOKS */ +#endif /* HAVE_EX_DATA */ -void wolfSSL_RAND_Cleanup(void) +#ifdef HAVE_EX_DATA_CRYPTO +/** + * Issues unique index for the class specified by class_index. + * Other parameter except class_index are ignored. + * Currently, following class_index are accepted: + * - WOLF_CRYPTO_EX_INDEX_SSL + * - WOLF_CRYPTO_EX_INDEX_SSL_CTX + * - WOLF_CRYPTO_EX_INDEX_X509 + * @param class_index index one of CRYPTO_EX_INDEX_xxx + * @param argp parameters to be saved + * @param argl parameters to be saved + * @param new_func a pointer to WOLFSSL_CRYPTO_EX_new + * @param dup_func a pointer to WOLFSSL_CRYPTO_EX_dup + * @param free_func a pointer to WOLFSSL_CRYPTO_EX_free + * @return index value grater or equal to zero on success, -1 on failure. + */ +int wolfSSL_CRYPTO_get_ex_new_index(int class_index, long argl, void *argp, + WOLFSSL_CRYPTO_EX_new* new_func, + WOLFSSL_CRYPTO_EX_dup* dup_func, + WOLFSSL_CRYPTO_EX_free* free_func) { -#ifndef WOLFSSL_NO_OPENSSL_RAND_CB - if (wolfSSL_RAND_InitMutex() == 0 && wc_LockMutex(&gRandMethodMutex) == 0) { - if (gRandMethods && gRandMethods->cleanup) - gRandMethods->cleanup(); - wc_UnLockMutex(&gRandMethodMutex); - } + WOLFSSL_ENTER("wolfSSL_CRYPTO_get_ex_new_index"); - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (wc_FreeMutex(&gRandMethodMutex) == 0) - gRandMethodsInit = 0; - #endif -#endif -#ifdef HAVE_GLOBAL_RNG - if (wc_LockMutex(&globalRNGMutex) == 0) { - if (initGlobalRNG) { - wc_FreeRng(&globalRNG); - initGlobalRNG = 0; - } - wc_UnLockMutex(&globalRNGMutex); - } -#endif + return wolfssl_local_get_ex_new_index(class_index, argl, argp, new_func, + dup_func, free_func); } +#endif /* HAVE_EX_DATA_CRYPTO */ -/* returns WOLFSSL_SUCCESS if the bytes generated are valid otherwise - * WOLFSSL_FAILURE */ -int wolfSSL_RAND_pseudo_bytes(unsigned char* buf, int num) -{ - int ret; - int hash; - byte secret[DRBG_SEED_LEN]; /* secret length arbitrarily chosen */ - -#ifndef WOLFSSL_NO_OPENSSL_RAND_CB - if (wolfSSL_RAND_InitMutex() == 0 && wc_LockMutex(&gRandMethodMutex) == 0) { - if (gRandMethods && gRandMethods->pseudorand) { - ret = gRandMethods->pseudorand(buf, num); - wc_UnLockMutex(&gRandMethodMutex); - return ret; - } - wc_UnLockMutex(&gRandMethodMutex); - } -#endif +/******************************************************************************* + * END OF EX_DATA APIs + ******************************************************************************/ -#ifdef WOLFSSL_HAVE_PRF - #ifndef NO_SHA256 - hash = WC_SHA256; - #elif defined(WOLFSSL_SHA384) - hash = WC_SHA384; - #elif !defined(NO_SHA) - hash = WC_SHA; - #elif !defined(NO_MD5) - hash = WC_MD5; - #endif +/******************************************************************************* + * START OF BUF_MEM API + ******************************************************************************/ - /* get secret value from source of entropy */ - ret = wolfSSL_RAND_bytes(secret, DRBG_SEED_LEN); +#if defined(OPENSSL_EXTRA) - /* uses input buffer to seed for pseudo random number generation, each - * thread will potentially have different results this way */ - if (ret == WOLFSSL_SUCCESS) { - PRIVATE_KEY_UNLOCK(); - ret = wc_PRF(buf, num, secret, DRBG_SEED_LEN, (const byte*)buf, num, - hash, NULL, INVALID_DEVID); - PRIVATE_KEY_LOCK(); - ret = (ret == 0) ? WOLFSSL_SUCCESS: WOLFSSL_FAILURE; +/* Begin functions for openssl/buffer.h */ +WOLFSSL_BUF_MEM* wolfSSL_BUF_MEM_new(void) +{ + WOLFSSL_BUF_MEM* buf; + buf = (WOLFSSL_BUF_MEM*)XMALLOC(sizeof(WOLFSSL_BUF_MEM), NULL, + DYNAMIC_TYPE_OPENSSL); + if (buf) { + XMEMSET(buf, 0, sizeof(WOLFSSL_BUF_MEM)); } -#else - /* fall back to just doing wolfSSL_RAND_bytes if PRF not avialbale */ - ret = wolfSSL_RAND_bytes(buf, num); - (void)hash; - (void)secret; -#endif - return ret; + return buf; } -/* returns WOLFSSL_SUCCESS (1) if the bytes generated are valid otherwise 0 - * on failure */ -int wolfSSL_RAND_bytes(unsigned char* buf, int num) +/* non-compat API returns length of buffer on success */ +int wolfSSL_BUF_MEM_grow_ex(WOLFSSL_BUF_MEM* buf, size_t len, + char zeroFill) { - int ret = 0; - WC_RNG* rng = NULL; - WC_DECLARE_VAR(tmpRNG, WC_RNG, 1, 0); - int initTmpRng = 0; -#ifdef HAVE_GLOBAL_RNG - int used_global = 0; -#endif - - WOLFSSL_ENTER("wolfSSL_RAND_bytes"); - /* sanity check */ - if (buf == NULL || num < 0) - /* return code compliant with OpenSSL */ - return 0; + size_t mx; + char* tmp; - /* if a RAND callback has been set try and use it */ -#ifndef WOLFSSL_NO_OPENSSL_RAND_CB - if (wolfSSL_RAND_InitMutex() == 0 && wc_LockMutex(&gRandMethodMutex) == 0) { - if (gRandMethods && gRandMethods->bytes) { - ret = gRandMethods->bytes(buf, num); - wc_UnLockMutex(&gRandMethodMutex); - return ret; - } - wc_UnLockMutex(&gRandMethodMutex); + /* verify provided arguments. The return value is an int holding the + * resulting length, so reject any len that cannot be represented as a + * non-negative int. This also prevents truncating size_t to int. */ + if (buf == NULL || len > (size_t)WC_MAX_SINT_OF(int)) { + return 0; /* BAD_FUNC_ARG; */ } -#endif -#ifdef HAVE_GLOBAL_RNG - if (initGlobalRNG) { - if (wc_LockMutex(&globalRNGMutex) != 0) { - WOLFSSL_MSG("Bad Lock Mutex rng"); - return ret; - } - /* the above access to initGlobalRNG is racey -- recheck it now that we - * have the lock. - */ - if (initGlobalRNG) { - #if defined(HAVE_GETPID) && !defined(WOLFSSL_NO_GETPID) && \ - ((defined(HAVE_FIPS) && FIPS_VERSION3_LE(6,0,0)) || \ - defined(HAVE_SELFTEST)) - pid_t p; - - p = getpid(); - if (p != currentRandPid) { - wc_UnLockMutex(&globalRNGMutex); - if (wolfSSL_RAND_poll() != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("Issue with check pid and reseed"); - ret = WOLFSSL_FAILURE; - } - /* reclaim lock after wolfSSL_RAND_poll */ - if (wc_LockMutex(&globalRNGMutex) != 0) { - WOLFSSL_MSG("Bad Lock Mutex rng"); - return ret; - } - currentRandPid = p; - } - #endif - rng = &globalRNG; - used_global = 1; - } - else { - wc_UnLockMutex(&globalRNGMutex); - } + /* check to see if fits in existing length */ + if (buf->length > len) { + buf->length = len; + return (int)len; } - if (used_global == 0) -#endif - { - WC_ALLOC_VAR_EX(tmpRNG, WC_RNG, 1, NULL, DYNAMIC_TYPE_RNG, - return ret); - if (wc_InitRng(tmpRNG) == 0) { - rng = tmpRNG; - initTmpRng = 1; + /* check to see if fits in max buffer */ + if (buf->max >= len) { + if (buf->data != NULL && zeroFill) { + XMEMSET(&buf->data[buf->length], 0, len - buf->length); } + buf->length = len; + return (int)len; } - if (rng) { - /* handles size greater than RNG_MAX_BLOCK_LEN */ - int blockCount = num / RNG_MAX_BLOCK_LEN; - - while (blockCount--) { - ret = wc_RNG_GenerateBlock(rng, buf, RNG_MAX_BLOCK_LEN); - if (ret != 0) { - WOLFSSL_MSG("Bad wc_RNG_GenerateBlock"); - break; - } - num -= RNG_MAX_BLOCK_LEN; - buf += RNG_MAX_BLOCK_LEN; - } - if (ret == 0 && num) - ret = wc_RNG_GenerateBlock(rng, buf, (word32)num); + /* expand size, to handle growth */ + mx = (len + 3) / 3 * 4; - if (ret != 0) - WOLFSSL_MSG("Bad wc_RNG_GenerateBlock"); - else - ret = WOLFSSL_SUCCESS; +#ifdef WOLFSSL_NO_REALLOC + tmp = (char*)XMALLOC(mx, NULL, DYNAMIC_TYPE_OPENSSL); + if (tmp != NULL && buf->data != NULL) { + /* only the existing content is valid in the old buffer; copying + * len_int (the new, larger size) would read past buf->max */ + XMEMCPY(tmp, buf->data, buf->length); + XFREE(buf->data, NULL, DYNAMIC_TYPE_OPENSSL); + buf->data = NULL; } - -#ifdef HAVE_GLOBAL_RNG - if (used_global == 1) - wc_UnLockMutex(&globalRNGMutex); +#else + /* use realloc */ + tmp = (char*)XREALLOC(buf->data, mx, NULL, DYNAMIC_TYPE_OPENSSL); #endif - if (initTmpRng) - wc_FreeRng(tmpRNG); - WC_FREE_VAR_EX(tmpRNG, NULL, DYNAMIC_TYPE_RNG); - - return ret; -} - - -int wolfSSL_RAND_poll(void) -{ - byte entropy[16]; - int ret = 0; - word32 entropy_sz = 16; - WOLFSSL_ENTER("wolfSSL_RAND_poll"); - if (initGlobalRNG == 0){ - WOLFSSL_MSG("Global RNG no Init"); - return WOLFSSL_FAILURE; + if (tmp == NULL) { + return 0; /* ERR_R_MALLOC_FAILURE; */ } + buf->data = tmp; - /* lock intentionally covers wc_GenerateSeed as well, since it writes - * globalRNG.seed; do not narrow this scope or the seed write races */ - if (wc_LockMutex(&globalRNGMutex) != 0) { - WOLFSSL_MSG("Bad Lock Mutex rng"); - return WOLFSSL_FAILURE; - } + buf->max = mx; + if (zeroFill) + XMEMSET(&buf->data[buf->length], 0, len - buf->length); + buf->length = len; - ret = wc_GenerateSeed(&globalRNG.seed, entropy, entropy_sz); - if (ret != 0) { - WOLFSSL_MSG("Bad wc_GenerateSeed"); - ret = WOLFSSL_FAILURE; - } - else { -#ifdef HAVE_HASHDRBG - ret = wc_RNG_DRBG_Reseed(&globalRNG, entropy, entropy_sz); - if (ret != 0) { - WOLFSSL_MSG("Error reseeding DRBG"); - ret = WOLFSSL_FAILURE; - } - else { - ret = WOLFSSL_SUCCESS; - } -#elif defined(HAVE_INTEL_RDRAND) - WOLFSSL_MSG("Not polling with RAND_poll, RDRAND used without " - "HAVE_HASHDRBG"); - ret = WOLFSSL_SUCCESS; -#else - WOLFSSL_MSG("RAND_poll called with HAVE_HASHDRBG not set"); - ret = WOLFSSL_FAILURE; -#endif - } + return (int)len; - wc_UnLockMutex(&globalRNGMutex); +} - return ret; +/* returns length of buffer on success */ +int wolfSSL_BUF_MEM_grow(WOLFSSL_BUF_MEM* buf, size_t len) +{ + return wolfSSL_BUF_MEM_grow_ex(buf, len, 1); } - /* If a valid struct is provided with function pointers, will override - RAND_seed, bytes, cleanup, add, pseudo_bytes and status. If a NULL - pointer is passed in, it will cancel any previous function overrides. +/* non-compat API returns length of buffer on success */ +int wolfSSL_BUF_MEM_resize(WOLFSSL_BUF_MEM* buf, size_t len) +{ + char* tmp; + size_t mx; - Returns WOLFSSL_SUCCESS on success, WOLFSSL_FAILURE on failure. */ - int wolfSSL_RAND_set_rand_method(const WOLFSSL_RAND_METHOD *methods) - { - #ifndef WOLFSSL_NO_OPENSSL_RAND_CB - if (wolfSSL_RAND_InitMutex() == 0 && - wc_LockMutex(&gRandMethodMutex) == 0) { - gRandMethods = methods; - wc_UnLockMutex(&gRandMethodMutex); - return WOLFSSL_SUCCESS; - } - #else - (void)methods; - #endif - return WOLFSSL_FAILURE; + /* verify provided arguments. The return value is an int, so reject any + * len that cannot be represented as a positive int. */ + if (buf == NULL || len == 0 || len > (size_t)WC_MAX_SINT_OF(int)) { + return 0; /* BAD_FUNC_ARG; */ } - /* Returns WOLFSSL_SUCCESS if the RNG has been seeded with enough data */ - int wolfSSL_RAND_status(void) - { - int ret = WOLFSSL_SUCCESS; - int useGlobalRng = 1; - #ifndef WOLFSSL_NO_OPENSSL_RAND_CB - if (wolfSSL_RAND_InitMutex() == 0 && - wc_LockMutex(&gRandMethodMutex) == 0) { - if (gRandMethods && gRandMethods->status) { - ret = gRandMethods->status(); - useGlobalRng = 0; - } - wc_UnLockMutex(&gRandMethodMutex); - } - else { - ret = WOLFSSL_FAILURE; - useGlobalRng = 0; - } - #endif + if (len == buf->length) + return (int)len; - /* Drive the global RNG so init / DRBG state failures (mutex - * acquisition, reseed required, corrupted state) surface to the - * caller. DRBG output is deterministic between reseeds, so this - * does not directly probe the entropy source. */ - #ifdef HAVE_GLOBAL_RNG - if (useGlobalRng) { - if (wolfSSL_RAND_Init() != WOLFSSL_SUCCESS) { - ret = WOLFSSL_FAILURE; - } - else if (wc_LockMutex(&globalRNGMutex) != 0) { - ret = WOLFSSL_FAILURE; - } - else { - byte b = 0; - int genRet = wc_RNG_GenerateBlock(&globalRNG, &b, 1); - wc_UnLockMutex(&globalRNGMutex); - ForceZero(&b, 1); - if (genRet != 0) - ret = WOLFSSL_FAILURE; - } - } - #endif - (void)useGlobalRng; - return ret; - } + if (len > buf->length) + return wolfSSL_BUF_MEM_grow_ex(buf, len, 0); + + /* expand size, to handle growth */ + mx = (len + 3) / 3 * 4; - void wolfSSL_RAND_add(const void* add, int len, double entropy) + /* We want to shrink the internal buffer */ +#ifdef WOLFSSL_NO_REALLOC + tmp = (char*)XMALLOC(mx, NULL, DYNAMIC_TYPE_OPENSSL); + if (tmp != NULL && buf->data != NULL) { - #ifndef WOLFSSL_NO_OPENSSL_RAND_CB - if (wolfSSL_RAND_InitMutex() == 0 && - wc_LockMutex(&gRandMethodMutex) == 0) { - if (gRandMethods && gRandMethods->add) { - /* callback has return code, but RAND_add does not */ - (void)gRandMethods->add(add, len, entropy); - } - wc_UnLockMutex(&gRandMethodMutex); - } - #else - /* wolfSSL seeds/adds internally, use explicit RNG if you want - to take control */ - (void)add; - (void)len; - (void)entropy; - #endif + XMEMCPY(tmp, buf->data, len); + XFREE(buf->data,NULL,DYNAMIC_TYPE_OPENSSL); + buf->data = NULL; } - - -#ifndef NO_WOLFSSL_STUB -void wolfSSL_RAND_screen(void) -{ - WOLFSSL_STUB("RAND_screen"); -} -#endif - -#ifndef WOLFSSL_RAND_LOAD_FILE_BUF_SZ -#define WOLFSSL_RAND_LOAD_FILE_BUF_SZ 256 -#endif -#ifndef WOLFSSL_RAND_LOAD_FILE_MAX_BYTES -#define WOLFSSL_RAND_LOAD_FILE_MAX_BYTES (1L << 20) -#endif - -int wolfSSL_RAND_load_file(const char* fname, long len) -{ -#if !defined(NO_FILESYSTEM) && defined(HAVE_HASHDRBG) - XFILE f; - long maxBytes; - long readSoFar = 0; - int ret = 0; -#ifndef WOLFSSL_SMALL_STACK - unsigned char buf[WOLFSSL_RAND_LOAD_FILE_BUF_SZ]; #else - unsigned char* buf; + tmp = (char*)XREALLOC(buf->data, mx, NULL, DYNAMIC_TYPE_OPENSSL); #endif - WOLFSSL_ENTER("wolfSSL_RAND_load_file"); - - if (fname == NULL) - return WOLFSSL_FATAL_ERROR; - - /* OpenSSL semantics: RAND_load_file(file, -1) reads up to an - * implementation-defined maximum. WOLFSSL_RAND_LOAD_FILE_MAX_BYTES - * caps the read so callers passing -1 to ingest a seed file aren't - * silently truncated at a small default. */ - maxBytes = (len < 0) ? WOLFSSL_RAND_LOAD_FILE_MAX_BYTES : len; - if (maxBytes == 0) + if (tmp == NULL) return 0; - f = XFOPEN(fname, "rb"); - if (f == XBADFILE) { - WOLFSSL_MSG("RAND_load_file: cannot open file"); - return WOLFSSL_FATAL_ERROR; - } - -#ifdef WOLFSSL_SMALL_STACK - buf = (unsigned char*)XMALLOC(WOLFSSL_RAND_LOAD_FILE_BUF_SZ, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (buf == NULL) { - XFCLOSE(f); - return WOLFSSL_FATAL_ERROR; - } -#endif -#ifdef WOLFSSL_CHECK_MEM_ZERO - wc_MemZero_Add("wolfSSL_RAND_load_file buf", buf, - WOLFSSL_RAND_LOAD_FILE_BUF_SZ); -#endif + buf->data = tmp; + buf->length = len; + buf->max = mx; - if (initGlobalRNG == 0 && wolfSSL_RAND_Init() != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("RAND_load_file: global RNG not available"); - ret = WOLFSSL_FATAL_ERROR; - goto cleanup; - } + return (int)len; +} - while (readSoFar < maxBytes) { - size_t toRead = (size_t)((maxBytes - readSoFar) < - WOLFSSL_RAND_LOAD_FILE_BUF_SZ - ? (maxBytes - readSoFar) : WOLFSSL_RAND_LOAD_FILE_BUF_SZ); - size_t n = XFREAD(buf, 1, toRead, f); - if (n == 0) - break; - if (wc_LockMutex(&globalRNGMutex) != 0) { - ret = WOLFSSL_FATAL_ERROR; - break; - } - if (wc_RNG_DRBG_Reseed(&globalRNG, buf, (word32)n) != 0) { - wc_UnLockMutex(&globalRNGMutex); - WOLFSSL_MSG("RAND_load_file: DRBG reseed failed"); - ret = WOLFSSL_FATAL_ERROR; - break; - } - wc_UnLockMutex(&globalRNGMutex); - readSoFar += (long)n; +void wolfSSL_BUF_MEM_free(WOLFSSL_BUF_MEM* buf) +{ + if (buf) { + XFREE(buf->data, NULL, DYNAMIC_TYPE_OPENSSL); + buf->data = NULL; + buf->max = 0; + buf->length = 0; + XFREE(buf, NULL, DYNAMIC_TYPE_OPENSSL); } - -cleanup: - XFCLOSE(f); - ForceZero(buf, WOLFSSL_RAND_LOAD_FILE_BUF_SZ); -#ifdef WOLFSSL_SMALL_STACK - XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#elif defined(WOLFSSL_CHECK_MEM_ZERO) - wc_MemZero_Check(buf, WOLFSSL_RAND_LOAD_FILE_BUF_SZ); -#endif - - if (ret < 0) - return WOLFSSL_FATAL_ERROR; - return (int)readSoFar; -#else - /* Without HAVE_HASHDRBG / filesystem support there is no way to feed - * external entropy to the wolfCrypt RNG; return success so callers - * in those configurations are not broken. */ - (void)fname; - if (len == -1) - return 1024; - return (int)len; -#endif } +/* End Functions for openssl/buffer.h */ #endif /* OPENSSL_EXTRA */ /******************************************************************************* - * END OF RAND API + * END OF BUF_MEM API ******************************************************************************/ +#define WOLFSSL_CONF_INCLUDED +#include + /******************************************************************************* * START OF EVP_CIPHER API ******************************************************************************/ diff --git a/src/ssl_api_cert.c b/src/ssl_api_cert.c index b879e93eeb..5809d3faa2 100644 --- a/src/ssl_api_cert.c +++ b/src/ssl_api_cert.c @@ -2632,6 +2632,335 @@ int wolfSSL_get0_chain_certs(WOLFSSL *ssl, WOLF_STACK_OF(WOLFSSL_X509) **sk) #endif +#ifdef WOLFSSL_CERT_SETUP_CB +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + /* registers client cert callback, called during handshake if server + requests client auth but user has not loaded client cert/key */ + void wolfSSL_CTX_set_client_cert_cb(WOLFSSL_CTX *ctx, client_cert_cb cb) + { + WOLFSSL_ENTER("wolfSSL_CTX_set_client_cert_cb"); + + if (ctx != NULL) { + ctx->CBClientCert = cb; + } + } +#endif + + /* Set the certificate setup callback on the SSL/TLS CTX object. + * + * The callback is called during the handshake to allow the certificate and + * key to be chosen or loaded on demand. + * + * @param [in, out] ctx SSL/TLS CTX object. + * @param [in] cb Certificate setup callback. NULL to clear. + * @param [in] arg Context to pass to the callback. + */ + void wolfSSL_CTX_set_cert_cb(WOLFSSL_CTX* ctx, + CertSetupCallback cb, void *arg) + { + WOLFSSL_ENTER("wolfSSL_CTX_set_cert_cb"); + if (ctx == NULL) + return; + + ctx->certSetupCb = cb; + ctx->certSetupCbArg = arg; + } + + /** + * Internal wrapper for calling certSetupCb + * @param ssl The SSL/TLS Object + * @return 0 on success + */ + int CertSetupCbWrapper(WOLFSSL* ssl) + { + int ret = 0; + if (ssl->ctx->certSetupCb != NULL) { + WOLFSSL_MSG("Calling user cert setup callback"); + ret = ssl->ctx->certSetupCb(ssl, ssl->ctx->certSetupCbArg); + if (ret == 1) { + WOLFSSL_MSG("User cert callback returned success"); + ret = 0; + } + else if (ret == 0) { + SendAlert(ssl, alert_fatal, internal_error); + ret = CLIENT_CERT_CB_ERROR; + } + else if (ret < 0) { + ret = WOLFSSL_ERROR_WANT_X509_LOOKUP; + } + else { + WOLFSSL_MSG("Unexpected user callback return"); + ret = CLIENT_CERT_CB_ERROR; + } + } + return ret; + } +#endif /* WOLFSSL_CERT_SETUP_CB */ + + +#ifdef SESSION_CERTS + /* Decode the X509 DER encoded certificate into a WOLFSSL_X509 object. + * + * x509 WOLFSSL_X509 object to decode into. + * in X509 DER data. + * len Length of the X509 DER data. + * returns the new certificate on success, otherwise NULL. + */ + static int DecodeToX509(WOLFSSL_X509* x509, const byte* in, int len) + { + int ret; + WC_DECLARE_VAR(cert, DecodedCert, 1, 0); + if (x509 == NULL || in == NULL || len <= 0) + return BAD_FUNC_ARG; + + WC_ALLOC_VAR_EX(cert, DecodedCert, 1, NULL, DYNAMIC_TYPE_DCERT, + return MEMORY_E); + + /* Create a DecodedCert object and copy fields into WOLFSSL_X509 object. + */ + InitDecodedCert(cert, (byte*)in, (word32)len, NULL); + if ((ret = ParseCertRelative(cert, CERT_TYPE, 0, NULL, NULL)) == 0) { + /* Check if x509 was not previously initialized by wolfSSL_X509_new() */ + if (x509->dynamicMemory != TRUE) + InitX509(x509, 0, NULL); + ret = CopyDecodedToX509(x509, cert); + } + FreeDecodedCert(cert); + WC_FREE_VAR_EX(cert, NULL, DYNAMIC_TYPE_DCERT); + + return ret; + } +#endif /* SESSION_CERTS */ + + +#ifdef KEEP_PEER_CERT + /* Get a copy of the peer's certificate. + * + * The certificate is decoded from the session chain when not already + * available on the object. Caller must free the returned certificate with + * wolfSSL_X509_free(). + * + * @param [in, out] ssl SSL/TLS object. + * @return Peer's X509 certificate on success. + * @return NULL when ssl is NULL, no peer certificate was kept or dynamic + * memory allocation fails. + */ + WOLFSSL_ABI + WOLFSSL_X509* wolfSSL_get_peer_certificate(WOLFSSL* ssl) + { + WOLFSSL_X509* ret = NULL; + WOLFSSL_ENTER("wolfSSL_get_peer_certificate"); + if (ssl != NULL) { + if (ssl->peerCert.issuer.sz) + ret = wolfSSL_X509_dup(&ssl->peerCert); +#ifdef SESSION_CERTS + else if (ssl->session->chain.count > 0) { + if (DecodeToX509(&ssl->peerCert, + ssl->session->chain.certs[0].buffer, + ssl->session->chain.certs[0].length) == 0) { + ret = wolfSSL_X509_dup(&ssl->peerCert); + } + } +#endif + } + WOLFSSL_LEAVE("wolfSSL_get_peer_certificate", ret != NULL); + return ret; + } + +#endif /* KEEP_PEER_CERT */ + +#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) +/* Return stack of peer certs. + * Caller does not need to free return. The stack is Free'd when WOLFSSL* ssl + * is. + */ +WOLF_STACK_OF(WOLFSSL_X509)* wolfSSL_get_peer_cert_chain(const WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_get_peer_cert_chain"); + + if (ssl == NULL) + return NULL; + + /* Try to populate if NULL or empty */ + if (ssl->peerCertChain == NULL || + wolfSSL_sk_X509_num(ssl->peerCertChain) == 0) { + wolfSSL_set_peer_cert_chain((WOLFSSL*) ssl); + } + return ssl->peerCertChain; +} + + +static int x509GetIssuerFromCM(WOLFSSL_X509 **issuer, WOLFSSL_CERT_MANAGER* cm, + WOLFSSL_X509 *x); +/** + * Recursively push the issuer CA chain onto the stack + * @param cm The cert manager that is queried for the issuer + * @param x This cert's issuer will be queried in cm + * @param sk The issuer is pushed onto this stack + * @return 0 on success or no issuer found + * WOLFSSL_FATAL_ERROR on a fatal error + */ +static int PushCAx509Chain(WOLFSSL_CERT_MANAGER* cm, + WOLFSSL_X509 *x, WOLFSSL_STACK* sk) +{ + int i; + for (i = 0; i < MAX_CHAIN_DEPTH; i++) { + WOLFSSL_X509* issuer = NULL; + if (x509GetIssuerFromCM(&issuer, cm, x) != WOLFSSL_SUCCESS) + break; + if (wolfSSL_sk_X509_push(sk, issuer) <= 0) { + wolfSSL_X509_free(issuer); + issuer = NULL; + return WOLFSSL_FATAL_ERROR; + } + x = issuer; + } + return 0; +} + + +/* Builds up and creates a stack of peer certificates for ssl->peerCertChain + or ssl->verifiedChain based off of the ssl session chain. Attempts to place + CA certificates at the bottom of the stack for a verified chain. Returns + stack of WOLFSSL_X509 certs or NULL on failure */ +static WOLF_STACK_OF(WOLFSSL_X509)* CreatePeerCertChain(const WOLFSSL* ssl, + int verifiedFlag) +{ + WOLFSSL_STACK* sk; + WOLFSSL_X509* x509; + int i = 0; + int err; + + WOLFSSL_ENTER("wolfSSL_set_peer_cert_chain"); + if ((ssl == NULL) || (ssl->session->chain.count == 0)) + return NULL; + + sk = wolfSSL_sk_X509_new_null(); + for (i = 0; i < ssl->session->chain.count; i++) { + x509 = wolfSSL_X509_new_ex(ssl->heap); + if (x509 == NULL) { + WOLFSSL_MSG("Error Creating X509"); + wolfSSL_sk_X509_pop_free(sk, NULL); + return NULL; + } + err = DecodeToX509(x509, ssl->session->chain.certs[i].buffer, + ssl->session->chain.certs[i].length); + if (err == 0 && wolfSSL_sk_X509_push(sk, x509) <= 0) + err = WOLFSSL_FATAL_ERROR; + if (err == 0 && i == ssl->session->chain.count-1 && verifiedFlag) { + /* On the last element in the verified chain try to add the CA chain + * if we have one for this cert */ + SSL_CM_WARNING(ssl); + err = PushCAx509Chain(SSL_CM(ssl), x509, sk); + } + if (err != 0) { + WOLFSSL_MSG("Error decoding cert"); + wolfSSL_X509_free(x509); + x509 = NULL; + wolfSSL_sk_X509_pop_free(sk, NULL); + return NULL; + } + } + + if (sk == NULL) { + WOLFSSL_MSG("Null session chain"); + } + return sk; +} + + +/* Builds up and creates a stack of peer certificates for ssl->peerCertChain + returns the stack on success and NULL on failure */ +WOLF_STACK_OF(WOLFSSL_X509)* wolfSSL_set_peer_cert_chain(WOLFSSL* ssl) +{ + WOLFSSL_STACK* sk; + + WOLFSSL_ENTER("wolfSSL_set_peer_cert_chain"); + if ((ssl == NULL) || (ssl->session->chain.count == 0)) + return NULL; + + sk = CreatePeerCertChain(ssl, 0); + + if (sk != NULL) { + if (ssl->options.side == WOLFSSL_SERVER_END) { + if (ssl->session->peer) + wolfSSL_X509_free(ssl->session->peer); + + ssl->session->peer = wolfSSL_sk_X509_shift(sk); + ssl->session->peerVerifyRet = ssl->peerVerifyRet; + } + if (ssl->peerCertChain != NULL) + wolfSSL_sk_X509_pop_free(ssl->peerCertChain, NULL); + /* This is Free'd when ssl is Free'd */ + ssl->peerCertChain = sk; + } + return sk; +} + +#ifdef KEEP_PEER_CERT +/** + * Implemented in a similar way that ngx_ssl_ocsp_validate does it when + * SSL_get0_verified_chain is not available. + * @param ssl WOLFSSL object to extract certs from + * @return Stack of verified certs + */ +WOLF_STACK_OF(WOLFSSL_X509) *wolfSSL_get0_verified_chain(const WOLFSSL *ssl) +{ + WOLF_STACK_OF(WOLFSSL_X509)* chain = NULL; + WOLFSSL_X509_STORE_CTX* storeCtx = NULL; + WOLFSSL_X509* peerCert = NULL; + + WOLFSSL_ENTER("wolfSSL_get0_verified_chain"); + + if (ssl == NULL || ssl->ctx == NULL) { + WOLFSSL_MSG("Bad parameter"); + return NULL; + } + + peerCert = wolfSSL_get_peer_certificate((WOLFSSL*)ssl); + if (peerCert == NULL) { + WOLFSSL_MSG("wolfSSL_get_peer_certificate error"); + return NULL; + } + /* wolfSSL_get_peer_certificate returns a copy. We want the internal + * member so that we don't have to worry about free'ing it. We call + * wolfSSL_get_peer_certificate so that we don't have to worry about + * setting up the internal pointer. */ + wolfSSL_X509_free(peerCert); + peerCert = (WOLFSSL_X509*)&ssl->peerCert; + chain = CreatePeerCertChain((WOLFSSL*)ssl, 1); + if (chain == NULL) { + WOLFSSL_MSG("wolfSSL_get_peer_cert_chain error"); + return NULL; + } + + if (ssl->verifiedChain != NULL) { + wolfSSL_sk_X509_pop_free(ssl->verifiedChain, NULL); + } + ((WOLFSSL*)ssl)->verifiedChain = chain; + + storeCtx = wolfSSL_X509_STORE_CTX_new(); + if (storeCtx == NULL) { + WOLFSSL_MSG("wolfSSL_X509_STORE_CTX_new error"); + return NULL; + } + if (wolfSSL_X509_STORE_CTX_init(storeCtx, SSL_STORE(ssl), + peerCert, chain) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("wolfSSL_X509_STORE_CTX_init error"); + wolfSSL_X509_STORE_CTX_free(storeCtx); + return NULL; + } + if (wolfSSL_X509_verify_cert(storeCtx) <= 0) { + WOLFSSL_MSG("wolfSSL_X509_verify_cert error"); + wolfSSL_X509_STORE_CTX_free(storeCtx); + return NULL; + } + wolfSSL_X509_STORE_CTX_free(storeCtx); + return chain; +} +#endif /* KEEP_PEER_CERT */ +#endif /* SESSION_CERTS && OPENSSL_EXTRA */ + #endif /* !WOLFCRYPT_ONLY */ #endif /* !WOLFSSL_SSL_API_CERT_INCLUDED */ diff --git a/src/ssl_api_crl_ocsp.c b/src/ssl_api_crl_ocsp.c index 677aad4681..5a2d2bc81c 100644 --- a/src/ssl_api_crl_ocsp.c +++ b/src/ssl_api_crl_ocsp.c @@ -630,5 +630,112 @@ void wolfSSL_CTX_set_ocsp_status_verify_cb(WOLFSSL_CTX* ctx, #endif /* !NO_CERTS */ +#ifdef OPENSSL_EXTRA + +/* Split an OCSP responder URL into its parts. + * + * URL is of the form: http[s]://host[:port][/path] + * Host, port and path are allocated and must be freed by the caller. + * + * @param [in] url URL of OCSP responder. + * @param [out] host Host name of responder. + * @param [out] port Port of responder. "80" or "443" when not in URL. + * @param [out] path Path of responder. "/" when not in URL. + * @param [out] ssl 1 when scheme is https, 0 when http. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when a parameter is NULL, the URL is malformed or + * dynamic memory allocation fails. + */ +int wolfSSL_OCSP_parse_url(const char* url, char** host, char** port, + char** path, int* ssl) +{ + const char* u; + const char* upath; /* path in u */ + const char* uport; /* port in u */ + const char* hostEnd; + + WOLFSSL_ENTER("OCSP_parse_url"); + + if (url == NULL || host == NULL || port == NULL || path == NULL || + ssl == NULL) { + return WOLFSSL_FAILURE; + } + + u = url; + *host = NULL; + *port = NULL; + *path = NULL; + *ssl = 0; + + if (*(u++) != 'h') goto err; + if (*(u++) != 't') goto err; + if (*(u++) != 't') goto err; + if (*(u++) != 'p') goto err; + if (*u == 's') { + *ssl = 1; + u++; + *port = CopyString("443", -1, NULL, DYNAMIC_TYPE_OPENSSL); + } + else if (*u == ':') { + *ssl = 0; + *port = CopyString("80", -1, NULL, DYNAMIC_TYPE_OPENSSL); + } + else + goto err; + if (*port == NULL) + goto err; + if (*(u++) != ':') goto err; + if (*(u++) != '/') goto err; + if (*(u++) != '/') goto err; + + /* Look for path */ + upath = XSTRSTR(u, "/"); + *path = CopyString(upath == NULL ? "/" : upath, -1, NULL, + DYNAMIC_TYPE_OPENSSL); + if (*path == NULL) + goto err; + + /* Look for port */ + uport = XSTRSTR(u, ":"); + if (uport != NULL) { + if (*(++uport) == '\0') + goto err; + /* port must be before path */ + if (upath != NULL && uport >= upath) + goto err; + XFREE(*port, NULL, DYNAMIC_TYPE_OPENSSL); + if (upath) + *port = CopyString(uport, (int)(upath - uport), NULL, + DYNAMIC_TYPE_OPENSSL); + else + *port = CopyString(uport, -1, NULL, DYNAMIC_TYPE_OPENSSL); + if (*port == NULL) + goto err; + hostEnd = uport - 1; + } + else + hostEnd = upath; + + if (hostEnd) + *host = CopyString(u, (int)(hostEnd - u), NULL, DYNAMIC_TYPE_OPENSSL); + else + *host = CopyString(u, -1, NULL, DYNAMIC_TYPE_OPENSSL); + + if (*host == NULL) + goto err; + + return WOLFSSL_SUCCESS; +err: + XFREE(*host, NULL, DYNAMIC_TYPE_OPENSSL); + *host = NULL; + XFREE(*port, NULL, DYNAMIC_TYPE_OPENSSL); + *port = NULL; + XFREE(*path, NULL, DYNAMIC_TYPE_OPENSSL); + *path = NULL; + return WOLFSSL_FAILURE; +} + +#endif /* OPENSSL_EXTRA */ + #endif /* !WOLFSSL_SSL_API_CRL_OCSP_INCLUDED */ diff --git a/src/ssl_api_dtls.c b/src/ssl_api_dtls.c index 46ea02b567..4ee3e6a8f6 100644 --- a/src/ssl_api_dtls.c +++ b/src/ssl_api_dtls.c @@ -1455,6 +1455,117 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, return ret; } +struct chGoodDisableReadCbCtx { + ClientHelloGoodCb userCb; + void* userCtx; +}; + +/* ClientHello good callback that stops reading. + * + * Wraps the user's callback so that reading is disabled once a ClientHello + * with a valid cookie has been received. Used by wolfDTLS_accept_stateless(). + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context with user callback and its context. + * @return 0 on success or when no user callback set. + * @return Value returned by the user callback when negative. + */ +static int chGoodDisableReadCB(WOLFSSL* ssl, void* ctx) +{ + struct chGoodDisableReadCbCtx* cb = (struct chGoodDisableReadCbCtx*)ctx; + int ret = 0; + if (cb->userCb != NULL) + ret = cb->userCb(ssl, cb->userCtx); + if (ret >= 0) + wolfSSL_SSLDisableRead(ssl); + return ret; +} + +/** + * Statelessly listen for a connection + * @param ssl The ssl object to use for listening to connections + * @return WOLFSSL_SUCCESS - ClientHello containing a valid cookie was received + * The connection can be continued with wolfSSL_accept + * WOLFSSL_FAILURE - The I/O layer returned WANT_READ. This is either + * because there is no data to read and we are using + * non-blocking sockets or we sent a cookie request + * and we are waiting for a reply. The user should + * call wolfDTLS_accept_stateless again after data + * becomes available in the I/O layer. + * WOLFSSL_FATAL_ERROR - A fatal error occurred. The ssl object should + * be free'd and allocated again to continue. + */ +int wolfDTLS_accept_stateless(WOLFSSL* ssl) +{ + byte disableRead; + int ret = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR); + struct chGoodDisableReadCbCtx cb; + + WOLFSSL_ENTER("wolfDTLS_SetChGoodCb"); + + if (ssl == NULL) + return WOLFSSL_FATAL_ERROR; + + /* Save this to restore it later */ + disableRead = (byte)ssl->options.disableRead; + cb.userCb = ssl->chGoodCb; + cb.userCtx = ssl->chGoodCtx; + + /* Register our own callback so that we can disable reading */ + if (wolfDTLS_SetChGoodCb(ssl, chGoodDisableReadCB, &cb) != WOLFSSL_SUCCESS) + return WOLFSSL_FATAL_ERROR; + + ssl->options.returnOnGoodCh = 1; + ret = wolfSSL_accept(ssl); + ssl->options.returnOnGoodCh = 0; + /* restore user options */ + ssl->options.disableRead = disableRead; + (void)wolfDTLS_SetChGoodCb(ssl, cb.userCb, cb.userCtx); + if (ret == WOLFSSL_SUCCESS) { + WOLFSSL_MSG("should not happen. maybe the user called " + "wolfDTLS_accept_stateless instead of wolfSSL_accept"); + } + else if (ssl->error == WC_NO_ERR_TRACE(WANT_READ) || + ssl->error == WC_NO_ERR_TRACE(WANT_WRITE)) { + ssl->error = 0; + if (ssl->options.dtlsStateful) + ret = WOLFSSL_SUCCESS; + else + ret = WOLFSSL_FAILURE; + } + else { + ret = WOLFSSL_FATAL_ERROR; + } + return ret; +} + +/* Set the callback to call when a ClientHello with a valid cookie is received. + * + * WC_NO_INLINE: wolfDTLS_accept_stateless passes the address of a stack-local + * context here; the restore call before return clears it again. Preventing + * inlining hides that cross-frame assignment from GCC's -Wdangling-pointer + * analysis, which otherwise flags a false positive on GCC 14+. + * + * @param [in] ssl SSL/TLS object. + * @param [in] cb Callback to call. NULL to clear. + * @param [in] user_ctx Context to pass to the callback. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + */ +WC_NO_INLINE +int wolfDTLS_SetChGoodCb(WOLFSSL* ssl, ClientHelloGoodCb cb, void* user_ctx) +{ + WOLFSSL_ENTER("wolfDTLS_SetChGoodCb"); + + if (ssl == NULL) + return BAD_FUNC_ARG; + + ssl->chGoodCb = cb; + ssl->chGoodCtx = user_ctx; + + return WOLFSSL_SUCCESS; +} + #endif /* WOLFSSL_DTLS && !NO_WOLFSSL_SERVER */ #endif /* !WOLFCRYPT_ONLY */ diff --git a/src/ssl_api_hs.c b/src/ssl_api_hs.c new file mode 100644 index 0000000000..efa758c7f1 --- /dev/null +++ b/src/ssl_api_hs.c @@ -0,0 +1,2062 @@ +/* ssl_api_hs.c + * + * Copyright (C) 2006-2026 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 3 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 + */ + +#include + +#if !defined(WOLFSSL_SSL_API_HS_INCLUDED) + #ifndef WOLFSSL_IGNORE_FILE_WARN + #warning ssl_api_hs.c does not need to be compiled separately from ssl.c + #endif +#else + +#ifndef WOLFCRYPT_ONLY + +#ifndef NO_TLS +/* return underlying connect or accept, WOLFSSL_SUCCESS on ok */ +int wolfSSL_negotiate(WOLFSSL* ssl) +{ + int err = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR); + + WOLFSSL_ENTER("wolfSSL_negotiate"); + + if (ssl == NULL) + return WOLFSSL_FATAL_ERROR; + +#ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END) { +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version)) + err = wolfSSL_accept_TLSv13(ssl); + else +#endif + err = wolfSSL_accept(ssl); + } +#endif + +#ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_CLIENT_END) { +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version)) + err = wolfSSL_connect_TLSv13(ssl); + else +#endif + err = wolfSSL_connect(ssl); + } +#endif + + (void)ssl; + + WOLFSSL_LEAVE("wolfSSL_negotiate", err); + + return err; +} +#endif /* !NO_TLS */ + +/* client only parts */ +#if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS) + + /* please see note at top of README if you get an error from connect */ + WOLFSSL_ABI + int wolfSSL_connect(WOLFSSL* ssl) + { + #if !(defined(WOLFSSL_NO_TLS12) && defined(NO_OLD_TLS) && \ + defined(WOLFSSL_TLS13)) + int neededState; + byte advanceState; + #endif + int ret = 0; + + (void)ret; + + #ifdef HAVE_ERRNO_H + errno = 0; + #endif + + if (ssl == NULL) + return BAD_FUNC_ARG; + + #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE) + if (ssl->options.side == WOLFSSL_NEITHER_END) { + ssl->error = InitSSL_Side(ssl, WOLFSSL_CLIENT_END); + if (ssl->error != WOLFSSL_SUCCESS) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + ssl->error = 0; /* expected to be zero here */ + } + + #ifdef OPENSSL_EXTRA + if (ssl->CBIS != NULL) { + ssl->CBIS(ssl, WOLFSSL_ST_CONNECT, WOLFSSL_SUCCESS); + ssl->cbmode = WOLFSSL_CB_WRITE; + } + #endif + #endif /* OPENSSL_EXTRA || WOLFSSL_EITHER_SIDE */ + + #if defined(WOLFSSL_NO_TLS12) && defined(NO_OLD_TLS) && \ + defined(WOLFSSL_TLS13) + return wolfSSL_connect_TLSv13(ssl); + #else + #ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) { + WOLFSSL_MSG("TLS 1.3"); + return wolfSSL_connect_TLSv13(ssl); + } + #endif + + WOLFSSL_MSG("TLS 1.2 or lower"); + WOLFSSL_ENTER("wolfSSL_connect"); + + /* make sure this wolfSSL object has arrays and rng setup. Protects + * case where the WOLFSSL object is reused via wolfSSL_clear() */ + if ((ret = ReinitSSL(ssl, ssl->ctx, 0)) != 0) { + return ret; + } + +#ifdef WOLFSSL_WOLFSENTRY_HOOKS + if ((ssl->ConnectFilter != NULL) && + (ssl->options.connectState == CONNECT_BEGIN)) { + wolfSSL_netfilter_decision_t res; + if ((ssl->ConnectFilter(ssl, ssl->ConnectFilter_arg, &res) == + WOLFSSL_SUCCESS) && + (res == WOLFSSL_NETFILTER_REJECT)) { + ssl->error = SOCKET_FILTERED_E; + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } +#endif /* WOLFSSL_WOLFSENTRY_HOOKS */ + + if (ssl->options.side != WOLFSSL_CLIENT_END) { + ssl->error = SIDE_ERROR; + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + + #ifdef WOLFSSL_DTLS + if (ssl->version.major == DTLS_MAJOR) { + ssl->options.dtls = 1; + ssl->options.tls = 1; + ssl->options.tls1_1 = 1; + ssl->options.dtlsStateful = 1; + } + #endif + + /* fragOffset is non-zero when sending fragments. On the last + * fragment, fragOffset is zero again, and the state can be + * advanced. */ + advanceState = ssl->fragOffset == 0 && + (ssl->options.connectState == CONNECT_BEGIN || + ssl->options.connectState == HELLO_AGAIN || + (ssl->options.connectState >= FIRST_REPLY_DONE && + ssl->options.connectState <= FIRST_REPLY_FOURTH)); + +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls && IsAtLeastTLSv1_3(ssl->version)) + advanceState = advanceState && !ssl->dtls13SendingAckOrRtx; +#endif /* WOLFSSL_DTLS13 */ + + if (ssl->buffers.outputBuffer.length > 0 + #ifdef WOLFSSL_ASYNC_CRYPT + /* do not send buffered or advance state if last error was an + async pending operation */ + && ssl->error != WC_NO_ERR_TRACE(WC_PENDING_E) + #endif + ) { + ret = SendBuffered(ssl); + if (ret == 0) { + if (ssl->fragOffset == 0 && !ssl->options.buildingMsg) { + if (advanceState) { + ssl->options.connectState++; + WOLFSSL_MSG("connect state: Advanced from last " + "buffered fragment send"); + #ifdef WOLFSSL_ASYNC_IO + /* Cleanup async */ + FreeAsyncCtx(ssl, 0); + #endif + } + } + else { + WOLFSSL_MSG("connect state: " + "Not advanced, more fragments to send"); + } + } + else { + ssl->error = ret; + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) + ssl->dtls13SendingAckOrRtx = 0; +#endif /* WOLFSSL_DTLS13 */ + } + + ret = RetrySendAlert(ssl); + if (ret != 0) { + ssl->error = ret; + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + + switch (ssl->options.connectState) { + + case CONNECT_BEGIN : + /* always send client hello first */ + if ( (ssl->error = SendClientHello(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + ssl->options.connectState = CLIENT_HELLO_SENT; + WOLFSSL_MSG("connect state: CLIENT_HELLO_SENT"); + FALL_THROUGH; + + case CLIENT_HELLO_SENT : + neededState = ssl->options.resuming ? SERVER_FINISHED_COMPLETE : + SERVER_HELLODONE_COMPLETE; + #ifdef WOLFSSL_DTLS + /* In DTLS, when resuming, we can go straight to FINISHED, + * or do a cookie exchange and then skip to FINISHED, assume + * we need the cookie exchange first. */ + if (IsDtlsNotSctpMode(ssl)) + neededState = SERVER_HELLOVERIFYREQUEST_COMPLETE; + #endif + /* get response */ + WOLFSSL_MSG("Server state up to needed state."); + while (ssl->options.serverState < neededState) { + WOLFSSL_MSG("Progressing server state..."); + #ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) + return wolfSSL_connect_TLSv13(ssl); + #endif + WOLFSSL_MSG("ProcessReply..."); + if ( (ssl->error = ProcessReply(ssl)) < 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + /* if resumption failed, reset needed state */ + else if (neededState == SERVER_FINISHED_COMPLETE) { + if (!ssl->options.resuming) { + #ifdef WOLFSSL_DTLS + if (IsDtlsNotSctpMode(ssl)) + neededState = SERVER_HELLOVERIFYREQUEST_COMPLETE; + else + #endif + neededState = SERVER_HELLODONE_COMPLETE; + } + } + WOLFSSL_MSG("ProcessReply done."); + +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls && IsAtLeastTLSv1_3(ssl->version) + && ssl->dtls13Rtx.sendAcks == 1 + && ssl->options.seenUnifiedHdr) { + /* we aren't negotiated the version yet, so we aren't sure + * the other end can speak v1.3. On the other side we have + * received a unified records, assuming that the + * ServerHello got lost, we will send an empty ACK. In case + * the server is a DTLS with version less than 1.3, it + * should just ignore the message */ + ssl->dtls13Rtx.sendAcks = 0; + if ((ssl->error = SendDtls13Ack(ssl)) < 0) { + if (ssl->error == WC_NO_ERR_TRACE(WANT_WRITE)) + ssl->dtls13SendingAckOrRtx = 1; + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } +#endif /* WOLFSSL_DTLS13 */ + } + + ssl->options.connectState = HELLO_AGAIN; + WOLFSSL_MSG("connect state: HELLO_AGAIN"); + FALL_THROUGH; + + case HELLO_AGAIN : + + #ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) + return wolfSSL_connect_TLSv13(ssl); + #endif + + #ifdef WOLFSSL_DTLS + if (ssl->options.serverState == + SERVER_HELLOVERIFYREQUEST_COMPLETE) { + if (IsDtlsNotSctpMode(ssl)) { + /* re-init hashes, exclude first hello and verify request */ + if ((ssl->error = InitHandshakeHashes(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + if ( (ssl->error = SendClientHello(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } + } + #endif + + ssl->options.connectState = HELLO_AGAIN_REPLY; + WOLFSSL_MSG("connect state: HELLO_AGAIN_REPLY"); + FALL_THROUGH; + + case HELLO_AGAIN_REPLY : + #ifdef WOLFSSL_DTLS + if (IsDtlsNotSctpMode(ssl)) { + neededState = ssl->options.resuming ? + SERVER_FINISHED_COMPLETE : SERVER_HELLODONE_COMPLETE; + + /* get response */ + while (ssl->options.serverState < neededState) { + if ( (ssl->error = ProcessReply(ssl)) < 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + /* if resumption failed, reset needed state */ + if (neededState == SERVER_FINISHED_COMPLETE) { + if (!ssl->options.resuming) + neededState = SERVER_HELLODONE_COMPLETE; + } + } + } + #endif + + ssl->options.connectState = FIRST_REPLY_DONE; + WOLFSSL_MSG("connect state: FIRST_REPLY_DONE"); + FALL_THROUGH; + + case FIRST_REPLY_DONE : + if (ssl->options.certOnly) + return WOLFSSL_SUCCESS; + #if !defined(NO_CERTS) && !defined(WOLFSSL_NO_CLIENT_AUTH) + #ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) + return wolfSSL_connect_TLSv13(ssl); + #endif + if (ssl->options.sendVerify) { + if ( (ssl->error = SendCertificate(ssl)) != 0) { + wolfssl_local_MaybeCheckAlertOnErr(ssl, ssl->error); + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + WOLFSSL_MSG("sent: certificate"); + } + + #endif + ssl->options.connectState = FIRST_REPLY_FIRST; + WOLFSSL_MSG("connect state: FIRST_REPLY_FIRST"); + FALL_THROUGH; + + case FIRST_REPLY_FIRST : + #ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) + return wolfSSL_connect_TLSv13(ssl); + #endif + if (!ssl->options.resuming) { + if ( (ssl->error = SendClientKeyExchange(ssl)) != 0) { + wolfssl_local_MaybeCheckAlertOnErr(ssl, ssl->error); +#ifdef WOLFSSL_EXTRA_ALERTS + if (ssl->error == WC_NO_ERR_TRACE(NO_PEER_KEY) || + ssl->error == WC_NO_ERR_TRACE(PSK_KEY_ERROR)) { + SendAlert(ssl, alert_fatal, handshake_failure); + } +#endif + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + WOLFSSL_MSG("sent: client key exchange"); + } + + ssl->options.connectState = FIRST_REPLY_SECOND; + WOLFSSL_MSG("connect state: FIRST_REPLY_SECOND"); + FALL_THROUGH; + + #if !defined(WOLFSSL_NO_TLS12) || !defined(NO_OLD_TLS) + case FIRST_REPLY_SECOND : + /* CLIENT: Fail-safe for Server Authentication. */ + if (!ssl->options.peerAuthGood) { + WOLFSSL_MSG("Server authentication did not happen"); + ssl->error = NO_PEER_VERIFY; + return WOLFSSL_FATAL_ERROR; + } + + #if !defined(NO_CERTS) && !defined(WOLFSSL_NO_CLIENT_AUTH) + if (ssl->options.sendVerify) { + if ( (ssl->error = SendCertificateVerify(ssl)) != 0) { + wolfssl_local_MaybeCheckAlertOnErr(ssl, ssl->error); + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + WOLFSSL_MSG("sent: certificate verify"); + } + #endif /* !NO_CERTS && !WOLFSSL_NO_CLIENT_AUTH */ + ssl->options.connectState = FIRST_REPLY_THIRD; + WOLFSSL_MSG("connect state: FIRST_REPLY_THIRD"); + FALL_THROUGH; + + case FIRST_REPLY_THIRD : + if ( (ssl->error = SendChangeCipher(ssl)) != 0) { + wolfssl_local_MaybeCheckAlertOnErr(ssl, ssl->error); + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + WOLFSSL_MSG("sent: change cipher spec"); + ssl->options.connectState = FIRST_REPLY_FOURTH; + WOLFSSL_MSG("connect state: FIRST_REPLY_FOURTH"); + FALL_THROUGH; + + case FIRST_REPLY_FOURTH : + if ( (ssl->error = SendFinished(ssl)) != 0) { + wolfssl_local_MaybeCheckAlertOnErr(ssl, ssl->error); + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + WOLFSSL_MSG("sent: finished"); + ssl->options.connectState = FINISHED_DONE; + WOLFSSL_MSG("connect state: FINISHED_DONE"); + FALL_THROUGH; + +#ifdef WOLFSSL_DTLS13 + case WAIT_FINISHED_ACK: + ssl->options.connectState = FINISHED_DONE; + FALL_THROUGH; +#endif /* WOLFSSL_DTLS13 */ + + case FINISHED_DONE : + /* get response */ + while (ssl->options.serverState < SERVER_FINISHED_COMPLETE) + if ( (ssl->error = ProcessReply(ssl)) < 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + + ssl->options.connectState = SECOND_REPLY_DONE; + WOLFSSL_MSG("connect state: SECOND_REPLY_DONE"); + FALL_THROUGH; + + case SECOND_REPLY_DONE: + #ifndef NO_HANDSHAKE_DONE_CB + if (ssl->hsDoneCb) { + int cbret = ssl->hsDoneCb(ssl, ssl->hsDoneCtx); + if (cbret < 0) { + ssl->error = cbret; + WOLFSSL_MSG("HandShake Done Cb don't continue error"); + return WOLFSSL_FATAL_ERROR; + } + } + #endif /* NO_HANDSHAKE_DONE_CB */ + + if (!ssl->options.dtls) { + if (!ssl->options.keepResources) { + FreeHandshakeResources(ssl); + } + } + #ifdef WOLFSSL_DTLS + else { + ssl->options.dtlsHsRetain = 1; + } + #endif /* WOLFSSL_DTLS */ + + #if defined(WOLFSSL_ASYNC_CRYPT) && defined(HAVE_SECURE_RENEGOTIATION) + /* This may be necessary in async so that we don't try to + * renegotiate again */ + if (ssl->secure_renegotiation && + ssl->secure_renegotiation->startScr) { + ssl->secure_renegotiation->startScr = 0; + } + #endif /* WOLFSSL_ASYNC_CRYPT && HAVE_SECURE_RENEGOTIATION */ + #if defined(WOLFSSL_ASYNC_IO) && !defined(WOLFSSL_ASYNC_CRYPT) + /* Free the remaining async context if not using it for crypto */ + FreeAsyncCtx(ssl, 1); + #endif + + ssl->error = 0; /* clear the error */ + + WOLFSSL_LEAVE("wolfSSL_connect", WOLFSSL_SUCCESS); + return WOLFSSL_SUCCESS; + #endif /* !WOLFSSL_NO_TLS12 || !NO_OLD_TLS */ + + default: + WOLFSSL_MSG("Unknown connect state ERROR"); + return WOLFSSL_FATAL_ERROR; /* unknown connect state */ + } + #endif /* !WOLFSSL_NO_TLS12 || !NO_OLD_TLS || !WOLFSSL_TLS13 */ + } + + +/* connect enough to get peer cert chain */ +int wolfSSL_connect_cert(WOLFSSL* ssl) +{ + int ret; + + if (ssl == NULL) + return WOLFSSL_FAILURE; + + ssl->options.certOnly = 1; + ret = wolfSSL_connect(ssl); + ssl->options.certOnly = 0; + + return ret; +} +#endif /* !NO_WOLFSSL_CLIENT && !NO_TLS */ +/* end client only parts */ + +/* server only parts */ +#if !defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS) + + WOLFSSL_ABI + /* Accept a connection from a client. + * + * Performs the server side of the handshake, resuming from where it last + * stopped when non-blocking. Dispatches to the TLS 1.3 or DTLS handshake + * when negotiated. + * + * @param [in, out] ssl SSL/TLS object. + * @return WOLFSSL_SUCCESS when the handshake completes. + * @return WOLFSSL_FATAL_ERROR when ssl is NULL or the handshake fails. + * Call wolfSSL_get_error() for the reason. WOLFSSL_ERROR_WANT_READ + * and WOLFSSL_ERROR_WANT_WRITE mean call again. + */ + int wolfSSL_accept(WOLFSSL* ssl) + { +#if !(defined(WOLFSSL_NO_TLS12) && defined(NO_OLD_TLS) && \ + defined(WOLFSSL_TLS13)) + word16 havePSK = 0; + word16 haveAnon = 0; + word16 haveMcast = 0; +#endif + int ret = 0; + + (void)ret; + + if (ssl == NULL) + return WOLFSSL_FATAL_ERROR; + + #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE) + if (ssl->options.side == WOLFSSL_NEITHER_END) { + WOLFSSL_MSG("Setting WOLFSSL_SSL to be server side"); + ssl->error = InitSSL_Side(ssl, WOLFSSL_SERVER_END); + if (ssl->error != WOLFSSL_SUCCESS) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + ssl->error = 0; /* expected to be zero here */ + } + #endif /* OPENSSL_EXTRA || WOLFSSL_EITHER_SIDE */ + +#if defined(WOLFSSL_NO_TLS12) && defined(NO_OLD_TLS) && defined(WOLFSSL_TLS13) + return wolfSSL_accept_TLSv13(ssl); +#else + #ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) + return wolfSSL_accept_TLSv13(ssl); + #endif + WOLFSSL_ENTER("wolfSSL_accept"); + + /* make sure this wolfSSL object has arrays and rng setup. Protects + * case where the WOLFSSL object is reused via wolfSSL_clear() */ + if ((ret = ReinitSSL(ssl, ssl->ctx, 0)) != 0) { + return ret; + } + +#ifdef WOLFSSL_WOLFSENTRY_HOOKS + if ((ssl->AcceptFilter != NULL) && + ((ssl->options.acceptState == ACCEPT_BEGIN) +#ifdef HAVE_SECURE_RENEGOTIATION + || (ssl->options.acceptState == ACCEPT_BEGIN_RENEG) +#endif + )) + { + wolfSSL_netfilter_decision_t res; + if ((ssl->AcceptFilter(ssl, ssl->AcceptFilter_arg, &res) == + WOLFSSL_SUCCESS) && + (res == WOLFSSL_NETFILTER_REJECT)) { + ssl->error = SOCKET_FILTERED_E; + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } +#endif /* WOLFSSL_WOLFSENTRY_HOOKS */ + + #ifdef HAVE_ERRNO_H + errno = 0; + #endif + + #ifndef NO_PSK + havePSK = ssl->options.havePSK; + #endif + (void)havePSK; + + #ifdef HAVE_ANON + haveAnon = ssl->options.useAnon; + #endif + (void)haveAnon; + + #ifdef WOLFSSL_MULTICAST + haveMcast = ssl->options.haveMcast; + #endif + (void)haveMcast; + + if (ssl->options.side != WOLFSSL_SERVER_END) { + ssl->error = SIDE_ERROR; + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + + #ifndef NO_CERTS + /* in case used set_accept_state after init */ + if (!havePSK && !haveAnon && !haveMcast) { + #ifdef WOLFSSL_CERT_SETUP_CB + if (ssl->ctx->certSetupCb != NULL) { + WOLFSSL_MSG("CertSetupCb set. server cert and " + "key not checked"); + } + else + #endif + { + if (!ssl->buffers.certificate || + !ssl->buffers.certificate->buffer) { + + WOLFSSL_MSG("accept error: server cert required"); + ssl->error = NO_PRIVATE_KEY; + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + + if (!ssl->buffers.key || !ssl->buffers.key->buffer) { + /* allow no private key if using existing key */ + #ifdef WOLF_PRIVATE_KEY_ID + if (ssl->devId != INVALID_DEVID + #ifdef HAVE_PK_CALLBACKS + || wolfSSL_CTX_IsPrivatePkSet(ssl->ctx) + #endif + ) { + WOLFSSL_MSG("Allowing no server private key " + "(external)"); + } + else + #endif + { + WOLFSSL_MSG("accept error: server key required"); + ssl->error = NO_PRIVATE_KEY; + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } + } + } + #endif + + #ifdef WOLFSSL_DTLS + if (ssl->version.major == DTLS_MAJOR) { + ssl->options.dtls = 1; + ssl->options.tls = 1; + ssl->options.tls1_1 = 1; + if (!IsDtlsNotSctpMode(ssl) || IsSCR(ssl)) + ssl->options.dtlsStateful = 1; + } + #endif + + if (ssl->buffers.outputBuffer.length > 0 + #ifdef WOLFSSL_ASYNC_CRYPT + /* do not send buffered or advance state if last error was an + async pending operation */ + && ssl->error != WC_NO_ERR_TRACE(WC_PENDING_E) + #endif + ) { + ret = SendBuffered(ssl); + if (ret == 0) { + /* fragOffset is non-zero when sending fragments. On the last + * fragment, fragOffset is zero again, and the state can be + * advanced. */ + if (ssl->fragOffset == 0 && !ssl->options.buildingMsg) { + if (ssl->options.acceptState == ACCEPT_FIRST_REPLY_DONE || + ssl->options.acceptState == SERVER_HELLO_SENT || + ssl->options.acceptState == CERT_SENT || + ssl->options.acceptState == CERT_STATUS_SENT || + ssl->options.acceptState == KEY_EXCHANGE_SENT || + ssl->options.acceptState == CERT_REQ_SENT || + ssl->options.acceptState == ACCEPT_SECOND_REPLY_DONE || + ssl->options.acceptState == TICKET_SENT || + ssl->options.acceptState == CHANGE_CIPHER_SENT) { + ssl->options.acceptState++; + WOLFSSL_MSG("accept state: Advanced from last " + "buffered fragment send"); + #ifdef WOLFSSL_ASYNC_IO + /* Cleanup async */ + FreeAsyncCtx(ssl, 0); + #endif + } + } + else { + WOLFSSL_MSG("accept state: " + "Not advanced, more fragments to send"); + } + } + else { + ssl->error = ret; + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) + ssl->dtls13SendingAckOrRtx = 0; +#endif /* WOLFSSL_DTLS13 */ + } + + ret = RetrySendAlert(ssl); + if (ret != 0) { + ssl->error = ret; + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + + switch (ssl->options.acceptState) { + + case ACCEPT_BEGIN : +#ifdef HAVE_SECURE_RENEGOTIATION + case ACCEPT_BEGIN_RENEG: +#endif + /* get response */ + while (ssl->options.clientState < CLIENT_HELLO_COMPLETE) + if ( (ssl->error = ProcessReply(ssl)) < 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } +#ifdef WOLFSSL_TLS13 + ssl->options.acceptState = ACCEPT_CLIENT_HELLO_DONE; + WOLFSSL_MSG("accept state ACCEPT_CLIENT_HELLO_DONE"); + FALL_THROUGH; + + case ACCEPT_CLIENT_HELLO_DONE : + if (ssl->options.tls1_3) { + return wolfSSL_accept_TLSv13(ssl); + } +#endif + + ssl->options.acceptState = ACCEPT_FIRST_REPLY_DONE; + WOLFSSL_MSG("accept state ACCEPT_FIRST_REPLY_DONE"); + FALL_THROUGH; + + case ACCEPT_FIRST_REPLY_DONE : + if (ssl->options.returnOnGoodCh) { + /* Higher level in stack wants us to return. Simulate a + * WANT_WRITE to accomplish this. */ + ssl->error = WANT_WRITE; + return WOLFSSL_FATAL_ERROR; + } + if ( (ssl->error = SendServerHello(ssl)) != 0) { + wolfssl_local_MaybeCheckAlertOnErr(ssl, ssl->error); + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + ssl->options.acceptState = SERVER_HELLO_SENT; + WOLFSSL_MSG("accept state SERVER_HELLO_SENT"); + FALL_THROUGH; + + case SERVER_HELLO_SENT : + #ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) { + return wolfSSL_accept_TLSv13(ssl); + } + #endif + #ifndef NO_CERTS + if (!ssl->options.resuming) + if ( (ssl->error = SendCertificate(ssl)) != 0) { + wolfssl_local_MaybeCheckAlertOnErr(ssl, ssl->error); + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + #endif + ssl->options.acceptState = CERT_SENT; + WOLFSSL_MSG("accept state CERT_SENT"); + FALL_THROUGH; + + case CERT_SENT : + #ifndef NO_CERTS + if (!ssl->options.resuming) + if ( (ssl->error = SendCertificateStatus(ssl)) != 0) { + wolfssl_local_MaybeCheckAlertOnErr(ssl, ssl->error); + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + #endif + ssl->options.acceptState = CERT_STATUS_SENT; + WOLFSSL_MSG("accept state CERT_STATUS_SENT"); + FALL_THROUGH; + + case CERT_STATUS_SENT : + #ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) { + return wolfSSL_accept_TLSv13(ssl); + } + #endif + if (!ssl->options.resuming) + if ( (ssl->error = SendServerKeyExchange(ssl)) != 0) { + wolfssl_local_MaybeCheckAlertOnErr(ssl, ssl->error); + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + ssl->options.acceptState = KEY_EXCHANGE_SENT; + WOLFSSL_MSG("accept state KEY_EXCHANGE_SENT"); + FALL_THROUGH; + + case KEY_EXCHANGE_SENT : + #ifndef NO_CERTS + if (!ssl->options.resuming) { + if (ssl->options.verifyPeer) { + if ( (ssl->error = SendCertificateRequest(ssl)) != 0) { + wolfssl_local_MaybeCheckAlertOnErr(ssl, ssl->error); + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } + else { + /* SERVER: Peer auth good if not verifying client. */ + ssl->options.peerAuthGood = 1; + } + } + #endif + ssl->options.acceptState = CERT_REQ_SENT; + WOLFSSL_MSG("accept state CERT_REQ_SENT"); + FALL_THROUGH; + + case CERT_REQ_SENT : + if (!ssl->options.resuming) + if ( (ssl->error = SendServerHelloDone(ssl)) != 0) { + wolfssl_local_MaybeCheckAlertOnErr(ssl, ssl->error); + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + ssl->options.acceptState = SERVER_HELLO_DONE; + WOLFSSL_MSG("accept state SERVER_HELLO_DONE"); + FALL_THROUGH; + + case SERVER_HELLO_DONE : + if (!ssl->options.resuming) { + while (ssl->options.clientState < CLIENT_FINISHED_COMPLETE) + if ( (ssl->error = ProcessReply(ssl)) < 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } + ssl->options.acceptState = ACCEPT_SECOND_REPLY_DONE; + WOLFSSL_MSG("accept state ACCEPT_SECOND_REPLY_DONE"); + FALL_THROUGH; + + case ACCEPT_SECOND_REPLY_DONE : + #ifndef NO_CERTS + /* SERVER: When not resuming and verifying peer but no certificate + * received and not failing when not received then peer auth good. + */ + if (!ssl->options.resuming && ssl->options.verifyPeer && + !ssl->options.havePeerCert && !ssl->options.failNoCert) { + ssl->options.peerAuthGood = 1; + } + #endif /* !NO_CERTS */ + #ifdef WOLFSSL_NO_CLIENT_AUTH + if (!ssl->options.resuming) { + ssl->options.peerAuthGood = 1; + } + #endif + +#ifdef HAVE_SESSION_TICKET + if (ssl->options.createTicket && !ssl->options.noTicketTls12) { + if ( (ssl->error = SendTicket(ssl)) != 0) { + wolfssl_local_MaybeCheckAlertOnErr(ssl, ssl->error); + WOLFSSL_MSG("Thought we need ticket but failed"); + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } +#endif /* HAVE_SESSION_TICKET */ + ssl->options.acceptState = TICKET_SENT; + WOLFSSL_MSG("accept state TICKET_SENT"); + FALL_THROUGH; + + case TICKET_SENT: + /* SERVER: Fail-safe for CLient Authentication. */ + if (!ssl->options.peerAuthGood) { + WOLFSSL_MSG("Client authentication did not happen"); + return WOLFSSL_FATAL_ERROR; + } + + if ( (ssl->error = SendChangeCipher(ssl)) != 0) { + wolfssl_local_MaybeCheckAlertOnErr(ssl, ssl->error); + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + ssl->options.acceptState = CHANGE_CIPHER_SENT; + WOLFSSL_MSG("accept state CHANGE_CIPHER_SENT"); + FALL_THROUGH; + + case CHANGE_CIPHER_SENT : + if ( (ssl->error = SendFinished(ssl)) != 0) { + wolfssl_local_MaybeCheckAlertOnErr(ssl, ssl->error); + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + + ssl->options.acceptState = ACCEPT_FINISHED_DONE; + WOLFSSL_MSG("accept state ACCEPT_FINISHED_DONE"); + FALL_THROUGH; + + case ACCEPT_FINISHED_DONE : + if (ssl->options.resuming) { + while (ssl->options.clientState < CLIENT_FINISHED_COMPLETE) { + if ( (ssl->error = ProcessReply(ssl)) < 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } + } + ssl->options.acceptState = ACCEPT_THIRD_REPLY_DONE; + WOLFSSL_MSG("accept state ACCEPT_THIRD_REPLY_DONE"); + FALL_THROUGH; + + case ACCEPT_THIRD_REPLY_DONE : +#ifndef NO_HANDSHAKE_DONE_CB + if (ssl->hsDoneCb) { + int cbret = ssl->hsDoneCb(ssl, ssl->hsDoneCtx); + if (cbret < 0) { + ssl->error = cbret; + WOLFSSL_MSG("HandShake Done Cb don't continue error"); + return WOLFSSL_FATAL_ERROR; + } + } +#endif /* NO_HANDSHAKE_DONE_CB */ + + if (!ssl->options.dtls) { + if (!ssl->options.keepResources) { + FreeHandshakeResources(ssl); + } + } +#ifdef WOLFSSL_DTLS + else { + ssl->options.dtlsHsRetain = 1; + } +#endif /* WOLFSSL_DTLS */ + +#if defined(WOLFSSL_ASYNC_CRYPT) && defined(HAVE_SECURE_RENEGOTIATION) + /* This may be necessary in async so that we don't try to + * renegotiate again */ + if (ssl->secure_renegotiation && + ssl->secure_renegotiation->startScr) { + ssl->secure_renegotiation->startScr = 0; + } +#endif /* WOLFSSL_ASYNC_CRYPT && HAVE_SECURE_RENEGOTIATION */ +#if defined(WOLFSSL_ASYNC_IO) && !defined(WOLFSSL_ASYNC_CRYPT) + /* Free the remaining async context if not using it for crypto */ + FreeAsyncCtx(ssl, 1); +#endif + +#if defined(WOLFSSL_SESSION_EXPORT) && defined(WOLFSSL_DTLS) + if (ssl->dtls_export) { + if ((ssl->error = wolfSSL_send_session(ssl)) != 0) { + WOLFSSL_MSG("Export DTLS session error"); + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + } +#endif + ssl->error = 0; /* clear the error */ + + WOLFSSL_LEAVE("wolfSSL_accept", WOLFSSL_SUCCESS); + return WOLFSSL_SUCCESS; + + default: + WOLFSSL_MSG("Unknown accept state ERROR"); + return WOLFSSL_FATAL_ERROR; + } +#endif /* !WOLFSSL_NO_TLS12 */ + } + +#endif /* !NO_WOLFSSL_SERVER && !NO_TLS */ +/* end server only parts */ + +#ifndef NO_HANDSHAKE_DONE_CB + +/* Set the callback to call when the handshake completes. + * + * @param [in, out] ssl SSL/TLS object. + * @param [in] cb Callback to call. NULL to clear. + * @param [in] user_ctx Context to pass to the callback. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + */ +int wolfSSL_SetHsDoneCb(WOLFSSL* ssl, HandShakeDoneCb cb, void* user_ctx) +{ + WOLFSSL_ENTER("wolfSSL_SetHsDoneCb"); + + if (ssl == NULL) + return BAD_FUNC_ARG; + + ssl->hsDoneCb = cb; + ssl->hsDoneCtx = user_ctx; + + return WOLFSSL_SUCCESS; +} + +#endif /* NO_HANDSHAKE_DONE_CB */ + +#ifdef WOLFSSL_CALLBACKS + + typedef struct itimerval Itimerval; + + /* don't keep calling simple functions while setting up timer and signals + if no inlining these are the next best */ + + #define AddTimes(a, b, c) \ + do { \ + (c).tv_sec = (a).tv_sec + (b).tv_sec; \ + (c).tv_usec = (a).tv_usec + (b).tv_usec;\ + if ((c).tv_usec >= 1000000) { \ + (c).tv_sec++; \ + (c).tv_usec -= 1000000; \ + } \ + } while (0) + + + #define SubtractTimes(a, b, c) \ + do { \ + (c).tv_sec = (a).tv_sec - (b).tv_sec; \ + (c).tv_usec = (a).tv_usec - (b).tv_usec;\ + if ((c).tv_usec < 0) { \ + (c).tv_sec--; \ + (c).tv_usec += 1000000; \ + } \ + } while (0) + + #define CmpTimes(a, b, cmp) \ + (((a).tv_sec == (b).tv_sec) ? \ + ((a).tv_usec cmp (b).tv_usec) : \ + ((a).tv_sec cmp (b).tv_sec)) \ + + + /* do nothing handler */ + static void myHandler(int signo) + { + (void)signo; + return; + } + + + /* Perform a handshake with monitoring callbacks and a timeout. + * + * An interval timer is used to abort the handshake when it takes longer + * than the timeout. Any existing timer is restored afterwards. + * + * @param [in, out] ssl SSL/TLS object. + * @param [in] hsCb Handshake information callback. May be NULL. + * @param [in] toCb Timeout callback. May be NULL. + * @param [in] timeout Maximum time to take. Zero for no timeout. + * @return WOLFSSL_SUCCESS when the handshake completes. + * @return WOLFSSL_FATAL_ERROR when ssl is NULL, the timeout value is bad, + * setting the timer fails or the handshake fails. + */ + static int wolfSSL_ex_wrapper(WOLFSSL* ssl, HandShakeCallBack hsCb, + TimeoutCallBack toCb, WOLFSSL_TIMEVAL timeout) + { + int ret = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR); + int oldTimerOn = 0; /* was timer already on */ + WOLFSSL_TIMEVAL startTime; + WOLFSSL_TIMEVAL endTime; + WOLFSSL_TIMEVAL totalTime; + Itimerval myTimeout; + Itimerval oldTimeout; /* if old timer adjust from total time to reset */ + struct sigaction act, oact; + + #define ERR_OUT(x) { ssl->hsInfoOn = 0; ssl->toInfoOn = 0; return x; } + + if (hsCb) { + ssl->hsInfoOn = 1; + InitHandShakeInfo(&ssl->handShakeInfo, ssl); + } + if (toCb) { + ssl->toInfoOn = 1; + InitTimeoutInfo(&ssl->timeoutInfo); + + if (gettimeofday(&startTime, 0) < 0) + ERR_OUT(GETTIME_ERROR); + + /* use setitimer to simulate getitimer, init 0 myTimeout */ + myTimeout.it_interval.tv_sec = 0; + myTimeout.it_interval.tv_usec = 0; + myTimeout.it_value.tv_sec = 0; + myTimeout.it_value.tv_usec = 0; + if (setitimer(ITIMER_REAL, &myTimeout, &oldTimeout) < 0) + ERR_OUT(SETITIMER_ERROR); + + if (oldTimeout.it_value.tv_sec || oldTimeout.it_value.tv_usec) { + oldTimerOn = 1; + + /* is old timer going to expire before ours */ + if (CmpTimes(oldTimeout.it_value, timeout, <)) { + timeout.tv_sec = oldTimeout.it_value.tv_sec; + timeout.tv_usec = oldTimeout.it_value.tv_usec; + } + } + myTimeout.it_value.tv_sec = timeout.tv_sec; + myTimeout.it_value.tv_usec = timeout.tv_usec; + + /* set up signal handler, don't restart socket send/recv */ + act.sa_handler = myHandler; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; +#ifdef SA_INTERRUPT + act.sa_flags |= SA_INTERRUPT; +#endif + if (sigaction(SIGALRM, &act, &oact) < 0) + ERR_OUT(SIGACT_ERROR); + + if (setitimer(ITIMER_REAL, &myTimeout, 0) < 0) + ERR_OUT(SETITIMER_ERROR); + } + + /* do main work */ +#ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_CLIENT_END) + ret = wolfSSL_connect(ssl); +#endif +#ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END) + ret = wolfSSL_accept(ssl); +#endif + + /* do callbacks */ + if (toCb) { + if (oldTimerOn) { + if (gettimeofday(&endTime, 0) < 0) + ERR_OUT(SYSLIB_FAILED_E); + SubtractTimes(endTime, startTime, totalTime); + /* adjust old timer for elapsed time */ + if (CmpTimes(totalTime, oldTimeout.it_value, <)) + SubtractTimes(oldTimeout.it_value, totalTime, + oldTimeout.it_value); + else { + /* reset value to interval, may be off */ + oldTimeout.it_value.tv_sec = oldTimeout.it_interval.tv_sec; + oldTimeout.it_value.tv_usec =oldTimeout.it_interval.tv_usec; + } + /* keep iter the same whether there or not */ + } + /* restore old handler */ + if (sigaction(SIGALRM, &oact, 0) < 0) + ret = SIGACT_ERROR; /* more pressing error, stomp */ + else + /* use old settings which may turn off (expired or not there) */ + if (setitimer(ITIMER_REAL, &oldTimeout, 0) < 0) + ret = SETITIMER_ERROR; + + /* if we had a timeout call callback */ + if (ssl->timeoutInfo.timeoutName[0]) { + ssl->timeoutInfo.timeoutValue.tv_sec = timeout.tv_sec; + ssl->timeoutInfo.timeoutValue.tv_usec = timeout.tv_usec; + (toCb)(&ssl->timeoutInfo); + } + ssl->toInfoOn = 0; + } + + /* clean up buffers allocated by AddPacketInfo */ + FreeTimeoutInfo(&ssl->timeoutInfo, ssl->heap); + + if (hsCb) { + FinishHandShakeInfo(&ssl->handShakeInfo); + (hsCb)(&ssl->handShakeInfo); + ssl->hsInfoOn = 0; + } + return ret; + } + + +#ifndef NO_WOLFSSL_CLIENT + + /* Connect to a server with monitoring callbacks and a timeout. + * + * @param [in, out] ssl SSL/TLS object. + * @param [in] hsCb Handshake information callback. May be NULL. + * @param [in] toCb Timeout callback. May be NULL. + * @param [in] timeout Maximum time to take. Zero for no timeout. + * @return WOLFSSL_SUCCESS when the handshake completes. + * @return WOLFSSL_FATAL_ERROR when the handshake fails or times out. + */ + int wolfSSL_connect_ex(WOLFSSL* ssl, HandShakeCallBack hsCb, + TimeoutCallBack toCb, WOLFSSL_TIMEVAL timeout) + { + WOLFSSL_ENTER("wolfSSL_connect_ex"); + return wolfSSL_ex_wrapper(ssl, hsCb, toCb, timeout); + } + +#endif + + +#ifndef NO_WOLFSSL_SERVER + + /* Accept a connection from a client with monitoring callbacks and a + * timeout. + * + * @param [in, out] ssl SSL/TLS object. + * @param [in] hsCb Handshake information callback. May be NULL. + * @param [in] toCb Timeout callback. May be NULL. + * @param [in] timeout Maximum time to take. Zero for no timeout. + * @return WOLFSSL_SUCCESS when the handshake completes. + * @return WOLFSSL_FATAL_ERROR when the handshake fails or times out. + */ + int wolfSSL_accept_ex(WOLFSSL* ssl, HandShakeCallBack hsCb, + TimeoutCallBack toCb, WOLFSSL_TIMEVAL timeout) + { + WOLFSSL_ENTER("wolfSSL_accept_ex"); + return wolfSSL_ex_wrapper(ssl, hsCb, toCb, timeout); + } + +#endif + +#endif /* WOLFSSL_CALLBACKS */ + + +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EXTRA) || \ + defined(WOLFSSL_WPAS_SMALL) + + /* Set the SSL/TLS object to be a server. + * + * Resets the handshake state and cipher suites. Must be called before the + * handshake starts. + * + * @param [in, out] ssl SSL/TLS object. + */ + void wolfSSL_set_accept_state(WOLFSSL* ssl) + { + WOLFSSL_ENTER("wolfSSL_set_accept_state"); + + if (ssl == NULL) + return; + + if (ssl->options.side == WOLFSSL_CLIENT_END) { + #ifdef HAVE_ECC + WC_DECLARE_VAR(key, ecc_key, 1, 0); + word32 idx = 0; + + #ifdef WOLFSSL_SMALL_STACK + key = (ecc_key*)XMALLOC(sizeof(ecc_key), ssl->heap, + DYNAMIC_TYPE_ECC); + if (key == NULL) { + WOLFSSL_MSG("Error allocating memory for ecc_key"); + } + #endif + if (ssl->options.haveStaticECC && ssl->buffers.key != NULL) { + if (wc_ecc_init(key) >= 0) { + if (wc_EccPrivateKeyDecode(ssl->buffers.key->buffer, &idx, + key, ssl->buffers.key->length) != 0) { + ssl->options.haveECDSAsig = 0; + ssl->options.haveECC = 0; + ssl->options.haveStaticECC = 0; + } + wc_ecc_free(key); + } + } + WC_FREE_VAR_EX(key, ssl->heap, DYNAMIC_TYPE_ECC); + #endif + + #ifndef NO_DH + if (!ssl->options.haveDH && ssl->ctx->haveDH) { + ssl->buffers.serverDH_P = ssl->ctx->serverDH_P; + ssl->buffers.serverDH_G = ssl->ctx->serverDH_G; + ssl->options.haveDH = 1; + } + #endif + } + + if (InitSSL_Side(ssl, WOLFSSL_SERVER_END) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Error initializing server side"); + } + } + +#endif /* OPENSSL_EXTRA || WOLFSSL_EXTRA || WOLFSSL_WPAS_SMALL */ + + /* return true if connection established */ + /* this works for TLS and DTLS */ + int wolfSSL_is_init_finished(const WOLFSSL* ssl) + { + if (ssl == NULL) + return 0; + +#if defined(WOLFSSL_DTLS13) && !defined(NO_WOLFSSL_CLIENT) + if (ssl->options.side == WOLFSSL_CLIENT_END && ssl->options.dtls + && IsAtLeastTLSv1_3(ssl->version)) { + return ssl->options.serverState == SERVER_FINISHED_ACKED; + } +#endif /* WOLFSSL_DTLS13 && !NO_WOLFSSL_CLIENT */ + + /* Can't use ssl->options.connectState and ssl->options.acceptState + * because they differ in meaning for TLS <=1.2 and 1.3 */ + if (ssl->options.handShakeState == HANDSHAKE_DONE) + return 1; + + return 0; + } + +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) +/* Set the SSL/TLS object to be a client. + * + * Resets the handshake state and cipher suites. Must be called before the + * handshake starts. + * + * @param [in, out] ssl SSL/TLS object. + */ +void wolfSSL_set_connect_state(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_set_connect_state"); + if (ssl == NULL) { + WOLFSSL_MSG("WOLFSSL struct pointer passed in was null"); + return; + } + + #ifndef NO_DH + /* client creates its own DH parameters on handshake */ + if (ssl->buffers.serverDH_P.buffer && ssl->buffers.weOwnDH) { + XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap, + DYNAMIC_TYPE_PUBLIC_KEY); + } + ssl->buffers.serverDH_P.buffer = NULL; + if (ssl->buffers.serverDH_G.buffer && ssl->buffers.weOwnDH) { + XFREE(ssl->buffers.serverDH_G.buffer, ssl->heap, + DYNAMIC_TYPE_PUBLIC_KEY); + } + ssl->buffers.serverDH_G.buffer = NULL; + #endif + + if (InitSSL_Side(ssl, WOLFSSL_CLIENT_END) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Error initializing client side"); + } +} +#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */ + +#ifdef OPENSSL_EXTRA + +#define STATE_STRINGS_PROTO(s) \ + { \ + {"SSLv3 " s, \ + "SSLv3 " s, \ + "SSLv3 " s}, \ + {"TLSv1 " s, \ + "TLSv1 " s, \ + "TLSv1 " s}, \ + {"TLSv1_1 " s, \ + "TLSv1_1 " s, \ + "TLSv1_1 " s}, \ + {"TLSv1_2 " s, \ + "TLSv1_2 " s, \ + "TLSv1_2 " s}, \ + {"TLSv1_3 " s, \ + "TLSv1_3 " s, \ + "TLSv1_3 " s}, \ + {"DTLSv1 " s, \ + "DTLSv1 " s, \ + "DTLSv1 " s}, \ + {"DTLSv1_2 " s, \ + "DTLSv1_2 " s, \ + "DTLSv1_2 " s}, \ + {"DTLSv1_3 " s, \ + "DTLSv1_3 " s, \ + "DTLSv1_3 " s}, \ + } + +#define STATE_STRINGS_PROTO_RW(s) \ + { \ + {"SSLv3 read " s, \ + "SSLv3 write " s, \ + "SSLv3 " s}, \ + {"TLSv1 read " s, \ + "TLSv1 write " s, \ + "TLSv1 " s}, \ + {"TLSv1_1 read " s, \ + "TLSv1_1 write " s, \ + "TLSv1_1 " s}, \ + {"TLSv1_2 read " s, \ + "TLSv1_2 write " s, \ + "TLSv1_2 " s}, \ + {"TLSv1_3 read " s, \ + "TLSv1_3 write " s, \ + "TLSv1_3 " s}, \ + {"DTLSv1 read " s, \ + "DTLSv1 write " s, \ + "DTLSv1 " s}, \ + {"DTLSv1_2 read " s, \ + "DTLSv1_2 write " s, \ + "DTLSv1_2 " s}, \ + {"DTLSv1_3 read " s, \ + "DTLSv1_3 write " s, \ + "DTLSv1_3 " s}, \ + } + +/* Gets the current state of the WOLFSSL structure + * + * ssl WOLFSSL structure to get state of + * + * Returns a human readable string of the WOLFSSL structure state + */ +const char* wolfSSL_state_string_long(const WOLFSSL* ssl) +{ + + static const char* OUTPUT_STR[24][8][3] = { + STATE_STRINGS_PROTO("Initialization"), + STATE_STRINGS_PROTO_RW("Server Hello Request"), + STATE_STRINGS_PROTO_RW("Server Hello Verify Request"), + STATE_STRINGS_PROTO_RW("Server Hello Retry Request"), + STATE_STRINGS_PROTO_RW("Server Hello"), + STATE_STRINGS_PROTO_RW("Server Certificate Status"), + STATE_STRINGS_PROTO_RW("Server Encrypted Extensions"), + STATE_STRINGS_PROTO_RW("Server Session Ticket"), + STATE_STRINGS_PROTO_RW("Server Certificate Request"), + STATE_STRINGS_PROTO_RW("Server Cert"), + STATE_STRINGS_PROTO_RW("Server Key Exchange"), + STATE_STRINGS_PROTO_RW("Server Hello Done"), + STATE_STRINGS_PROTO_RW("Server Change CipherSpec"), + STATE_STRINGS_PROTO_RW("Server Finished"), + STATE_STRINGS_PROTO_RW("server Key Update"), + STATE_STRINGS_PROTO_RW("Client Hello"), + STATE_STRINGS_PROTO_RW("Client Key Exchange"), + STATE_STRINGS_PROTO_RW("Client Cert"), + STATE_STRINGS_PROTO_RW("Client Change CipherSpec"), + STATE_STRINGS_PROTO_RW("Client Certificate Verify"), + STATE_STRINGS_PROTO_RW("Client End Of Early Data"), + STATE_STRINGS_PROTO_RW("Client Finished"), + STATE_STRINGS_PROTO_RW("Client Key Update"), + STATE_STRINGS_PROTO("Handshake Done"), + }; + enum ProtocolVer { + SSL_V3 = 0, + TLS_V1, + TLS_V1_1, + TLS_V1_2, + TLS_V1_3, + DTLS_V1, + DTLS_V1_2, + DTLS_V1_3, + UNKNOWN = 100 + }; + + enum IOMode { + SS_READ = 0, + SS_WRITE, + SS_NEITHER + }; + + enum SslState { + ss_null_state = 0, + ss_server_hellorequest, + ss_server_helloverify, + ss_server_helloretryrequest, + ss_server_hello, + ss_server_certificatestatus, + ss_server_encryptedextensions, + ss_server_sessionticket, + ss_server_certrequest, + ss_server_cert, + ss_server_keyexchange, + ss_server_hellodone, + ss_server_changecipherspec, + ss_server_finished, + ss_server_keyupdate, + ss_client_hello, + ss_client_keyexchange, + ss_client_cert, + ss_client_changecipherspec, + ss_client_certverify, + ss_client_endofearlydata, + ss_client_finished, + ss_client_keyupdate, + ss_handshake_done + }; + + int protocol = 0; + int cbmode = 0; + int state = 0; + + WOLFSSL_ENTER("wolfSSL_state_string_long"); + if (ssl == NULL) { + WOLFSSL_MSG("Null argument passed in"); + return NULL; + } + + /* Get state of callback */ + if (ssl->cbmode == WOLFSSL_CB_MODE_WRITE) { + cbmode = SS_WRITE; + } + else if (ssl->cbmode == WOLFSSL_CB_MODE_READ) { + cbmode = SS_READ; + } + else { + cbmode = SS_NEITHER; + } + + /* Get protocol version */ + switch (ssl->version.major) { + case SSLv3_MAJOR: + switch (ssl->version.minor) { + case SSLv3_MINOR: + protocol = SSL_V3; + break; + case TLSv1_MINOR: + protocol = TLS_V1; + break; + case TLSv1_1_MINOR: + protocol = TLS_V1_1; + break; + case TLSv1_2_MINOR: + protocol = TLS_V1_2; + break; + case TLSv1_3_MINOR: + protocol = TLS_V1_3; + break; + default: + protocol = UNKNOWN; + } + break; + case DTLS_MAJOR: + switch (ssl->version.minor) { + case DTLS_MINOR: + protocol = DTLS_V1; + break; + case DTLSv1_2_MINOR: + protocol = DTLS_V1_2; + break; + case DTLSv1_3_MINOR: + protocol = DTLS_V1_3; + break; + default: + protocol = UNKNOWN; + } + break; + default: + protocol = UNKNOWN; + } + + /* accept process */ + if (ssl->cbmode == WOLFSSL_CB_MODE_READ) { + state = ssl->cbtype; + switch (state) { + case hello_request: + state = ss_server_hellorequest; + break; + case client_hello: + state = ss_client_hello; + break; + case server_hello: + state = ss_server_hello; + break; + case hello_verify_request: + state = ss_server_helloverify; + break; + case session_ticket: + state = ss_server_sessionticket; + break; + case end_of_early_data: + state = ss_client_endofearlydata; + break; + case hello_retry_request: + state = ss_server_helloretryrequest; + break; + case encrypted_extensions: + state = ss_server_encryptedextensions; + break; + case certificate: + if (ssl->options.side == WOLFSSL_SERVER_END) + state = ss_client_cert; + else if (ssl->options.side == WOLFSSL_CLIENT_END) + state = ss_server_cert; + else { + WOLFSSL_MSG("Unknown State"); + state = ss_null_state; + } + break; + case server_key_exchange: + state = ss_server_keyexchange; + break; + case certificate_request: + state = ss_server_certrequest; + break; + case server_hello_done: + state = ss_server_hellodone; + break; + case certificate_verify: + state = ss_client_certverify; + break; + case client_key_exchange: + state = ss_client_keyexchange; + break; + case finished: + if (ssl->options.side == WOLFSSL_SERVER_END) + state = ss_client_finished; + else if (ssl->options.side == WOLFSSL_CLIENT_END) + state = ss_server_finished; + else { + WOLFSSL_MSG("Unknown State"); + state = ss_null_state; + } + break; + case certificate_status: + state = ss_server_certificatestatus; + break; + case key_update: + if (ssl->options.side == WOLFSSL_SERVER_END) + state = ss_client_keyupdate; + else if (ssl->options.side == WOLFSSL_CLIENT_END) + state = ss_server_keyupdate; + else { + WOLFSSL_MSG("Unknown State"); + state = ss_null_state; + } + break; + case change_cipher_hs: + if (ssl->options.side == WOLFSSL_SERVER_END) + state = ss_client_changecipherspec; + else if (ssl->options.side == WOLFSSL_CLIENT_END) + state = ss_server_changecipherspec; + else { + WOLFSSL_MSG("Unknown State"); + state = ss_null_state; + } + break; + default: + WOLFSSL_MSG("Unknown State"); + state = ss_null_state; + } + } + else { + /* Send process */ + if (ssl->options.side == WOLFSSL_SERVER_END) + state = ssl->options.serverState; + else + state = ssl->options.clientState; + + switch (state) { + case SERVER_HELLOVERIFYREQUEST_COMPLETE: + state = ss_server_helloverify; + break; + case SERVER_HELLO_RETRY_REQUEST_COMPLETE: + state = ss_server_helloretryrequest; + break; + case SERVER_HELLO_COMPLETE: + state = ss_server_hello; + break; + case SERVER_ENCRYPTED_EXTENSIONS_COMPLETE: + state = ss_server_encryptedextensions; + break; + case SERVER_CERT_COMPLETE: + state = ss_server_cert; + break; + case SERVER_KEYEXCHANGE_COMPLETE: + state = ss_server_keyexchange; + break; + case SERVER_HELLODONE_COMPLETE: + state = ss_server_hellodone; + break; + case SERVER_CHANGECIPHERSPEC_COMPLETE: + state = ss_server_changecipherspec; + break; + case SERVER_FINISHED_COMPLETE: + state = ss_server_finished; + break; + case CLIENT_HELLO_RETRY: + case CLIENT_HELLO_COMPLETE: + state = ss_client_hello; + break; + case CLIENT_KEYEXCHANGE_COMPLETE: + state = ss_client_keyexchange; + break; + case CLIENT_CHANGECIPHERSPEC_COMPLETE: + state = ss_client_changecipherspec; + break; + case CLIENT_FINISHED_COMPLETE: + state = ss_client_finished; + break; + case HANDSHAKE_DONE: + state = ss_handshake_done; + break; + default: + WOLFSSL_MSG("Unknown State"); + state = ss_null_state; + } + } + + if (protocol == UNKNOWN) { + WOLFSSL_MSG("Unknown protocol"); + return ""; + } + else { + return OUTPUT_STR[state][protocol][cbmode]; + } +} + +#endif /* OPENSSL_EXTRA */ + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) \ + || defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) + +#ifndef NO_TLS +/* Perform the handshake. + * + * Calls the connect or accept for the side of the object. + * + * @param [in, out] s SSL/TLS object. + * @return WOLFSSL_SUCCESS when the handshake completes. + * @return WOLFSSL_FATAL_ERROR when the side is not set or the handshake + * fails. + */ +int wolfSSL_SSL_do_handshake_internal(WOLFSSL *s) +{ + WOLFSSL_ENTER("wolfSSL_SSL_do_handshake_internal"); + if (s == NULL) + return WOLFSSL_FAILURE; + + if (s->options.side == WOLFSSL_CLIENT_END) { + #ifndef NO_WOLFSSL_CLIENT + return wolfSSL_connect(s); + #else + WOLFSSL_MSG("Client not compiled in"); + return WOLFSSL_FAILURE; + #endif + } + +#ifndef NO_WOLFSSL_SERVER + return wolfSSL_accept(s); +#else + WOLFSSL_MSG("Server not compiled in"); + return WOLFSSL_FAILURE; +#endif +} + +/* Perform the handshake. + * + * @param [in, out] s SSL/TLS object. + * @return WOLFSSL_SUCCESS when the handshake completes. + * @return WOLFSSL_FATAL_ERROR when the handshake fails. Call + * wolfSSL_get_error() for the reason. + */ +int wolfSSL_SSL_do_handshake(WOLFSSL *s) +{ + WOLFSSL_ENTER("wolfSSL_SSL_do_handshake"); +#ifdef WOLFSSL_QUIC + if (WOLFSSL_IS_QUIC(s)) { + return wolfSSL_quic_do_handshake(s); + } +#endif + return wolfSSL_SSL_do_handshake_internal(s); +} +#endif /* !NO_TLS */ + +/* Determine whether the handshake has not completed. + * + * @param [in] ssl SSL/TLS object. + * @return 1 when the handshake has not completed. + * @return 0 when the handshake has completed. + */ +#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L +int wolfSSL_SSL_in_init(const WOLFSSL *ssl) +#else +int wolfSSL_SSL_in_init(WOLFSSL *ssl) +#endif +{ + WOLFSSL_ENTER("wolfSSL_SSL_in_init"); + + return !wolfSSL_is_init_finished(ssl); +} + +/* Determine whether the handshake has not started. + * + * @param [in] ssl SSL/TLS object. + * @return 1 when the handshake has not started. + * @return 0 when the handshake has started or ssl is NULL. + */ +int wolfSSL_SSL_in_before(const WOLFSSL *ssl) +{ + WOLFSSL_ENTER("wolfSSL_SSL_in_before"); + + if (ssl == NULL) + return WOLFSSL_FAILURE; + + return ssl->options.handShakeState == NULL_STATE; +} + +/* Determine whether the handshake is in progress. + * + * @param [in] ssl SSL/TLS object. + * @return 1 when the handshake has started but not completed. + * @return 0 otherwise or when ssl is NULL. + */ +int wolfSSL_SSL_in_connect_init(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_SSL_in_connect_init"); + + if (ssl == NULL) + return WOLFSSL_FAILURE; + + if (ssl->options.side == WOLFSSL_CLIENT_END) { + return ssl->options.connectState > CONNECT_BEGIN && + ssl->options.connectState < SECOND_REPLY_DONE; + } + + return ssl->options.acceptState > ACCEPT_BEGIN && + ssl->options.acceptState < ACCEPT_THIRD_REPLY_DONE; +} + +#endif /* OPENSSL_ALL || WOLFSSL_NGINX || WOLFSSL_HAPROXY || + OPENSSL_EXTRA || HAVE_LIGHTY */ + + +#ifndef NO_CERTS +#ifdef HAVE_PK_CALLBACKS + +/* callback for premaster secret generation */ +void wolfSSL_CTX_SetGenPreMasterCb(WOLFSSL_CTX* ctx, CallbackGenPreMaster cb) +{ + if (ctx) + ctx->GenPreMasterCb = cb; +} +/* Set premaster secret generation callback context */ +void wolfSSL_SetGenPreMasterCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->GenPreMasterCtx = ctx; +} +/* Get premaster secret generation callback context */ +void* wolfSSL_GetGenPreMasterCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->GenPreMasterCtx; + + return NULL; +} + +/* callback for master secret generation */ +void wolfSSL_CTX_SetGenMasterSecretCb(WOLFSSL_CTX* ctx, + CallbackGenMasterSecret cb) +{ + if (ctx) + ctx->GenMasterCb = cb; +} +/* Set master secret generation callback context */ +void wolfSSL_SetGenMasterSecretCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->GenMasterCtx = ctx; +} +/* Get master secret generation callback context */ +void* wolfSSL_GetGenMasterSecretCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->GenMasterCtx; + + return NULL; +} + +/* callback for extended master secret generation */ +void wolfSSL_CTX_SetGenExtMasterSecretCb(WOLFSSL_CTX* ctx, + CallbackGenExtMasterSecret cb) +{ + if (ctx) + ctx->GenExtMasterCb = cb; +} +/* Set extended master secret generation callback context */ +void wolfSSL_SetGenExtMasterSecretCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->GenExtMasterCtx = ctx; +} +/* Get extended master secret generation callback context */ +void* wolfSSL_GetGenExtMasterSecretCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->GenExtMasterCtx; + + return NULL; +} + + +/* callback for session key generation */ +void wolfSSL_CTX_SetGenSessionKeyCb(WOLFSSL_CTX* ctx, CallbackGenSessionKey cb) +{ + if (ctx) + ctx->GenSessionKeyCb = cb; +} +/* Set session key generation callback context */ +void wolfSSL_SetGenSessionKeyCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->GenSessionKeyCtx = ctx; +} +/* Get session key generation callback context */ +void* wolfSSL_GetGenSessionKeyCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->GenSessionKeyCtx; + + return NULL; +} + +/* callback for setting encryption keys */ +void wolfSSL_CTX_SetEncryptKeysCb(WOLFSSL_CTX* ctx, CallbackEncryptKeys cb) +{ + if (ctx) + ctx->EncryptKeysCb = cb; +} +/* Set encryption keys callback context */ +void wolfSSL_SetEncryptKeysCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->EncryptKeysCtx = ctx; +} +/* Get encryption keys callback context */ +void* wolfSSL_GetEncryptKeysCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->EncryptKeysCtx; + + return NULL; +} + +/* callback for Tls finished */ +/* the callback can be used to build TLS Finished message if enabled */ +void wolfSSL_CTX_SetTlsFinishedCb(WOLFSSL_CTX* ctx, CallbackTlsFinished cb) +{ + if (ctx) + ctx->TlsFinishedCb = cb; +} +/* Set Tls finished callback context */ +void wolfSSL_SetTlsFinishedCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->TlsFinishedCtx = ctx; +} +/* Get Tls finished callback context */ +void* wolfSSL_GetTlsFinishedCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->TlsFinishedCtx; + + return NULL; +} +#if !defined(WOLFSSL_NO_TLS12) && !defined(WOLFSSL_AEAD_ONLY) +/* callback for verify data */ +void wolfSSL_CTX_SetVerifyMacCb(WOLFSSL_CTX* ctx, CallbackVerifyMac cb) +{ + if (ctx) + ctx->VerifyMacCb = cb; +} + +/* Set set keys callback context */ +void wolfSSL_SetVerifyMacCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->VerifyMacCtx = ctx; +} +/* Get set keys callback context */ +void* wolfSSL_GetVerifyMacCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->VerifyMacCtx; + + return NULL; +} +#endif /* !WOLFSSL_NO_TLS12 && !WOLFSSL_AEAD_ONLY */ + +void wolfSSL_CTX_SetHKDFExpandLabelCb(WOLFSSL_CTX* ctx, + CallbackHKDFExpandLabel cb) +{ + if (ctx) + ctx->HKDFExpandLabelCb = cb; +} +#ifdef WOLFSSL_PUBLIC_ASN +/* Set the callback to call to process the peer's certificate. + * + * @param [in, out] ctx SSL/TLS CTX object. + * @param [in] cb Callback to call. NULL to clear. + */ +void wolfSSL_CTX_SetProcessPeerCertCb(WOLFSSL_CTX* ctx, + CallbackProcessPeerCert cb) +{ + if (ctx) + ctx->ProcessPeerCertCb = cb; +} +#endif /* WOLFSSL_PUBLIC_ASN */ +void wolfSSL_CTX_SetProcessServerSigKexCb(WOLFSSL_CTX* ctx, + CallbackProcessServerSigKex cb) +{ + if (ctx) + ctx->ProcessServerSigKexCb = cb; +} +/* Set the callback to call to encrypt and decrypt TLS records. + * + * @param [in, out] ctx SSL/TLS CTX object. + * @param [in] cb Callback to call. NULL to clear. + */ +void wolfSSL_CTX_SetPerformTlsRecordProcessingCb(WOLFSSL_CTX* ctx, + CallbackPerformTlsRecordProcessing cb) +{ + if (ctx) + ctx->PerformTlsRecordProcessingCb = cb; +} +#endif /* HAVE_PK_CALLBACKS */ +#endif /* NO_CERTS */ + +#if defined(HAVE_PK_CALLBACKS) && defined(HAVE_HKDF) + +/* Set the callback to call to perform the HKDF extract operation. + * + * @param [in, out] ctx SSL/TLS CTX object. + * @param [in] cb Callback to call. NULL to clear. + */ +void wolfSSL_CTX_SetHKDFExtractCb(WOLFSSL_CTX* ctx, CallbackHKDFExtract cb) +{ + if (ctx) + ctx->HkdfExtractCb = cb; +} + +/* Set the context to pass to the HKDF extract callback. + * + * @param [in, out] ssl SSL/TLS object. + * @param [in] ctx Context to pass to the callback. + */ +void wolfSSL_SetHKDFExtractCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->HkdfExtractCtx = ctx; +} + +/* Get the context passed to the HKDF extract callback. + * + * @param [in] ssl SSL/TLS object. + * @return Context on success. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetHKDFExtractCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->HkdfExtractCtx; + + return NULL; +} +#endif /* HAVE_PK_CALLBACKS && HAVE_HKDF */ + +#endif /* !WOLFCRYPT_ONLY */ + +#endif /* !WOLFSSL_SSL_API_HS_INCLUDED */ diff --git a/src/ssl_api_pk.c b/src/ssl_api_pk.c index d18590e8ac..c5cafebff8 100644 --- a/src/ssl_api_pk.c +++ b/src/ssl_api_pk.c @@ -2749,6 +2749,179 @@ int wolfSSL_CTX_set_dh_auto(WOLFSSL_CTX* ctx, int onoff) return WOLFSSL_SUCCESS; } + #if defined(WOLFCRYPT_HAVE_SRP) && !defined(NO_SHA256) \ + && !defined(WC_NO_RNG) + static const byte srp_N[] = { + 0xEE, 0xAF, 0x0A, 0xB9, 0xAD, 0xB3, 0x8D, 0xD6, 0x9C, 0x33, 0xF8, + 0x0A, 0xFA, 0x8F, 0xC5, 0xE8, 0x60, 0x72, 0x61, 0x87, 0x75, 0xFF, + 0x3C, 0x0B, 0x9E, 0xA2, 0x31, 0x4C, 0x9C, 0x25, 0x65, 0x76, 0xD6, + 0x74, 0xDF, 0x74, 0x96, 0xEA, 0x81, 0xD3, 0x38, 0x3B, 0x48, 0x13, + 0xD6, 0x92, 0xC6, 0xE0, 0xE0, 0xD5, 0xD8, 0xE2, 0x50, 0xB9, 0x8B, + 0xE4, 0x8E, 0x49, 0x5C, 0x1D, 0x60, 0x89, 0xDA, 0xD1, 0x5D, 0xC7, + 0xD7, 0xB4, 0x61, 0x54, 0xD6, 0xB6, 0xCE, 0x8E, 0xF4, 0xAD, 0x69, + 0xB1, 0x5D, 0x49, 0x82, 0x55, 0x9B, 0x29, 0x7B, 0xCF, 0x18, 0x85, + 0xC5, 0x29, 0xF5, 0x66, 0x66, 0x0E, 0x57, 0xEC, 0x68, 0xED, 0xBC, + 0x3C, 0x05, 0x72, 0x6C, 0xC0, 0x2F, 0xD4, 0xCB, 0xF4, 0x97, 0x6E, + 0xAA, 0x9A, 0xFD, 0x51, 0x38, 0xFE, 0x83, 0x76, 0x43, 0x5B, 0x9F, + 0xC6, 0x1D, 0x2F, 0xC0, 0xEB, 0x06, 0xE3 + }; + static const byte srp_g[] = { + 0x02 + }; + + /* Set the SRP username on the SSL/TLS CTX object. + * + * The SRP side is taken from the method of the CTX object. When a password + * has already been set with wolfSSL_CTX_set_srp_password() then the saved + * password is applied here. + * + * @param [in, out] ctx SSL/TLS CTX object. + * @param [in] username SRP username. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ctx, its SRP object or username is NULL, + * the side is not set, or a wolfCrypt SRP operation fails. + */ + int wolfSSL_CTX_set_srp_username(WOLFSSL_CTX* ctx, char* username) + { + int r = 0; + SrpSide srp_side = SRP_CLIENT_SIDE; + + WOLFSSL_ENTER("wolfSSL_CTX_set_srp_username"); + if (ctx == NULL || ctx->srp == NULL || username==NULL) + return WOLFSSL_FAILURE; + + if (ctx->method->side == WOLFSSL_SERVER_END){ + srp_side = SRP_SERVER_SIDE; + } else if (ctx->method->side == WOLFSSL_CLIENT_END){ + srp_side = SRP_CLIENT_SIDE; + } else { + WOLFSSL_MSG("Init CTX failed"); + return WOLFSSL_FAILURE; + } + + if (wc_SrpInit(ctx->srp, SRP_TYPE_SHA256, srp_side) < 0) { + WOLFSSL_MSG("Init SRP CTX failed"); + XFREE(ctx->srp, ctx->heap, DYNAMIC_TYPE_SRP); + ctx->srp = NULL; + return WOLFSSL_FAILURE; + } + r = wc_SrpSetUsername(ctx->srp, (const byte*)username, + (word32)XSTRLEN(username)); + if (r < 0) { + WOLFSSL_MSG("fail to set srp username."); + return WOLFSSL_FAILURE; + } + + /* if wolfSSL_CTX_set_srp_password has already been called, */ + /* use saved password here */ + if (ctx->srp_password != NULL) { + if (ctx->srp->user == NULL) + return WOLFSSL_FAILURE; + return wolfSSL_CTX_set_srp_password(ctx, (char*)ctx->srp_password); + } + + return WOLFSSL_SUCCESS; + } + + /* Set the SRP password on the SSL/TLS CTX object. + * + * When the username has been set, the SRP parameters and a random salt are + * set on the SRP object with the password. Otherwise the password is saved + * for wolfSSL_CTX_set_srp_username() to apply. + * + * @param [in, out] ctx SSL/TLS CTX object. + * @param [in] password SRP password. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ctx, its SRP object or password is NULL, a + * wolfCrypt SRP operation fails or dynamic memory allocation + * fails. + */ + int wolfSSL_CTX_set_srp_password(WOLFSSL_CTX* ctx, char* password) + { + int r; + byte salt[SRP_SALT_SIZE]; + + WOLFSSL_ENTER("wolfSSL_CTX_set_srp_password"); + if (ctx == NULL || ctx->srp == NULL || password == NULL) + return WOLFSSL_FAILURE; + + if (ctx->srp->user != NULL) { + WC_RNG rng; + if (wc_InitRng(&rng) < 0) { + WOLFSSL_MSG("wc_InitRng failed"); + return WOLFSSL_FAILURE; + } + XMEMSET(salt, 0, sizeof(salt)/sizeof(salt[0])); + r = wc_RNG_GenerateBlock(&rng, salt, sizeof(salt)/sizeof(salt[0])); + wc_FreeRng(&rng); + if (r < 0) { + WOLFSSL_MSG("wc_RNG_GenerateBlock failed"); + return WOLFSSL_FAILURE; + } + if (wc_SrpSetParams(ctx->srp, srp_N, sizeof(srp_N)/sizeof(srp_N[0]), + srp_g, sizeof(srp_g)/sizeof(srp_g[0]), + salt, sizeof(salt)/sizeof(salt[0])) < 0){ + WOLFSSL_MSG("wc_SrpSetParam failed"); + return WOLFSSL_FAILURE; + } + r = wc_SrpSetPassword(ctx->srp, (const byte*)password, + (word32)XSTRLEN(password)); + if (r < 0) { + WOLFSSL_MSG("wc_SrpSetPassword failed."); + return WOLFSSL_FAILURE; + } + XFREE(ctx->srp_password, NULL, DYNAMIC_TYPE_SRP); + ctx->srp_password = NULL; + } else { + /* save password for wolfSSL_set_srp_username */ + XFREE(ctx->srp_password, ctx->heap, DYNAMIC_TYPE_SRP); + + ctx->srp_password = (byte*)XMALLOC(XSTRLEN(password) + 1, ctx->heap, + DYNAMIC_TYPE_SRP); + if (ctx->srp_password == NULL){ + WOLFSSL_MSG("memory allocation error"); + return WOLFSSL_FAILURE; + } + XMEMCPY(ctx->srp_password, password, XSTRLEN(password) + 1); + } + return WOLFSSL_SUCCESS; + } + + /** + * The modulus passed to wc_SrpSetParams in ssl_api_pk.c is constant so + * check that the requested strength is less than or equal to the size of + * the static modulus size. + * @param ctx Not used + * @param strength Minimum number of bits for the modulus + * @return 1 if strength is less than or equal to static modulus + * 0 if strength is greater than static modulus + */ + int wolfSSL_CTX_set_srp_strength(WOLFSSL_CTX *ctx, int strength) + { + (void)ctx; + WOLFSSL_ENTER("wolfSSL_CTX_set_srp_strength"); + if (strength > (int)(sizeof(srp_N)*8)) { + WOLFSSL_MSG("Bad Parameter"); + return WOLFSSL_FAILURE; + } + return WOLFSSL_SUCCESS; + } + + /* Get the SRP username set on the CTX object of an SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return SRP username on success. + * @return NULL when ssl, its CTX object or the SRP object is NULL. + */ + char* wolfSSL_get_srp_username(WOLFSSL *ssl) + { + if (ssl && ssl->ctx && ssl->ctx->srp) { + return (char*) ssl->ctx->srp->user; + } + return NULL; + } + #endif /* WOLFCRYPT_HAVE_SRP && !NO_SHA256 && !WC_NO_RNG */ + #endif /* OPENSSL_EXTRA */ #endif /* !WOLFCRYPT_ONLY */ diff --git a/src/ssl_api_rw.c b/src/ssl_api_rw.c new file mode 100644 index 0000000000..6dfd318fe4 --- /dev/null +++ b/src/ssl_api_rw.c @@ -0,0 +1,913 @@ +/* ssl_api_rw.c + * + * Copyright (C) 2006-2026 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 3 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 + */ + +#include + +#if !defined(WOLFSSL_SSL_API_RW_INCLUDED) + #ifndef WOLFSSL_IGNORE_FILE_WARN + #warning ssl_api_rw.c does not need to be compiled separately from ssl.c + #endif +#else + +#ifndef WOLFCRYPT_ONLY + +#ifndef NO_TLS + +/* Write application data to the peer. + * + * Performs the handshake when it has not completed. When a write duplicate is + * in use, work delegated by the read side, such as sending a key update, is + * done here first. + * + * @param [in, out] ssl SSL/TLS object. + * @param [in] data Application data to write. + * @param [in] sz Length of data in bytes. + * @return Number of bytes written on success. + * @return BAD_FUNC_ARG when ssl or data is NULL. + * @return WOLFSSL_FATAL_ERROR when the handshake or write fails. Call + * wolfSSL_get_error() for the reason. + */ +static int wolfSSL_write_internal(WOLFSSL* ssl, const void* data, size_t sz) +{ + int ret = 0; + + WOLFSSL_ENTER("wolfSSL_write"); + + if (ssl == NULL || data == NULL) + return BAD_FUNC_ARG; + +#ifdef WOLFSSL_QUIC + if (WOLFSSL_IS_QUIC(ssl)) { + WOLFSSL_MSG("SSL_write() on QUIC not allowed"); + return BAD_FUNC_ARG; + } +#endif + +#ifdef HAVE_WRITE_DUP + if (ssl->dupSide == READ_DUP_SIDE) { + WOLFSSL_MSG("Read dup side cannot write"); + return WRITE_DUP_WRITE_E; + } + /* Only enter special dupWrite logic when error is cleared. This will help + * with handling async data and other edge case errors. */ + if (ssl->dupWrite != NULL && ssl->error == 0) { + int dupErr = 0; /* local copy */ + /* Lock ssl->dupWrite to gather what needs to be done. */ + if (wc_LockMutex(&ssl->dupWrite->dupMutex) != 0) + return BAD_MUTEX_E; + dupErr = ssl->dupWrite->dupErr; +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version)) { + /* TLS 1.3: if the read side received a KeyUpdate(update_requested) + * it cannot respond; send the response from here. */ + ssl->keys.keyUpdateRespond |= ssl->dupWrite->keyUpdateRespond; + ssl->dupWrite->keyUpdateRespond = 0; +#ifdef WOLFSSL_POST_HANDSHAKE_AUTH + ssl->postHandshakeAuthPending |= + ssl->dupWrite->postHandshakeAuthPending; + ssl->dupWrite->postHandshakeAuthPending = 0; + if (ssl->postHandshakeAuthPending) { + /* Take ownership of the delegated auth state. */ + CertReqCtx** tail = &ssl->dupWrite->postHandshakeCertReqCtx; + while (*tail != NULL) + tail = &(*tail)->next; + *tail = ssl->certReqCtx; + ssl->certReqCtx = ssl->dupWrite->postHandshakeCertReqCtx; + ssl->dupWrite->postHandshakeCertReqCtx = NULL; + FreeHandshakeHashes(ssl); + ssl->hsHashes = ssl->dupWrite->postHandshakeHashState; + ssl->dupWrite->postHandshakeHashState = NULL; + ssl->options.sendVerify = + ssl->dupWrite->postHandshakeSendVerify; + ssl->options.sigAlgo = ssl->dupWrite->postHandshakeSigAlgo; + ssl->options.hashAlgo = ssl->dupWrite->postHandshakeHashAlgo; + } +#endif /* WOLFSSL_POST_HANDSHAKE_AUTH */ +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) { + /* Schedule key update to be sent. */ + if (ssl->keys.keyUpdateRespond) + ssl->dtls13DoKeyUpdate = 1; + + /* Copy over ACKs */ + ssl->dtls13Rtx.sendAcks |= ssl->dupWrite->sendAcks; + if (ssl->dupWrite->sendAcks) { + /* Insert each record number so the + * ACK message is properly ordered. */ + struct Dtls13RecordNumber* rn; + for (rn = ssl->dupWrite->sendAckList; rn != NULL; + rn = rn->next) { + ret = Dtls13RtxAddAck(ssl, rn->epoch, rn->seq); + if (ret != 0) + break; + } + /* Clear only on success so no ACKs get dropped */ + if (ret == 0) { + rn = ssl->dupWrite->sendAckList; + ssl->dupWrite->sendAckList = NULL; + ssl->dupWrite->sendAcks = 0; + while (rn != NULL) { + struct Dtls13RecordNumber* next = rn->next; + XFREE(rn, ssl->heap, DYNAMIC_TYPE_DTLS_MSG); + rn = next; + } + } + } + + /* Remove KeyUpdate record from RTX list. */ + if (ssl->dupWrite->keyUpdateAcked) { + Dtls13RtxRemoveRecord(ssl, ssl->dupWrite->keyUpdateEpoch, + ssl->dupWrite->keyUpdateSeq); + } + /* Store if KeyUpdate was ACKed. */ + ssl->dtls13KeyUpdateAcked |= ssl->dupWrite->keyUpdateAcked; + ssl->dupWrite->keyUpdateAcked = 0; + } +#endif /* WOLFSSL_DTLS13 */ + } +#endif /* WOLFSSL_TLS13 */ + wc_UnLockMutex(&ssl->dupWrite->dupMutex); + + if (dupErr != 0) { + WOLFSSL_MSG("Write dup error from other side"); + ssl->error = dupErr; + return WOLFSSL_FATAL_ERROR; + } + if (ret != 0) { + ssl->error = ret; + return WOLFSSL_FATAL_ERROR; + } + + +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version)) { +#ifdef WOLFSSL_POST_HANDSHAKE_AUTH + /* Read side received a CertificateRequest but couldn't write; + * send Certificate+CertificateVerify+Finished from the write + * side. */ + if (ssl->postHandshakeAuthPending) { + /* reset handshake states */ + ssl->postHandshakeAuthPending = 0; + ssl->options.clientState = CLIENT_HELLO_COMPLETE; + ssl->options.connectState = FIRST_REPLY_DONE; + ssl->options.handShakeState = CLIENT_HELLO_COMPLETE; + ssl->options.processReply = 0; /* doProcessInit */ + if (wolfSSL_connect_TLSv13(ssl) != WOLFSSL_SUCCESS) { + if (ssl->error != WC_NO_ERR_TRACE(WANT_WRITE) && + ssl->error != WC_NO_ERR_TRACE(WC_PENDING_E)) { + WOLFSSL_MSG("Post-handshake auth send failed"); + ssl->error = POST_HAND_AUTH_ERROR; + } + return WOLFSSL_FATAL_ERROR; + } + } +#endif /* WOLFSSL_POST_HANDSHAKE_AUTH */ +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) { + if (ssl->dtls13KeyUpdateAcked) + ret = DoDtls13KeyUpdateAck(ssl); + ssl->dtls13KeyUpdateAcked = 0; + if (ret == 0) + ret = Dtls13DoScheduledWork(ssl); + } + else +#endif /* WOLFSSL_DTLS13 */ + if (ssl->keys.keyUpdateRespond) /* cleared in SendTls13KeyUpdate */ + ret = Tls13UpdateKeys(ssl); + if (ret != 0) { + ssl->error = ret; + return WOLFSSL_FATAL_ERROR; + } + /* WANT_WRITE is safe to clear. Data is buffered in output buffer + * or in DTLS RTX queue */ + ret = 0; + } +#endif /* WOLFSSL_TLS13 */ + } +#endif + +#ifdef HAVE_ERRNO_H + errno = 0; +#endif + + #ifdef OPENSSL_EXTRA + if (ssl->CBIS != NULL) { + ssl->CBIS(ssl, WOLFSSL_CB_WRITE, WOLFSSL_SUCCESS); + ssl->cbmode = WOLFSSL_CB_WRITE; + } + #endif + ret = SendData(ssl, data, sz); + + WOLFSSL_LEAVE("wolfSSL_write", ret); + + if (ret < 0) + return WOLFSSL_FATAL_ERROR; + else + return ret; +} + +WOLFSSL_ABI +/* Write application data to the peer. + * + * @param [in, out] ssl SSL/TLS object. + * @param [in] data Application data to write. + * @param [in] sz Length of data in bytes. + * @return Number of bytes written on success. + * @return BAD_FUNC_ARG when ssl or data is NULL, or sz is negative. + * @return WOLFSSL_FATAL_ERROR when the write fails. Call + * wolfSSL_get_error() for the reason. + */ +int wolfSSL_write(WOLFSSL* ssl, const void* data, int sz) +{ + WOLFSSL_ENTER("wolfSSL_write"); + + if (sz < 0) + return BAD_FUNC_ARG; + + return wolfSSL_write_internal(ssl, data, (size_t)sz); +} + +/* Inject data into the input buffer as if it was received from the peer. + * + * Used when the application reads the transport itself. + * + * @param [in, out] ssl SSL/TLS object. + * @param [in] data Data to inject. + * @param [in] sz Length of data in bytes. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl or data is NULL, or sz is not positive. + * @return MEMORY_E when growing the input buffer fails. + */ +int wolfSSL_inject(WOLFSSL* ssl, const void* data, int sz) +{ + int maxLength; + int usedLength; + + WOLFSSL_ENTER("wolfSSL_inject"); + + if (ssl == NULL || data == NULL || sz <= 0) + return BAD_FUNC_ARG; + + usedLength = (int)(ssl->buffers.inputBuffer.length - + ssl->buffers.inputBuffer.idx); + maxLength = (int)(ssl->buffers.inputBuffer.bufferSize - + (word32)usedLength); + + if (sz > maxLength) { + /* Need to make space */ + int ret; + if (ssl->buffers.clearOutputBuffer.length > 0) { + /* clearOutputBuffer points into so reallocating inputBuffer will + * invalidate clearOutputBuffer and lose app data */ + WOLFSSL_MSG("Can't inject while there is application data to read"); + return APP_DATA_READY; + } + ret = GrowInputBuffer(ssl, sz, usedLength); + if (ret < 0) + return ret; + } + + XMEMCPY(ssl->buffers.inputBuffer.buffer + ssl->buffers.inputBuffer.idx, + data, sz); + ssl->buffers.inputBuffer.length += sz; + + return WOLFSSL_SUCCESS; +} + + +/* Write application data to the peer and return the number of bytes written. + * + * @param [in, out] ssl SSL/TLS object. + * @param [in] data Application data to write. + * @param [in] sz Length of data in bytes. + * @param [out] wr Number of bytes written. May be NULL. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when the write fails. Call wolfSSL_get_error() for + * the reason. + */ +int wolfSSL_write_ex(WOLFSSL* ssl, const void* data, size_t sz, size_t* wr) +{ + int ret; + + if (wr != NULL) { + *wr = 0; + } + + ret = wolfSSL_write_internal(ssl, data, sz); + if (ret >= 0) { + if (wr != NULL) { + *wr = (size_t)ret; + } + + /* handle partial write cases, if not set then a partial write is + * considered a failure case, or if set and ret is 0 then is a fail */ + if (ret == 0 && ssl->options.partialWrite) { + ret = 0; + } + else if ((size_t)ret < sz && !ssl->options.partialWrite) { + ret = 0; + } + else { + /* wrote out all application data, or wrote out 1 byte or more with + * partial write flag set */ + ret = 1; + } + } + else { + ret = 0; + } + + return ret; +} + + +/* Read application data from the peer. + * + * Performs the handshake when it has not completed. + * + * @param [in, out] ssl SSL/TLS object. + * @param [out] data Buffer to hold application data. + * @param [in] sz Length of buffer in bytes. + * @param [in] peek When 1, data is not removed from the input buffer. + * @return Number of bytes read on success. + * @return 0 when the peer has closed the connection. + * @return BAD_FUNC_ARG when ssl or data is NULL. + * @return WOLFSSL_FATAL_ERROR when the handshake or read fails. Call + * wolfSSL_get_error() for the reason. + */ +static int wolfSSL_read_internal(WOLFSSL* ssl, void* data, size_t sz, int peek) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_read_internal"); + + if (ssl == NULL || data == NULL) + return BAD_FUNC_ARG; + +#ifdef WOLFSSL_QUIC + if (WOLFSSL_IS_QUIC(ssl)) { + WOLFSSL_MSG("SSL_read() on QUIC not allowed"); + return BAD_FUNC_ARG; + } +#endif +#if defined(WOLFSSL_ERROR_CODE_OPENSSL) && defined(OPENSSL_EXTRA) + /* This additional logic is meant to simulate following openSSL behavior: + * After bidirectional SSL_shutdown complete, SSL_read returns 0 and + * SSL_get_error_code returns SSL_ERROR_ZERO_RETURN. + * This behavior is used to know the disconnect of the underlying + * transport layer. + * + * In this logic, CBIORecv is called with a read size of 0 to check the + * transport layer status. It also returns WOLFSSL_FAILURE so that + * SSL_read does not return a positive number on failure. + */ + + /* make sure bidirectional TLS shutdown completes */ + if (ssl->error == WOLFSSL_ERROR_SYSCALL || ssl->options.shutdownDone) { + /* ask the underlying transport the connection is closed */ + if (ssl->CBIORecv(ssl, (char*)data, 0, ssl->IOCB_ReadCtx) + == WC_NO_ERR_TRACE(WOLFSSL_CBIO_ERR_CONN_CLOSE)) + { + ssl->options.isClosed = 1; + ssl->error = WOLFSSL_ERROR_ZERO_RETURN; + } + return WOLFSSL_FAILURE; + } +#endif + +#ifdef HAVE_WRITE_DUP + if (ssl->dupWrite && ssl->dupSide == WRITE_DUP_SIDE) { + WOLFSSL_MSG("Write dup side cannot read"); + return WRITE_DUP_READ_E; + } +#endif + +#ifdef HAVE_ERRNO_H + errno = 0; +#endif + + ret = ReceiveData(ssl, (byte*)data, sz, peek); + +#ifdef HAVE_WRITE_DUP + if (ssl->dupWrite) { + if (ssl->error != 0 && ssl->error != WC_NO_ERR_TRACE(WANT_READ) + #ifdef WOLFSSL_ASYNC_CRYPT + && ssl->error != WC_NO_ERR_TRACE(WC_PENDING_E) + #endif + ) { + int notifyErr; + + WOLFSSL_MSG("Notifying write side of fatal read error"); + notifyErr = NotifyWriteSide(ssl, ssl->error); + if (notifyErr < 0) { + ret = ssl->error = notifyErr; + } + } + } +#endif + + WOLFSSL_LEAVE("wolfSSL_read_internal", ret); + + if (ret < 0) + return WOLFSSL_FATAL_ERROR; + else + return ret; +} + + +/* Read application data from the peer without removing it. + * + * The same data is returned by the next call to wolfSSL_read(). + * + * @param [in, out] ssl SSL/TLS object. + * @param [out] data Buffer to hold application data. + * @param [in] sz Length of buffer in bytes. + * @return Number of bytes read on success. + * @return BAD_FUNC_ARG when ssl or data is NULL, or sz is negative. + * @return WOLFSSL_FATAL_ERROR when the read fails. + */ +int wolfSSL_peek(WOLFSSL* ssl, void* data, int sz) +{ + WOLFSSL_ENTER("wolfSSL_peek"); + + if (sz < 0) + return BAD_FUNC_ARG; + + return wolfSSL_read_internal(ssl, data, (size_t)sz, TRUE); +} + + +WOLFSSL_ABI +/* Read application data from the peer. + * + * @param [in, out] ssl SSL/TLS object. + * @param [out] data Buffer to hold application data. + * @param [in] sz Length of buffer in bytes. + * @return Number of bytes read on success. + * @return 0 when the peer has closed the connection. + * @return BAD_FUNC_ARG when ssl or data is NULL, or sz is negative. + * @return WOLFSSL_FATAL_ERROR when the read fails. Call wolfSSL_get_error() + * for the reason. + */ +int wolfSSL_read(WOLFSSL* ssl, void* data, int sz) +{ + WOLFSSL_ENTER("wolfSSL_read"); + + if (sz < 0) + return BAD_FUNC_ARG; + + #ifdef OPENSSL_EXTRA + if (ssl == NULL) { + return BAD_FUNC_ARG; + } + if (ssl->CBIS != NULL) { + ssl->CBIS(ssl, WOLFSSL_CB_READ, WOLFSSL_SUCCESS); + ssl->cbmode = WOLFSSL_CB_READ; + } + #endif + return wolfSSL_read_internal(ssl, data, (size_t)sz, FALSE); +} + + +/* returns 0 on failure and 1 on read */ +int wolfSSL_read_ex(WOLFSSL* ssl, void* data, size_t sz, size_t* rd) +{ + int ret; + + #ifdef OPENSSL_EXTRA + if (ssl == NULL) { + return BAD_FUNC_ARG; + } + if (ssl->CBIS != NULL) { + ssl->CBIS(ssl, WOLFSSL_CB_READ, WOLFSSL_SUCCESS); + ssl->cbmode = WOLFSSL_CB_READ; + } + #endif + ret = wolfSSL_read_internal(ssl, data, sz, FALSE); + + if (ret > 0 && rd != NULL) { + *rd = (size_t)ret; + } + + return ret > 0 ? 1 : 0; +} + +#endif /* !NO_TLS */ + +#ifndef NO_TLS + + +#ifndef WOLFSSL_LEANPSK + +/* Write application data to the peer with socket flags. + * + * Flags are set on the socket for the write and restored afterwards. + * + * @param [in, out] ssl SSL/TLS object. + * @param [in] data Application data to write. + * @param [in] sz Length of data in bytes. + * @param [in] flags Flags to pass to the send call. + * @return Number of bytes written on success. + * @return BAD_FUNC_ARG when ssl or data is NULL, or sz is negative. + * @return WOLFSSL_FATAL_ERROR when the write fails. + */ +int wolfSSL_send(WOLFSSL* ssl, const void* data, int sz, int flags) +{ + int ret; + int oldFlags; + + WOLFSSL_ENTER("wolfSSL_send"); + + if (ssl == NULL || data == NULL || sz < 0) + return BAD_FUNC_ARG; + + oldFlags = ssl->wflags; + + ssl->wflags = flags; + ret = wolfSSL_write(ssl, data, sz); + ssl->wflags = oldFlags; + + WOLFSSL_LEAVE("wolfSSL_send", ret); + + return ret; +} + + +/* Read application data from the peer with socket flags. + * + * Flags are set on the socket for the read and restored afterwards. + * + * @param [in, out] ssl SSL/TLS object. + * @param [out] data Buffer to hold application data. + * @param [in] sz Length of buffer in bytes. + * @param [in] flags Flags to pass to the recv call. + * @return Number of bytes read on success. + * @return BAD_FUNC_ARG when ssl or data is NULL, or sz is negative. + * @return WOLFSSL_FATAL_ERROR when the read fails. + */ +int wolfSSL_recv(WOLFSSL* ssl, void* data, int sz, int flags) +{ + int ret; + int oldFlags; + + WOLFSSL_ENTER("wolfSSL_recv"); + + if (ssl == NULL || data == NULL || sz < 0) + return BAD_FUNC_ARG; + + oldFlags = ssl->rflags; + + ssl->rflags = flags; + ret = wolfSSL_read(ssl, data, sz); + ssl->rflags = oldFlags; + + WOLFSSL_LEAVE("wolfSSL_recv", ret); + + return ret; +} +#endif + +/* Send a user_canceled alert to the peer and shut down the connection. + * + * @param [in, out] ssl SSL/TLS object. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_SHUTDOWN_NOT_DONE when the shutdown is not complete. + * @return WOLFSSL_FAILURE when ssl is NULL or sending the alert fails. + */ +int wolfSSL_SendUserCanceled(WOLFSSL* ssl) +{ + int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); + WOLFSSL_ENTER("wolfSSL_recv"); + + if (ssl != NULL) { + ssl->error = SendAlert(ssl, alert_warning, user_canceled); + if (ssl->error < 0) { + WOLFSSL_ERROR(ssl->error); + } + else { + ret = wolfSSL_shutdown(ssl); + } + } + + WOLFSSL_LEAVE("wolfSSL_SendUserCanceled", ret); + + return ret; +} + +/* WOLFSSL_SUCCESS on ok */ +WOLFSSL_ABI +int wolfSSL_shutdown(WOLFSSL* ssl) +{ + int ret = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR); + WOLFSSL_ENTER("wolfSSL_shutdown"); + + if (ssl == NULL) + return WOLFSSL_FATAL_ERROR; + + if (ssl->options.quietShutdown) { + WOLFSSL_MSG("quiet shutdown, no close notify sent"); + ret = WOLFSSL_SUCCESS; + } + else { + + /* Try to flush the buffer first, it might contain the alert */ + if (ssl->error == WC_NO_ERR_TRACE(WANT_WRITE) && + ssl->buffers.outputBuffer.length > 0) { + ret = SendBuffered(ssl); + if (ret != 0) { + ssl->error = ret; + /* for error tracing */ + if (ret != WC_NO_ERR_TRACE(WANT_WRITE)) + WOLFSSL_ERROR(ret); + ret = WOLFSSL_FATAL_ERROR; + WOLFSSL_LEAVE("wolfSSL_shutdown", ret); + return ret; + } + + ssl->error = WOLFSSL_ERROR_NONE; + /* we succeeded in sending the alert now */ + if (ssl->options.sentNotify) { + /* just after we send the alert, if we didn't receive the alert + * from the other peer yet, return WOLFSSL_STHUDOWN_NOT_DONE */ + if (!ssl->options.closeNotify) { + ret = WOLFSSL_SHUTDOWN_NOT_DONE; + WOLFSSL_LEAVE("wolfSSL_shutdown", ret); + return ret; + } + else { + ssl->options.shutdownDone = 1; + ret = WOLFSSL_SUCCESS; + } + } + } + + /* try to send close notify, not an error if can't */ + if (!ssl->options.isClosed && !ssl->options.connReset && + !ssl->options.sentNotify) { + ssl->error = SendAlert(ssl, alert_warning, close_notify); + + /* the alert is now sent or sitting in the buffer, + * where will be sent eventually */ + if (ssl->error == 0 || ssl->error == WC_NO_ERR_TRACE(WANT_WRITE)) + ssl->options.sentNotify = 1; + + if (ssl->error < 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + + if (ssl->options.closeNotify) { + ret = WOLFSSL_SUCCESS; + ssl->options.shutdownDone = 1; + } + else { + ret = WOLFSSL_SHUTDOWN_NOT_DONE; + WOLFSSL_LEAVE("wolfSSL_shutdown", ret); + return ret; + } + } + +#ifdef WOLFSSL_SHUTDOWNONCE + if (ssl->options.isClosed || ssl->options.connReset) { + /* Shutdown has already occurred. + * Caller is free to ignore this error. */ + return SSL_SHUTDOWN_ALREADY_DONE_E; + } +#endif + + /* wolfSSL_shutdown called again for bidirectional shutdown */ + if (ssl->options.sentNotify && !ssl->options.closeNotify) { + /* If there is still buffered application data waiting to be read, + * do not process incoming records here. clearOutputBuffer.buffer + * points into inputBuffer, and ProcessReply() may call + * GrowInputBuffer(), which frees and reallocates inputBuffer. + * Require the pending data to be drained first. */ + if (ssl->buffers.clearOutputBuffer.length > 0) { + WOLFSSL_MSG("Pending application data, read it before shutdown"); + ret = WOLFSSL_SHUTDOWN_NOT_DONE; + WOLFSSL_LEAVE("wolfSSL_shutdown", ret); + return ret; + } + ret = ProcessReply(ssl); + if ((ret == WC_NO_ERR_TRACE(ZERO_RETURN)) || + (ret == WC_NO_ERR_TRACE(SOCKET_ERROR_E))) { + /* simulate OpenSSL behavior */ + ssl->options.shutdownDone = 1; + /* Clear error */ + ssl->error = WOLFSSL_ERROR_NONE; + ret = WOLFSSL_SUCCESS; + } + else if (ret == WC_NO_ERR_TRACE(MEMORY_E)) { + ret = WOLFSSL_FATAL_ERROR; + } + else if (ret == WC_NO_ERR_TRACE(WANT_READ)) { + ssl->error = ret; + ret = WOLFSSL_FATAL_ERROR; + } + else if (ssl->error == WOLFSSL_ERROR_NONE) { + ret = WOLFSSL_SHUTDOWN_NOT_DONE; + } + else { + WOLFSSL_ERROR(ssl->error); + ret = WOLFSSL_FATAL_ERROR; + } + } + } + +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) + /* reset WOLFSSL structure state for possible reuse */ + if (ret == WOLFSSL_SUCCESS) { + if (wolfSSL_clear(ssl) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("could not clear WOLFSSL"); + ret = WOLFSSL_FATAL_ERROR; + } + } +#endif + + WOLFSSL_LEAVE("wolfSSL_shutdown", ret); + + return ret; +} +#endif /* !NO_TLS */ + +/* + * TODO This ssl parameter needs to be changed to const once our ABI checker + * stops flagging qualifier additions as ABI breaking. + */ +WOLFSSL_ABI +int wolfSSL_pending(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_pending"); + if (ssl == NULL) + return WOLFSSL_FAILURE; + + return (int)ssl->buffers.clearOutputBuffer.length; +} + +/* Determine whether there is application data available to read. + * + * @param [in] ssl SSL/TLS object. + * @return 1 when there is data buffered. + * @return 0 when there is no data buffered. + * @return WOLFSSL_FAILURE when ssl is NULL. + */ +int wolfSSL_has_pending(const WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_has_pending"); + if (ssl == NULL) + return WOLFSSL_FAILURE; + + return ssl->buffers.clearOutputBuffer.length > 0; +} + +#ifndef USE_WINDOWS_API + #if !defined(NO_WRITEV) && !defined(NO_TLS) + + /* simulate writev semantics, doesn't actually do block at a time though + because of SSL_write behavior and because front adds may be small */ + int wolfSSL_writev(WOLFSSL* ssl, const struct iovec* iov, int iovcnt) + { + #ifdef WOLFSSL_SMALL_STACK + byte staticBuffer[1]; /* force heap usage */ + #else + byte staticBuffer[FILE_BUFFER_SIZE]; + #endif + byte* myBuffer = staticBuffer; + int dynamic = 0; + size_t sending = 0; + size_t idx = 0; + int i; + int ret; + + WOLFSSL_ENTER("wolfSSL_writev"); + + for (i = 0; i < iovcnt; i++) + if (! WC_SAFE_SUM_UNSIGNED(size_t, sending, iov[i].iov_len, + sending)) + return BUFFER_E; + + if (sending > sizeof(staticBuffer)) { + myBuffer = (byte*)XMALLOC(sending, ssl->heap, + DYNAMIC_TYPE_WRITEV); + if (!myBuffer) + return MEMORY_ERROR; + + dynamic = 1; + } + + for (i = 0; i < iovcnt; i++) { + XMEMCPY(&myBuffer[idx], iov[i].iov_base, iov[i].iov_len); + idx += (int)iov[i].iov_len; + } + + /* myBuffer may not be initialized fully, but the span up to the + * sending length will be. + */ + PRAGMA_GCC_DIAG_PUSH + PRAGMA_GCC("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") + ret = wolfSSL_write_internal(ssl, myBuffer, sending); + PRAGMA_GCC_DIAG_POP + + if (dynamic) + XFREE(myBuffer, ssl->heap, DYNAMIC_TYPE_WRITEV); + + return ret; + } + #endif +#endif + + +#ifdef OPENSSL_EXTRA +/* returns SSL_WRITING, SSL_READING or SSL_NOTHING */ +int wolfSSL_want(WOLFSSL* ssl) +{ + int rw_state = WOLFSSL_NOTHING; + if (ssl) { + if (ssl->error == WC_NO_ERR_TRACE(WANT_READ)) + rw_state = WOLFSSL_READING; + else if (ssl->error == WC_NO_ERR_TRACE(WANT_WRITE)) + rw_state = WOLFSSL_WRITING; + } + return rw_state; +} +#endif + +/* return TRUE if current error is want read */ +int wolfSSL_want_read(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_want_read"); + if (ssl->error == WC_NO_ERR_TRACE(WANT_READ)) + return 1; + + return 0; +} + +/* return TRUE if current error is want write */ +int wolfSSL_want_write(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_want_write"); + if (ssl->error == WC_NO_ERR_TRACE(WANT_WRITE)) + return 1; + + return 0; +} + + +/* Get the shutdown state of the connection. + * + * @param [in] ssl SSL/TLS object. + * @return Bit set of WOLFSSL_SENT_SHUTDOWN and WOLFSSL_RECEIVED_SHUTDOWN. + * @return 0 when ssl is NULL or no close_notify has been sent or received. + */ +int wolfSSL_get_shutdown(const WOLFSSL* ssl) +{ + int isShutdown = 0; + + WOLFSSL_ENTER("wolfSSL_get_shutdown"); + + if (ssl) { +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) + if (ssl->options.shutdownDone) { + /* The SSL object was possibly cleared with wolfSSL_clear after + * a successful shutdown. Simulate a response for a full + * bidirectional shutdown. */ + isShutdown = WOLFSSL_SENT_SHUTDOWN | WOLFSSL_RECEIVED_SHUTDOWN; + } + else +#endif + { + /* in OpenSSL, WOLFSSL_SENT_SHUTDOWN = 1, when closeNotifySent * + * WOLFSSL_RECEIVED_SHUTDOWN = 2, from close notify or fatal err */ + if (ssl->options.sentNotify) + isShutdown |= WOLFSSL_SENT_SHUTDOWN; + if (ssl->options.closeNotify||ssl->options.connReset) + isShutdown |= WOLFSSL_RECEIVED_SHUTDOWN; + } + + } + + WOLFSSL_LEAVE("wolfSSL_get_shutdown", isShutdown); + return isShutdown; +} + +#endif /* !WOLFCRYPT_ONLY */ + +#endif /* !WOLFSSL_SSL_API_RW_INCLUDED */ diff --git a/src/ssl_asn1.c b/src/ssl_asn1.c index 68f3d1f0e5..ec71c443ae 100644 --- a/src/ssl_asn1.c +++ b/src/ssl_asn1.c @@ -36,6 +36,8 @@ * ASN1_item APIs ******************************************************************************/ +#ifndef OPENSSL_EXTRA_NO_ASN1 + #ifndef NO_ASN #ifdef OPENSSL_EXTRA @@ -4967,4 +4969,1437 @@ int wolfSSL_ASN1_TYPE_get(const WOLFSSL_ASN1_TYPE *a) #endif /* !NO_ASN */ +#endif /* !OPENSSL_EXTRA_NO_ASN1 */ + +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) +/* Table of OID information: NID, OID sum, OID group and names. + * + * Entries of an OID group are contiguous. Lookups search the entries of one + * group linearly, so the order of entries within a group has been changed to + * put the most commonly used first and the legacy and rarely used last. The + * order is not otherwise significant. Keep new entries with their group. + */ +const WOLFSSL_ObjectInfo wolfssl_object_info[] = { +#ifndef NO_CERTS + /* oidCertExtType */ + { WC_NID_basic_constraints, BASIC_CA_OID, oidCertExtType, + "basicConstraints", "X509v3 Basic Constraints"}, + { WC_NID_subject_alt_name, ALT_NAMES_OID, oidCertExtType, "subjectAltName", + "X509v3 Subject Alternative Name"}, + { WC_NID_crl_distribution_points, CRL_DIST_OID, oidCertExtType, + "crlDistributionPoints", "X509v3 CRL Distribution Points"}, + { WC_NID_info_access, AUTH_INFO_OID, oidCertExtType, "authorityInfoAccess", + "Authority Information Access"}, + { WC_NID_authority_key_identifier, AUTH_KEY_OID, oidCertExtType, + "authorityKeyIdentifier", "X509v3 Authority Key Identifier"}, + { WC_NID_subject_key_identifier, SUBJ_KEY_OID, oidCertExtType, + "subjectKeyIdentifier", "X509v3 Subject Key Identifier"}, + { WC_NID_key_usage, KEY_USAGE_OID, oidCertExtType, "keyUsage", + "X509v3 Key Usage"}, + { WC_NID_inhibit_any_policy, INHIBIT_ANY_OID, oidCertExtType, + "inhibitAnyPolicy", "X509v3 Inhibit Any Policy"}, + { WC_NID_ext_key_usage, EXT_KEY_USAGE_OID, oidCertExtType, + "extendedKeyUsage", "X509v3 Extended Key Usage"}, + { WC_NID_name_constraints, NAME_CONS_OID, oidCertExtType, + "nameConstraints", "X509v3 Name Constraints"}, + { WC_NID_certificate_policies, CERT_POLICY_OID, oidCertExtType, + "certificatePolicies", "X509v3 Certificate Policies"}, +#if defined(WOLFSSL_APACHE_HTTPD) && defined(OPENSSL_EXTRA) + /* "1.3.6.1.4.1.311.20.2.3" */ + { WC_NID_ms_upn, WOLFSSL_MS_UPN_SUM, oidCertExtType, WOLFSSL_SN_MS_UPN, + WOLFSSL_LN_MS_UPN }, +#endif + + /* oidCertAuthInfoType */ + { WC_NID_ad_OCSP, AIA_OCSP_OID, oidCertAuthInfoType, "OCSP", + "OCSP"}, + { WC_NID_ad_ca_issuers, AIA_CA_ISSUER_OID, oidCertAuthInfoType, + "caIssuers", "CA Issuers"}, + + /* oidCertPolicyType */ + { WC_NID_any_policy, CP_ANY_OID, oidCertPolicyType, "anyPolicy", + "X509v3 Any Policy"}, + + /* oidCertAltNameType */ + { WC_NID_hw_name_oid, HW_NAME_OID, oidCertAltNameType, "Hardware name",""}, + + /* oidCertKeyUseType */ + { WC_NID_anyExtendedKeyUsage, EKU_ANY_OID, oidCertKeyUseType, + "anyExtendedKeyUsage", "Any Extended Key Usage"}, + { EKU_SERVER_AUTH_OID, EKU_SERVER_AUTH_OID, oidCertKeyUseType, + "serverAuth", "TLS Web Server Authentication"}, + { EKU_CLIENT_AUTH_OID, EKU_CLIENT_AUTH_OID, oidCertKeyUseType, + "clientAuth", "TLS Web Client Authentication"}, + { EKU_OCSP_SIGN_OID, EKU_OCSP_SIGN_OID, oidCertKeyUseType, + "OCSPSigning", "OCSP Signing"}, + + /* oidCertNameType */ + /* Ordered most commonly used first: entries of a group are searched + * linearly. Distinguished name attributes are first, then the extended + * validation ones, then the rarely used and legacy. */ + { WC_NID_commonName, WC_NAME_COMMON_NAME_OID, oidCertNameType, + "CN", "commonName"}, + { WC_NID_organizationName, WC_NAME_ORGANIZATION_NAME_OID, oidCertNameType, + "O", "organizationName"}, + { WC_NID_organizationalUnitName, WC_NAME_ORGANIZATION_UNIT_NAME_OID, + oidCertNameType, "OU", "organizationalUnitName"}, + { WC_NID_countryName, WC_NAME_COUNTRY_NAME_OID, oidCertNameType, + "C", "countryName"}, + { WC_NID_stateOrProvinceName, WC_NAME_STATE_NAME_OID, oidCertNameType, + "ST", "stateOrProvinceName"}, + { WC_NID_localityName, WC_NAME_LOCALITY_NAME_OID, oidCertNameType, + "L", "localityName"}, + { WC_NID_emailAddress, WC_NAME_EMAIL_ADDRESS_OID, oidCertNameType, + "emailAddress", "emailAddress"}, + { WC_NID_serialNumber, WC_NAME_SERIAL_NUMBER_OID, oidCertNameType, + "serialNumber", "serialNumber"}, + { WC_NID_domainComponent, WC_NAME_DOMAIN_COMPONENT_OID, oidCertNameType, + "DC", "domainComponent"}, + + /* Extended validation attributes. */ + { WC_NID_streetAddress, WC_NAME_STREET_ADDRESS_OID, oidCertNameType, + "street", "streetAddress"}, + { WC_NID_postalCode, WC_NAME_POSTAL_CODE_OID, oidCertNameType, "postalCode", + "postalCode"}, + { WC_NID_businessCategory, WC_NAME_BUSINESS_CATEGORY_OID, oidCertNameType, + "businessCategory", "businessCategory"}, + { WC_NID_jurisdictionCountryName, WC_NAME_JURIS_COUNTRY_OID, + oidCertNameType, "jurisdictionC", "jurisdictionCountryName"}, + { WC_NID_jurisdictionStateOrProvinceName, WC_NAME_JURIS_STATE_PROV_OID, + oidCertNameType, "jurisdictionST", "jurisdictionStateOrProvinceName"}, + + /* Rarely used and legacy attributes. */ + { WC_NID_userId, WC_NAME_USER_ID_OID, oidCertNameType, "UID", "userId"}, + { WC_NID_title, WC_NAME_TITLE_OID, oidCertNameType, "title", "title"}, + { WC_NID_description, WC_NAME_DESCRIPTION_OID, oidCertNameType, + "description", "description"}, + { WC_NID_rfc822Mailbox, WC_NAME_RFC822_MAILBOX_OID, oidCertNameType, + "rfc822Mailbox", "rfc822Mailbox"}, + { WC_NID_favouriteDrink, WC_NAME_FAVOURITE_DRINK_OID, oidCertNameType, + "favouriteDrink", "favouriteDrink"}, +#if !defined(WOLFSSL_CERT_REQ) + { WC_NID_surname, WC_NAME_SURNAME_OID, oidCertNameType, "SN", "surname"}, +#endif + { WC_NID_netscape_cert_type, NETSCAPE_CT_OID, oidCertNameType, + "nsCertType", "Netscape Cert Type"}, +#if defined(WOLFSSL_APACHE_HTTPD) && defined(OPENSSL_EXTRA) + /* "1.3.6.1.5.5.7.8.7" */ + { WC_NID_id_on_dnsSRV, WOLFSSL_DNS_SRV_SUM, oidCertNameType, + WOLFSSL_SN_DNS_SRV, WOLFSSL_LN_DNS_SRV }, +#endif + +#if defined(WOLFSSL_CERT_REQ) || defined(WOLFSSL_CERT_NAME_ALL) + { WC_NID_pkcs9_challengePassword, CHALLENGE_PASSWORD_OID, + oidCsrAttrType, "challengePassword", "challengePassword"}, + { WC_NID_pkcs9_contentType, PKCS9_CONTENT_TYPE_OID, + oidCsrAttrType, "contentType", "contentType" }, + { WC_NID_pkcs9_unstructuredName, UNSTRUCTURED_NAME_OID, + oidCsrAttrType, "unstructuredName", "unstructuredName" }, + { WC_NID_name, WC_NAME_NAME_OID, oidCsrAttrType, "name", "name" }, + { WC_NID_surname, SURNAME_OID, + oidCsrAttrType, "surname", "surname" }, + { WC_NID_givenName, WC_NAME_GIVEN_NAME_OID, + oidCsrAttrType, "givenName", "givenName" }, + { WC_NID_initials, WC_NAME_INITIALIS_OID, + oidCsrAttrType, "initials", "initials" }, + { WC_NID_dnQualifier, DNQUALIFIER_OID, + oidCsrAttrType, "dnQualifier", "dnQualifier" }, + { WC_NID_serialNumber, SERIAL_NUMBER_OID, + oidCsrAttrType, "serialNumber", "serialNumber" }, + { WC_NID_userId, USER_ID_OID, oidCsrAttrType, "UID", "userId" }, +#endif +#endif +#ifdef OPENSSL_EXTRA /* OPENSSL_EXTRA_X509_SMALL only needs the above */ + /* oidHashType */ + /* Ordered most commonly used first: entries of a group are searched + * linearly. SHA-2 first, then SHA-3, then the rarely used. Legacy + * digests are last. */ + #ifdef WOLFSSL_SM3 + { WC_NID_sm3, SM3h, oidHashType, "SM3", "sm3"}, + #endif + #ifndef NO_SHA256 + { WC_NID_sha256, SHA256h, oidHashType, "SHA256", "sha256"}, + #endif + #ifdef WOLFSSL_SHA384 + { WC_NID_sha384, SHA384h, oidHashType, "SHA384", "sha384"}, + #endif + #ifdef WOLFSSL_SHA512 + { WC_NID_sha512, SHA512h, oidHashType, "SHA512", "sha512"}, + #endif + #ifdef WOLFSSL_SHA224 + { WC_NID_sha224, SHA224h, oidHashType, "SHA224", "sha224"}, + #endif + #ifdef WOLFSSL_SHA3 + #ifndef WOLFSSL_NOSHA3_256 + { WC_NID_sha3_256, SHA3_256h, oidHashType, "SHA3-256", "sha3-256"}, + #endif + #ifndef WOLFSSL_NOSHA3_384 + { WC_NID_sha3_384, SHA3_384h, oidHashType, "SHA3-384", "sha3-384"}, + #endif + #ifndef WOLFSSL_NOSHA3_512 + { WC_NID_sha3_512, SHA3_512h, oidHashType, "SHA3-512", "sha3-512"}, + #endif + #ifndef WOLFSSL_NOSHA3_224 + { WC_NID_sha3_224, SHA3_224h, oidHashType, "SHA3-224", "sha3-224"}, + #endif + #endif /* WOLFSSL_SHA3 */ + #ifdef WOLFSSL_SHAKE128 + { WC_NID_shake128, SHAKE128h, oidHashType, "SHAKE128", "shake128"}, + #endif + #ifdef WOLFSSL_SHAKE256 + { WC_NID_shake256, SHAKE256h, oidHashType, "SHAKE256", "shake256"}, + #endif + + /* Legacy digests. */ + #ifndef NO_SHA + { WC_NID_sha1, SHAh, oidHashType, "SHA1", "sha1"}, + #endif + #ifndef NO_MD5 + { WC_NID_md5, MD5h, oidHashType, "MD5", "md5"}, + #endif + #ifndef NO_MD4 + { WC_NID_md4, MD4h, oidHashType, "MD4", "md4"}, + #endif + #ifdef WOLFSSL_MD2 + { WC_NID_md2, MD2h, oidHashType, "MD2", "md2"}, + #endif + /* oidSigType */ + /* Ordered most commonly used first: entries of a group are searched + * linearly. Legacy signature algorithms are last. */ + #ifdef HAVE_ED25519 + { WC_NID_ED25519, CTC_ED25519, oidSigType, "ED25519", "ED25519"}, + #endif + #ifdef HAVE_ED448 + { WC_NID_ED448, CTC_ED448, oidSigType, "ED448", "ED448"}, + #endif + #ifndef NO_RSA + #ifndef NO_SHA256 + { WC_NID_sha256WithRSAEncryption, CTC_SHA256wRSA, oidSigType, + "RSA-SHA256", "sha256WithRSAEncryption"}, + #endif + #ifdef WOLFSSL_SHA384 + { WC_NID_sha384WithRSAEncryption, CTC_SHA384wRSA, oidSigType, + "RSA-SHA384", "sha384WithRSAEncryption"}, + #endif + #ifdef WOLFSSL_SHA512 + { WC_NID_sha512WithRSAEncryption, CTC_SHA512wRSA, oidSigType, + "RSA-SHA512", "sha512WithRSAEncryption"}, + #endif + #ifdef WC_RSA_PSS + { WC_NID_rsassaPss, CTC_RSASSAPSS, oidSigType, + "RSASSA-PSS", "rsassaPss" }, + #endif + #ifdef WOLFSSL_SHA224 + { WC_NID_sha224WithRSAEncryption, CTC_SHA224wRSA, oidSigType, + "RSA-SHA224", "sha224WithRSAEncryption"}, + #endif + #ifdef WOLFSSL_SHA3 + #ifndef WOLFSSL_NOSHA3_256 + { WC_NID_RSA_SHA3_256, CTC_SHA3_256wRSA, oidSigType, "RSA-SHA3-256", + "sha3-256WithRSAEncryption"}, + #endif + #ifndef WOLFSSL_NOSHA3_384 + { WC_NID_RSA_SHA3_384, CTC_SHA3_384wRSA, oidSigType, "RSA-SHA3-384", + "sha3-384WithRSAEncryption"}, + #endif + #ifndef WOLFSSL_NOSHA3_512 + { WC_NID_RSA_SHA3_512, CTC_SHA3_512wRSA, oidSigType, "RSA-SHA3-512", + "sha3-512WithRSAEncryption"}, + #endif + #ifndef WOLFSSL_NOSHA3_224 + { WC_NID_RSA_SHA3_224, CTC_SHA3_224wRSA, oidSigType, "RSA-SHA3-224", + "sha3-224WithRSAEncryption"}, + #endif + #endif + #endif /* NO_RSA */ + #ifdef HAVE_ECC + #ifndef NO_SHA256 + { WC_NID_ecdsa_with_SHA256, CTC_SHA256wECDSA, oidSigType, + "ecdsa-with-SHA256","sha256WithECDSA"}, + #endif + #ifdef WOLFSSL_SHA384 + { WC_NID_ecdsa_with_SHA384, CTC_SHA384wECDSA, oidSigType, + "ecdsa-with-SHA384","sha384WithECDSA"}, + #endif + #ifdef WOLFSSL_SHA512 + { WC_NID_ecdsa_with_SHA512, CTC_SHA512wECDSA, oidSigType, + "ecdsa-with-SHA512","sha512WithECDSA"}, + #endif + #ifdef WOLFSSL_SHA224 + { WC_NID_ecdsa_with_SHA224, CTC_SHA224wECDSA, oidSigType, + "ecdsa-with-SHA224","sha224WithECDSA"}, + #endif + #ifdef WOLFSSL_SHA3 + #ifndef WOLFSSL_NOSHA3_256 + { WC_NID_ecdsa_with_SHA3_256, CTC_SHA3_256wECDSA, oidSigType, + "id-ecdsa-with-SHA3-256", "ecdsa_with_SHA3-256"}, + #endif + #ifndef WOLFSSL_NOSHA3_384 + { WC_NID_ecdsa_with_SHA3_384, CTC_SHA3_384wECDSA, oidSigType, + "id-ecdsa-with-SHA3-384", "ecdsa_with_SHA3-384"}, + #endif + #ifndef WOLFSSL_NOSHA3_512 + { WC_NID_ecdsa_with_SHA3_512, CTC_SHA3_512wECDSA, oidSigType, + "id-ecdsa-with-SHA3-512", "ecdsa_with_SHA3-512"}, + #endif + #ifndef WOLFSSL_NOSHA3_224 + { WC_NID_ecdsa_with_SHA3_224, CTC_SHA3_224wECDSA, oidSigType, + "id-ecdsa-with-SHA3-224", "ecdsa_with_SHA3-224"}, + #endif + #endif + #endif /* HAVE_ECC */ + /* Legacy MD2, MD5 and SHA-1 based signatures. */ + #ifndef NO_RSA + #ifdef WOLFSSL_MD2 + { WC_NID_md2WithRSAEncryption, CTC_MD2wRSA, oidSigType, "RSA-MD2", + "md2WithRSAEncryption"}, + #endif + #ifndef NO_MD5 + { WC_NID_md5WithRSAEncryption, CTC_MD5wRSA, oidSigType, "RSA-MD5", + "md5WithRSAEncryption"}, + #endif + #ifndef NO_SHA + { WC_NID_sha1WithRSAEncryption, CTC_SHAwRSA, oidSigType, "RSA-SHA1", + "sha1WithRSAEncryption"}, + #endif + #endif /* NO_RSA */ + #ifdef HAVE_ECC + #ifndef NO_SHA + { WC_NID_ecdsa_with_SHA1, CTC_SHAwECDSA, oidSigType, "ecdsa-with-SHA1", + "shaWithECDSA"}, + #endif + #endif /* HAVE_ECC */ + /* DSA is rarely used. */ + #ifndef NO_DSA + #ifndef NO_SHA + { WC_NID_dsaWithSHA1, CTC_SHAwDSA, oidSigType, + "DSA-SHA1", "dsaWithSHA1"}, + { WC_NID_dsa_with_SHA256, CTC_SHA256wDSA, oidSigType, "dsa_with_SHA256", + "dsa_with_SHA256"}, + #endif + #endif /* NO_DSA */ + + /* oidKeyType */ + #ifndef NO_DSA + { WC_NID_dsa, DSAk, oidKeyType, "DSA", "dsaEncryption"}, + #endif /* NO_DSA */ + #ifndef NO_RSA + { WC_NID_rsaEncryption, RSAk, oidKeyType, "rsaEncryption", + "rsaEncryption"}, + #ifdef WC_RSA_PSS + { WC_NID_rsassaPss, RSAPSSk, oidKeyType, "RSASSA-PSS", "rsassaPss"}, + #endif + #endif /* NO_RSA */ + #ifdef HAVE_ECC + { WC_NID_X9_62_id_ecPublicKey, ECDSAk, oidKeyType, "id-ecPublicKey", + "id-ecPublicKey"}, + #endif /* HAVE_ECC */ + #ifndef NO_DH + { WC_NID_dhKeyAgreement, DHk, oidKeyType, "dhKeyAgreement", + "dhKeyAgreement"}, + #endif + #ifdef HAVE_ED448 + { WC_NID_ED448, ED448k, oidKeyType, "ED448", "ED448"}, + #endif + #ifdef HAVE_ED25519 + { WC_NID_ED25519, ED25519k, oidKeyType, "ED25519", "ED25519"}, + #endif + #ifdef HAVE_FALCON + { CTC_FALCON_LEVEL1, FALCON_LEVEL1k, oidKeyType, "Falcon Level 1", + "Falcon Level 1"}, + { CTC_FALCON_LEVEL5, FALCON_LEVEL5k, oidKeyType, "Falcon Level 5", + "Falcon Level 5"}, + #endif /* HAVE_FALCON */ + #ifdef WOLFSSL_HAVE_MLDSA + #ifdef WOLFSSL_MLDSA_FIPS204_DRAFT + /* Pre-standardization (NIST PQC round 3) Dilithium OID labels. + * These coexist with the FIPS 204 "ML-DSA 44/65/87" entries below + * and are intentionally kept under the Dilithium name. */ + { CTC_DILITHIUM_LEVEL2, DILITHIUM_LEVEL2k, oidKeyType, + "Dilithium Level 2", "Dilithium Level 2"}, + { CTC_DILITHIUM_LEVEL3, DILITHIUM_LEVEL3k, oidKeyType, + "Dilithium Level 3", "Dilithium Level 3"}, + { CTC_DILITHIUM_LEVEL5, DILITHIUM_LEVEL5k, oidKeyType, + "Dilithium Level 5", "Dilithium Level 5"}, + #endif /* WOLFSSL_MLDSA_FIPS204_DRAFT */ + { CTC_ML_DSA_44, ML_DSA_44k, oidKeyType, + "ML-DSA 44", "ML-DSA 44"}, + { CTC_ML_DSA_65, ML_DSA_65k, oidKeyType, + "ML-DSA 65", "ML-DSA 65"}, + { CTC_ML_DSA_87, ML_DSA_87k, oidKeyType, + "ML-DSA 87", "ML-DSA 87"}, + #endif /* WOLFSSL_HAVE_MLDSA */ + + /* oidCurveType */ + #ifdef HAVE_ECC + /* Ordered most commonly used first: entries of a group are searched + * linearly. */ + #ifdef WOLFSSL_SM2 + { WC_NID_sm2, ECC_SM2P256V1_OID, oidCurveType, "sm2", "sm2"}, + #endif + { WC_NID_X9_62_prime256v1, ECC_SECP256R1_OID, oidCurveType, + "prime256v1", "prime256v1"}, + { WC_NID_secp224r1, ECC_SECP224R1_OID, oidCurveType, "secp224r1", + "secp224r1"}, + { WC_NID_secp384r1, ECC_SECP384R1_OID, oidCurveType, "secp384r1", + "secp384r1"}, + { WC_NID_secp521r1, ECC_SECP521R1_OID, oidCurveType, "secp521r1", + "secp521r1"}, + + { WC_NID_brainpoolP160r1, ECC_BRAINPOOLP160R1_OID, oidCurveType, + "brainpoolP160r1", "brainpoolP160r1"}, + { WC_NID_brainpoolP192r1, ECC_BRAINPOOLP192R1_OID, oidCurveType, + "brainpoolP192r1", "brainpoolP192r1"}, + { WC_NID_brainpoolP224r1, ECC_BRAINPOOLP224R1_OID, oidCurveType, + "brainpoolP224r1", "brainpoolP224r1"}, + { WC_NID_brainpoolP256r1, ECC_BRAINPOOLP256R1_OID, oidCurveType, + "brainpoolP256r1", "brainpoolP256r1"}, + { WC_NID_brainpoolP320r1, ECC_BRAINPOOLP320R1_OID, oidCurveType, + "brainpoolP320r1", "brainpoolP320r1"}, + { WC_NID_brainpoolP384r1, ECC_BRAINPOOLP384R1_OID, oidCurveType, + "brainpoolP384r1", "brainpoolP384r1"}, + { WC_NID_brainpoolP512r1, ECC_BRAINPOOLP512R1_OID, oidCurveType, + "brainpoolP512r1", "brainpoolP512r1"}, + + { WC_NID_X9_62_prime192v1, ECC_SECP192R1_OID, oidCurveType, + "prime192v1", "prime192v1"}, + { WC_NID_X9_62_prime192v2, ECC_PRIME192V2_OID, oidCurveType, + "prime192v2", "prime192v2"}, + { WC_NID_X9_62_prime192v3, ECC_PRIME192V3_OID, oidCurveType, + "prime192v3", "prime192v3"}, + + { WC_NID_X9_62_prime239v1, ECC_PRIME239V1_OID, oidCurveType, + "prime239v1", "prime239v1"}, + { WC_NID_X9_62_prime239v2, ECC_PRIME239V2_OID, oidCurveType, + "prime239v2", "prime239v2"}, + { WC_NID_X9_62_prime239v3, ECC_PRIME239V3_OID, oidCurveType, + "prime239v3", "prime239v3"}, + + { WC_NID_secp112r1, ECC_SECP112R1_OID, oidCurveType, "secp112r1", + "secp112r1"}, + { WC_NID_secp112r2, ECC_SECP112R2_OID, oidCurveType, "secp112r2", + "secp112r2"}, + + { WC_NID_secp128r1, ECC_SECP128R1_OID, oidCurveType, "secp128r1", + "secp128r1"}, + { WC_NID_secp128r2, ECC_SECP128R2_OID, oidCurveType, "secp128r2", + "secp128r2"}, + + { WC_NID_secp160r1, ECC_SECP160R1_OID, oidCurveType, "secp160r1", + "secp160r1"}, + { WC_NID_secp160r2, ECC_SECP160R2_OID, oidCurveType, "secp160r2", + "secp160r2"}, + + { WC_NID_secp160k1, ECC_SECP160K1_OID, oidCurveType, "secp160k1", + "secp160k1"}, + { WC_NID_secp192k1, ECC_SECP192K1_OID, oidCurveType, "secp192k1", + "secp192k1"}, + { WC_NID_secp224k1, ECC_SECP224K1_OID, oidCurveType, "secp224k1", + "secp224k1"}, + { WC_NID_secp256k1, ECC_SECP256K1_OID, oidCurveType, "secp256k1", + "secp256k1"}, + #endif /* HAVE_ECC */ + + /* oidBlkType */ + #ifdef WOLFSSL_AES_128 + { AES128CBCb, AES128CBCb, oidBlkType, "AES-128-CBC", "aes-128-cbc"}, + #endif + #ifdef WOLFSSL_AES_192 + { AES192CBCb, AES192CBCb, oidBlkType, "AES-192-CBC", "aes-192-cbc"}, + #endif + #ifdef WOLFSSL_AES_256 + { AES256CBCb, AES256CBCb, oidBlkType, "AES-256-CBC", "aes-256-cbc"}, + #endif + #ifndef NO_DES3 + { WC_NID_des, DESb, oidBlkType, "DES-CBC", "des-cbc"}, + { WC_NID_des3, DES3b, oidBlkType, "DES-EDE3-CBC", "des-ede3-cbc"}, + #endif /* !NO_DES3 */ + #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) + { WC_NID_chacha20_poly1305, WC_NID_chacha20_poly1305, oidBlkType, + "ChaCha20-Poly1305", "chacha20-poly1305"}, + #endif + + /* oidOcspType */ + #ifdef HAVE_OCSP + { WC_NID_id_pkix_OCSP_basic, OCSP_BASIC_OID, oidOcspType, + "basicOCSPResponse", "Basic OCSP Response"}, + { OCSP_NONCE_OID, OCSP_NONCE_OID, oidOcspType, "Nonce", "OCSP Nonce"}, + #endif /* HAVE_OCSP */ + + #ifndef NO_PWDBASED + /* oidKdfType */ + { PBKDF2_OID, PBKDF2_OID, oidKdfType, "PBKDFv2", "PBKDF2"}, + + /* oidPBEType */ + { PBE_SHA1_RC4_128, PBE_SHA1_RC4_128, oidPBEType, + "PBE-SHA1-RC4-128", "pbeWithSHA1And128BitRC4"}, + { PBE_SHA1_DES, PBE_SHA1_DES, oidPBEType, "PBE-SHA1-DES", + "pbeWithSHA1AndDES-CBC"}, + { PBE_SHA1_DES3, PBE_SHA1_DES3, oidPBEType, "PBE-SHA1-3DES", + "pbeWithSHA1And3-KeyTripleDES-CBC"}, + #endif + + /* oidKeyWrapType */ + #ifdef WOLFSSL_AES_128 + { AES128_WRAP, AES128_WRAP, oidKeyWrapType, "AES-128 wrap", + "aes128-wrap"}, + #endif + #ifdef WOLFSSL_AES_192 + { AES192_WRAP, AES192_WRAP, oidKeyWrapType, "AES-192 wrap", + "aes192-wrap"}, + #endif + #ifdef WOLFSSL_AES_256 + { AES256_WRAP, AES256_WRAP, oidKeyWrapType, "AES-256 wrap", + "aes256-wrap"}, + #endif + + #ifndef NO_PKCS7 + #ifndef NO_DH + /* oidCmsKeyAgreeType */ + #ifndef NO_SHA + { dhSinglePass_stdDH_sha1kdf_scheme, dhSinglePass_stdDH_sha1kdf_scheme, + oidCmsKeyAgreeType, "dhSinglePass-stdDH-sha1kdf-scheme", + "dhSinglePass-stdDH-sha1kdf-scheme"}, + #endif + #ifdef WOLFSSL_SHA224 + { dhSinglePass_stdDH_sha224kdf_scheme, + dhSinglePass_stdDH_sha224kdf_scheme, oidCmsKeyAgreeType, + "dhSinglePass-stdDH-sha224kdf-scheme", + "dhSinglePass-stdDH-sha224kdf-scheme"}, + #endif + #ifndef NO_SHA256 + { dhSinglePass_stdDH_sha256kdf_scheme, + dhSinglePass_stdDH_sha256kdf_scheme, oidCmsKeyAgreeType, + "dhSinglePass-stdDH-sha256kdf-scheme", + "dhSinglePass-stdDH-sha256kdf-scheme"}, + #endif + #ifdef WOLFSSL_SHA384 + { dhSinglePass_stdDH_sha384kdf_scheme, + dhSinglePass_stdDH_sha384kdf_scheme, oidCmsKeyAgreeType, + "dhSinglePass-stdDH-sha384kdf-scheme", + "dhSinglePass-stdDH-sha384kdf-scheme"}, + #endif + #ifdef WOLFSSL_SHA512 + { dhSinglePass_stdDH_sha512kdf_scheme, + dhSinglePass_stdDH_sha512kdf_scheme, oidCmsKeyAgreeType, + "dhSinglePass-stdDH-sha512kdf-scheme", + "dhSinglePass-stdDH-sha512kdf-scheme"}, + #endif + #endif + #endif + #if defined(WOLFSSL_APACHE_HTTPD) + /* "1.3.6.1.5.5.7.1.24" */ + { WC_NID_tlsfeature, WOLFSSL_TLS_FEATURE_SUM, oidTlsExtType, + WOLFSSL_SN_TLS_FEATURE, WOLFSSL_LN_TLS_FEATURE }, + #endif +#endif /* OPENSSL_EXTRA */ +}; + +#define WOLFSSL_OBJECT_INFO_SZ \ + (sizeof(wolfssl_object_info) / sizeof(*wolfssl_object_info)) +const size_t wolfssl_object_info_sz = WOLFSSL_OBJECT_INFO_SZ; + +/* Index of the runs of entries in wolfssl_object_info[] that share an OID + * group. Entries of a group are contiguous, so a group is one [start, start + + * count) range. Looking up by group first bounds a search to that range + * instead of the whole table. + * + * The entries of wolfssl_object_info[] are conditionally compiled, so the + * ranges differ with build configuration and are calculated in + * wolfssl_object_info_slice_init() at wolfSSL_Init() time. + */ +typedef struct WolfsslObjectInfoSlice { + word32 type; + word16 start; + word16 count; +} WolfsslObjectInfoSlice; + +/* Maximum number of OID groups with entries in wolfssl_object_info[]. */ +#define WOLFSSL_OBJECT_INFO_SLICE_MAX 24 + +static WolfsslObjectInfoSlice wolfssl_object_info_slice[ + WOLFSSL_OBJECT_INFO_SLICE_MAX]; +/* Number of slices calculated. 0 when not calculated yet. */ +static int wolfssl_object_info_slice_cnt = 0; + +/* Calculate the index of OID group runs in wolfssl_object_info[]. + * + * Entries of a group are contiguous. Called once from wolfSSL_Init(). + * On overflow the index is discarded and lookups search all entries. + */ +void wolfssl_object_info_slice_init(void) +{ + size_t i; + int cnt = 0; + + for (i = 0; i < WOLFSSL_OBJECT_INFO_SZ; i++) { + /* Continue the run when the group is the same as the last. */ + if ((cnt > 0) && (wolfssl_object_info[i].type == + wolfssl_object_info_slice[cnt - 1].type)) { + wolfssl_object_info_slice[cnt - 1].count++; + continue; + } + /* More groups than expected - fall back to searching all entries. */ + if (cnt == WOLFSSL_OBJECT_INFO_SLICE_MAX) { + WOLFSSL_MSG("OID group index too small"); + cnt = 0; + break; + } + wolfssl_object_info_slice[cnt].type = wolfssl_object_info[i].type; + wolfssl_object_info_slice[cnt].start = (word16)i; + wolfssl_object_info_slice[cnt].count = 1; + cnt++; + } + + wolfssl_object_info_slice_cnt = cnt; +} + +/* Get the range of wolfssl_object_info[] entries in an OID group. + * + * When the index has not been calculated, all entries are in range. Callers + * must check the group of an entry as well. + * + * start and end are always set: an empty range when the group has no entries. + * + * @param [in] grp OID group to find. + * @param [out] start First index of group. + * @param [out] end One past last index of group. + * @return 1 when there is a range to search. + * @return 0 when no entries have this group. + */ +static int wolfssl_object_info_range(word32 grp, size_t* start, size_t* end) +{ + int i; + + /* Empty range so that a caller looping over it does nothing. */ + *start = 0; + *end = 0; + + for (i = 0; i < wolfssl_object_info_slice_cnt; i++) { + if (wolfssl_object_info_slice[i].type == grp) { + *start = wolfssl_object_info_slice[i].start; + *end = *start + wolfssl_object_info_slice[i].count; + return 1; + } + } + /* Index not calculated - search all entries. */ + if (wolfssl_object_info_slice_cnt == 0) { + *end = WOLFSSL_OBJECT_INFO_SZ; + return 1; + } + + return 0; +} +#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ + +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + +/* Get the OID sum for a NID in an OID group. + * + * @param [in] nid NID to find. + * @param [in] grp OID group the NID is in. + * @return OID sum on success. + * @return -1 as an unsigned value when the NID is not in the group. + */ +word32 nid2oid(int nid, int grp) +{ + size_t i; + size_t end; + + /* Find the entry with the NID in the group. Only the entries of the + * group need to be searched. Match on group as well as NID: the same NID + * may appear in more than one group. */ + if (wolfssl_object_info_range((word32)grp, &i, &end)) { + for (; i < end; i++) { + if ((wolfssl_object_info[i].nid == nid) && + (wolfssl_object_info[i].type == (word32)grp)) { + return (word32)wolfssl_object_info[i].id; + } + } + } + + WOLFSSL_MSG("NID not in table"); + /* MSVC warns without the cast */ + return (word32)-1; +} + +/* Get the NID for an OID sum. + * + * The entries of grp are searched first. When not found there, every entry is + * searched as callers may not know the group. + * + * @param [in] oid OID sum to find. + * @param [in] grp OID group the OID is expected to be in. + * @return NID on success. + * @return WOLFSSL_FATAL_ERROR when the OID is not in the table. + */ +int oid2nid(word32 oid, int grp) +{ + size_t i; + size_t end; + + /* Find the entry with the OID in the group. Only the entries of the + * group need to be searched. */ + if (wolfssl_object_info_range((word32)grp, &i, &end)) { + for (; i < end; i++) { + if ((wolfssl_object_info[i].id == (int)oid) && + (wolfssl_object_info[i].type == (word32)grp)) { + return wolfssl_object_info[i].nid; + } + } + } + + /* Not in the group - search every entry. + * + * Callers may not know the group. wolfSSL_OBJ_txt2obj() creates an object + * from a numerical OID string with no group set, and + * wolfSSL_OBJ_obj2nid() then looks it up with grp of 0. */ + for (i = 0; i < WOLFSSL_OBJECT_INFO_SZ; i++) { + if (wolfssl_object_info[i].id == (int)oid) { + return wolfssl_object_info[i].nid; + } + } + + WOLFSSL_MSG("OID not in table"); + return WOLFSSL_FATAL_ERROR; +} + +#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ + + +#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \ + !defined(WOLFCRYPT_ONLY) + +/* Convert shortname to NID. + * + * For OpenSSL compatibility. + * + * @param [in] sn Short name of OID. + * @return NID corresponding to shortname on success. + * @return WC_NID_undef when not recognized. + */ +int wc_OBJ_sn2nid(const char *sn) +{ + const WOLFSSL_ObjectInfo *obj_info = wolfssl_object_info; + size_t i; + WOLFSSL_ENTER("wc_OBJ_sn2nid"); + for (i = 0; i < wolfssl_object_info_sz; i++, obj_info++) { + if (XSTRCMP(sn, obj_info->sName) == 0) + return obj_info->nid; + } + WOLFSSL_MSG("short name not found in table"); + return WC_NID_undef; +} + + /* NID variables are dependent on compatibility header files currently + * + * returns a pointer to a new WOLFSSL_ASN1_OBJECT struct on success and NULL + * on fail + */ + + WOLFSSL_ASN1_OBJECT* wolfSSL_OBJ_nid2obj(int id) + { + return wolfSSL_OBJ_nid2obj_ex(id, NULL); + } + + + /* Create or fill an ASN.1 OBJECT_ID object from a NID. + * + * The OID group is not known and so is looked up in the table with the + * NID. The DER encoding of the OID is created on the object. + * + * @param [in] id NID of object. + * @param [in, out] arg_obj Object to fill. NULL to allocate a new object. + * @return ASN.1 OBJECT_ID object on success. + * @return NULL when the NID is not in the table, the short name is too + * long or dynamic memory allocation fails. + */ + WOLFSSL_LOCAL WOLFSSL_ASN1_OBJECT* wolfSSL_OBJ_nid2obj_ex(int id, + WOLFSSL_ASN1_OBJECT* arg_obj) + { + word32 oidSz = 0; + int nid = 0; + const byte* oid; + word32 type = 0; + WOLFSSL_ASN1_OBJECT* obj = arg_obj; + byte objBuf[MAX_OID_SZ + MAX_LENGTH_SZ + 1]; /* +1 for object tag */ + word32 objSz = 0; + const char* sName = NULL; + int i; + +#ifdef WOLFSSL_DEBUG_OPENSSL + WOLFSSL_ENTER("wolfSSL_OBJ_nid2obj"); +#endif + + for (i = 0; i < (int)wolfssl_object_info_sz; i++) { + if (wolfssl_object_info[i].nid == id) { + nid = id; + id = wolfssl_object_info[i].id; + sName = wolfssl_object_info[i].sName; + type = wolfssl_object_info[i].type; + break; + } + } + if (i == (int)wolfssl_object_info_sz) { + WOLFSSL_MSG("NID not in table"); + #ifdef WOLFSSL_QT + sName = NULL; + type = (word32)id; + #else + return NULL; + #endif + } + + #ifdef HAVE_ECC + if (type == 0 && wc_ecc_get_oid((word32)id, &oid, &oidSz) > 0) { + type = oidCurveType; + } + #endif /* HAVE_ECC */ + + if (sName != NULL) { + if (XSTRLEN(sName) > WOLFSSL_MAX_SNAME - 1) { + WOLFSSL_MSG("Attempted short name is too large"); + return NULL; + } + } + + oid = OidFromId((word32)id, type, &oidSz); + + /* set object ID to buffer */ + if (obj == NULL){ + obj = wolfSSL_ASN1_OBJECT_new(); + if (obj == NULL) { + WOLFSSL_MSG("Issue creating WOLFSSL_ASN1_OBJECT struct"); + return NULL; + } + } + obj->nid = nid; + obj->type = id; + obj->grp = (int)type; + + obj->sName[0] = '\0'; + if (sName != NULL) { + XMEMCPY(obj->sName, (char*)sName, XSTRLEN((char*)sName)); + } + + objBuf[0] = ASN_OBJECT_ID; objSz++; + objSz += SetLength(oidSz, objBuf + 1); + if (oidSz) { + XMEMCPY(objBuf + objSz, oid, oidSz); + objSz += oidSz; + } + + if (obj->objSz == 0 || objSz != obj->objSz) { + obj->objSz = objSz; + if(((obj->dynamic & WOLFSSL_ASN1_DYNAMIC_DATA) != 0) || + (obj->obj == NULL)) { + if (obj->obj != NULL) + XFREE((byte*)obj->obj, NULL, DYNAMIC_TYPE_ASN1); + obj->obj = (byte*)XMALLOC(obj->objSz, NULL, DYNAMIC_TYPE_ASN1); + if (obj->obj == NULL) { + wolfSSL_ASN1_OBJECT_free(obj); + return NULL; + } + obj->dynamic |= WOLFSSL_ASN1_DYNAMIC_DATA; + } + else { + obj->dynamic &= (unsigned char)~WOLFSSL_ASN1_DYNAMIC_DATA; + } + } + XMEMCPY((byte*)obj->obj, objBuf, obj->objSz); + + (void)type; + + return obj; + } + + /* Get the description of a numerical OID string. + * + * Only OIDs that have no long name in the table are translated. + * + * @param [in] oid Numerical OID string. eg. "2.5.29.37.0". + * @return Description of OID on success. + * @return NULL when the OID has no description. + */ + static const char* oid_translate_num_to_str(const char* oid) + { + const struct oid_dict { + const char* num; + const char* desc; + } oid_dict[] = { + { "2.5.29.37.0", "Any Extended Key Usage" }, + { "1.3.6.1.5.5.7.3.1", "TLS Web Server Authentication" }, + { "1.3.6.1.5.5.7.3.2", "TLS Web Client Authentication" }, + { "1.3.6.1.5.5.7.3.3", "Code Signing" }, + { "1.3.6.1.5.5.7.3.4", "E-mail Protection" }, + { "1.3.6.1.5.5.7.3.8", "Time Stamping" }, + { "1.3.6.1.5.5.7.3.9", "OCSP Signing" }, + { NULL, NULL } + }; + const struct oid_dict* idx; + + for (idx = oid_dict; idx->num != NULL; idx++) { + if (!XSTRCMP(oid, idx->num)) { + return idx->desc; + } + } + return NULL; + } + + /* Write the numerical form of an ASN.1 OBJECT_ID object's OID into a + * buffer. + * + * String is of the form "1.2.840.113549.1.9.1" and is always NUL + * terminated. Truncated when the buffer is too small. + * + * @param [out] buf Buffer to hold string. + * @param [in] bufLen Length of buffer in bytes. + * @param [in] a ASN.1 OBJECT_ID object. + * @return Length of string that would be written, excluding the NUL + * terminator, on success. + * @return 0 when decoding the object fails. + */ + static int wolfssl_obj2txt_numeric(char *buf, int bufLen, + const WOLFSSL_ASN1_OBJECT *a) + { + int bufSz; + int length; + word32 idx = 0; + byte tag; + + if (GetASNTag(a->obj, &idx, &tag, a->objSz) != 0) { + return WOLFSSL_FAILURE; + } + + if (tag != ASN_OBJECT_ID) { + WOLFSSL_MSG("Bad ASN1 Object"); + return WOLFSSL_FAILURE; + } + + if (GetLength((const byte*)a->obj, &idx, &length, + a->objSz) < 0 || length < 0) { + return ASN_PARSE_E; + } + + if (bufLen < MAX_OID_STRING_SZ) { + bufSz = bufLen - 1; + } + else { + bufSz = MAX_OID_STRING_SZ; + } + + if ((bufSz = DecodePolicyOID(buf, (word32)bufSz, a->obj + idx, + (word32)length)) <= 0) { + WOLFSSL_MSG("Error decoding OID"); + return WOLFSSL_FAILURE; + } + + buf[bufSz] = '\0'; + + return bufSz; + } + + /* If no_name is one then use numerical form, otherwise short name. + * + * Returns the buffer size on success, WOLFSSL_FAILURE on error + */ + int wolfSSL_OBJ_obj2txt(char *buf, int bufLen, const WOLFSSL_ASN1_OBJECT *a, + int no_name) + { + int bufSz; + const char* desc; + const char* name; + + WOLFSSL_ENTER("wolfSSL_OBJ_obj2txt"); + + if (buf == NULL || bufLen <= 1 || a == NULL) { + WOLFSSL_MSG("Bad input argument"); + return WOLFSSL_FAILURE; + } + + if (no_name == 1) { + return wolfssl_obj2txt_numeric(buf, bufLen, a); + } + + /* return long name unless using x509small, then return short name */ +#if defined(OPENSSL_EXTRA_X509_SMALL) && !defined(OPENSSL_EXTRA) + name = a->sName; +#else + name = wolfSSL_OBJ_nid2ln(wolfSSL_OBJ_obj2nid(a)); +#endif + + if (name == NULL) { + WOLFSSL_MSG("Name not found"); + bufSz = 0; + } + else if (XSTRLEN(name) + 1 < (word32)bufLen - 1) { + bufSz = (int)XSTRLEN(name); + } + else { + bufSz = bufLen - 1; + } + if (bufSz) { + XMEMCPY(buf, name, (size_t)bufSz); + } + else if (a->type == WOLFSSL_GEN_DNS || a->type == WOLFSSL_GEN_EMAIL || + a->type == WOLFSSL_GEN_URI) { + size_t objLen = XSTRLEN((const char*)a->obj); + if (objLen >= (size_t)bufLen) { + bufSz = bufLen - 1; + } + else { + bufSz = (int)objLen; + } + XMEMCPY(buf, a->obj, (size_t)bufSz); + } + else if ((bufSz = wolfssl_obj2txt_numeric(buf, bufLen, a)) > 0) { + if ((desc = oid_translate_num_to_str(buf))) { + bufSz = (int)XSTRLEN(desc); + bufSz = (int)min((word32)bufSz,(word32) bufLen - 1); + XMEMCPY(buf, desc, (size_t)bufSz); + } + } + else { + bufSz = 0; + } + + buf[bufSz] = '\0'; + + return bufSz; + } +#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ + +#if defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) || \ + defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(HAVE_STUNNEL) || \ + defined(WOLFSSL_NGINX) || defined(HAVE_POCO_LIB) || \ + defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_WPAS_SMALL) + /* Returns the long name that corresponds with an ASN1_OBJECT nid value. + * n : NID value of ASN1_OBJECT to search */ + const char* wolfSSL_OBJ_nid2ln(int n) + { + const WOLFSSL_ObjectInfo *obj_info = wolfssl_object_info; + size_t i; + WOLFSSL_ENTER("wolfSSL_OBJ_nid2ln"); + for (i = 0; i < wolfssl_object_info_sz; i++, obj_info++) { + if (obj_info->nid == n) { + return obj_info->lName; + } + } + WOLFSSL_MSG("NID not found in table"); + return NULL; + } +#endif /* OPENSSL_EXTRA, HAVE_LIGHTY, WOLFSSL_MYSQL_COMPATIBLE, HAVE_STUNNEL, + WOLFSSL_NGINX, HAVE_POCO_LIB, WOLFSSL_HAPROXY, WOLFSSL_WPAS_SMALL */ + +#if defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) || \ + defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(HAVE_STUNNEL) || \ + defined(WOLFSSL_NGINX) || defined(HAVE_POCO_LIB) || \ + defined(WOLFSSL_HAPROXY) + /* Return the corresponding short name for the nid . + * or NULL if short name can't be found. + */ + const char * wolfSSL_OBJ_nid2sn(int n) { + const WOLFSSL_ObjectInfo *obj_info = wolfssl_object_info; + size_t i; + WOLFSSL_ENTER("wolfSSL_OBJ_nid2sn"); + + if (n == WC_NID_md5) { + /* WC_NID_surname == WC_NID_md5 and WC_NID_surname comes before + * WC_NID_md5 in wolfssl_object_info. As a result, the loop below + * will incorrectly return "SN" instead of "MD5." WC_NID_surname + * isn't the true OpenSSL NID, but other functions rely on this + * table and modifying it to conform with OpenSSL's NIDs isn't + * trivial. */ + return "MD5"; + } + for (i = 0; i < wolfssl_object_info_sz; i++, obj_info++) { + if (obj_info->nid == n) { + return obj_info->sName; + } + } + WOLFSSL_MSG_EX("SN not found (nid:%d)",n); + return NULL; + } + +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + /* Get the NID for a short name. + * + * @param [in] sn Short name of object. eg. "CN". + * @return NID on success. + * @return WC_NID_undef when sn is NULL or not recognized. + */ + int wolfSSL_OBJ_sn2nid(const char *sn) { + WOLFSSL_ENTER("wolfSSL_OBJ_sn2nid"); + if (sn == NULL) + return WC_NID_undef; + return wc_OBJ_sn2nid(sn); + } +#endif + + /* Get the length of the OID in an ASN.1 OBJECT_ID object. + * + * @param [in] o ASN.1 OBJECT_ID object. + * @return Length of the OID in bytes on success. + * @return 0 when o is NULL or decoding the object fails. + */ + size_t wolfSSL_OBJ_length(const WOLFSSL_ASN1_OBJECT* o) + { + size_t ret = 0; + int err = 0; + word32 idx = 0; + int len = 0; + + WOLFSSL_ENTER("wolfSSL_OBJ_length"); + + if (o == NULL || o->obj == NULL) { + WOLFSSL_MSG("Bad argument."); + err = 1; + } + + if (err == 0 && GetASNObjectId(o->obj, &idx, &len, o->objSz)) { + WOLFSSL_MSG("Error parsing ASN.1 header."); + err = 1; + } + if (err == 0) { + ret = (size_t)len; + } + + WOLFSSL_LEAVE("wolfSSL_OBJ_length", (int)ret); + + return ret; + } + + /* Get the OID in an ASN.1 OBJECT_ID object. + * + * Returned data is owned by the object and must not be freed. + * + * @param [in] o ASN.1 OBJECT_ID object. + * @return OID of object on success. + * @return NULL when o is NULL or decoding the object fails. + */ + const unsigned char* wolfSSL_OBJ_get0_data(const WOLFSSL_ASN1_OBJECT* o) + { + const unsigned char* ret = NULL; + int err = 0; + word32 idx = 0; + int len = 0; + + WOLFSSL_ENTER("wolfSSL_OBJ_get0_data"); + + if (o == NULL || o->obj == NULL) { + WOLFSSL_MSG("Bad argument."); + err = 1; + } + + if (err == 0 && GetASNObjectId(o->obj, &idx, &len, o->objSz)) { + WOLFSSL_MSG("Error parsing ASN.1 header."); + err = 1; + } + if (err == 0) { + ret = o->obj + idx; + } + + return ret; + } + + + /* Gets the NID value that corresponds with the ASN1 object. + * + * o ASN1 object to get NID of + * + * Return NID on success and a negative value on failure + */ + int wolfSSL_OBJ_obj2nid(const WOLFSSL_ASN1_OBJECT *o) + { + word32 oid = 0; + word32 idx = 0; + int ret; + +#ifdef WOLFSSL_DEBUG_OPENSSL + WOLFSSL_ENTER("wolfSSL_OBJ_obj2nid"); +#endif + + if (o == NULL) { + return WOLFSSL_FATAL_ERROR; + } + + #ifdef WOLFSSL_QT + if (o->grp == oidCertExtType) { + /* If nid is an unknown extension, return WC_NID_undef */ + if (wolfSSL_OBJ_nid2sn(o->nid) == NULL) + return WC_NID_undef; + } + #endif + + if (o->nid > 0) + return o->nid; + if ((ret = GetObjectId(o->obj, &idx, &oid, + (word32)o->grp, o->objSz)) < 0) { + if (ret == WC_NO_ERR_TRACE(ASN_OBJECT_ID_E)) { + /* Put ASN object tag in front and try again */ + int len = SetObjectId((int)o->objSz, NULL) + (int)o->objSz; + byte* buf = (byte*)XMALLOC((size_t)len, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (!buf) { + WOLFSSL_MSG("malloc error"); + return WOLFSSL_FATAL_ERROR; + } + idx = (word32)SetObjectId((int)o->objSz, buf); + XMEMCPY(buf + idx, o->obj, o->objSz); + idx = 0; + ret = GetObjectId(buf, &idx, &oid, (word32)o->grp, (word32)len); + XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (ret < 0) { + WOLFSSL_MSG("Issue getting OID of object"); + return WOLFSSL_FATAL_ERROR; + } + } + else { + WOLFSSL_MSG("Issue getting OID of object"); + return WOLFSSL_FATAL_ERROR; + } + } + + return oid2nid(oid, o->grp); + } + + /* Return the corresponding NID for the long name + * or WC_NID_undef if NID can't be found. + */ + int wolfSSL_OBJ_ln2nid(const char *ln) + { + const WOLFSSL_ObjectInfo *obj_info = wolfssl_object_info; + size_t lnlen; + WOLFSSL_ENTER("wolfSSL_OBJ_ln2nid"); + if (ln && (lnlen = XSTRLEN(ln)) > 0) { + /* Accept input like "/commonName=" */ + if (ln[0] == '/') { + ln++; + lnlen--; + } + if (lnlen) { + size_t i; + + if (ln[lnlen-1] == '=') { + lnlen--; + } + for (i = 0; i < wolfssl_object_info_sz; i++, obj_info++) { + if (lnlen == XSTRLEN(obj_info->lName) && + XSTRNCMP(ln, obj_info->lName, lnlen) == 0) { + return obj_info->nid; + } + } + } + } + return WC_NID_undef; + } + + /* compares two objects, return 0 if equal */ + int wolfSSL_OBJ_cmp(const WOLFSSL_ASN1_OBJECT* a, + const WOLFSSL_ASN1_OBJECT* b) + { + WOLFSSL_ENTER("wolfSSL_OBJ_cmp"); + + if (a && b && a->obj && b->obj) { + if (a->objSz == b->objSz) { + return XMEMCMP(a->obj, b->obj, a->objSz); + } + else if (a->type == EXT_KEY_USAGE_OID || + b->type == EXT_KEY_USAGE_OID) { + /* Special case for EXT_KEY_USAGE_OID so that + * cmp will be treated as a substring search */ + /* Used in libest to check for id-kp-cmcRA in + * EXT_KEY_USAGE extension */ + unsigned int idx; + const byte* s; /* shorter */ + unsigned int sLen; + const byte* l; /* longer */ + unsigned int lLen; + if (a->objSz > b->objSz) { + s = b->obj; sLen = b->objSz; + l = a->obj; lLen = a->objSz; + } + else { + s = a->obj; sLen = a->objSz; + l = b->obj; lLen = b->objSz; + } + for (idx = 0; idx <= lLen - sLen; idx++) { + if (XMEMCMP(l + idx, s, sLen) == 0) { + /* Found substring */ + return 0; + } + } + } + } + + return WOLFSSL_FATAL_ERROR; + } +#endif /* OPENSSL_EXTRA, HAVE_LIGHTY, WOLFSSL_MYSQL_COMPATIBLE, HAVE_STUNNEL, + WOLFSSL_NGINX, HAVE_POCO_LIB, WOLFSSL_HAPROXY */ +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) || \ + defined(HAVE_LIGHTY) || defined(WOLFSSL_MYSQL_COMPATIBLE) || \ + defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \ + defined(HAVE_POCO_LIB) || defined(WOLFSSL_HAPROXY) + /* Gets the NID value that is related to the OID string passed in. Example + * string would be "2.5.29.14" for subject key ID. + * + * returns NID value on success and WC_NID_undef on error + */ + int wolfSSL_OBJ_txt2nid(const char* s) + { + unsigned int i; + #ifdef WOLFSSL_CERT_EXT + int ret; + unsigned int sum = 0; + unsigned int outSz = MAX_OID_SZ; + unsigned char out[MAX_OID_SZ]; + + XMEMSET(out, 0, sizeof(out)); + #endif + + WOLFSSL_ENTER("wolfSSL_OBJ_txt2nid"); + + if (s == NULL) { + return WC_NID_undef; + } + + #ifdef WOLFSSL_CERT_EXT + ret = EncodePolicyOID(out, &outSz, s, NULL); + if (ret == 0) { + /* sum OID */ + sum = wc_oid_sum(out, outSz); + } + #endif /* WOLFSSL_CERT_EXT */ + + /* get the group that the OID's sum is in + * @TODO possible conflict with multiples */ + for (i = 0; i < wolfssl_object_info_sz; i++) { + int len; + #ifdef WOLFSSL_CERT_EXT + if (ret == 0) { + if (wolfssl_object_info[i].id == (int)sum) { + return wolfssl_object_info[i].nid; + } + } + #endif + + /* try as a short name */ + len = (int)XSTRLEN(s); + if ((int)XSTRLEN(wolfssl_object_info[i].sName) == len && + XSTRNCMP(wolfssl_object_info[i].sName, s, (word32)len) == 0) { + return wolfssl_object_info[i].nid; + } + + /* try as a long name */ + if ((int)XSTRLEN(wolfssl_object_info[i].lName) == len && + XSTRNCMP(wolfssl_object_info[i].lName, s, (word32)len) == 0) { + return wolfssl_object_info[i].nid; + } + } + + return WC_NID_undef; + } +#endif +#if defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) || \ + defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(HAVE_STUNNEL) || \ + defined(WOLFSSL_NGINX) || defined(HAVE_POCO_LIB) || \ + defined(WOLFSSL_HAPROXY) + + /* Create a new ASN.1 OBJECT_ID object from a name or numerical OID. + * + * @param [in] s Short name, long name or numerical OID string. + * @param [in] no_name When 0, s may be a short name, long name or + * numerical OID. When 1, s must be a numerical OID. + * @return ASN.1 OBJECT_ID object on success. + * @return NULL when s is NULL, not recognized or dynamic memory + * allocation fails. + */ +#if defined(WOLFSSL_CERT_EXT) && defined(WOLFSSL_CERT_GEN) + WOLFSSL_ASN1_OBJECT* wolfSSL_OBJ_txt2obj(const char* s, int no_name) + { + int i, ret; + int nid = WC_NID_undef; + unsigned int outSz = MAX_OID_SZ; + unsigned char out[MAX_OID_SZ]; + WOLFSSL_ASN1_OBJECT* obj; + + WOLFSSL_ENTER("wolfSSL_OBJ_txt2obj"); + + if (s == NULL) + return NULL; + + /* If s is numerical value, try to sum oid */ + ret = EncodePolicyOID(out, &outSz, s, NULL); + if (ret == 0 && outSz > 0) { + /* If numerical encode succeeded then just + * create object from that because sums are + * not unique and can cause confusion. */ + obj = wolfSSL_ASN1_OBJECT_new(); + if (obj == NULL) { + WOLFSSL_MSG("Issue creating WOLFSSL_ASN1_OBJECT struct"); + return NULL; + } + obj->dynamic |= WOLFSSL_ASN1_DYNAMIC; + obj->obj = (byte*)XMALLOC(1 + MAX_LENGTH_SZ + outSz, NULL, + DYNAMIC_TYPE_ASN1); + if (obj->obj == NULL) { + wolfSSL_ASN1_OBJECT_free(obj); + return NULL; + } + obj->dynamic |= WOLFSSL_ASN1_DYNAMIC_DATA; + i = SetObjectId((int)outSz, (byte*)obj->obj); + XMEMCPY((byte*)obj->obj + i, out, outSz); + obj->objSz = (word32)i + outSz; + return obj; + } + + /* TODO: update short names in wolfssl_object_info and check OID sums + are correct */ + for (i = 0; i < (int)wolfssl_object_info_sz; i++) { + /* Short name, long name, and numerical value are interpreted */ + if (no_name == 0 && + ((XSTRCMP(s, wolfssl_object_info[i].sName) == 0) || + (XSTRCMP(s, wolfssl_object_info[i].lName) == 0))) + { + nid = wolfssl_object_info[i].nid; + } + } + + if (nid != WC_NID_undef) + return wolfSSL_OBJ_nid2obj(nid); + + return NULL; + } +#endif + + /* compatibility function. Its intended use is to remove OID's from an + * internal table that have been added with OBJ_create. wolfSSL manages its + * own internal OID values and does not currently support OBJ_create. */ + void wolfSSL_OBJ_cleanup(void) + { + WOLFSSL_ENTER("wolfSSL_OBJ_cleanup"); + } + + #ifndef NO_WOLFSSL_STUB + /* Add an OID to the internal table. + * + * Not implemented. wolfSSL manages its own OID values. + * + * @param [in] oid Numerical OID string. Not used. + * @param [in] sn Short name of object. Not used. + * @param [in] ln Long name of object. Not used. + * @return WOLFSSL_FAILURE always. + */ + int wolfSSL_OBJ_create(const char *oid, const char *sn, const char *ln) + { + (void)oid; + (void)sn; + (void)ln; + WOLFSSL_STUB("wolfSSL_OBJ_create"); + return WOLFSSL_FAILURE; + } + #endif +#endif /* OPENSSL_ALL || HAVE_LIGHTY || WOLFSSL_MYSQL_COMPATIBLE || + HAVE_STUNNEL || WOLFSSL_NGINX || HAVE_POCO_LIB || WOLFSSL_HAPROXY */ + #endif /* !WOLFSSL_SSL_ASN1_INCLUDED */ diff --git a/src/ssl_crypto.c b/src/ssl_crypto.c index 92ae36e582..723b0351ee 100644 --- a/src/ssl_crypto.c +++ b/src/ssl_crypto.c @@ -3530,5 +3530,911 @@ void wolfSSL_RC4(WOLFSSL_RC4_KEY* key, size_t len, const unsigned char* in, * END OF RC4 API ******************************************************************************/ +#ifndef WOLFCRYPT_ONLY + +/******************************************************************************* + * START OF RAND API + ******************************************************************************/ + +#if defined(OPENSSL_EXTRA) && !defined(WOLFSSL_NO_OPENSSL_RAND_CB) +/* Initialize the mutex protecting the RAND method. + * + * Does nothing when the mutex is statically initialized. + * + * @return 0 on success. + * @return BAD_MUTEX_E when initializing the mutex fails. + */ +static int wolfSSL_RAND_InitMutex(void) +{ +#ifndef WOLFSSL_MUTEX_INITIALIZER + if (gRandMethodsInit == 0) { + if (wc_InitMutex(&gRandMethodMutex) != 0) { + WOLFSSL_MSG("Bad Init Mutex rand methods"); + return BAD_MUTEX_E; + } + gRandMethodsInit = 1; + } +#endif + return 0; +} +#endif + +#ifdef OPENSSL_EXTRA + +#if defined(HAVE_GETPID) && !defined(WOLFSSL_NO_GETPID) && \ + ((defined(HAVE_FIPS) && FIPS_VERSION3_LE(6,0,0)) || defined(HAVE_SELFTEST)) +/* In older FIPS bundles add check for reseed here since it does not exist in + * the older random.c certified files. */ +static pid_t currentRandPid = 0; +#endif + +/* Checks if the global RNG has been created. If not then one is created. + * + * Returns WOLFSSL_SUCCESS when no error is encountered. + */ +int wolfSSL_RAND_Init(void) +{ + int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); +#ifdef HAVE_GLOBAL_RNG + if (wc_LockMutex(&globalRNGMutex) == 0) { + if (initGlobalRNG == 0) { + ret = wc_InitRng(&globalRNG); + if (ret == 0) { + #if defined(HAVE_GETPID) && !defined(WOLFSSL_NO_GETPID) && \ + ((defined(HAVE_FIPS) && FIPS_VERSION3_LE(6,0,0)) || \ + defined(HAVE_SELFTEST)) + + currentRandPid = getpid(); + #endif + initGlobalRNG = 1; + ret = WOLFSSL_SUCCESS; + } + } + else { + /* GlobalRNG is already initialized */ + ret = WOLFSSL_SUCCESS; + } + + wc_UnLockMutex(&globalRNGMutex); + } +#endif + return ret; +} + + +/* WOLFSSL_SUCCESS on ok */ +int wolfSSL_RAND_seed(const void* seed, int len) +{ +#ifndef WOLFSSL_NO_OPENSSL_RAND_CB + if (wolfSSL_RAND_InitMutex() == 0 && wc_LockMutex(&gRandMethodMutex) == 0) { + if (gRandMethods && gRandMethods->seed) { + int ret = gRandMethods->seed(seed, len); + wc_UnLockMutex(&gRandMethodMutex); + return ret; + } + wc_UnLockMutex(&gRandMethodMutex); + } +#else + (void)seed; + (void)len; +#endif + + /* Make sure global shared RNG (globalRNG) is initialized */ + return wolfSSL_RAND_Init(); +} + + +/* Returns the path for reading seed data from. + * Uses the env variable $RANDFILE first if set, if not then used $HOME/.rnd + * + * Note uses stdlib by default unless XGETENV macro is overwritten + * + * fname buffer to hold path + * len length of fname buffer + * + * Returns a pointer to fname on success and NULL on failure + */ +const char* wolfSSL_RAND_file_name(char* fname, unsigned long len) +{ +#if !defined(NO_FILESYSTEM) && defined(XGETENV) && !defined(NO_GETENV) + char* rt; + + WOLFSSL_ENTER("wolfSSL_RAND_file_name"); + + if (fname == NULL) { + return NULL; + } + + XMEMSET(fname, 0, len); + +/* // NOLINTBEGIN(concurrency-mt-unsafe) */ + if ((rt = XGETENV("RANDFILE")) != NULL) { + if (len > XSTRLEN(rt)) { + XMEMCPY(fname, rt, XSTRLEN(rt)); + } + else { + WOLFSSL_MSG("RANDFILE too large for buffer"); + rt = NULL; + } + } +/* // NOLINTEND(concurrency-mt-unsafe) */ + + /* $RANDFILE was not set or is too large, check $HOME */ + if (rt == NULL) { + const char ap[] = "/.rnd"; + + WOLFSSL_MSG("Environment variable RANDFILE not set"); + +/* // NOLINTBEGIN(concurrency-mt-unsafe) */ + if ((rt = XGETENV("HOME")) == NULL) { + #ifdef XALTHOMEVARNAME + if ((rt = XGETENV(XALTHOMEVARNAME)) == NULL) { + WOLFSSL_MSG("Environment variable HOME and " XALTHOMEVARNAME + " not set"); + return NULL; + } + #else + WOLFSSL_MSG("Environment variable HOME not set"); + return NULL; + #endif + } +/* // NOLINTEND(concurrency-mt-unsafe) */ + + if (len > XSTRLEN(rt) + XSTRLEN(ap)) { + fname[0] = '\0'; + XSTRNCAT(fname, rt, len); + XSTRNCAT(fname, ap, len - XSTRLEN(rt)); + return fname; + } + else { + WOLFSSL_MSG("Path too large for buffer"); + return NULL; + } + } + + return fname; +#else + WOLFSSL_ENTER("wolfSSL_RAND_file_name"); + WOLFSSL_MSG("RAND_file_name requires filesystem and getenv support, " + "not compiled in"); + (void)fname; + (void)len; + return NULL; +#endif +} + + +#ifndef WOLFSSL_RAND_WRITE_FILE_BUF_SZ +#define WOLFSSL_RAND_WRITE_FILE_BUF_SZ 1024 +#endif +/* Writes WOLFSSL_RAND_WRITE_FILE_BUF_SZ bytes (1024 by default) from the RNG + * to the given file name. + * + * fname name of file to write to + * + * Returns the number of bytes written + */ +int wolfSSL_RAND_write_file(const char* fname) +{ + int bytes = 0; + + WOLFSSL_ENTER("wolfSSL_RAND_write_file"); + + if (fname == NULL) { + return WOLFSSL_FAILURE; + } + +#ifndef NO_FILESYSTEM + { + #ifndef WOLFSSL_SMALL_STACK + unsigned char buf[WOLFSSL_RAND_WRITE_FILE_BUF_SZ]; + #else + unsigned char* buf = (unsigned char *)XMALLOC( + WOLFSSL_RAND_WRITE_FILE_BUF_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (buf == NULL) { + WOLFSSL_MSG("malloc failed"); + return WOLFSSL_FAILURE; + } + #endif + bytes = WOLFSSL_RAND_WRITE_FILE_BUF_SZ; + + if (initGlobalRNG == 0 && wolfSSL_RAND_Init() != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("No RNG to use"); + WC_FREE_VAR_EX(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return 0; + } + + if (wc_LockMutex(&globalRNGMutex) != 0) { + WOLFSSL_MSG("Bad Lock Mutex rng"); + WC_FREE_VAR_EX(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return 0; + } + + if (wc_RNG_GenerateBlock(&globalRNG, buf, (word32)bytes) != 0) { + wc_UnLockMutex(&globalRNGMutex); + WOLFSSL_MSG("Error generating random buffer"); + bytes = 0; + } + else { + XFILE f; + + wc_UnLockMutex(&globalRNGMutex); + + #ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("wolfSSL_RAND_write_file buf", buf, bytes); + #endif + + f = XFOPEN(fname, "wb"); + if (f == XBADFILE) { + WOLFSSL_MSG("Error opening the file"); + bytes = 0; + } + else { + size_t bytes_written = XFWRITE(buf, 1, (size_t)bytes, f); + bytes = (int)bytes_written; + XFCLOSE(f); + } + } + /* wipe the whole buffer, not just (word32)bytes: error paths set + * bytes = 0 but the buffer may still hold generated random data */ + ForceZero(buf, WOLFSSL_RAND_WRITE_FILE_BUF_SZ); + #ifdef WOLFSSL_SMALL_STACK + XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + #elif defined(WOLFSSL_CHECK_MEM_ZERO) + wc_MemZero_Check(buf, sizeof(buf)); + #endif + } +#endif + + return bytes; +} + +#ifndef FREERTOS_TCP + +/* These constant values are protocol values made by egd */ +#if defined(USE_WOLFSSL_IO) && !defined(USE_WINDOWS_API) && \ + !defined(HAVE_FIPS) && defined(HAVE_HASHDRBG) && !defined(NETOS) && \ + defined(HAVE_SYS_UN_H) + #define WOLFSSL_EGD_NBLOCK 0x01 + #include +#endif + +/* This collects entropy from the path nm and seeds the global PRNG with it. + * + * nm is the file path to the egd server + * + * Returns the number of bytes read. + */ +int wolfSSL_RAND_egd(const char* nm) +{ +#ifdef WOLFSSL_EGD_NBLOCK + struct sockaddr_un rem; + int fd; + int ret = WOLFSSL_SUCCESS; + word32 bytes = 0; + word32 idx = 0; +#ifndef WOLFSSL_SMALL_STACK + unsigned char buf[256]; +#else + unsigned char* buf; + buf = (unsigned char*)XMALLOC(256, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (buf == NULL) { + WOLFSSL_MSG("Not enough memory"); + return WOLFSSL_FATAL_ERROR; + } +#endif + + XMEMSET(&rem, 0, sizeof(struct sockaddr_un)); + if (nm == NULL) { + WC_FREE_VAR_EX(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_FATAL_ERROR; + } + + fd = wc_socket_cloexec(AF_UNIX, SOCK_STREAM, 0); + if (fd < 0) { + WOLFSSL_MSG("Error creating socket"); + WC_FREE_VAR_EX(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_FATAL_ERROR; + } + rem.sun_family = AF_UNIX; + XSTRNCPY(rem.sun_path, nm, sizeof(rem.sun_path) - 1); + rem.sun_path[sizeof(rem.sun_path)-1] = '\0'; + + /* connect to egd server */ + if (connect(fd, (struct sockaddr*)&rem, sizeof(struct sockaddr_un)) == -1) { + WOLFSSL_MSG("error connecting to egd server"); + ret = WOLFSSL_FATAL_ERROR; + } + +#ifdef WOLFSSL_CHECK_MEM_ZERO + if (ret == WOLFSSL_SUCCESS) { + wc_MemZero_Add("wolfSSL_RAND_egd buf", buf, 256); + } +#endif + while (ret == WOLFSSL_SUCCESS && bytes < 255 && idx + 2 < 256) { + buf[idx] = WOLFSSL_EGD_NBLOCK; + buf[idx + 1] = 255 - bytes; /* request 255 bytes from server */ + ret = (int)write(fd, buf + idx, 2); + if (ret != 2) { + if (errno == EAGAIN) { + ret = WOLFSSL_SUCCESS; + continue; + } + WOLFSSL_MSG("error requesting entropy from egd server"); + ret = WOLFSSL_FATAL_ERROR; + break; + } + + /* attempting to read */ + buf[idx] = 0; + ret = (int)read(fd, buf + idx, 256 - bytes); + if (ret == 0) { + WOLFSSL_MSG("error reading entropy from egd server"); + ret = WOLFSSL_FATAL_ERROR; + break; + } + if (ret > 0 && buf[idx] > 0) { + bytes += buf[idx]; /* egd stores amount sent in first byte */ + if (bytes + idx > 255 || buf[idx] > ret) { + WOLFSSL_MSG("Buffer error"); + ret = WOLFSSL_FATAL_ERROR; + break; + } + XMEMMOVE(buf + idx, buf + idx + 1, buf[idx]); + idx = bytes; + ret = WOLFSSL_SUCCESS; + if (bytes >= 255) { + break; + } + } + else { + if (errno == EAGAIN || errno == EINTR) { + WOLFSSL_MSG("EGD would read"); + ret = WOLFSSL_SUCCESS; /* try again */ + } + else if (buf[idx] == 0) { + /* if egd returned 0 then there is no more entropy to be had. + Do not try more reads. */ + ret = WOLFSSL_SUCCESS; + break; + } + else { + WOLFSSL_MSG("Error with read"); + ret = WOLFSSL_FATAL_ERROR; + } + } + } + + if (bytes > 0 && ret == WOLFSSL_SUCCESS) { + /* call to check global RNG is created */ + if (wolfSSL_RAND_Init() != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Error with initializing global RNG structure"); + ret = WOLFSSL_FATAL_ERROR; + } + else if (wc_LockMutex(&globalRNGMutex) != 0) { + WOLFSSL_MSG("Bad Lock Mutex rng"); + ret = WOLFSSL_FATAL_ERROR; + } + else { + if (wc_RNG_DRBG_Reseed(&globalRNG, (const byte*) buf, bytes) + != 0) { + WOLFSSL_MSG("Error with reseeding DRBG structure"); + ret = WOLFSSL_FATAL_ERROR; + } + wc_UnLockMutex(&globalRNGMutex); + + #ifdef SHOW_SECRETS + /* print out entropy found only when no error occurred */ + if (ret == WOLFSSL_SUCCESS) { + word32 i; + printf("EGD Entropy = "); + for (i = 0; i < bytes; i++) { + printf("%02X", buf[i]); + } + printf("\n"); + } + #endif + } + } + + ForceZero(buf, bytes); +#ifdef WOLFSSL_SMALL_STACK + XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#elif defined(WOLFSSL_CHECK_MEM_ZERO) + wc_MemZero_Check(buf, 256); +#endif + close(fd); + + if (ret == WOLFSSL_SUCCESS) { + return (int)bytes; + } + else { + return ret; + } +#else + WOLFSSL_MSG("Type of socket needed is not available"); + WOLFSSL_MSG("\tor using mode where DRBG API is not available"); + (void)nm; + + return WOLFSSL_FATAL_ERROR; +#endif /* WOLFSSL_EGD_NBLOCK */ +} + +#endif /* !FREERTOS_TCP */ + +void wolfSSL_RAND_Cleanup(void) +{ +#ifndef WOLFSSL_NO_OPENSSL_RAND_CB + if (wolfSSL_RAND_InitMutex() == 0 && wc_LockMutex(&gRandMethodMutex) == 0) { + if (gRandMethods && gRandMethods->cleanup) + gRandMethods->cleanup(); + wc_UnLockMutex(&gRandMethodMutex); + } + + #ifndef WOLFSSL_MUTEX_INITIALIZER + if (wc_FreeMutex(&gRandMethodMutex) == 0) + gRandMethodsInit = 0; + #endif +#endif +#ifdef HAVE_GLOBAL_RNG + if (wc_LockMutex(&globalRNGMutex) == 0) { + if (initGlobalRNG) { + wc_FreeRng(&globalRNG); + initGlobalRNG = 0; + } + wc_UnLockMutex(&globalRNGMutex); + } +#endif +} + +/* returns WOLFSSL_SUCCESS if the bytes generated are valid otherwise + * WOLFSSL_FAILURE */ +int wolfSSL_RAND_pseudo_bytes(unsigned char* buf, int num) +{ + int ret; + int hash; + byte secret[DRBG_SEED_LEN]; /* secret length arbitrarily chosen */ + +#ifndef WOLFSSL_NO_OPENSSL_RAND_CB + if (wolfSSL_RAND_InitMutex() == 0 && wc_LockMutex(&gRandMethodMutex) == 0) { + if (gRandMethods && gRandMethods->pseudorand) { + ret = gRandMethods->pseudorand(buf, num); + wc_UnLockMutex(&gRandMethodMutex); + return ret; + } + wc_UnLockMutex(&gRandMethodMutex); + } +#endif + +#ifdef WOLFSSL_HAVE_PRF + #ifndef NO_SHA256 + hash = WC_SHA256; + #elif defined(WOLFSSL_SHA384) + hash = WC_SHA384; + #elif !defined(NO_SHA) + hash = WC_SHA; + #elif !defined(NO_MD5) + hash = WC_MD5; + #endif + + /* get secret value from source of entropy */ + ret = wolfSSL_RAND_bytes(secret, DRBG_SEED_LEN); + + /* uses input buffer to seed for pseudo random number generation, each + * thread will potentially have different results this way */ + if (ret == WOLFSSL_SUCCESS) { + PRIVATE_KEY_UNLOCK(); + ret = wc_PRF(buf, num, secret, DRBG_SEED_LEN, (const byte*)buf, num, + hash, NULL, INVALID_DEVID); + PRIVATE_KEY_LOCK(); + ret = (ret == 0) ? WOLFSSL_SUCCESS: WOLFSSL_FAILURE; + } +#else + /* fall back to just doing wolfSSL_RAND_bytes if PRF not avialbale */ + ret = wolfSSL_RAND_bytes(buf, num); + (void)hash; + (void)secret; +#endif + return ret; +} + +/* returns WOLFSSL_SUCCESS (1) if the bytes generated are valid otherwise 0 + * on failure */ +int wolfSSL_RAND_bytes(unsigned char* buf, int num) +{ + int ret = 0; + WC_RNG* rng = NULL; + WC_DECLARE_VAR(tmpRNG, WC_RNG, 1, 0); + int initTmpRng = 0; +#ifdef HAVE_GLOBAL_RNG + int used_global = 0; +#endif + + WOLFSSL_ENTER("wolfSSL_RAND_bytes"); + /* sanity check */ + if (buf == NULL || num < 0) + /* return code compliant with OpenSSL */ + return 0; + + /* if a RAND callback has been set try and use it */ +#ifndef WOLFSSL_NO_OPENSSL_RAND_CB + if (wolfSSL_RAND_InitMutex() == 0 && wc_LockMutex(&gRandMethodMutex) == 0) { + if (gRandMethods && gRandMethods->bytes) { + ret = gRandMethods->bytes(buf, num); + wc_UnLockMutex(&gRandMethodMutex); + return ret; + } + wc_UnLockMutex(&gRandMethodMutex); + } +#endif +#ifdef HAVE_GLOBAL_RNG + if (initGlobalRNG) { + if (wc_LockMutex(&globalRNGMutex) != 0) { + WOLFSSL_MSG("Bad Lock Mutex rng"); + return ret; + } + /* the above access to initGlobalRNG is racey -- recheck it now that we + * have the lock. + */ + if (initGlobalRNG) { + #if defined(HAVE_GETPID) && !defined(WOLFSSL_NO_GETPID) && \ + ((defined(HAVE_FIPS) && FIPS_VERSION3_LE(6,0,0)) || \ + defined(HAVE_SELFTEST)) + pid_t p; + + p = getpid(); + if (p != currentRandPid) { + wc_UnLockMutex(&globalRNGMutex); + if (wolfSSL_RAND_poll() != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Issue with check pid and reseed"); + ret = WOLFSSL_FAILURE; + } + + /* reclaim lock after wolfSSL_RAND_poll */ + if (wc_LockMutex(&globalRNGMutex) != 0) { + WOLFSSL_MSG("Bad Lock Mutex rng"); + return ret; + } + currentRandPid = p; + } + #endif + rng = &globalRNG; + used_global = 1; + } + else { + wc_UnLockMutex(&globalRNGMutex); + } + } + + if (used_global == 0) +#endif + { + WC_ALLOC_VAR_EX(tmpRNG, WC_RNG, 1, NULL, DYNAMIC_TYPE_RNG, + return ret); + if (wc_InitRng(tmpRNG) == 0) { + rng = tmpRNG; + initTmpRng = 1; + } + } + if (rng) { + /* handles size greater than RNG_MAX_BLOCK_LEN */ + int blockCount = num / RNG_MAX_BLOCK_LEN; + + while (blockCount--) { + ret = wc_RNG_GenerateBlock(rng, buf, RNG_MAX_BLOCK_LEN); + if (ret != 0) { + WOLFSSL_MSG("Bad wc_RNG_GenerateBlock"); + break; + } + num -= RNG_MAX_BLOCK_LEN; + buf += RNG_MAX_BLOCK_LEN; + } + + if (ret == 0 && num) + ret = wc_RNG_GenerateBlock(rng, buf, (word32)num); + + if (ret != 0) + WOLFSSL_MSG("Bad wc_RNG_GenerateBlock"); + else + ret = WOLFSSL_SUCCESS; + } + +#ifdef HAVE_GLOBAL_RNG + if (used_global == 1) + wc_UnLockMutex(&globalRNGMutex); +#endif + if (initTmpRng) + wc_FreeRng(tmpRNG); + WC_FREE_VAR_EX(tmpRNG, NULL, DYNAMIC_TYPE_RNG); + + return ret; +} + + +/* Reseed the global random number generator with entropy from the system. + * + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when the global RNG is not initialized, getting the + * seed fails, reseeding fails or there is no DRBG to reseed. + */ +int wolfSSL_RAND_poll(void) +{ + byte entropy[16]; + int ret = 0; + word32 entropy_sz = 16; + + WOLFSSL_ENTER("wolfSSL_RAND_poll"); + if (initGlobalRNG == 0){ + WOLFSSL_MSG("Global RNG no Init"); + return WOLFSSL_FAILURE; + } + + /* lock intentionally covers wc_GenerateSeed as well, since it writes + * globalRNG.seed; do not narrow this scope or the seed write races */ + if (wc_LockMutex(&globalRNGMutex) != 0) { + WOLFSSL_MSG("Bad Lock Mutex rng"); + return WOLFSSL_FAILURE; + } + + ret = wc_GenerateSeed(&globalRNG.seed, entropy, entropy_sz); + if (ret != 0) { + WOLFSSL_MSG("Bad wc_GenerateSeed"); + ret = WOLFSSL_FAILURE; + } + else { +#ifdef HAVE_HASHDRBG + ret = wc_RNG_DRBG_Reseed(&globalRNG, entropy, entropy_sz); + if (ret != 0) { + WOLFSSL_MSG("Error reseeding DRBG"); + ret = WOLFSSL_FAILURE; + } + else { + ret = WOLFSSL_SUCCESS; + } +#elif defined(HAVE_INTEL_RDRAND) + WOLFSSL_MSG("Not polling with RAND_poll, RDRAND used without " + "HAVE_HASHDRBG"); + ret = WOLFSSL_SUCCESS; +#else + WOLFSSL_MSG("RAND_poll called with HAVE_HASHDRBG not set"); + ret = WOLFSSL_FAILURE; +#endif + } + + wc_UnLockMutex(&globalRNGMutex); + + return ret; +} + + /* If a valid struct is provided with function pointers, will override + RAND_seed, bytes, cleanup, add, pseudo_bytes and status. If a NULL + pointer is passed in, it will cancel any previous function overrides. + + Returns WOLFSSL_SUCCESS on success, WOLFSSL_FAILURE on failure. */ + int wolfSSL_RAND_set_rand_method(const WOLFSSL_RAND_METHOD *methods) + { + #ifndef WOLFSSL_NO_OPENSSL_RAND_CB + if (wolfSSL_RAND_InitMutex() == 0 && + wc_LockMutex(&gRandMethodMutex) == 0) { + gRandMethods = methods; + wc_UnLockMutex(&gRandMethodMutex); + return WOLFSSL_SUCCESS; + } + #else + (void)methods; + #endif + return WOLFSSL_FAILURE; + } + + /* Returns WOLFSSL_SUCCESS if the RNG has been seeded with enough data */ + int wolfSSL_RAND_status(void) + { + int ret = WOLFSSL_SUCCESS; + int useGlobalRng = 1; + #ifndef WOLFSSL_NO_OPENSSL_RAND_CB + if (wolfSSL_RAND_InitMutex() == 0 && + wc_LockMutex(&gRandMethodMutex) == 0) { + if (gRandMethods && gRandMethods->status) { + ret = gRandMethods->status(); + useGlobalRng = 0; + } + wc_UnLockMutex(&gRandMethodMutex); + } + else { + ret = WOLFSSL_FAILURE; + useGlobalRng = 0; + } + #endif + + /* Drive the global RNG so init / DRBG state failures (mutex + * acquisition, reseed required, corrupted state) surface to the + * caller. DRBG output is deterministic between reseeds, so this + * does not directly probe the entropy source. */ + #ifdef HAVE_GLOBAL_RNG + if (useGlobalRng) { + if (wolfSSL_RAND_Init() != WOLFSSL_SUCCESS) { + ret = WOLFSSL_FAILURE; + } + else if (wc_LockMutex(&globalRNGMutex) != 0) { + ret = WOLFSSL_FAILURE; + } + else { + byte b = 0; + int genRet = wc_RNG_GenerateBlock(&globalRNG, &b, 1); + wc_UnLockMutex(&globalRNGMutex); + ForceZero(&b, 1); + if (genRet != 0) + ret = WOLFSSL_FAILURE; + } + } + #endif + (void)useGlobalRng; + return ret; + } + + /* Add seed data to the random number generator. + * + * Calls the add method of the RAND method when set. Otherwise the data is + * used to reseed the global DRBG. + * + * @param [in] add Seed data. + * @param [in] len Length of seed data in bytes. + * @param [in] entropy Estimate of entropy in the data. Not used. + */ + void wolfSSL_RAND_add(const void* add, int len, double entropy) + { + #ifndef WOLFSSL_NO_OPENSSL_RAND_CB + if (wolfSSL_RAND_InitMutex() == 0 && + wc_LockMutex(&gRandMethodMutex) == 0) { + if (gRandMethods && gRandMethods->add) { + /* callback has return code, but RAND_add does not */ + (void)gRandMethods->add(add, len, entropy); + } + wc_UnLockMutex(&gRandMethodMutex); + } + #else + /* wolfSSL seeds/adds internally, use explicit RNG if you want + to take control */ + (void)add; + (void)len; + (void)entropy; + #endif + } + + +#ifndef NO_WOLFSSL_STUB +/* Add screen contents to the random number generator. + * + * Not implemented. For OpenSSL compatibility only. + */ +void wolfSSL_RAND_screen(void) +{ + WOLFSSL_STUB("RAND_screen"); +} +#endif + +#ifndef WOLFSSL_RAND_LOAD_FILE_BUF_SZ +#define WOLFSSL_RAND_LOAD_FILE_BUF_SZ 256 +#endif +#ifndef WOLFSSL_RAND_LOAD_FILE_MAX_BYTES +#define WOLFSSL_RAND_LOAD_FILE_MAX_BYTES (1L << 20) +#endif + +/* Seed the random number generator with the contents of a file. + * + * Data read is used to reseed the global DRBG. + * + * @param [in] fname Name of file to read seed data from. + * @param [in] len Maximum number of bytes to read. -1 to read up to + * WOLFSSL_RAND_LOAD_FILE_MAX_BYTES. + * @return Number of bytes read on success. + * @return 0 when len is 0. + * @return WOLFSSL_FATAL_ERROR when fname is NULL, the file cannot be opened, + * the global RNG is not available, reseeding fails or dynamic memory + * allocation fails. + */ +int wolfSSL_RAND_load_file(const char* fname, long len) +{ +#if !defined(NO_FILESYSTEM) && defined(HAVE_HASHDRBG) + XFILE f; + long maxBytes; + long readSoFar = 0; + int ret = 0; +#ifndef WOLFSSL_SMALL_STACK + unsigned char buf[WOLFSSL_RAND_LOAD_FILE_BUF_SZ]; +#else + unsigned char* buf; +#endif + + WOLFSSL_ENTER("wolfSSL_RAND_load_file"); + + if (fname == NULL) + return WOLFSSL_FATAL_ERROR; + + /* OpenSSL semantics: RAND_load_file(file, -1) reads up to an + * implementation-defined maximum. WOLFSSL_RAND_LOAD_FILE_MAX_BYTES + * caps the read so callers passing -1 to ingest a seed file aren't + * silently truncated at a small default. */ + maxBytes = (len < 0) ? WOLFSSL_RAND_LOAD_FILE_MAX_BYTES : len; + if (maxBytes == 0) + return 0; + + f = XFOPEN(fname, "rb"); + if (f == XBADFILE) { + WOLFSSL_MSG("RAND_load_file: cannot open file"); + return WOLFSSL_FATAL_ERROR; + } + +#ifdef WOLFSSL_SMALL_STACK + buf = (unsigned char*)XMALLOC(WOLFSSL_RAND_LOAD_FILE_BUF_SZ, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (buf == NULL) { + XFCLOSE(f); + return WOLFSSL_FATAL_ERROR; + } +#endif +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("wolfSSL_RAND_load_file buf", buf, + WOLFSSL_RAND_LOAD_FILE_BUF_SZ); +#endif + + if (initGlobalRNG == 0 && wolfSSL_RAND_Init() != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("RAND_load_file: global RNG not available"); + ret = WOLFSSL_FATAL_ERROR; + goto cleanup; + } + + while (readSoFar < maxBytes) { + size_t toRead = (size_t)((maxBytes - readSoFar) < + WOLFSSL_RAND_LOAD_FILE_BUF_SZ + ? (maxBytes - readSoFar) : WOLFSSL_RAND_LOAD_FILE_BUF_SZ); + size_t n = XFREAD(buf, 1, toRead, f); + if (n == 0) + break; + if (wc_LockMutex(&globalRNGMutex) != 0) { + ret = WOLFSSL_FATAL_ERROR; + break; + } + if (wc_RNG_DRBG_Reseed(&globalRNG, buf, (word32)n) != 0) { + wc_UnLockMutex(&globalRNGMutex); + WOLFSSL_MSG("RAND_load_file: DRBG reseed failed"); + ret = WOLFSSL_FATAL_ERROR; + break; + } + wc_UnLockMutex(&globalRNGMutex); + readSoFar += (long)n; + } + +cleanup: + XFCLOSE(f); + ForceZero(buf, WOLFSSL_RAND_LOAD_FILE_BUF_SZ); +#ifdef WOLFSSL_SMALL_STACK + XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#elif defined(WOLFSSL_CHECK_MEM_ZERO) + wc_MemZero_Check(buf, WOLFSSL_RAND_LOAD_FILE_BUF_SZ); +#endif + + if (ret < 0) + return WOLFSSL_FATAL_ERROR; + return (int)readSoFar; +#else + /* Without HAVE_HASHDRBG / filesystem support there is no way to feed + * external entropy to the wolfCrypt RNG; return success so callers + * in those configurations are not broken. */ + (void)fname; + if (len == -1) + return 1024; + return (int)len; +#endif +} + +#endif /* OPENSSL_EXTRA */ + +/******************************************************************************* + * END OF RAND API + ******************************************************************************/ + +#endif /* !WOLFCRYPT_ONLY */ + #endif /* WOLFSSL_SSL_CRYPTO_INCLUDED */ diff --git a/src/ssl_err.c b/src/ssl_err.c new file mode 100644 index 0000000000..c5b60e7565 --- /dev/null +++ b/src/ssl_err.c @@ -0,0 +1,715 @@ +/* ssl_err.c + * + * Copyright (C) 2006-2026 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 3 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 + */ + +#include + +#if !defined(WOLFSSL_SSL_ERR_INCLUDED) + #ifndef WOLFSSL_IGNORE_FILE_WARN + #warning ssl_err.c does not need to be compiled separately from ssl.c + #endif +#else + +#ifndef WOLFCRYPT_ONLY + + +/* Get the string describing an error value. + * + * When data is NULL, a static buffer is used and the string is overwritten by + * the next call that passes NULL. + * + * @param [in] errNumber Error value. + * @param [in, out] data Buffer to hold string. Must be at least + * WOLFSSL_MAX_ERROR_SZ bytes. May be NULL. + * @return Buffer holding string. + */ +char* wolfSSL_ERR_error_string(unsigned long errNumber, char* data) +{ + WOLFSSL_ENTER("wolfSSL_ERR_error_string"); + if (data) { + SetErrorString((int)errNumber, data); + return data; + } + else { + static char tmp[WOLFSSL_MAX_ERROR_SZ] = {0}; + SetErrorString((int)errNumber, tmp); + return tmp; + } +} + + +/* Get the string describing an error value into a buffer of limited size. + * + * String is truncated to fit, including the NUL terminator. + * + * @param [in] e Error value. + * @param [in, out] buf Buffer to hold string. + * @param [in] len Length of buffer in bytes. + */ +void wolfSSL_ERR_error_string_n(unsigned long e, char* buf, unsigned long len) +{ + WOLFSSL_ENTER("wolfSSL_ERR_error_string_n"); + if (len >= WOLFSSL_MAX_ERROR_SZ) + wolfSSL_ERR_error_string(e, buf); + else { + WOLFSSL_MSG("Error buffer too short, truncating"); + if (len) { + char tmp[WOLFSSL_MAX_ERROR_SZ]; + wolfSSL_ERR_error_string(e, tmp); + XMEMCPY(buf, tmp, len-1); + buf[len-1] = '\0'; + } + } +} + +#if !defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM) \ + && defined(XFPRINTF) +/* Print the string describing an error value to a file. + * + * @param [in] fp File to print to. + * @param [in] err Error value. + */ +void wolfSSL_ERR_print_errors_fp(XFILE fp, int err) +{ + char data[WOLFSSL_MAX_ERROR_SZ + 1]; + + WOLFSSL_ENTER("wolfSSL_ERR_print_errors_fp"); + SetErrorString(err, data); + if (XFPRINTF(fp, "%s", data) < 0) + WOLFSSL_MSG("fprintf failed in wolfSSL_ERR_print_errors_fp"); +} +#endif + +#if !defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM) \ + && defined(XFPRINTF) +#if defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE) +/* Print the entries of the error queue to a file. + * + * @param [in] fp File to print to. + */ +void wolfSSL_ERR_dump_errors_fp(XFILE fp) +{ + wc_ERR_print_errors_fp(fp); +} + +/* Pass the entries of the error queue to a callback. + * + * @param [in] cb Callback to pass each error string to. + * @param [in] u Context to pass to the callback. + */ +void wolfSSL_ERR_print_errors_cb (int (*cb)(const char *str, size_t len, + void *u), void *u) +{ + wc_ERR_print_errors_cb(cb, u); +} +#endif +#endif + +#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) || defined(HAVE_MEMCACHED) + /* Get the last error value from the error queue and remove it. + * + * @return Error value on success. + * @return NOT_COMPILED_IN negated when there is no error queue. + */ + unsigned long wolfSSL_ERR_get_error(void) + { + WOLFSSL_ENTER("wolfSSL_ERR_get_error"); +#ifdef WOLFSSL_HAVE_ERROR_QUEUE + return (unsigned long)wc_GetErrorNodeErr(); +#else + return (unsigned long)(0 - NOT_COMPILED_IN); +#endif + } +#endif + +#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) +#ifdef WOLFSSL_HAVE_ERROR_QUEUE +#ifndef NO_BIO + /* Print the entries of the error queue to a BIO. + * + * Entries are removed from the queue as they are printed. + * + * @param [in, out] bio BIO to print to. + */ + void wolfSSL_ERR_print_errors(WOLFSSL_BIO* bio) + { + const char* file = NULL; + const char* reason = NULL; + int ret; + int line = 0; + char buf[WOLFSSL_MAX_ERROR_SZ * 2]; + + WOLFSSL_ENTER("wolfSSL_ERR_print_errors"); + + if (bio == NULL) { + WOLFSSL_MSG("BIO passed in was null"); + return; + } + + do { + ret = wc_PeekErrorNode(0, &file, &reason, &line); + if (ret >= 0) { + const char* r = wolfSSL_ERR_reason_error_string( + (unsigned long)(0 - ret)); + if (XSNPRINTF(buf, sizeof(buf), + "error:%d:wolfSSL library:%s:%s:%d\n", + ret, r, file, line) + >= (int)sizeof(buf)) + { + WOLFSSL_MSG("Buffer overrun formatting error message"); + } + wolfSSL_BIO_write(bio, buf, (int)XSTRLEN(buf)); + wc_RemoveErrorNode(0); + } + } while (ret >= 0); + if (wolfSSL_BIO_write(bio, "", 1) != 1) { + WOLFSSL_MSG("Issue writing final string terminator"); + } + } +#endif +#endif +#endif + +#ifdef OPENSSL_EXTRA + /* Free the error strings. + * + * Error strings are handled internally. For OpenSSL compatibility only. + */ + void wolfSSL_ERR_free_strings(void) + { + /* handled internally */ + } +#endif + +#if defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE) || \ + defined(HAVE_CURL) + /* Remove all entries from the error queue. + */ + void wolfSSL_ERR_clear_error(void) + { + WOLFSSL_ENTER("wolfSSL_ERR_clear_error"); + #if defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE) + wc_ClearErrorNodes(); + #endif + } +#endif + +#ifdef OPENSSL_EXTRA + /* Get the last error value from the error queue with its file and line. + * + * Entry is removed from the queue. + * + * @param [out] file Name of file error occurred in. + * @param [out] line Line number error occurred on. + * @return Error value on success. + * @return 0 when there are no entries in the queue or there is no error + * queue. + */ + unsigned long wolfSSL_ERR_get_error_line(const char** file, int* line) + { + #ifdef WOLFSSL_HAVE_ERROR_QUEUE + int ret = wc_PullErrorNode(file, NULL, line); + if (ret < 0) { + if (ret == WC_NO_ERR_TRACE(BAD_STATE_E)) + return 0; /* no errors in queue */ + WOLFSSL_MSG("Issue getting error node"); + WOLFSSL_LEAVE("wolfSSL_ERR_get_error_line", ret); + ret = 0 - ret; /* return absolute value of error */ + + /* panic and try to clear out nodes */ + wc_ClearErrorNodes(); + } + return (unsigned long)ret; + #else + (void)file; + (void)line; + + return 0; + #endif + } +#endif + +#ifdef OPENSSL_EXTRA +#if (defined(DEBUG_WOLFSSL) || defined(OPENSSL_EXTRA)) && \ + (!defined(_WIN32) && !defined(NO_ERROR_QUEUE)) + static const char WOLFSSL_SYS_ACCEPT_T[] = "accept"; + static const char WOLFSSL_SYS_BIND_T[] = "bind"; + static const char WOLFSSL_SYS_CONNECT_T[] = "connect"; + static const char WOLFSSL_SYS_FOPEN_T[] = "fopen"; + static const char WOLFSSL_SYS_FREAD_T[] = "fread"; + static const char WOLFSSL_SYS_GETADDRINFO_T[] = "getaddrinfo"; + static const char WOLFSSL_SYS_GETSOCKOPT_T[] = "getsockopt"; + static const char WOLFSSL_SYS_GETSOCKNAME_T[] = "getsockname"; + static const char WOLFSSL_SYS_GETHOSTBYNAME_T[] = "gethostbyname"; + static const char WOLFSSL_SYS_GETNAMEINFO_T[] = "getnameinfo"; + static const char WOLFSSL_SYS_GETSERVBYNAME_T[] = "getservbyname"; + static const char WOLFSSL_SYS_IOCTLSOCKET_T[] = "ioctlsocket"; + static const char WOLFSSL_SYS_LISTEN_T[] = "listen"; + static const char WOLFSSL_SYS_OPENDIR_T[] = "opendir"; + static const char WOLFSSL_SYS_SETSOCKOPT_T[] = "setsockopt"; + static const char WOLFSSL_SYS_SOCKET_T[] = "socket"; + + /* Get the name of a system function. + * + * Maps the int identifier to a function name for compatibility. + * + * @param [in] fun System function identifier. WOLFSSL_SYS_*. + * @return Name of function on success. + * @return "NULL" when the identifier is not known. + */ + static const char* wolfSSL_ERR_sys_func(int fun) + { + switch (fun) { + case WOLFSSL_SYS_ACCEPT: return WOLFSSL_SYS_ACCEPT_T; + case WOLFSSL_SYS_BIND: return WOLFSSL_SYS_BIND_T; + case WOLFSSL_SYS_CONNECT: return WOLFSSL_SYS_CONNECT_T; + case WOLFSSL_SYS_FOPEN: return WOLFSSL_SYS_FOPEN_T; + case WOLFSSL_SYS_FREAD: return WOLFSSL_SYS_FREAD_T; + case WOLFSSL_SYS_GETADDRINFO: return WOLFSSL_SYS_GETADDRINFO_T; + case WOLFSSL_SYS_GETSOCKOPT: return WOLFSSL_SYS_GETSOCKOPT_T; + case WOLFSSL_SYS_GETSOCKNAME: return WOLFSSL_SYS_GETSOCKNAME_T; + case WOLFSSL_SYS_GETHOSTBYNAME: return WOLFSSL_SYS_GETHOSTBYNAME_T; + case WOLFSSL_SYS_GETNAMEINFO: return WOLFSSL_SYS_GETNAMEINFO_T; + case WOLFSSL_SYS_GETSERVBYNAME: return WOLFSSL_SYS_GETSERVBYNAME_T; + case WOLFSSL_SYS_IOCTLSOCKET: return WOLFSSL_SYS_IOCTLSOCKET_T; + case WOLFSSL_SYS_LISTEN: return WOLFSSL_SYS_LISTEN_T; + case WOLFSSL_SYS_OPENDIR: return WOLFSSL_SYS_OPENDIR_T; + case WOLFSSL_SYS_SETSOCKOPT: return WOLFSSL_SYS_SETSOCKOPT_T; + case WOLFSSL_SYS_SOCKET: return WOLFSSL_SYS_SOCKET_T; + default: + return "NULL"; + } + } +#endif +#endif + +#ifdef OPENSSL_EXTRA + /* Add an error to the error queue. + * + * @param [in] lib Library the error occurred in. Not used. + * @param [in] fun System function the error occurred in. WOLFSSL_SYS_*. + * @param [in] err Error value. + * @param [in] file Name of file the error occurred in. + * @param [in] line Line number the error occurred on. + */ + void wolfSSL_ERR_put_error(int lib, int fun, int err, const char* file, + int line) + { + WOLFSSL_ENTER("wolfSSL_ERR_put_error"); + + #if !defined(DEBUG_WOLFSSL) && !defined(OPENSSL_EXTRA) + (void)fun; + (void)err; + (void)file; + (void)line; + WOLFSSL_MSG("Not compiled in debug mode"); + #elif defined(OPENSSL_EXTRA) && \ + (defined(_WIN32) || defined(NO_ERROR_QUEUE)) + (void)fun; + (void)file; + (void)line; + WOLFSSL_ERROR(err); + #else + WOLFSSL_ERROR_LINE(err, wolfSSL_ERR_sys_func(fun), (unsigned int)line, + file, NULL); + #endif + (void)lib; + } + + + /* Get the last error value from the error queue with its data. + * + * Entry is removed from the queue. Similar to + * wolfSSL_ERR_get_error_line() but takes a flags argument for more + * flexibility. + * + * @param [out] file Name of file error occurred in. + * @param [out] line Line number error occurred on. + * @param [out] data Error data. A string when the WOLFSSL_ERR_TXT_STRING + * flag is returned. + * @param [out] flags Format of data. WOLFSSL_ERR_TXT_STRING. + * @return Error value on success. + * @return 0 when there are no entries in the queue or there is no error + * queue. + */ + unsigned long wolfSSL_ERR_get_error_line_data(const char** file, int* line, + const char** data, int *flags) + { +#ifdef WOLFSSL_HAVE_ERROR_QUEUE + int ret; + + WOLFSSL_ENTER("wolfSSL_ERR_get_error_line_data"); + + if (flags != NULL) + *flags = WOLFSSL_ERR_TXT_STRING; /* Clear the flags */ + + ret = wc_PullErrorNode(file, data, line); + if (ret < 0) { + if (ret == WC_NO_ERR_TRACE(BAD_STATE_E)) + return 0; /* no errors in queue */ + WOLFSSL_MSG("Error with pulling error node!"); + WOLFSSL_LEAVE("wolfSSL_ERR_get_error_line_data", ret); + ret = 0 - ret; /* return absolute value of error */ + + /* panic and try to clear out nodes */ + wc_ClearErrorNodes(); + } + + return (unsigned long)ret; +#else + WOLFSSL_ENTER("wolfSSL_ERR_get_error_line_data"); + WOLFSSL_MSG("Error queue turned off, can not get error line"); + (void)file; + (void)line; + (void)data; + (void)flags; + return 0; +#endif + } +#endif + +#ifdef OPENSSL_EXTRA +/* Get the last error value from the error queue without removing it. + * + * @return Error value on success. + * @return 0 when there are no entries in the queue. + */ +unsigned long wolfSSL_ERR_peek_error(void) +{ + WOLFSSL_ENTER("wolfSSL_ERR_peek_error"); + + return wolfSSL_ERR_peek_error_line_data(NULL, NULL, NULL, NULL); +} + +#ifdef WOLFSSL_DEBUG_TRACE_ERROR_CODES_H +#include +#endif + +/* Get the library that an error value belongs to. + * + * @param [in] err Error value. + * @return WOLFSSL_ERR_LIB_* value on success. + * @return WOLFSSL_ERR_LIB_SSL when the library is not identifiable. + */ +int wolfSSL_ERR_GET_LIB(unsigned long err) +{ + unsigned long value; + + value = (err & 0xFFFFFFL); + switch (value) { + case -PARSE_ERROR: + return WOLFSSL_ERR_LIB_SSL; + case -ASN_NO_PEM_HEADER: + case -WOLFSSL_PEM_R_NO_START_LINE_E: + case -WOLFSSL_PEM_R_PROBLEMS_GETTING_PASSWORD_E: + case -WOLFSSL_PEM_R_BAD_PASSWORD_READ_E: + case -WOLFSSL_PEM_R_BAD_DECRYPT_E: + return WOLFSSL_ERR_LIB_PEM; + case -WOLFSSL_EVP_R_BAD_DECRYPT_E: + case -WOLFSSL_EVP_R_BN_DECODE_ERROR: + case -WOLFSSL_EVP_R_DECODE_ERROR: + case -WOLFSSL_EVP_R_PRIVATE_KEY_DECODE_ERROR: + return WOLFSSL_ERR_LIB_EVP; + case -WOLFSSL_ASN1_R_HEADER_TOO_LONG_E: + return WOLFSSL_ERR_LIB_ASN1; + default: + return 0; + } +} + +#ifdef WOLFSSL_DEBUG_TRACE_ERROR_CODES +#include +#endif + +/* This function is to find global error values that are the same through out + * all library version. With wolfSSL having only one set of error codes the + * return value is pretty straight forward. The only thing needed is all wolfSSL + * error values are typically negative. + * + * Returns the error reason + */ +int wolfSSL_ERR_GET_REASON(unsigned long err) +{ + int ret = (int)err; + + WOLFSSL_ENTER("wolfSSL_ERR_GET_REASON"); + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) + /* Nginx looks for this error to know to stop parsing certificates. + * Same for HAProxy. */ + if ((err == (unsigned long)((ERR_LIB_PEM << 24) | PEM_R_NO_START_LINE)) || + ((err & 0xFFFFFFL) == + (unsigned long)(-WC_NO_ERR_TRACE(ASN_NO_PEM_HEADER))) || + ((err & 0xFFFL) == (unsigned long)PEM_R_NO_START_LINE)) + return PEM_R_NO_START_LINE; + if (err == (unsigned long)((ERR_LIB_SSL << 24) | -SSL_R_HTTP_REQUEST)) + return SSL_R_HTTP_REQUEST; +#endif +#if defined(OPENSSL_ALL) && defined(WOLFSSL_PYTHON) + if (err == (unsigned long)((ERR_LIB_ASN1 << 24) | ASN1_R_HEADER_TOO_LONG)) + return ASN1_R_HEADER_TOO_LONG; +#endif + + /* check if error value is in range of wolfCrypt or wolfSSL errors */ + ret = 0 - ret; /* setting as negative value */ + + if ((ret <= WC_SPAN1_FIRST_E && ret >= WC_SPAN1_LAST_E) || + (ret <= WC_SPAN2_FIRST_E && ret >= WC_SPAN2_LAST_E) || + (ret <= WOLFSSL_FIRST_E && ret >= WOLFSSL_LAST_E)) + { + return ret; + } + else { + WOLFSSL_MSG("Not in range of typical error values"); + ret = (int)err; + } + + return ret; +} +#endif + +#ifdef OPENSSL_EXTRA +#if !defined(NETOS) +/* Load the SSL error strings. + * + * Error strings are handled internally. For OpenSSL compatibility only. + */ +void wolfSSL_ERR_load_SSL_strings(void) +{ + +} +#endif +#endif + +#ifdef OPENSSL_EXTRA +/* Get the last error value from the error queue with its file and line + * without removing it. + * + * @param [out] file Name of file error occurred in. + * @param [out] line Line number error occurred on. + * @return Error value on success. + * @return 0 when there are no entries in the queue. + * @return NOT_COMPILED_IN negated when there is no error queue. + */ +unsigned long wolfSSL_ERR_peek_last_error_line(const char **file, int *line) +{ + WOLFSSL_ENTER("wolfSSL_ERR_peek_last_error"); + + (void)line; + (void)file; +#ifdef WOLFSSL_HAVE_ERROR_QUEUE + { + int ret; + + if ((ret = wc_PeekErrorNode(-1, file, NULL, line)) < 0) { + WOLFSSL_MSG("Issue peeking at error node in queue"); + return 0; + } + #if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) \ + || defined(WOLFSSL_HAPROXY) + if (ret == -WC_NO_ERR_TRACE(ASN_NO_PEM_HEADER)) + return (ERR_LIB_PEM << 24) | PEM_R_NO_START_LINE; + #endif + #if defined(OPENSSL_ALL) && defined(WOLFSSL_PYTHON) + if (ret == ASN1_R_HEADER_TOO_LONG) { + return (ERR_LIB_ASN1 << 24) | ASN1_R_HEADER_TOO_LONG; + } + #endif + return (unsigned long)ret; + } +#else + return (unsigned long)(0 - NOT_COMPILED_IN); +#endif +} +#endif + +#if defined(OPENSSL_ALL) || (defined(OPENSSL_EXTRA) && \ + (defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \ + defined(HAVE_LIGHTY) || defined(WOLFSSL_HAPROXY) || \ + defined(WOLFSSL_OPENSSH))) +/* Remove the error queue entries of a thread. + * + * Not implemented. For OpenSSL compatibility only. + * + * @param [in] pid Thread identifier. Not used. + */ +void wolfSSL_ERR_remove_thread_state(void* pid) +{ + (void) pid; + return; +} +#endif + +#if defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) +/* Load the ERR error strings. + * + * Error strings are handled internally. For OpenSSL compatibility only. + * + * @return WOLFSSL_SUCCESS always. + */ +int wolfSSL_ERR_load_ERR_strings(void) +{ + return WOLFSSL_SUCCESS; +} + +/* Load the crypto error strings. + * + * Error strings are handled internally. For OpenSSL compatibility only. + */ +void wolfSSL_ERR_load_crypto_strings(void) +{ + WOLFSSL_ENTER("wolfSSL_ERR_load_crypto_strings"); + /* Do nothing */ + return; +} +#endif + +#if defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) +#ifndef NO_BIO +/* Load the BIO error strings. + * + * Error strings are handled internally. For OpenSSL compatibility only. + */ +void wolfSSL_ERR_load_BIO_strings(void) { + WOLFSSL_ENTER("wolfSSL_ERR_load_BIO_strings"); + /* do nothing */ +} +#endif +#endif + +#if defined(OPENSSL_EXTRA) +/* Get the last error value from the error queue without removing it. + * + * Some error values are mapped to the OpenSSL equivalent. + * + * @return Error value on success. + * @return 0 when there are no entries in the queue. + * @return NOT_COMPILED_IN negated when there is no error queue. + */ +unsigned long wolfSSL_ERR_peek_last_error(void) +{ + WOLFSSL_ENTER("wolfSSL_ERR_peek_last_error"); + +#ifdef WOLFSSL_HAVE_ERROR_QUEUE + { + int ret; + + if ((ret = wc_PeekErrorNode(-1, NULL, NULL, NULL)) < 0) { + WOLFSSL_MSG("Issue peeking at error node in queue"); + return 0; + } + if (ret == -WC_NO_ERR_TRACE(ASN_NO_PEM_HEADER)) + return (WOLFSSL_ERR_LIB_PEM << 24) | + -WC_NO_ERR_TRACE(WOLFSSL_PEM_R_NO_START_LINE_E); + #if defined(WOLFSSL_PYTHON) + if (ret == ASN1_R_HEADER_TOO_LONG) + return (WOLFSSL_ERR_LIB_ASN1 << 24) | + -WC_NO_ERR_TRACE(WOLFSSL_ASN1_R_HEADER_TOO_LONG_E); + #endif + return (unsigned long)ret; + } +#else + return (unsigned long)(0 - NOT_COMPILED_IN); +#endif +} +#endif + +#ifdef OPENSSL_EXTRA +/* Determine whether an error value is to be ignored when peeking. + * + * @param [in] err Error value. + * @return 1 when the error is to be ignored. + * @return 0 otherwise. + */ +static int peek_ignore_err(int err) +{ + switch(err) { + case -WC_NO_ERR_TRACE(WANT_READ): + case -WC_NO_ERR_TRACE(WANT_WRITE): + case -WC_NO_ERR_TRACE(ZERO_RETURN): + case -WOLFSSL_ERROR_ZERO_RETURN: + case -WC_NO_ERR_TRACE(SOCKET_PEER_CLOSED_E): + case -WC_NO_ERR_TRACE(SOCKET_ERROR_E): + return 1; + default: + return 0; + } +} + +/* Get the last error value from the error queue with its data without + * removing it. + * + * Errors that are not real errors, such as WANT_READ, are skipped. + * + * @param [out] file Name of file error occurred in. + * @param [out] line Line number error occurred on. + * @param [out] data Error data. Always set to "" when not NULL. + * @param [out] flags Format of data. Always set to WOLFSSL_ERR_TXT_STRING + * when not NULL. + * @return Error value on success. + * @return 0 when there are no entries in the queue. + */ +unsigned long wolfSSL_ERR_peek_error_line_data(const char **file, int *line, + const char **data, int *flags) +{ + unsigned long err; + + WOLFSSL_ENTER("wolfSSL_ERR_peek_error_line_data"); + err = wc_PeekErrorNodeLineData(file, line, data, flags, peek_ignore_err); + + if (err == -WC_NO_ERR_TRACE(ASN_NO_PEM_HEADER)) + return (WOLFSSL_ERR_LIB_PEM << 24) | + -WC_NO_ERR_TRACE(WOLFSSL_PEM_R_NO_START_LINE_E); +#ifdef OPENSSL_ALL + /* PARSE_ERROR is returned if an HTTP request is detected. */ + else if (err == -WC_NO_ERR_TRACE(PARSE_ERROR)) + /* SSL_R_HTTP_REQUEST */ + return (WOLFSSL_ERR_LIB_SSL << 24) | -WC_NO_ERR_TRACE(PARSE_ERROR); +#endif +#if defined(OPENSSL_ALL) && defined(WOLFSSL_PYTHON) + else if (err == ASN1_R_HEADER_TOO_LONG) + return (WOLFSSL_ERR_LIB_ASN1 << 24) | + -WC_NO_ERR_TRACE(WOLFSSL_ASN1_R_HEADER_TOO_LONG_E); +#endif + return err; +} +#endif + +#if defined(OPENSSL_EXTRA) +/* Remove the error queue entries of a thread. + * + * All entries of the current thread's queue are removed, not just those of the + * given thread. + * + * @param [in] id Thread identifier. Not used. + */ +void wolfSSL_ERR_remove_state(unsigned long id) +{ + WOLFSSL_ENTER("wolfSSL_ERR_remove_state"); + (void)id; + if (wc_ERR_remove_state() != 0) { + WOLFSSL_MSG("Error with removing the state"); + } +} +#endif + +#endif /* !WOLFCRYPT_ONLY */ + +#endif /* !WOLFSSL_SSL_ERR_INCLUDED */ diff --git a/wolfssl/internal.h b/wolfssl/internal.h index d54496e0f9..bd36e94944 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -7436,6 +7436,7 @@ WOLFSSL_LOCAL int wolfSSL_sk_BY_DIR_entry_push(WOLF_STACK_OF(wolfSSL_BY_DIR_entr #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) WOLFSSL_LOCAL int oid2nid(word32 oid, int grp); WOLFSSL_LOCAL word32 nid2oid(int nid, int grp); +WOLFSSL_LOCAL void wolfssl_object_info_slice_init(void); #endif #ifdef WOLFSSL_DTLS