diff --git a/CMakeLists.txt b/CMakeLists.txt index 217a9e1574..31b77bae8c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2945,6 +2945,9 @@ if(WOLFSSL_EXAMPLES) tests/api/test_lms_xmss.c tests/api/test_dtls.c tests/api/test_dtls13.c + tests/api/test_ssl_cert.c + tests/api/test_ssl_pk.c + tests/api/test_ssl_ext.c tests/api/test_ocsp.c tests/api/test_evp.c tests/api/test_tls_ext.c diff --git a/src/include.am b/src/include.am index 563a6fa3e8..d61d2ee17d 100644 --- a/src/include.am +++ b/src/include.am @@ -21,6 +21,8 @@ EXTRA_DIST += src/pk_rsa.c EXTRA_DIST += src/pk_ec.c 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_pk.c EXTRA_DIST += src/ssl_asn1.c EXTRA_DIST += src/ssl_bn.c diff --git a/src/ssl.c b/src/ssl.c index efbbf3074e..9bc25948e1 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -149,6 +149,12 @@ #endif #endif /* !WOLFCRYPT_ONLY || OPENSSL_EXTRA */ +#if !defined(WOLFCRYPT_ONLY) && defined(WOLFSSL_SYS_CRYPTO_POLICY) +/* The system wide crypto-policy. Configured by wolfSSL_crypto_policy_enable. + * */ +static struct SystemCryptoPolicy crypto_policy; +#endif /* !WOLFCRYPT_ONLY && WOLFSSL_SYS_CRYPTO_POLICY */ + /* * ssl.c Build Options: * @@ -318,12 +324,6 @@ int wc_OBJ_sn2nid(const char *sn) #ifndef WOLFCRYPT_ONLY -#if defined(WOLFSSL_SYS_CRYPTO_POLICY) -/* The system wide crypto-policy. Configured by wolfSSL_crypto_policy_enable. - * */ -static struct SystemCryptoPolicy crypto_policy; -#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - #if !defined(NO_RSA) || !defined(NO_DH) || defined(HAVE_ECC) || \ (defined(OPENSSL_EXTRA) && defined(WOLFSSL_KEY_GEN) && !defined(NO_DSA)) @@ -1114,25 +1114,6 @@ int wolfSSL_set_fd(WOLFSSL* ssl, int fd) return ret; } -#ifdef WOLFSSL_DTLS -int wolfSSL_set_dtls_fd_connected(WOLFSSL* ssl, int fd) -{ - int ret; - - WOLFSSL_ENTER("wolfSSL_set_dtls_fd_connected"); - - if (ssl == NULL) { - return BAD_FUNC_ARG; - } - - ret = wolfSSL_set_fd(ssl, fd); - if (ret == WOLFSSL_SUCCESS) - ssl->buffers.dtlsCtx.connected = 1; - - return ret; -} -#endif - int wolfSSL_set_read_fd(WOLFSSL* ssl, int fd) { @@ -1327,14 +1308,6 @@ int wolfSSL_get_wfd(const WOLFSSL* ssl) } -int wolfSSL_dtls(WOLFSSL* ssl) -{ - int dtlsOpt = 0; - if (ssl) - dtlsOpt = ssl->options.dtls; - return dtlsOpt; -} - #ifdef WOLFSSL_WOLFSENTRY_HOOKS int wolfSSL_CTX_set_AcceptFilter( @@ -1387,5007 +1360,2794 @@ int wolfSSL_set_ConnectFilter( #endif /* WOLFSSL_WOLFSENTRY_HOOKS */ -#ifndef WOLFSSL_LEANPSK -#if defined(WOLFSSL_DTLS) && defined(XINET_PTON) && \ - !defined(WOLFSSL_NO_SOCK) && defined(HAVE_SOCKADDR) -void* wolfSSL_dtls_create_peer(int port, char* ip) -{ - SOCKADDR_IN *addr; - addr = (SOCKADDR_IN*)XMALLOC(sizeof(*addr), NULL, - DYNAMIC_TYPE_SOCKADDR); - if (addr == NULL) { - return NULL; + +#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 - addr->sin_family = AF_INET; - addr->sin_port = XHTONS((word16)port); - if (XINET_PTON(AF_INET, ip, &addr->sin_addr) < 1) { - XFREE(addr, NULL, DYNAMIC_TYPE_SOCKADDR); - return NULL; +#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 - return addr; -} + (void)ssl; -int wolfSSL_dtls_free_peer(void* addr) -{ - XFREE(addr, NULL, DYNAMIC_TYPE_SOCKADDR); - return WOLFSSL_SUCCESS; + WOLFSSL_LEAVE("wolfSSL_negotiate", err); + + return err; } -#endif +#endif /* !NO_TLS */ -#ifdef WOLFSSL_DTLS -static int SockAddrSet(WOLFSSL_SOCKADDR* sockAddr, void* peer, - unsigned int peerSz, void* heap) -{ - if (peer == NULL || peerSz == 0) { - if (sockAddr->sa != NULL) - XFREE(sockAddr->sa, heap, DYNAMIC_TYPE_SOCKADDR); - sockAddr->sa = NULL; - sockAddr->sz = 0; - sockAddr->bufSz = 0; - return WOLFSSL_SUCCESS; +WOLFSSL_ABI +WC_RNG* wolfSSL_GetRNG(WOLFSSL* ssl) +{ + if (ssl) { + return ssl->rng; } - if (peerSz > sockAddr->bufSz) { - if (sockAddr->sa != NULL) - XFREE(sockAddr->sa, heap, DYNAMIC_TYPE_SOCKADDR); - sockAddr->sa = - (void*)XMALLOC(peerSz, heap, DYNAMIC_TYPE_SOCKADDR); - if (sockAddr->sa == NULL) { - sockAddr->sz = 0; - sockAddr->bufSz = 0; - return WOLFSSL_FAILURE; - } - sockAddr->bufSz = peerSz; - } - XMEMCPY(sockAddr->sa, peer, peerSz); - sockAddr->sz = peerSz; - return WOLFSSL_SUCCESS; + return NULL; } -#endif -int wolfSSL_dtls_set_peer(WOLFSSL* ssl, void* peer, unsigned int peerSz) -{ -#ifdef WOLFSSL_DTLS - int ret; - if (ssl == NULL) - return WOLFSSL_FAILURE; -#ifdef WOLFSSL_RW_THREADED - if (wc_LockRwLock_Wr(&ssl->buffers.dtlsCtx.peerLock) != 0) - return WOLFSSL_FAILURE; +#ifndef WOLFSSL_LEANPSK +/* object size based on build */ +int wolfSSL_GetObjectSize(void) +{ +#ifdef SHOW_SIZES + printf("sizeof suites = %lu\n", (unsigned long)sizeof(Suites)); + printf("sizeof ciphers(2) = %lu\n", (unsigned long)sizeof(Ciphers)); +#ifndef NO_RC4 + printf("\tsizeof arc4 = %lu\n", (unsigned long)sizeof(Arc4)); #endif - ret = SockAddrSet(&ssl->buffers.dtlsCtx.peer, peer, peerSz, ssl->heap); - if (ret == WOLFSSL_SUCCESS && !(peer == NULL || peerSz == 0)) - ssl->buffers.dtlsCtx.userSet = 1; - else - ssl->buffers.dtlsCtx.userSet = 0; -#ifdef WOLFSSL_RW_THREADED - if (wc_UnLockRwLock(&ssl->buffers.dtlsCtx.peerLock) != 0) - ret = WOLFSSL_FAILURE; + printf("\tsizeof aes = %lu\n", (unsigned long)sizeof(Aes)); +#ifndef NO_DES3 + printf("\tsizeof des3 = %lu\n", (unsigned long)sizeof(Des3)); #endif - return ret; -#else - (void)ssl; - (void)peer; - (void)peerSz; - return WOLFSSL_NOT_IMPLEMENTED; +#ifdef HAVE_CHACHA + printf("\tsizeof chacha = %lu\n", (unsigned long)sizeof(ChaCha)); #endif -} - -#if defined(WOLFSSL_DTLS_CID) && !defined(WOLFSSL_NO_SOCK) -int wolfSSL_dtls_set_pending_peer(WOLFSSL* ssl, void* peer, unsigned int peerSz) -{ -#ifdef WOLFSSL_DTLS - int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); - - if (ssl == NULL) - return WOLFSSL_FAILURE; -#ifdef WOLFSSL_RW_THREADED - if (wc_LockRwLock_Rd(&ssl->buffers.dtlsCtx.peerLock) != 0) - return WOLFSSL_FAILURE; +#ifdef WOLFSSL_SM4 + printf("\tsizeof sm4 = %lu\n", (unsigned long)sizeof(Sm4)); #endif - if (ssl->buffers.dtlsCtx.peer.sa != NULL && - ssl->buffers.dtlsCtx.peer.sz == peerSz && - sockAddrEqual((SOCKADDR_S*)ssl->buffers.dtlsCtx.peer.sa, - (XSOCKLENT)ssl->buffers.dtlsCtx.peer.sz, (SOCKADDR_S*)peer, - (XSOCKLENT)peerSz)) { - /* Already the current peer. */ - if (ssl->buffers.dtlsCtx.pendingPeer.sa != NULL) { - /* Clear any other pendingPeer */ - XFREE(ssl->buffers.dtlsCtx.pendingPeer.sa, ssl->heap, - DYNAMIC_TYPE_SOCKADDR); - ssl->buffers.dtlsCtx.pendingPeer.sa = NULL; - ssl->buffers.dtlsCtx.pendingPeer.sz = 0; - ssl->buffers.dtlsCtx.pendingPeer.bufSz = 0; - } - ret = WOLFSSL_SUCCESS; - } - else { - ret = SockAddrSet(&ssl->buffers.dtlsCtx.pendingPeer, peer, peerSz, - ssl->heap); - } - if (ret == WOLFSSL_SUCCESS) - ssl->buffers.dtlsCtx.processingPendingRecord = 0; -#ifdef WOLFSSL_RW_THREADED - if (wc_UnLockRwLock(&ssl->buffers.dtlsCtx.peerLock) != 0) - ret = WOLFSSL_FAILURE; + printf("sizeof cipher specs = %lu\n", (unsigned long) + sizeof(CipherSpecs)); + printf("sizeof keys = %lu\n", (unsigned long)sizeof(Keys)); + printf("sizeof Hashes(2) = %lu\n", (unsigned long)sizeof(Hashes)); +#ifndef NO_MD5 + printf("\tsizeof MD5 = %lu\n", (unsigned long)sizeof(wc_Md5)); #endif - return ret; -#else - (void)ssl; - (void)peer; - (void)peerSz; - return WOLFSSL_NOT_IMPLEMENTED; +#ifndef NO_SHA + printf("\tsizeof SHA = %lu\n", (unsigned long)sizeof(wc_Sha)); #endif -} -#endif /* WOLFSSL_DTLS_CID && !WOLFSSL_NO_SOCK */ - -int wolfSSL_dtls_get_peer(WOLFSSL* ssl, void* peer, unsigned int* peerSz) -{ -#ifdef WOLFSSL_DTLS - int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); - if (ssl == NULL) - return WOLFSSL_FAILURE; -#ifdef WOLFSSL_RW_THREADED - if (wc_LockRwLock_Rd(&ssl->buffers.dtlsCtx.peerLock) != 0) - return WOLFSSL_FAILURE; +#ifdef WOLFSSL_SHA224 + printf("\tsizeof SHA224 = %lu\n", (unsigned long)sizeof(wc_Sha224)); #endif - if (peer != NULL && peerSz != NULL - && *peerSz >= ssl->buffers.dtlsCtx.peer.sz - && ssl->buffers.dtlsCtx.peer.sa != NULL) { - *peerSz = ssl->buffers.dtlsCtx.peer.sz; - XMEMCPY(peer, ssl->buffers.dtlsCtx.peer.sa, *peerSz); - ret = WOLFSSL_SUCCESS; - } -#ifdef WOLFSSL_RW_THREADED - if (wc_UnLockRwLock(&ssl->buffers.dtlsCtx.peerLock) != 0) - ret = WOLFSSL_FAILURE; +#ifndef NO_SHA256 + printf("\tsizeof SHA256 = %lu\n", (unsigned long)sizeof(wc_Sha256)); #endif - return ret; -#else - (void)ssl; - (void)peer; - (void)peerSz; - return WOLFSSL_NOT_IMPLEMENTED; +#ifdef WOLFSSL_SHA384 + printf("\tsizeof SHA384 = %lu\n", (unsigned long)sizeof(wc_Sha384)); +#endif +#ifdef WOLFSSL_SHA384 + printf("\tsizeof SHA512 = %lu\n", (unsigned long)sizeof(wc_Sha512)); +#endif +#ifdef WOLFSSL_SM3 + printf("\tsizeof sm3 = %lu\n", (unsigned long)sizeof(Sm3)); +#endif + printf("sizeof Buffers = %lu\n", (unsigned long)sizeof(Buffers)); + printf("sizeof Options = %lu\n", (unsigned long)sizeof(Options)); + printf("sizeof Arrays = %lu\n", (unsigned long)sizeof(Arrays)); +#ifndef NO_RSA + printf("sizeof RsaKey = %lu\n", (unsigned long)sizeof(RsaKey)); +#endif +#ifdef HAVE_ECC + printf("sizeof ecc_key = %lu\n", (unsigned long)sizeof(ecc_key)); +#endif + printf("sizeof WOLFSSL_CIPHER = %lu\n", (unsigned long) + sizeof(WOLFSSL_CIPHER)); + printf("sizeof WOLFSSL_SESSION = %lu\n", (unsigned long) + sizeof(WOLFSSL_SESSION)); + printf("sizeof WOLFSSL = %lu\n", (unsigned long)sizeof(WOLFSSL)); + printf("sizeof WOLFSSL_CTX = %lu\n", (unsigned long) + sizeof(WOLFSSL_CTX)); #endif + + return sizeof(WOLFSSL); } -int wolfSSL_dtls_get0_peer(WOLFSSL* ssl, const void** peer, - unsigned int* peerSz) +int wolfSSL_CTX_GetObjectSize(void) { -#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_RW_THREADED) - if (ssl == NULL) - return WOLFSSL_FAILURE; - - if (peer == NULL || peerSz == NULL) - return WOLFSSL_FAILURE; + return sizeof(WOLFSSL_CTX); +} - *peer = ssl->buffers.dtlsCtx.peer.sa; - *peerSz = ssl->buffers.dtlsCtx.peer.sz; - return WOLFSSL_SUCCESS; -#else - (void)ssl; - (void)peer; - (void)peerSz; - return WOLFSSL_NOT_IMPLEMENTED; -#endif +int wolfSSL_METHOD_GetObjectSize(void) +{ + return sizeof(WOLFSSL_METHOD); } +#endif -#if defined(WOLFSSL_SCTP) && defined(WOLFSSL_DTLS) +#ifdef WOLFSSL_STATIC_MEMORY -int wolfSSL_CTX_dtls_set_sctp(WOLFSSL_CTX* ctx) +int wolfSSL_CTX_load_static_memory(WOLFSSL_CTX** ctx, + wolfSSL_method_func method, unsigned char* buf, unsigned int sz, int flag, + int maxSz) { - WOLFSSL_ENTER("wolfSSL_CTX_dtls_set_sctp"); + WOLFSSL_HEAP_HINT* hint = NULL; - if (ctx == NULL) + if (ctx == NULL || buf == NULL) { return BAD_FUNC_ARG; + } - ctx->dtlsSctp = 1; - return WOLFSSL_SUCCESS; -} + if (*ctx == NULL && method == NULL) { + return BAD_FUNC_ARG; + } + /* If there is a heap already, capture it in hint. */ + if (*ctx && (*ctx)->heap != NULL) { + hint = (*ctx)->heap; + } -int wolfSSL_dtls_set_sctp(WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_dtls_set_sctp"); + if (wc_LoadStaticMemory(&hint, buf, sz, flag, maxSz)) { + WOLFSSL_MSG("Error loading static memory"); + return WOLFSSL_FAILURE; + } - if (ssl == NULL) - return BAD_FUNC_ARG; + if (*ctx) { + if ((*ctx)->heap == NULL) { + (*ctx)->heap = (void*)hint; + } + } + else { + /* create ctx if needed */ + *ctx = wolfSSL_CTX_new_ex(method(hint), hint); + if (*ctx == NULL) { + WOLFSSL_MSG("Error creating ctx"); + return WOLFSSL_FAILURE; + } + } - ssl->options.dtlsSctp = 1; return WOLFSSL_SUCCESS; } -#endif /* WOLFSSL_DTLS && WOLFSSL_SCTP */ - -#if (defined(WOLFSSL_SCTP) || defined(WOLFSSL_DTLS_MTU)) && \ - defined(WOLFSSL_DTLS) -int wolfSSL_CTX_dtls_set_mtu(WOLFSSL_CTX* ctx, word16 newMtu) +int wolfSSL_is_static_memory(WOLFSSL* ssl, WOLFSSL_MEM_CONN_STATS* mem_stats) { - if (ctx == NULL || newMtu > MAX_RECORD_SIZE) + if (ssl == NULL) { return BAD_FUNC_ARG; + } + WOLFSSL_ENTER("wolfSSL_is_static_memory"); - ctx->dtlsMtuSz = newMtu; - return WOLFSSL_SUCCESS; +#ifndef WOLFSSL_STATIC_MEMORY_LEAN + /* fill out statistics if wanted and WOLFMEM_TRACK_STATS flag */ + if (mem_stats != NULL && ssl->heap != NULL) { + WOLFSSL_HEAP_HINT* hint = ((WOLFSSL_HEAP_HINT*)(ssl->heap)); + WOLFSSL_HEAP* heap = hint->memory; + if (heap->flag & WOLFMEM_TRACK_STATS && hint->stats != NULL) { + XMEMCPY(mem_stats, hint->stats, sizeof(WOLFSSL_MEM_CONN_STATS)); + } + } +#endif + + (void)mem_stats; + return (ssl->heap) ? 1 : 0; } -int wolfSSL_dtls_set_mtu(WOLFSSL* ssl, word16 newMtu) +int wolfSSL_CTX_is_static_memory(WOLFSSL_CTX* ctx, WOLFSSL_MEM_STATS* mem_stats) { - if (ssl == NULL) + if (ctx == NULL) { return BAD_FUNC_ARG; - - if (newMtu > MAX_RECORD_SIZE) { - ssl->error = BAD_FUNC_ARG; - return WOLFSSL_FAILURE; - } - - ssl->dtlsMtuSz = newMtu; - return WOLFSSL_SUCCESS; -} - -#ifdef OPENSSL_EXTRA -/* Maps to compatibility API SSL_set_mtu and is same as wolfSSL_dtls_set_mtu, - * but expects only success or failure returns. */ -int wolfSSL_set_mtu_compat(WOLFSSL* ssl, unsigned short mtu) -{ - if (wolfSSL_dtls_set_mtu(ssl, mtu) == WOLFSSL_SUCCESS) - return WOLFSSL_SUCCESS; - else - return WOLFSSL_FAILURE; -} -#endif /* OPENSSL_EXTRA */ - -#endif /* WOLFSSL_DTLS && (WOLFSSL_SCTP || WOLFSSL_DTLS_MTU) */ - -#ifdef WOLFSSL_SRTP - -static const WOLFSSL_SRTP_PROTECTION_PROFILE gSrtpProfiles[] = { - /* AES CCM 128, Salt:112-bits, Auth HMAC-SHA1 Tag: 80-bits - * (master_key:128bits + master_salt:112bits) * 2 = 480 bits (60) */ - {"SRTP_AES128_CM_SHA1_80", SRTP_AES128_CM_SHA1_80, - (((128 + 112) * 2) / 8) }, - /* AES CCM 128, Salt:112-bits, Auth HMAC-SHA1 Tag: 32-bits - * (master_key:128bits + master_salt:112bits) * 2 = 480 bits (60) */ - {"SRTP_AES128_CM_SHA1_32", SRTP_AES128_CM_SHA1_32, - (((128 + 112) * 2) / 8) }, - /* NULL Cipher, Salt:112-bits, Auth HMAC-SHA1 Tag 80-bits */ - {"SRTP_NULL_SHA1_80", SRTP_NULL_SHA1_80, ((112 * 2) / 8)}, - /* NULL Cipher, Salt:112-bits, Auth HMAC-SHA1 Tag 32-bits */ - {"SRTP_NULL_SHA1_32", SRTP_NULL_SHA1_32, ((112 * 2) / 8)}, - /* AES GCM 128, Salt: 96-bits, Auth GCM Tag 128-bits - * (master_key:128bits + master_salt:96bits) * 2 = 448 bits (56) */ - {"SRTP_AEAD_AES_128_GCM", SRTP_AEAD_AES_128_GCM, (((128 + 96) * 2) / 8) }, - /* AES GCM 256, Salt: 96-bits, Auth GCM Tag 128-bits - * (master_key:256bits + master_salt:96bits) * 2 = 704 bits (88) */ - {"SRTP_AEAD_AES_256_GCM", SRTP_AEAD_AES_256_GCM, (((256 + 96) * 2) / 8) }, -}; - -static const WOLFSSL_SRTP_PROTECTION_PROFILE* DtlsSrtpFindProfile( - const char* profile_str, word32 profile_str_len, unsigned long id) -{ - int i; - const WOLFSSL_SRTP_PROTECTION_PROFILE* profile = NULL; - for (i=0; - i<(int)(sizeof(gSrtpProfiles)/sizeof(WOLFSSL_SRTP_PROTECTION_PROFILE)); - i++) { - if (profile_str != NULL) { - word32 srtp_profile_len = (word32)XSTRLEN(gSrtpProfiles[i].name); - if (srtp_profile_len == profile_str_len && - XMEMCMP(gSrtpProfiles[i].name, profile_str, profile_str_len) - == 0) { - profile = &gSrtpProfiles[i]; - break; - } - } - else if (id != 0 && gSrtpProfiles[i].id == id) { - profile = &gSrtpProfiles[i]; - break; - } - } - return profile; -} - -/* profile_str: accepts ":" colon separated list of SRTP profiles */ -static int DtlsSrtpSelProfiles(word16* id, const char* profile_str) -{ - const WOLFSSL_SRTP_PROTECTION_PROFILE* profile; - const char *current, *next = NULL; - word32 length = 0, current_length; - - *id = 0; /* reset destination ID's */ - - if (profile_str == NULL) { - return WOLFSSL_FAILURE; } + WOLFSSL_ENTER("wolfSSL_CTX_is_static_memory"); - /* loop on end of line or colon ":" */ - next = profile_str; - length = (word32)XSTRLEN(profile_str); - do { - current = next; - next = XSTRSTR(current, ":"); - if (next) { - current_length = (word32)(next - current); - ++next; /* ++ needed to skip ':' */ - } else { - current_length = (word32)XSTRLEN(current); - } - if (current_length < length) - length = current_length; - profile = DtlsSrtpFindProfile(current, current_length, 0); - if (profile != NULL) { - *id |= (1 << profile->id); /* selected bit based on ID */ +#ifndef WOLFSSL_STATIC_MEMORY_LEAN + /* fill out statistics if wanted */ + if (mem_stats != NULL && ctx->heap != NULL) { + WOLFSSL_HEAP* heap = ((WOLFSSL_HEAP_HINT*)(ctx->heap))->memory; + if (wolfSSL_GetMemStats(heap, mem_stats) != 1) { + return MEMORY_E; } - } while (next != NULL); - return WOLFSSL_SUCCESS; -} - -/** - * @brief Set the SRTP protection profiles for DTLS. - * - * @param ctx Pointer to the WOLFSSL_CTX structure representing the SSL/TLS - * context. - * @param profile_str A colon-separated string of SRTP profile names. - * @return 0 on success to match OpenSSL - * @return 1 on error to match OpenSSL - */ -int wolfSSL_CTX_set_tlsext_use_srtp(WOLFSSL_CTX* ctx, const char* profile_str) -{ - int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); - if (ctx != NULL) { - ret = DtlsSrtpSelProfiles(&ctx->dtlsSrtpProfiles, profile_str); - } - - if (ret == WC_NO_ERR_TRACE(WOLFSSL_FAILURE)) { - ret = 1; - } else { - ret = 0; - } - - return ret; -} - -/** - * @brief Set the SRTP protection profiles for DTLS. - * - * @param ssl Pointer to the WOLFSSL structure representing the SSL/TLS - * session. - * @param profile_str A colon-separated string of SRTP profile names. - * @return 0 on success to match OpenSSL - * @return 1 on error to match OpenSSL - */ -int wolfSSL_set_tlsext_use_srtp(WOLFSSL* ssl, const char* profile_str) -{ - int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); - if (ssl != NULL) { - ret = DtlsSrtpSelProfiles(&ssl->dtlsSrtpProfiles, profile_str); - } - - if (ret == WC_NO_ERR_TRACE(WOLFSSL_FAILURE)) { - ret = 1; - } else { - ret = 0; - } - - return ret; -} - -const WOLFSSL_SRTP_PROTECTION_PROFILE* wolfSSL_get_selected_srtp_profile( - WOLFSSL* ssl) -{ - const WOLFSSL_SRTP_PROTECTION_PROFILE* profile = NULL; - if (ssl) { - profile = DtlsSrtpFindProfile(NULL, 0, ssl->dtlsSrtpId); } - return profile; -} -#ifndef NO_WOLFSSL_STUB -WOLF_STACK_OF(WOLFSSL_SRTP_PROTECTION_PROFILE)* wolfSSL_get_srtp_profiles( - WOLFSSL* ssl) -{ - /* Not yet implemented - should return list of available SRTP profiles - * ssl->dtlsSrtpProfiles */ - (void)ssl; - return NULL; -} #endif -#define DTLS_SRTP_KEYING_MATERIAL_LABEL "EXTRACTOR-dtls_srtp" - -int wolfSSL_export_dtls_srtp_keying_material(WOLFSSL* ssl, - unsigned char* out, size_t* olen) -{ - const WOLFSSL_SRTP_PROTECTION_PROFILE* profile = NULL; - - if (ssl == NULL || olen == NULL) { - return BAD_FUNC_ARG; - } - - profile = DtlsSrtpFindProfile(NULL, 0, ssl->dtlsSrtpId); - if (profile == NULL) { - WOLFSSL_MSG("Not using DTLS SRTP"); - return EXT_MISSING; - } - if (out == NULL) { - *olen = (size_t)profile->kdfBits; - return WC_NO_ERR_TRACE(LENGTH_ONLY_E); - } - - if (*olen < (size_t)profile->kdfBits) { - return BUFFER_E; - } - - return wolfSSL_export_keying_material(ssl, out, (size_t)profile->kdfBits, - DTLS_SRTP_KEYING_MATERIAL_LABEL, - XSTR_SIZEOF(DTLS_SRTP_KEYING_MATERIAL_LABEL), NULL, 0, 0); + (void)mem_stats; + return (ctx->heap) ? 1 : 0; } -#endif /* WOLFSSL_SRTP */ - - -#ifdef WOLFSSL_DTLS_DROP_STATS +#endif /* WOLFSSL_STATIC_MEMORY */ -int wolfSSL_dtls_get_drop_stats(WOLFSSL* ssl, - word32* macDropCount, word32* replayDropCount) +#ifndef NO_TLS +/* return max record layer size plaintext input size */ +int wolfSSL_GetMaxOutputSize(WOLFSSL* ssl) { - int ret; - - WOLFSSL_ENTER("wolfSSL_dtls_get_drop_stats"); + WOLFSSL_ENTER("wolfSSL_GetMaxOutputSize"); if (ssl == NULL) - ret = BAD_FUNC_ARG; - else { - ret = WOLFSSL_SUCCESS; - if (macDropCount != NULL) - *macDropCount = ssl->macDropCount; - if (replayDropCount != NULL) - *replayDropCount = ssl->replayDropCount; + return BAD_FUNC_ARG; + + if (ssl->options.handShakeState != HANDSHAKE_DONE) { + WOLFSSL_MSG("Handshake not complete yet"); + return BAD_FUNC_ARG; } - WOLFSSL_LEAVE("wolfSSL_dtls_get_drop_stats", ret); - return ret; + return min(OUTPUT_RECORD_SIZE, wolfssl_local_GetMaxPlaintextSize(ssl)); } -#endif /* WOLFSSL_DTLS_DROP_STATS */ - -#if defined(WOLFSSL_MULTICAST) - -int wolfSSL_CTX_mcast_set_member_id(WOLFSSL_CTX* ctx, word16 id) +/* return record layer size of plaintext input size */ +int wolfSSL_GetOutputSize(WOLFSSL* ssl, int inSz) { - int ret = 0; - - WOLFSSL_ENTER("wolfSSL_CTX_mcast_set_member_id"); - - if (ctx == NULL || id > WOLFSSL_MAX_8BIT) - ret = BAD_FUNC_ARG; - - if (ret == 0) { - ctx->haveEMS = 0; - ctx->haveMcast = 1; - ctx->mcastID = (byte)id; -#ifndef WOLFSSL_USER_IO - ctx->CBIORecv = EmbedReceiveFromMcast; -#endif /* WOLFSSL_USER_IO */ - - ret = WOLFSSL_SUCCESS; - } - WOLFSSL_LEAVE("wolfSSL_CTX_mcast_set_member_id", ret); - return ret; -} + int maxSize; -int wolfSSL_mcast_get_max_peers(void) -{ - return WOLFSSL_MULTICAST_PEERS; -} + WOLFSSL_ENTER("wolfSSL_GetOutputSize"); -#ifdef WOLFSSL_DTLS -static WC_INLINE word32 UpdateHighwaterMark(word32 cur, word32 first, - word32 second, word32 high) -{ - word32 newCur = 0; + if (inSz < 0) + return BAD_FUNC_ARG; - if (cur < first) - newCur = first; - else if (cur < second) - newCur = second; - else if (cur < high) - newCur = high; + maxSize = wolfSSL_GetMaxOutputSize(ssl); + if (maxSize < 0) + return maxSize; /* error */ + if (inSz > maxSize) + return INPUT_SIZE_E; - return newCur; + return wolfssl_local_GetRecordSize(ssl, inSz, 1); } -#endif /* WOLFSSL_DTLS */ -int wolfSSL_set_secret(WOLFSSL* ssl, word16 epoch, - const byte* preMasterSecret, word32 preMasterSz, - const byte* clientRandom, const byte* serverRandom, - const byte* suite) +static int wolfSSL_write_internal(WOLFSSL* ssl, const void* data, size_t sz) { int ret = 0; - WOLFSSL_ENTER("wolfSSL_set_secret"); - - if (ssl == NULL || preMasterSecret == NULL || - preMasterSz == 0 || preMasterSz > ENCRYPT_LEN || - clientRandom == NULL || serverRandom == NULL || suite == NULL) { + WOLFSSL_ENTER("wolfSSL_write"); - ret = BAD_FUNC_ARG; - } + if (ssl == NULL || data == NULL) + return BAD_FUNC_ARG; - if (ret == 0 && ssl->arrays->preMasterSecret == NULL) { - ssl->arrays->preMasterSz = ENCRYPT_LEN; - ssl->arrays->preMasterSecret = (byte*)XMALLOC(ENCRYPT_LEN, ssl->heap, - DYNAMIC_TYPE_SECRET); - if (ssl->arrays->preMasterSecret == NULL) { - ret = MEMORY_E; - } +#ifdef WOLFSSL_QUIC + if (WOLFSSL_IS_QUIC(ssl)) { + WOLFSSL_MSG("SSL_write() on QUIC not allowed"); + return BAD_FUNC_ARG; } +#endif - if (ret == 0) { - XMEMCPY(ssl->arrays->preMasterSecret, preMasterSecret, preMasterSz); - XMEMSET(ssl->arrays->preMasterSecret + preMasterSz, 0, - ENCRYPT_LEN - preMasterSz); - ssl->arrays->preMasterSz = preMasterSz; - XMEMCPY(ssl->arrays->clientRandom, clientRandom, RAN_LEN); - XMEMCPY(ssl->arrays->serverRandom, serverRandom, RAN_LEN); - ssl->options.cipherSuite0 = suite[0]; - ssl->options.cipherSuite = suite[1]; - - ret = SetCipherSpecs(ssl); +#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; - if (ret == 0) - ret = MakeTlsMasterSecret(ssl); - - if (ret == 0) { - ssl->keys.encryptionOn = 1; - ret = SetKeysSide(ssl, ENCRYPT_AND_DECRYPT_SIDE); - } + /* 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; + } + } + } - if (ret == 0) { - if (ssl->options.dtls) { - #ifdef WOLFSSL_DTLS - WOLFSSL_DTLS_PEERSEQ* peerSeq; - int i; - - ssl->keys.dtls_epoch = epoch; - for (i = 0, peerSeq = ssl->keys.peerSeq; - i < WOLFSSL_DTLS_PEERSEQ_SZ; - i++, peerSeq++) { - - peerSeq->nextEpoch = epoch; - peerSeq->prevSeq_lo = peerSeq->nextSeq_lo; - peerSeq->prevSeq_hi = peerSeq->nextSeq_hi; - peerSeq->nextSeq_lo = 0; - peerSeq->nextSeq_hi = 0; - XMEMCPY(peerSeq->prevWindow, peerSeq->window, DTLS_SEQ_SZ); - XMEMSET(peerSeq->window, 0, DTLS_SEQ_SZ); - peerSeq->highwaterMark = UpdateHighwaterMark(0, - ssl->ctx->mcastFirstSeq, - ssl->ctx->mcastSecondSeq, - ssl->ctx->mcastMaxSeq); + /* 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; } - #else - (void)epoch; - #endif +#endif /* WOLFSSL_DTLS13 */ } - FreeHandshakeResources(ssl); - ret = WOLFSSL_SUCCESS; - } - else { - if (ssl) - ssl->error = ret; - ret = WOLFSSL_FATAL_ERROR; - } - WOLFSSL_LEAVE("wolfSSL_set_secret", ret); - return ret; -} - +#endif /* WOLFSSL_TLS13 */ + wc_UnLockMutex(&ssl->dupWrite->dupMutex); -#ifdef WOLFSSL_DTLS - -int wolfSSL_mcast_peer_add(WOLFSSL* ssl, word16 peerId, int sub) -{ - WOLFSSL_DTLS_PEERSEQ* p = NULL; - int ret = WOLFSSL_SUCCESS; - int i; + 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; + } - WOLFSSL_ENTER("wolfSSL_mcast_peer_add"); - if (ssl == NULL || peerId > WOLFSSL_MAX_8BIT) - return BAD_FUNC_ARG; - if (!sub) { - /* Make sure it isn't already present, while keeping the first - * open spot. */ - for (i = 0; i < WOLFSSL_DTLS_PEERSEQ_SZ; i++) { - if (ssl->keys.peerSeq[i].peerId == INVALID_PEER_ID) - p = &ssl->keys.peerSeq[i]; - if (ssl->keys.peerSeq[i].peerId == peerId) { - WOLFSSL_MSG("Peer ID already in multicast peer list."); - p = NULL; +#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; } - - if (p != NULL) { - XMEMSET(p, 0, sizeof(WOLFSSL_DTLS_PEERSEQ)); - p->peerId = peerId; - p->highwaterMark = UpdateHighwaterMark(0, - ssl->ctx->mcastFirstSeq, - ssl->ctx->mcastSecondSeq, - ssl->ctx->mcastMaxSeq); - } - else { - WOLFSSL_MSG("No room in peer list."); - ret = WOLFSSL_FATAL_ERROR; - } +#endif /* WOLFSSL_TLS13 */ } - else { - for (i = 0; i < WOLFSSL_DTLS_PEERSEQ_SZ; i++) { - if (ssl->keys.peerSeq[i].peerId == peerId) - p = &ssl->keys.peerSeq[i]; - } +#endif - if (p != NULL) { - p->peerId = INVALID_PEER_ID; - } - else { - WOLFSSL_MSG("Peer not found in list."); - } +#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_mcast_peer_add", ret); - return ret; -} + WOLFSSL_LEAVE("wolfSSL_write", ret); + if (ret < 0) + return WOLFSSL_FATAL_ERROR; + else + return ret; +} -/* If peerId is in the list of peers and its last sequence number is non-zero, - * return 1, otherwise return 0. */ -int wolfSSL_mcast_peer_known(WOLFSSL* ssl, unsigned short peerId) +WOLFSSL_ABI +int wolfSSL_write(WOLFSSL* ssl, const void* data, int sz) { - int known = 0; - int i; - - WOLFSSL_ENTER("wolfSSL_mcast_peer_known"); + WOLFSSL_ENTER("wolfSSL_write"); - if (ssl == NULL || peerId > WOLFSSL_MAX_8BIT) { + if (sz < 0) return BAD_FUNC_ARG; - } - - for (i = 0; i < WOLFSSL_DTLS_PEERSEQ_SZ; i++) { - if (ssl->keys.peerSeq[i].peerId == peerId) { - if (ssl->keys.peerSeq[i].nextSeq_hi || - ssl->keys.peerSeq[i].nextSeq_lo) { - - known = 1; - } - break; - } - } - WOLFSSL_LEAVE("wolfSSL_mcast_peer_known", known); - return known; + return wolfSSL_write_internal(ssl, data, (size_t)sz); } - -int wolfSSL_CTX_mcast_set_highwater_cb(WOLFSSL_CTX* ctx, word32 maxSeq, - word32 first, word32 second, - CallbackMcastHighwater cb) +int wolfSSL_inject(WOLFSSL* ssl, const void* data, int sz) { - if (ctx == NULL || (second && first > second) || - first > maxSeq || second > maxSeq || cb == NULL) { + 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; } - ctx->mcastHwCb = cb; - ctx->mcastFirstSeq = first; - ctx->mcastSecondSeq = second; - ctx->mcastMaxSeq = maxSeq; + XMEMCPY(ssl->buffers.inputBuffer.buffer + ssl->buffers.inputBuffer.idx, + data, sz); + ssl->buffers.inputBuffer.length += sz; return WOLFSSL_SUCCESS; } -int wolfSSL_mcast_set_highwater_ctx(WOLFSSL* ssl, void* ctx) +int wolfSSL_write_ex(WOLFSSL* ssl, const void* data, size_t sz, size_t* wr) { - if (ssl == NULL || ctx == NULL) - return BAD_FUNC_ARG; - - ssl->mcastHwCbCtx = ctx; + int ret; - return WOLFSSL_SUCCESS; -} + if (wr != NULL) { + *wr = 0; + } -#endif /* WOLFSSL_DTLS */ + ret = wolfSSL_write_internal(ssl, data, sz); + if (ret >= 0) { + if (wr != NULL) { + *wr = (size_t)ret; + } -#endif /* WOLFSSL_MULTICAST */ + /* 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; +} -#endif /* WOLFSSL_LEANPSK */ -#ifndef NO_TLS -/* return underlying connect or accept, WOLFSSL_SUCCESS on ok */ -int wolfSSL_negotiate(WOLFSSL* ssl) +static int wolfSSL_read_internal(WOLFSSL* ssl, void* data, size_t sz, int peek) { - int err = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR); + int ret; - WOLFSSL_ENTER("wolfSSL_negotiate"); + WOLFSSL_ENTER("wolfSSL_read_internal"); - if (ssl == NULL) - return WOLFSSL_FATAL_ERROR; + if (ssl == NULL || data == NULL) + return BAD_FUNC_ARG; -#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); +#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. + */ -#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 + /* 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 - err = wolfSSL_connect(ssl); + +#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 - (void)ssl; +#ifdef HAVE_ERRNO_H + errno = 0; +#endif - WOLFSSL_LEAVE("wolfSSL_negotiate", err); + ret = ReceiveData(ssl, (byte*)data, sz, peek); - return err; -} -#endif /* !NO_TLS */ +#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_ABI -WC_RNG* wolfSSL_GetRNG(WOLFSSL* ssl) -{ - if (ssl) { - return ssl->rng; + WOLFSSL_MSG("Notifying write side of fatal read error"); + notifyErr = NotifyWriteSide(ssl, ssl->error); + if (notifyErr < 0) { + ret = ssl->error = notifyErr; + } + } } +#endif - return NULL; + WOLFSSL_LEAVE("wolfSSL_read_internal", ret); + + if (ret < 0) + return WOLFSSL_FATAL_ERROR; + else + return ret; } -#ifndef WOLFSSL_LEANPSK -/* object size based on build */ -int wolfSSL_GetObjectSize(void) +int wolfSSL_peek(WOLFSSL* ssl, void* data, int sz) { -#ifdef SHOW_SIZES - printf("sizeof suites = %lu\n", (unsigned long)sizeof(Suites)); - printf("sizeof ciphers(2) = %lu\n", (unsigned long)sizeof(Ciphers)); -#ifndef NO_RC4 - printf("\tsizeof arc4 = %lu\n", (unsigned long)sizeof(Arc4)); -#endif - printf("\tsizeof aes = %lu\n", (unsigned long)sizeof(Aes)); -#ifndef NO_DES3 - printf("\tsizeof des3 = %lu\n", (unsigned long)sizeof(Des3)); -#endif -#ifdef HAVE_CHACHA - printf("\tsizeof chacha = %lu\n", (unsigned long)sizeof(ChaCha)); -#endif -#ifdef WOLFSSL_SM4 - printf("\tsizeof sm4 = %lu\n", (unsigned long)sizeof(Sm4)); -#endif - printf("sizeof cipher specs = %lu\n", (unsigned long) - sizeof(CipherSpecs)); - printf("sizeof keys = %lu\n", (unsigned long)sizeof(Keys)); - printf("sizeof Hashes(2) = %lu\n", (unsigned long)sizeof(Hashes)); -#ifndef NO_MD5 - printf("\tsizeof MD5 = %lu\n", (unsigned long)sizeof(wc_Md5)); -#endif -#ifndef NO_SHA - printf("\tsizeof SHA = %lu\n", (unsigned long)sizeof(wc_Sha)); -#endif -#ifdef WOLFSSL_SHA224 - printf("\tsizeof SHA224 = %lu\n", (unsigned long)sizeof(wc_Sha224)); -#endif -#ifndef NO_SHA256 - printf("\tsizeof SHA256 = %lu\n", (unsigned long)sizeof(wc_Sha256)); -#endif -#ifdef WOLFSSL_SHA384 - printf("\tsizeof SHA384 = %lu\n", (unsigned long)sizeof(wc_Sha384)); -#endif -#ifdef WOLFSSL_SHA384 - printf("\tsizeof SHA512 = %lu\n", (unsigned long)sizeof(wc_Sha512)); -#endif -#ifdef WOLFSSL_SM3 - printf("\tsizeof sm3 = %lu\n", (unsigned long)sizeof(Sm3)); -#endif - printf("sizeof Buffers = %lu\n", (unsigned long)sizeof(Buffers)); - printf("sizeof Options = %lu\n", (unsigned long)sizeof(Options)); - printf("sizeof Arrays = %lu\n", (unsigned long)sizeof(Arrays)); -#ifndef NO_RSA - printf("sizeof RsaKey = %lu\n", (unsigned long)sizeof(RsaKey)); -#endif -#ifdef HAVE_ECC - printf("sizeof ecc_key = %lu\n", (unsigned long)sizeof(ecc_key)); -#endif - printf("sizeof WOLFSSL_CIPHER = %lu\n", (unsigned long) - sizeof(WOLFSSL_CIPHER)); - printf("sizeof WOLFSSL_SESSION = %lu\n", (unsigned long) - sizeof(WOLFSSL_SESSION)); - printf("sizeof WOLFSSL = %lu\n", (unsigned long)sizeof(WOLFSSL)); - printf("sizeof WOLFSSL_CTX = %lu\n", (unsigned long) - sizeof(WOLFSSL_CTX)); -#endif - - return sizeof(WOLFSSL); -} + WOLFSSL_ENTER("wolfSSL_peek"); -int wolfSSL_CTX_GetObjectSize(void) -{ - return sizeof(WOLFSSL_CTX); -} + if (sz < 0) + return BAD_FUNC_ARG; -int wolfSSL_METHOD_GetObjectSize(void) -{ - return sizeof(WOLFSSL_METHOD); + return wolfSSL_read_internal(ssl, data, (size_t)sz, TRUE); } -#endif -#ifdef WOLFSSL_STATIC_MEMORY - -int wolfSSL_CTX_load_static_memory(WOLFSSL_CTX** ctx, - wolfSSL_method_func method, unsigned char* buf, unsigned int sz, int flag, - int maxSz) +WOLFSSL_ABI +int wolfSSL_read(WOLFSSL* ssl, void* data, int sz) { - WOLFSSL_HEAP_HINT* hint = NULL; + WOLFSSL_ENTER("wolfSSL_read"); - if (ctx == NULL || buf == NULL) { + if (sz < 0) return BAD_FUNC_ARG; - } - if (*ctx == NULL && method == NULL) { + #ifdef OPENSSL_EXTRA + if (ssl == NULL) { return BAD_FUNC_ARG; } - - /* If there is a heap already, capture it in hint. */ - if (*ctx && (*ctx)->heap != NULL) { - hint = (*ctx)->heap; - } - - if (wc_LoadStaticMemory(&hint, buf, sz, flag, maxSz)) { - WOLFSSL_MSG("Error loading static memory"); - return WOLFSSL_FAILURE; - } - - if (*ctx) { - if ((*ctx)->heap == NULL) { - (*ctx)->heap = (void*)hint; - } - } - else { - /* create ctx if needed */ - *ctx = wolfSSL_CTX_new_ex(method(hint), hint); - if (*ctx == NULL) { - WOLFSSL_MSG("Error creating ctx"); - return WOLFSSL_FAILURE; - } + if (ssl->CBIS != NULL) { + ssl->CBIS(ssl, WOLFSSL_CB_READ, WOLFSSL_SUCCESS); + ssl->cbmode = WOLFSSL_CB_READ; } - - return WOLFSSL_SUCCESS; + #endif + return wolfSSL_read_internal(ssl, data, (size_t)sz, FALSE); } -int wolfSSL_is_static_memory(WOLFSSL* ssl, WOLFSSL_MEM_CONN_STATS* mem_stats) +/* 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; } - WOLFSSL_ENTER("wolfSSL_is_static_memory"); + 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); -#ifndef WOLFSSL_STATIC_MEMORY_LEAN - /* fill out statistics if wanted and WOLFMEM_TRACK_STATS flag */ - if (mem_stats != NULL && ssl->heap != NULL) { - WOLFSSL_HEAP_HINT* hint = ((WOLFSSL_HEAP_HINT*)(ssl->heap)); - WOLFSSL_HEAP* heap = hint->memory; - if (heap->flag & WOLFMEM_TRACK_STATS && hint->stats != NULL) { - XMEMCPY(mem_stats, hint->stats, sizeof(WOLFSSL_MEM_CONN_STATS)); - } + if (ret > 0 && rd != NULL) { + *rd = (size_t)ret; } -#endif - (void)mem_stats; - return (ssl->heap) ? 1 : 0; + return ret > 0 ? 1 : 0; } +#endif /* !NO_TLS */ -int wolfSSL_CTX_is_static_memory(WOLFSSL_CTX* ctx, WOLFSSL_MEM_STATS* mem_stats) +#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) { - if (ctx == NULL) { + if (ssl == NULL) return BAD_FUNC_ARG; - } - WOLFSSL_ENTER("wolfSSL_CTX_is_static_memory"); -#ifndef WOLFSSL_STATIC_MEMORY_LEAN - /* fill out statistics if wanted */ - if (mem_stats != NULL && ctx->heap != NULL) { - WOLFSSL_HEAP* heap = ((WOLFSSL_HEAP_HINT*)(ctx->heap))->memory; - if (wolfSSL_GetMemStats(heap, mem_stats) != 1) { - return MEMORY_E; - } - } -#endif + ssl->devId = devId; - (void)mem_stats; - return (ctx->heap) ? 1 : 0; + return WOLFSSL_SUCCESS; } -#endif /* WOLFSSL_STATIC_MEMORY */ - -#ifndef NO_TLS -/* return max record layer size plaintext input size */ -int wolfSSL_GetMaxOutputSize(WOLFSSL* ssl) +WOLFSSL_ABI +int wolfSSL_CTX_SetDevId(WOLFSSL_CTX* ctx, int devId) { - WOLFSSL_ENTER("wolfSSL_GetMaxOutputSize"); - - if (ssl == NULL) + if (ctx == NULL) return BAD_FUNC_ARG; - if (ssl->options.handShakeState != HANDSHAKE_DONE) { - WOLFSSL_MSG("Handshake not complete yet"); - return BAD_FUNC_ARG; - } + ctx->devId = devId; - return min(OUTPUT_RECORD_SIZE, wolfssl_local_GetMaxPlaintextSize(ssl)); + return WOLFSSL_SUCCESS; } - -/* return record layer size of plaintext input size */ -int wolfSSL_GetOutputSize(WOLFSSL* ssl, int inSz) +/* helpers to get device id and heap */ +WOLFSSL_ABI +int wolfSSL_CTX_GetDevId(WOLFSSL_CTX* ctx, WOLFSSL* ssl) { - int maxSize; - - WOLFSSL_ENTER("wolfSSL_GetOutputSize"); + 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 (inSz < 0) - return BAD_FUNC_ARG; - maxSize = wolfSSL_GetMaxOutputSize(ssl); - if (maxSize < 0) - return maxSize; /* error */ - if (inSz > maxSize) - return INPUT_SIZE_E; +#ifndef NO_TLS - return wolfssl_local_GetRecordSize(ssl, inSz, 1); -} +#ifndef WOLFSSL_LEANPSK -#ifdef HAVE_ECC -int wolfSSL_CTX_SetMinEccKey_Sz(WOLFSSL_CTX* ctx, short keySz) +int wolfSSL_send(WOLFSSL* ssl, const void* data, int sz, int flags) { - short keySzBytes; + int ret; + int oldFlags; + + WOLFSSL_ENTER("wolfSSL_send"); - WOLFSSL_ENTER("wolfSSL_CTX_SetMinEccKey_Sz"); - if (ctx == NULL || keySz < 0) { - WOLFSSL_MSG("Key size must be positive value or ctx was null"); + if (ssl == NULL || data == NULL || sz < 0) return BAD_FUNC_ARG; - } - if (keySz % 8 == 0) { - keySzBytes = keySz / 8; - } - else { - keySzBytes = (keySz / 8) + 1; - } + oldFlags = ssl->wflags; -#if defined(WOLFSSL_SYS_CRYPTO_POLICY) - if (crypto_policy.enabled) { - if (ctx->minEccKeySz > (keySzBytes)) { - return CRYPTO_POLICY_FORBIDDEN; - } - } -#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ + ssl->wflags = flags; + ret = wolfSSL_write(ssl, data, sz); + ssl->wflags = oldFlags; - ctx->minEccKeySz = keySzBytes; -#ifndef NO_CERTS - ctx->cm->minEccKeySz = keySzBytes; -#endif - return WOLFSSL_SUCCESS; + WOLFSSL_LEAVE("wolfSSL_send", ret); + + return ret; } -int wolfSSL_SetMinEccKey_Sz(WOLFSSL* ssl, short keySz) +int wolfSSL_recv(WOLFSSL* ssl, void* data, int sz, int flags) { - short keySzBytes; + int ret; + int oldFlags; - WOLFSSL_ENTER("wolfSSL_SetMinEccKey_Sz"); - if (ssl == NULL || keySz < 0) { - WOLFSSL_MSG("Key size must be positive value or ctx was null"); - return BAD_FUNC_ARG; - } + WOLFSSL_ENTER("wolfSSL_recv"); - if (keySz % 8 == 0) { - keySzBytes = keySz / 8; - } - else { - keySzBytes = (keySz / 8) + 1; - } + if (ssl == NULL || data == NULL || sz < 0) + return BAD_FUNC_ARG; -#if defined(WOLFSSL_SYS_CRYPTO_POLICY) - if (crypto_policy.enabled) { - if (ssl->options.minEccKeySz > (keySzBytes)) { - return CRYPTO_POLICY_FORBIDDEN; - } - } -#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ + oldFlags = ssl->rflags; - ssl->options.minEccKeySz = keySzBytes; - return WOLFSSL_SUCCESS; -} + ssl->rflags = flags; + ret = wolfSSL_read(ssl, data, sz); + ssl->rflags = oldFlags; -#endif /* HAVE_ECC */ + WOLFSSL_LEAVE("wolfSSL_recv", ret); -#ifndef NO_RSA -int wolfSSL_CTX_SetMinRsaKey_Sz(WOLFSSL_CTX* ctx, short keySz) + return ret; +} +#endif + +int wolfSSL_SendUserCanceled(WOLFSSL* ssl) { - if (ctx == NULL || keySz < 0 || keySz % 8 != 0) { - WOLFSSL_MSG("Key size must be divisible by 8 or ctx was null"); - return BAD_FUNC_ARG; - } + int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); + WOLFSSL_ENTER("wolfSSL_recv"); -#if defined(WOLFSSL_SYS_CRYPTO_POLICY) - if (crypto_policy.enabled) { - if (ctx->minRsaKeySz > (keySz / 8)) { - return CRYPTO_POLICY_FORBIDDEN; + if (ssl != NULL) { + ssl->error = SendAlert(ssl, alert_warning, user_canceled); + if (ssl->error < 0) { + WOLFSSL_ERROR(ssl->error); + } + else { + ret = wolfSSL_shutdown(ssl); } } -#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - ctx->minRsaKeySz = keySz / 8; - ctx->cm->minRsaKeySz = keySz / 8; - return WOLFSSL_SUCCESS; -} + WOLFSSL_LEAVE("wolfSSL_SendUserCanceled", ret); + return ret; +} -int wolfSSL_SetMinRsaKey_Sz(WOLFSSL* ssl, short keySz) +/* WOLFSSL_SUCCESS on ok */ +WOLFSSL_ABI +int wolfSSL_shutdown(WOLFSSL* ssl) { - if (ssl == NULL || keySz < 0 || keySz % 8 != 0) { - WOLFSSL_MSG("Key size must be divisible by 8 or ssl was null"); - return BAD_FUNC_ARG; - } + int ret = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR); + WOLFSSL_ENTER("wolfSSL_shutdown"); -#if defined(WOLFSSL_SYS_CRYPTO_POLICY) - if (crypto_policy.enabled) { - if (ssl->options.minRsaKeySz > (keySz / 8)) { - return CRYPTO_POLICY_FORBIDDEN; - } + if (ssl == NULL) + return WOLFSSL_FATAL_ERROR; + + if (ssl->options.quietShutdown) { + WOLFSSL_MSG("quiet shutdown, no close notify sent"); + ret = WOLFSSL_SUCCESS; } -#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ + else { - ssl->options.minRsaKeySz = keySz / 8; - return WOLFSSL_SUCCESS; -} -#endif /* !NO_RSA */ + /* 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; + } -#ifndef NO_DH + 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; + } + } + } -#if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \ - !defined(HAVE_SELFTEST) -/* Enables or disables the session's DH key prime test. */ -int wolfSSL_SetEnableDhKeyTest(WOLFSSL* ssl, int enable) -{ - WOLFSSL_ENTER("wolfSSL_SetEnableDhKeyTest"); + /* 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); - if (ssl == NULL) - return BAD_FUNC_ARG; + /* 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 (!enable) - ssl->options.dhDoKeyTest = 0; - else - ssl->options.dhDoKeyTest = 1; + if (ssl->error < 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } - WOLFSSL_LEAVE("wolfSSL_SetEnableDhKeyTest", WOLFSSL_SUCCESS); - return WOLFSSL_SUCCESS; -} + 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 -int wolfSSL_CTX_SetMinDhKey_Sz(WOLFSSL_CTX* ctx, word16 keySz_bits) -{ - if (ctx == NULL || keySz_bits > 16000 || keySz_bits % 8 != 0) - return BAD_FUNC_ARG; + /* wolfSSL_shutdown called again for bidirectional shutdown */ + if (ssl->options.sentNotify && !ssl->options.closeNotify) { + 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(WOLFSSL_SYS_CRYPTO_POLICY) - if (crypto_policy.enabled) { - if (ctx->minDhKeySz > (keySz_bits / 8)) { - return CRYPTO_POLICY_FORBIDDEN; +#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_SYS_CRYPTO_POLICY */ +#endif - ctx->minDhKeySz = keySz_bits / 8; - return WOLFSSL_SUCCESS; -} + WOLFSSL_LEAVE("wolfSSL_shutdown", ret); + return ret; +} +#endif /* !NO_TLS */ -int wolfSSL_SetMinDhKey_Sz(WOLFSSL* ssl, word16 keySz_bits) +/* get current error state value */ +int wolfSSL_state(WOLFSSL* ssl) { - if (ssl == NULL || keySz_bits > 16000 || keySz_bits % 8 != 0) + if (ssl == NULL) { return BAD_FUNC_ARG; - -#if defined(WOLFSSL_SYS_CRYPTO_POLICY) - if (crypto_policy.enabled) { - if (ssl->options.minDhKeySz > (keySz_bits / 8)) { - return CRYPTO_POLICY_FORBIDDEN; - } } -#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - ssl->options.minDhKeySz = keySz_bits / 8; - return WOLFSSL_SUCCESS; + return ssl->error; } -int wolfSSL_CTX_SetMaxDhKey_Sz(WOLFSSL_CTX* ctx, word16 keySz_bits) +WOLFSSL_ABI +int wolfSSL_get_error(WOLFSSL* ssl, int ret) { - if (ctx == NULL || keySz_bits > 16000 || keySz_bits % 8 != 0) + WOLFSSL_ENTER("wolfSSL_get_error"); + + if (ret > 0) + return WOLFSSL_ERROR_NONE; + if (ssl == NULL) return BAD_FUNC_ARG; -#if defined(WOLFSSL_SYS_CRYPTO_POLICY) - if (crypto_policy.enabled) { - if (ctx->minDhKeySz > (keySz_bits / 8)) { - return CRYPTO_POLICY_FORBIDDEN; - } - } -#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ + WOLFSSL_LEAVE("wolfSSL_get_error", ssl->error); - ctx->maxDhKeySz = keySz_bits / 8; - return WOLFSSL_SUCCESS; + /* 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; } -int wolfSSL_SetMaxDhKey_Sz(WOLFSSL* ssl, word16 keySz_bits) +/* retrieve alert history, WOLFSSL_SUCCESS on ok */ +int wolfSSL_get_alert_history(WOLFSSL* ssl, WOLFSSL_ALERT_HISTORY *h) { - if (ssl == NULL || keySz_bits > 16000 || keySz_bits % 8 != 0) - return BAD_FUNC_ARG; - -#if defined(WOLFSSL_SYS_CRYPTO_POLICY) - if (crypto_policy.enabled) { - if (ssl->options.minDhKeySz > (keySz_bits / 8)) { - return CRYPTO_POLICY_FORBIDDEN; - } + if (ssl && h) { + *h = ssl->alert_history; } -#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - - ssl->options.maxDhKeySz = keySz_bits / 8; return WOLFSSL_SUCCESS; } - -int wolfSSL_GetDhKey_Sz(WOLFSSL* ssl) +#ifdef OPENSSL_EXTRA +/* returns SSL_WRITING, SSL_READING or SSL_NOTHING */ +int wolfSSL_want(WOLFSSL* ssl) { - if (ssl == NULL) - return BAD_FUNC_ARG; - - return (ssl->options.dhKeySz * 8); + 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 -#endif /* !NO_DH */ - - -static int wolfSSL_write_internal(WOLFSSL* ssl, const void* data, size_t sz) +/* return TRUE if current error is want read */ +int wolfSSL_want_read(WOLFSSL* ssl) { - int ret = 0; + WOLFSSL_ENTER("wolfSSL_want_read"); + if (ssl->error == WC_NO_ERR_TRACE(WANT_READ)) + return 1; - WOLFSSL_ENTER("wolfSSL_write"); + return 0; +} - if (ssl == NULL || data == NULL) - return BAD_FUNC_ARG; +/* 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; -#ifdef WOLFSSL_QUIC - if (WOLFSSL_IS_QUIC(ssl)) { - WOLFSSL_MSG("SSL_write() on QUIC not allowed"); - return BAD_FUNC_ARG; - } -#endif + return 0; +} -#ifdef HAVE_WRITE_DUP - if (ssl->dupSide == READ_DUP_SIDE) { - WOLFSSL_MSG("Read dup side cannot write"); - return WRITE_DUP_WRITE_E; +char* wolfSSL_ERR_error_string(unsigned long errNumber, char* data) +{ + WOLFSSL_ENTER("wolfSSL_ERR_error_string"); + if (data) { + SetErrorString((int)errNumber, data); + return data; } - /* 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; - } - } - } + else { + static char tmp[WOLFSSL_MAX_ERROR_SZ] = {0}; + SetErrorString((int)errNumber, tmp); + return tmp; + } +} - /* 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; +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'; } + } +} -#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 +/* don't free temporary arrays at end of handshake */ +void wolfSSL_KeepArrays(WOLFSSL* ssl) +{ + if (ssl) + ssl->options.saveArrays = 1; +} -#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; +/* user doesn't need temporary arrays anymore, Free */ +void wolfSSL_FreeArrays(WOLFSSL* ssl) +{ + if (ssl && ssl->options.handShakeState == HANDSHAKE_DONE) { + ssl->options.saveArrays = 0; + FreeArrays(ssl, 1); } - #endif - ret = SendData(ssl, data, sz); +} - WOLFSSL_LEAVE("wolfSSL_write", ret); +/* 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) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; - if (ret < 0) - return WOLFSSL_FATAL_ERROR; - else - return ret; + ssl->options.keepResources = 1; + + return 0; } -WOLFSSL_ABI -int wolfSSL_write(WOLFSSL* ssl, const void* data, int sz) +/* 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) { - WOLFSSL_ENTER("wolfSSL_write"); - - if (sz < 0) + if (ssl == NULL) return BAD_FUNC_ARG; - return wolfSSL_write_internal(ssl, data, (size_t)sz); + FreeHandshakeResources(ssl); + + return 0; } -int wolfSSL_inject(WOLFSSL* ssl, const void* data, int sz) +/* 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 maxLength; - int usedLength; + if (ctx == NULL) + return BAD_FUNC_ARG; - WOLFSSL_ENTER("wolfSSL_inject"); + ctx->useClientOrder = 1; - if (ssl == NULL || data == NULL || sz <= 0) + return 0; +} + +/* 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) +{ + if (ssl == 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; + ssl->options.useClientOrder = 1; - return WOLFSSL_SUCCESS; + return 0; } -int wolfSSL_write_ex(WOLFSSL* ssl, const void* data, size_t sz, size_t* wr) +const byte* wolfSSL_GetMacSecret(WOLFSSL* ssl, int verify) { - int ret; - - if (wr != NULL) { - *wr = 0; - } - - ret = wolfSSL_write_internal(ssl, data, sz); - if (ret >= 0) { - if (wr != NULL) { - *wr = (size_t)ret; - } +#ifndef WOLFSSL_AEAD_ONLY + if (ssl == NULL) + return NULL; - /* 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; - } + 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 ret; + return NULL; +#endif } - -static int wolfSSL_read_internal(WOLFSSL* ssl, void* data, size_t sz, int peek) +int wolfSSL_GetSide(WOLFSSL* ssl) { - 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 (ssl) + return ssl->options.side; - if (ret < 0) - return WOLFSSL_FATAL_ERROR; - else - return ret; + return BAD_FUNC_ARG; } +#ifdef ATOMIC_USER -int wolfSSL_peek(WOLFSSL* ssl, void* data, int sz) +void wolfSSL_CTX_SetMacEncryptCb(WOLFSSL_CTX* ctx, CallbackMacEncrypt cb) { - WOLFSSL_ENTER("wolfSSL_peek"); - - if (sz < 0) - return BAD_FUNC_ARG; - - return wolfSSL_read_internal(ssl, data, (size_t)sz, TRUE); + if (ctx) + ctx->MacEncryptCb = cb; } -WOLFSSL_ABI -int wolfSSL_read(WOLFSSL* ssl, void* data, int sz) +void wolfSSL_SetMacEncryptCtx(WOLFSSL* ssl, void *ctx) { - 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); + if (ssl) + ssl->MacEncryptCtx = ctx; } -/* returns 0 on failure and 1 on read */ -int wolfSSL_read_ex(WOLFSSL* ssl, void* data, size_t sz, size_t* rd) +void* wolfSSL_GetMacEncryptCtx(WOLFSSL* ssl) { - 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; - } + if (ssl) + return ssl->MacEncryptCtx; - return ret > 0 ? 1 : 0; + return NULL; } -#ifdef WOLFSSL_MULTICAST -int wolfSSL_mcast_read(WOLFSSL* ssl, word16* id, void* data, int sz) +void wolfSSL_CTX_SetDecryptVerifyCb(WOLFSSL_CTX* ctx, CallbackDecryptVerify cb) { - int ret = 0; - - WOLFSSL_ENTER("wolfSSL_mcast_read"); + if (ctx) + ctx->DecryptVerifyCb = cb; +} - if ((ssl == NULL) || (sz < 0)) - return BAD_FUNC_ARG; - ret = wolfSSL_read_internal(ssl, data, (size_t)sz, FALSE); - if (ssl->options.dtls && ssl->options.haveMcast && id != NULL) - *id = ssl->keys.curPeerId; - return ret; +void wolfSSL_SetDecryptVerifyCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->DecryptVerifyCtx = ctx; } -#endif /* WOLFSSL_MULTICAST */ -#endif /* !NO_TLS */ -/* helpers to set the device id, WOLFSSL_SUCCESS on ok */ -WOLFSSL_ABI -int wolfSSL_SetDevId(WOLFSSL* ssl, int devId) +void* wolfSSL_GetDecryptVerifyCtx(WOLFSSL* ssl) { - if (ssl == NULL) - return BAD_FUNC_ARG; - - ssl->devId = devId; + if (ssl) + return ssl->DecryptVerifyCtx; - return WOLFSSL_SUCCESS; + return NULL; } -WOLFSSL_ABI -int wolfSSL_CTX_SetDevId(WOLFSSL_CTX* ctx, int devId) +#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 == NULL) - return BAD_FUNC_ARG; - - ctx->devId = devId; - - return WOLFSSL_SUCCESS; + if (ctx) + ctx->EncryptMacCb = cb; } -/* helpers to get device id and heap */ -WOLFSSL_ABI -int wolfSSL_CTX_GetDevId(WOLFSSL_CTX* ctx, WOLFSSL* ssl) +/** + * 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) { - int devId = INVALID_DEVID; - if (ssl != NULL) - devId = ssl->devId; - if (ctx != NULL && devId == INVALID_DEVID) - devId = ctx->devId; - return devId; + if (ssl) + ssl->EncryptMacCtx = ctx; } -void* wolfSSL_CTX_GetHeap(WOLFSSL_CTX* ctx, WOLFSSL* ssl) + +/** + * 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) { - void* heap = NULL; - if (ctx != NULL) - heap = ctx->heap; - else if (ssl != NULL) - heap = ssl->heap; - return heap; -} + if (ssl) + return ssl->EncryptMacCtx; + return NULL; +} -#ifndef NO_TLS -#ifdef HAVE_SNI -WOLFSSL_ABI -int wolfSSL_UseSNI(WOLFSSL* ssl, byte type, const void* data, word16 size) +/** + * 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 (ssl == NULL) - return BAD_FUNC_ARG; - - return TLSX_UseSNI(&ssl->extensions, type, data, size, ssl->heap); + if (ctx) + ctx->VerifyDecryptCb = cb; } +/** + * 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; +} -WOLFSSL_ABI -int wolfSSL_CTX_UseSNI(WOLFSSL_CTX* ctx, byte type, const void* data, - word16 size) +/** + * 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 (ctx == NULL) - return BAD_FUNC_ARG; + if (ssl) + return ssl->VerifyDecryptCtx; - return TLSX_UseSNI(&ctx->extensions, type, data, size, ctx->heap); + return NULL; } +#endif /* HAVE_ENCRYPT_THEN_MAC !WOLFSSL_AEAD_ONLY */ -#ifndef NO_WOLFSSL_SERVER -void wolfSSL_SNI_SetOptions(WOLFSSL* ssl, byte type, byte options) + +const byte* wolfSSL_GetClientWriteKey(WOLFSSL* ssl) { - if (ssl && ssl->extensions) - TLSX_SNI_SetOptions(ssl->extensions, type, options); + if (ssl) + return ssl->keys.client_write_key; + + return NULL; } -void wolfSSL_CTX_SNI_SetOptions(WOLFSSL_CTX* ctx, byte type, byte options) +const byte* wolfSSL_GetClientWriteIV(WOLFSSL* ssl) { - if (ctx && ctx->extensions) - TLSX_SNI_SetOptions(ctx->extensions, type, options); + if (ssl) + return ssl->keys.client_write_IV; + + return NULL; } -byte wolfSSL_SNI_Status(WOLFSSL* ssl, byte type) +const byte* wolfSSL_GetServerWriteKey(WOLFSSL* ssl) { - return TLSX_SNI_Status(ssl ? ssl->extensions : NULL, type); + if (ssl) + return ssl->keys.server_write_key; + + return NULL; } -word16 wolfSSL_SNI_GetRequest(WOLFSSL* ssl, byte type, void** data) +const byte* wolfSSL_GetServerWriteIV(WOLFSSL* ssl) { - if (data) - *data = NULL; + if (ssl) + return ssl->keys.server_write_IV; + + return NULL; +} - if (ssl && ssl->extensions) - return TLSX_SNI_GetRequest(ssl->extensions, type, data, 0); +int wolfSSL_GetKeySize(WOLFSSL* ssl) +{ + if (ssl) + return ssl->specs.key_size; - return 0; + return BAD_FUNC_ARG; } -int wolfSSL_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz, - byte type, byte* sni, word32* inOutSz) +int wolfSSL_GetIVSize(WOLFSSL* ssl) { - if (clientHello && helloSz > 0 && sni && inOutSz && *inOutSz > 0) - return TLSX_SNI_GetFromBuffer(clientHello, helloSz, type, sni, inOutSz); + if (ssl) + return ssl->specs.iv_size; return BAD_FUNC_ARG; } -#endif /* !NO_WOLFSSL_SERVER */ -#endif /* HAVE_SNI */ +int wolfSSL_GetBulkCipher(WOLFSSL* ssl) +{ + if (ssl) + return ssl->specs.bulk_cipher_algorithm; + return BAD_FUNC_ARG; +} -#ifdef HAVE_TRUSTED_CA -int wolfSSL_UseTrustedCA(WOLFSSL* ssl, byte type, - const byte* certId, word32 certIdSz) +int wolfSSL_GetCipherType(WOLFSSL* ssl) { if (ssl == NULL) return BAD_FUNC_ARG; - if (type == WOLFSSL_TRUSTED_CA_PRE_AGREED) { - if (certId != NULL || certIdSz != 0) - return BAD_FUNC_ARG; - } - else if (type == WOLFSSL_TRUSTED_CA_X509_NAME) { - if (certId == NULL || certIdSz == 0) - return BAD_FUNC_ARG; - } - #ifndef NO_SHA - else if (type == WOLFSSL_TRUSTED_CA_KEY_SHA1 || - type == WOLFSSL_TRUSTED_CA_CERT_SHA1) { - if (certId == NULL || certIdSz != WC_SHA_DIGEST_SIZE) - return BAD_FUNC_ARG; - } - #endif - else - 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; - return TLSX_UseTrustedCA(&ssl->extensions, - type, certId, certIdSz, ssl->heap); + return WOLFSSL_FATAL_ERROR; } -#endif /* HAVE_TRUSTED_CA */ - - -#ifdef HAVE_MAX_FRAGMENT -#ifndef NO_WOLFSSL_CLIENT -int wolfSSL_UseMaxFragment(WOLFSSL* ssl, byte mfl) +int wolfSSL_GetCipherBlockSize(WOLFSSL* ssl) { if (ssl == NULL) return BAD_FUNC_ARG; -#ifdef WOLFSSL_ALLOW_MAX_FRAGMENT_ADJUST - /* The following is a non-standard way to reconfigure the max packet size - post-handshake for wolfSSL_write/wolfSSL_read */ - if (ssl->options.handShakeState == HANDSHAKE_DONE) { - switch (mfl) { - case WOLFSSL_MFL_2_8 : ssl->max_fragment = 256; break; - case WOLFSSL_MFL_2_9 : ssl->max_fragment = 512; break; - case WOLFSSL_MFL_2_10: ssl->max_fragment = 1024; break; - case WOLFSSL_MFL_2_11: ssl->max_fragment = 2048; break; - case WOLFSSL_MFL_2_12: ssl->max_fragment = 4096; break; - case WOLFSSL_MFL_2_13: ssl->max_fragment = 8192; break; - default: ssl->max_fragment = MAX_RECORD_SIZE; break; - } - return WOLFSSL_SUCCESS; - } -#endif /* WOLFSSL_MAX_FRAGMENT_ADJUST */ - - /* This call sets the max fragment TLS extension, which gets sent to server. - The server_hello response is what sets the `ssl->max_fragment` in - TLSX_MFL_Parse */ - return TLSX_UseMaxFragment(&ssl->extensions, mfl, ssl->heap); + return ssl->specs.block_size; } -int wolfSSL_CTX_UseMaxFragment(WOLFSSL_CTX* ctx, byte mfl) +int wolfSSL_GetAeadMacSize(WOLFSSL* ssl) { - if (ctx == NULL) + if (ssl == NULL) return BAD_FUNC_ARG; - return TLSX_UseMaxFragment(&ctx->extensions, mfl, ctx->heap); + return ssl->specs.aead_mac_size; } -#endif /* NO_WOLFSSL_CLIENT */ -#endif /* HAVE_MAX_FRAGMENT */ - -#ifdef HAVE_TRUNCATED_HMAC -#ifndef NO_WOLFSSL_CLIENT -int wolfSSL_UseTruncatedHMAC(WOLFSSL* ssl) +int wolfSSL_IsTLSv1_1(WOLFSSL* ssl) { if (ssl == NULL) return BAD_FUNC_ARG; - return TLSX_UseTruncatedHMAC(&ssl->extensions, ssl->heap); + if (ssl->options.tls1_1) + return 1; + + return 0; } -int wolfSSL_CTX_UseTruncatedHMAC(WOLFSSL_CTX* ctx) -{ - if (ctx == NULL) - return BAD_FUNC_ARG; - return TLSX_UseTruncatedHMAC(&ctx->extensions, ctx->heap); -} - -#endif /* NO_WOLFSSL_CLIENT */ -#endif /* HAVE_TRUNCATED_HMAC */ - -/* Elliptic Curves */ -#if defined(HAVE_SUPPORTED_CURVES) - -static int isValidCurveGroup(word16 name) -{ - switch (name) { - case WOLFSSL_ECC_SECP160K1: - case WOLFSSL_ECC_SECP160R1: - case WOLFSSL_ECC_SECP160R2: - case WOLFSSL_ECC_SECP192K1: - case WOLFSSL_ECC_SECP192R1: - case WOLFSSL_ECC_SECP224K1: - case WOLFSSL_ECC_SECP224R1: - case WOLFSSL_ECC_SECP256K1: - case WOLFSSL_ECC_SECP256R1: - case WOLFSSL_ECC_SECP384R1: - case WOLFSSL_ECC_SECP521R1: - case WOLFSSL_ECC_BRAINPOOLP256R1: - case WOLFSSL_ECC_BRAINPOOLP384R1: - case WOLFSSL_ECC_BRAINPOOLP512R1: - case WOLFSSL_ECC_SM2P256V1: - case WOLFSSL_ECC_X25519: - case WOLFSSL_ECC_X448: - case WOLFSSL_ECC_BRAINPOOLP256R1TLS13: - case WOLFSSL_ECC_BRAINPOOLP384R1TLS13: - case WOLFSSL_ECC_BRAINPOOLP512R1TLS13: +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; - case WOLFSSL_FFDHE_2048: - case WOLFSSL_FFDHE_3072: - case WOLFSSL_FFDHE_4096: - case WOLFSSL_FFDHE_6144: - case WOLFSSL_FFDHE_8192: + return BAD_FUNC_ARG; +} -#ifdef WOLFSSL_HAVE_MLKEM -#ifndef WOLFSSL_NO_ML_KEM - #ifndef WOLFSSL_TLS_NO_MLKEM_STANDALONE - case WOLFSSL_ML_KEM_512: - case WOLFSSL_ML_KEM_768: - case WOLFSSL_ML_KEM_1024: - #endif /* !WOLFSSL_TLS_NO_MLKEM_STANDALONE */ - #ifdef WOLFSSL_PQC_HYBRIDS - case WOLFSSL_SECP384R1MLKEM1024: - case WOLFSSL_X25519MLKEM768: - case WOLFSSL_SECP256R1MLKEM768: - #endif /* WOLFSSL_PQC_HYBRIDS */ - #ifdef WOLFSSL_EXTRA_PQC_HYBRIDS - case WOLFSSL_SECP256R1MLKEM512: - case WOLFSSL_SECP384R1MLKEM768: - case WOLFSSL_SECP521R1MLKEM1024: - case WOLFSSL_X25519MLKEM512: - case WOLFSSL_X448MLKEM768: - #endif /* WOLFSSL_EXTRA_PQC_HYBRIDS */ -#endif /* !WOLFSSL_NO_ML_KEM */ -#ifdef WOLFSSL_MLKEM_KYBER - case WOLFSSL_KYBER_LEVEL1: - case WOLFSSL_KYBER_LEVEL3: - case WOLFSSL_KYBER_LEVEL5: - case WOLFSSL_P256_KYBER_LEVEL1: - case WOLFSSL_P384_KYBER_LEVEL3: - case WOLFSSL_P521_KYBER_LEVEL5: - case WOLFSSL_X25519_KYBER_LEVEL1: - case WOLFSSL_X448_KYBER_LEVEL3: - case WOLFSSL_X25519_KYBER_LEVEL3: - case WOLFSSL_P256_KYBER_LEVEL3: -#endif /* WOLFSSL_MLKEM_KYBER */ -#endif - return 1; +#ifdef WORD64_AVAILABLE +int wolfSSL_GetPeerSequenceNumber(WOLFSSL* ssl, word64 *seq) +{ + if ((ssl == NULL) || (seq == NULL)) + return BAD_FUNC_ARG; - default: - return 0; - } + *seq = ((word64)ssl->keys.peer_sequence_number_hi << 32) | + ssl->keys.peer_sequence_number_lo; + return !(*seq); } -int wolfSSL_UseSupportedCurve(WOLFSSL* ssl, word16 name) +int wolfSSL_GetSequenceNumber(WOLFSSL* ssl, word64 *seq) { - if (ssl == NULL || !isValidCurveGroup(name)) + if ((ssl == NULL) || (seq == NULL)) return BAD_FUNC_ARG; - ssl->options.userCurves = 1; -#if defined(NO_TLS) - return WOLFSSL_FAILURE; -#else - return TLSX_UseSupportedCurve(&ssl->extensions, name, ssl->heap); -#endif /* NO_TLS */ + *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) -int wolfSSL_CTX_UseSupportedCurve(WOLFSSL_CTX* ctx, word16 name) +void wolfSSL_ERR_print_errors_fp(XFILE fp, int err) { - if (ctx == NULL || !isValidCurveGroup(name)) - return BAD_FUNC_ARG; + char data[WOLFSSL_MAX_ERROR_SZ + 1]; - ctx->userCurves = 1; -#if defined(NO_TLS) - return WOLFSSL_FAILURE; -#else - return TLSX_UseSupportedCurve(&ctx->extensions, name, ctx->heap); -#endif /* NO_TLS */ + 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) -int wolfSSL_CTX_set1_groups(WOLFSSL_CTX* ctx, int* groups, - int count) +#if defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE) +void wolfSSL_ERR_dump_errors_fp(XFILE fp) { - int i; - int _groups[WOLFSSL_MAX_GROUP_COUNT]; - WOLFSSL_ENTER("wolfSSL_CTX_set1_groups"); - if (count == 0) { - WOLFSSL_MSG("Group count is zero"); - return WOLFSSL_FAILURE; - } - if (count > WOLFSSL_MAX_GROUP_COUNT) { - WOLFSSL_MSG("Group count exceeds maximum"); - return WOLFSSL_FAILURE; - } - for (i = 0; i < count; i++) { - if (isValidCurveGroup((word16)groups[i])) { - _groups[i] = groups[i]; - } -#ifdef HAVE_ECC - else { - /* groups may be populated with curve NIDs */ - int oid = (int)nid2oid(groups[i], oidCurveType); - int name = (int)GetCurveByOID(oid); - if (name == 0) { - WOLFSSL_MSG("Invalid group name"); - return WOLFSSL_FAILURE; - } - _groups[i] = name; - } -#else - else { - WOLFSSL_MSG("Invalid group name"); - return WOLFSSL_FAILURE; - } -#endif - } - return wolfSSL_CTX_set_groups(ctx, _groups, count) == WOLFSSL_SUCCESS ? - WOLFSSL_SUCCESS : WOLFSSL_FAILURE; + wc_ERR_print_errors_fp(fp); } -int wolfSSL_set1_groups(WOLFSSL* ssl, int* groups, int count) +void wolfSSL_ERR_print_errors_cb (int (*cb)(const char *str, size_t len, + void *u), void *u) { - int i; - int _groups[WOLFSSL_MAX_GROUP_COUNT]; - WOLFSSL_ENTER("wolfSSL_CTX_set1_groups"); - if (count == 0) { - WOLFSSL_MSG("Group count is zero"); - return WOLFSSL_FAILURE; - } - if (count > WOLFSSL_MAX_GROUP_COUNT) { - WOLFSSL_MSG("Group count exceeds maximum"); - return WOLFSSL_FAILURE; - } - for (i = 0; i < count; i++) { - if (isValidCurveGroup((word16)groups[i])) { - _groups[i] = groups[i]; - } -#ifdef HAVE_ECC - else { - /* groups may be populated with curve NIDs */ - int oid = (int)nid2oid(groups[i], oidCurveType); - int name = (int)GetCurveByOID(oid); - if (name == 0) { - WOLFSSL_MSG("Invalid group name"); - return WOLFSSL_FAILURE; - } - _groups[i] = name; - } -#else - else { - WOLFSSL_MSG("Invalid group name"); - return WOLFSSL_FAILURE; - } -#endif - } - return wolfSSL_set_groups(ssl, _groups, count) == WOLFSSL_SUCCESS ? - WOLFSSL_SUCCESS : WOLFSSL_FAILURE; + wc_ERR_print_errors_cb(cb, u); } -#endif /* OPENSSL_EXTRA */ -#endif /* HAVE_SUPPORTED_CURVES */ - -/* Application-Layer Protocol Negotiation */ -#ifdef HAVE_ALPN +#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_UseALPN(WOLFSSL* ssl, char *protocol_name_list, - word32 protocol_name_listSz, byte options) +int wolfSSL_pending(WOLFSSL* ssl) { - char *list, *ptr = NULL, **token; - word16 len; - int idx = 0; - int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); - - WOLFSSL_ENTER("wolfSSL_UseALPN"); - - if (ssl == NULL || protocol_name_list == NULL) - return BAD_FUNC_ARG; - - if (protocol_name_listSz > (WOLFSSL_MAX_ALPN_NUMBER * - WOLFSSL_MAX_ALPN_PROTO_NAME_LEN + - WOLFSSL_MAX_ALPN_NUMBER)) { - WOLFSSL_MSG("Invalid arguments, protocol name list too long"); - return BAD_FUNC_ARG; - } - - if (!(options & WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) && - !(options & WOLFSSL_ALPN_FAILED_ON_MISMATCH)) { - WOLFSSL_MSG("Invalid arguments, options not supported"); - return BAD_FUNC_ARG; - } - - - list = (char *)XMALLOC(protocol_name_listSz+1, ssl->heap, - DYNAMIC_TYPE_ALPN); - if (list == NULL) { - WOLFSSL_MSG("Memory failure"); - return MEMORY_ERROR; - } - - token = (char **)XMALLOC(sizeof(char *) * (WOLFSSL_MAX_ALPN_NUMBER+1), - ssl->heap, DYNAMIC_TYPE_ALPN); - if (token == NULL) { - XFREE(list, ssl->heap, DYNAMIC_TYPE_ALPN); - WOLFSSL_MSG("Memory failure"); - return MEMORY_ERROR; - } - XMEMSET(token, 0, sizeof(char *) * (WOLFSSL_MAX_ALPN_NUMBER+1)); - - XSTRNCPY(list, protocol_name_list, protocol_name_listSz); - list[protocol_name_listSz] = '\0'; - - /* read all protocol name from the list */ - token[idx] = XSTRTOK(list, ",", &ptr); - while (idx < WOLFSSL_MAX_ALPN_NUMBER && token[idx] != NULL) - token[++idx] = XSTRTOK(NULL, ",", &ptr); - - /* add protocol name list in the TLS extension in reverse order */ - while ((idx--) > 0) { - len = (word16)XSTRLEN(token[idx]); - - ret = TLSX_UseALPN(&ssl->extensions, token[idx], len, options, - ssl->heap); - if (ret != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("TLSX_UseALPN failure"); - break; - } - } - - XFREE(token, ssl->heap, DYNAMIC_TYPE_ALPN); - XFREE(list, ssl->heap, DYNAMIC_TYPE_ALPN); + WOLFSSL_ENTER("wolfSSL_pending"); + if (ssl == NULL) + return WOLFSSL_FAILURE; - return ret; + return (int)ssl->buffers.clearOutputBuffer.length; } -int wolfSSL_ALPN_GetProtocol(WOLFSSL* ssl, char **protocol_name, word16 *size) +int wolfSSL_has_pending(const WOLFSSL* ssl) { - return TLSX_ALPN_GetRequest(ssl ? ssl->extensions : NULL, - (void **)protocol_name, size); + WOLFSSL_ENTER("wolfSSL_has_pending"); + if (ssl == NULL) + return WOLFSSL_FAILURE; + + return ssl->buffers.clearOutputBuffer.length > 0; } -int wolfSSL_ALPN_GetPeerProtocol(WOLFSSL* ssl, char **list, word16 *listSz) +#ifndef WOLFSSL_LEANPSK +/* turn on handshake group messages for context */ +int wolfSSL_CTX_set_group_messages(WOLFSSL_CTX* ctx) { - int i, len; - char *p; - byte *s; - - if (ssl == NULL || list == NULL || listSz == NULL) - return BAD_FUNC_ARG; + if (ctx == NULL) + return BAD_FUNC_ARG; - if (ssl->alpn_peer_requested == NULL - || ssl->alpn_peer_requested_length == 0) - return BUFFER_ERROR; - - /* ssl->alpn_peer_requested are the original bytes sent in a ClientHello, - * formatted as (len-byte chars+)+. To turn n protocols into a - * comma-separated C string, one needs (n-1) commas and a final 0 byte - * which has the same length as the original. - * The returned length is the strlen() of the C string, so -1 of that. */ - *listSz = ssl->alpn_peer_requested_length-1; - *list = p = (char *)XMALLOC(ssl->alpn_peer_requested_length, ssl->heap, - DYNAMIC_TYPE_TLSX); - if (p == NULL) - return MEMORY_ERROR; - - for (i = 0, s = ssl->alpn_peer_requested; - i < ssl->alpn_peer_requested_length; - p += len, i += len) - { - if (i) - *p++ = ','; - len = s[i++]; - /* guard against bad length bytes. */ - if (i + len > ssl->alpn_peer_requested_length) { - XFREE(*list, ssl->heap, DYNAMIC_TYPE_TLSX); - *list = NULL; - return WOLFSSL_FAILURE; - } - XMEMCPY(p, s + i, (size_t)len); - } - *p = 0; + ctx->groupMessages = 1; return WOLFSSL_SUCCESS; } - -/* used to free memory allocated by wolfSSL_ALPN_GetPeerProtocol */ -int wolfSSL_ALPN_FreePeerProtocol(WOLFSSL* ssl, char **list) +int wolfSSL_CTX_clear_group_messages(WOLFSSL_CTX* ctx) { - if (ssl == NULL) { - return BAD_FUNC_ARG; - } + if (ctx == NULL) + return BAD_FUNC_ARG; - XFREE(*list, ssl->heap, DYNAMIC_TYPE_TLSX); - *list = NULL; + ctx->groupMessages = 0; return WOLFSSL_SUCCESS; } +#endif -#endif /* HAVE_ALPN */ - -/* Secure Renegotiation */ -#ifdef HAVE_SERVER_RENEGOTIATION_INFO -/* user is forcing ability to use secure renegotiation, we discourage it */ -int wolfSSL_UseSecureRenegotiation(WOLFSSL* ssl) +#if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS) +/* connect enough to get peer cert chain */ +int wolfSSL_connect_cert(WOLFSSL* ssl) { - int ret = WC_NO_ERR_TRACE(BAD_FUNC_ARG); -#if defined(NO_TLS) - (void)ssl; -#else - if (ssl) - ret = TLSX_UseSecureRenegotiation(&ssl->extensions, ssl->heap); - else - ret = BAD_FUNC_ARG; + int ret; - if (ret == WOLFSSL_SUCCESS) { - TLSX* extension = TLSX_Find(ssl->extensions, TLSX_RENEGOTIATION_INFO); + if (ssl == NULL) + return WOLFSSL_FAILURE; + + ssl->options.certOnly = 1; + ret = wolfSSL_connect(ssl); + ssl->options.certOnly = 0; - if (extension) - ssl->secure_renegotiation = (SecureRenegotiation*)extension->data; - } -#endif /* !NO_TLS */ return ret; } +#endif + -int wolfSSL_CTX_UseSecureRenegotiation(WOLFSSL_CTX* ctx) +#ifndef WOLFSSL_LEANPSK +/* turn on handshake group messages for ssl object */ +int wolfSSL_set_group_messages(WOLFSSL* ssl) { - if (ctx == NULL) - return BAD_FUNC_ARG; + if (ssl == NULL) + return BAD_FUNC_ARG; + + ssl->options.groupMessages = 1; - ctx->useSecureReneg = 1; return WOLFSSL_SUCCESS; } -#ifdef HAVE_SECURE_RENEGOTIATION -/* do a secure renegotiation handshake, user forced, we discourage */ -static int _Rehandshake(WOLFSSL* ssl) +int wolfSSL_clear_group_messages(WOLFSSL* ssl) { - int ret; - if (ssl == NULL) - return BAD_FUNC_ARG; - - if (IsAtLeastTLSv1_3(ssl->version)) { - WOLFSSL_MSG("Secure Renegotiation not supported in TLS 1.3"); - return SECURE_RENEGOTIATION_E; - } - - if (ssl->secure_renegotiation == NULL) { - WOLFSSL_MSG("Secure Renegotiation not forced on by user"); - return SECURE_RENEGOTIATION_E; - } - - if (ssl->secure_renegotiation->enabled == 0) { - WOLFSSL_MSG("Secure Renegotiation not enabled at extension level"); - return SECURE_RENEGOTIATION_E; - } - -#ifdef WOLFSSL_DTLS - if (ssl->options.dtls && ssl->keys.dtls_epoch == 0xFFFF) { - WOLFSSL_MSG("Secure Renegotiation not allowed. Epoch would wrap"); - return SECURE_RENEGOTIATION_E; - } -#endif - - /* If the client started the renegotiation, the server will already - * have processed the client's hello. */ - if (ssl->options.side != WOLFSSL_SERVER_END || - ssl->options.acceptState != ACCEPT_FIRST_REPLY_DONE) { - - if (ssl->options.handShakeState != HANDSHAKE_DONE) { - if (!ssl->options.handShakeDone) { - WOLFSSL_MSG("Can't renegotiate until initial " - "handshake complete"); - return SECURE_RENEGOTIATION_E; - } - else { - WOLFSSL_MSG("Renegotiation already started. " - "Moving it forward."); - ret = wolfSSL_negotiate(ssl); - if (ret == WOLFSSL_SUCCESS) - ssl->secure_rene_count++; - return ret; - } - } - - /* reset handshake states */ - ssl->options.sendVerify = 0; - ssl->options.serverState = NULL_STATE; - ssl->options.clientState = NULL_STATE; - ssl->options.connectState = CONNECT_BEGIN; - ssl->options.acceptState = ACCEPT_BEGIN_RENEG; - ssl->options.handShakeState = NULL_STATE; - ssl->options.processReply = 0; /* TODO, move states in internal.h */ - - XMEMSET(&ssl->msgsReceived, 0, sizeof(ssl->msgsReceived)); - - ssl->secure_renegotiation->cache_status = SCR_CACHE_NEEDED; + return BAD_FUNC_ARG; -#if !defined(NO_WOLFSSL_SERVER) && !defined(WOLFSSL_NO_TLS12) - if (ssl->options.side == WOLFSSL_SERVER_END) { - ret = SendHelloRequest(ssl); - if (ret != 0) { - ssl->error = ret; - return WOLFSSL_FATAL_ERROR; - } - } -#endif /* !NO_WOLFSSL_SERVER && !WOLFSSL_NO_TLS12 */ + ssl->options.groupMessages = 0; - ret = InitHandshakeHashes(ssl); - if (ret != 0) { - ssl->error = ret; - return WOLFSSL_FATAL_ERROR; - } - } - ret = wolfSSL_negotiate(ssl); - if (ret == WOLFSSL_SUCCESS) - ssl->secure_rene_count++; - return ret; + return WOLFSSL_SUCCESS; } - -/* do a secure renegotiation handshake, user forced, we discourage */ -int wolfSSL_Rehandshake(WOLFSSL* ssl) +/* make minVersion the internal equivalent SSL version */ +static int SetMinVersionHelper(byte* minVersion, int version) { - int ret; - WOLFSSL_ENTER("wolfSSL_Rehandshake"); - - if (ssl == NULL) - return WOLFSSL_FAILURE; + (void)minVersion; -#ifdef HAVE_SESSION_TICKET - ret = WOLFSSL_SUCCESS; + switch (version) { +#if defined(WOLFSSL_ALLOW_SSLV3) && !defined(NO_OLD_TLS) + case WOLFSSL_SSLV3: + *minVersion = SSLv3_MINOR; + break; #endif - if (ssl->options.side == WOLFSSL_SERVER_END) { - /* Reset option to send certificate verify. */ - ssl->options.sendVerify = 0; - /* Reset resuming flag to do full secure handshake. */ - ssl->options.resuming = 0; - } - else { - /* Reset resuming flag to do full secure handshake. */ - ssl->options.resuming = 0; - #if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_CLIENT) - /* Clearing the ticket. */ - ret = wolfSSL_UseSessionTicket(ssl); +#ifndef NO_TLS + #ifndef NO_OLD_TLS + #ifdef WOLFSSL_ALLOW_TLSV10 + case WOLFSSL_TLSV1: + *minVersion = TLSv1_MINOR; + break; #endif - } - /* CLIENT/SERVER: Reset peer authentication for full secure handshake. */ - ssl->options.peerAuthGood = 0; -#ifdef HAVE_SESSION_TICKET - if (ret == WOLFSSL_SUCCESS) + 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 - ret = _Rehandshake(ssl); + #ifdef WOLFSSL_TLS13 + case WOLFSSL_TLSV1_3: + *minVersion = TLSv1_3_MINOR; + break; + #endif - return ret; -} +#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; +} -#ifndef NO_WOLFSSL_CLIENT -/* do a secure resumption handshake, user forced, we discourage */ -int wolfSSL_SecureResume(WOLFSSL* ssl) +/* Set minimum downgrade version allowed, WOLFSSL_SUCCESS on ok */ +WOLFSSL_ABI +int wolfSSL_CTX_SetMinVersion(WOLFSSL_CTX* ctx, int version) { - WOLFSSL_ENTER("wolfSSL_SecureResume"); + WOLFSSL_ENTER("wolfSSL_CTX_SetMinVersion"); - if (ssl == NULL) + if (ctx == NULL) { + WOLFSSL_MSG("Bad function argument"); return BAD_FUNC_ARG; - - if (ssl->options.side == WOLFSSL_SERVER_END) { - ssl->error = SIDE_ERROR; - return WOLFSSL_FATAL_ERROR; } - return _Rehandshake(ssl); -} - -#endif /* NO_WOLFSSL_CLIENT */ - -#endif /* HAVE_SECURE_RENEGOTIATION */ - -long wolfSSL_SSL_get_secure_renegotiation_support(WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_SSL_get_secure_renegotiation_support"); +#if defined(WOLFSSL_SYS_CRYPTO_POLICY) + if (crypto_policy.enabled) { + return CRYPTO_POLICY_FORBIDDEN; + } +#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - if (!ssl || !ssl->secure_renegotiation) - return WOLFSSL_FAILURE; - return ssl->secure_renegotiation->enabled; + return SetMinVersionHelper(&ctx->minDowngrade, version); } -#endif /* HAVE_SECURE_RENEGOTIATION_INFO */ -#if !defined(NO_WOLFSSL_CLIENT) && !defined(WOLFSSL_NO_TLS12) && \ - defined(WOLFSSL_HARDEN_TLS) && !defined(WOLFSSL_HARDEN_TLS_NO_SCR_CHECK) -WOLFSSL_API int wolfSSL_get_scr_check_enabled(const WOLFSSL* ssl) +/* Set minimum downgrade version allowed, WOLFSSL_SUCCESS on ok */ +int wolfSSL_SetMinVersion(WOLFSSL* ssl, int version) { - WOLFSSL_ENTER("wolfSSL_get_scr_check_enabled"); + WOLFSSL_ENTER("wolfSSL_SetMinVersion"); - if (ssl == NULL) + 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 ssl->scr_check_enabled; + return SetMinVersionHelper(&ssl->options.minDowngrade, version); } -WOLFSSL_API int wolfSSL_set_scr_check_enabled(WOLFSSL* ssl, byte enabled) -{ - WOLFSSL_ENTER("wolfSSL_set_scr_check_enabled"); +/* Function to get version as WOLFSSL_ enum value for wolfSSL_SetVersion */ +int wolfSSL_GetVersion(const WOLFSSL* ssl) +{ if (ssl == NULL) return BAD_FUNC_ARG; - ssl->scr_check_enabled = !!enabled; - return WOLFSSL_SUCCESS; -} -#endif - -#if defined(HAVE_SESSION_TICKET) -/* Session Ticket */ - -#if !defined(NO_WOLFSSL_SERVER) -int wolfSSL_CTX_NoTicketTLSv12(WOLFSSL_CTX* ctx) -{ - if (ctx == NULL) - return BAD_FUNC_ARG; - - ctx->noTicketTls12 = 1; + if (ssl->version.major == SSLv3_MAJOR) { + switch (ssl->version.minor) { + case SSLv3_MINOR : + return WOLFSSL_SSLV3; + case TLSv1_MINOR : + return WOLFSSL_TLSV1; + case TLSv1_1_MINOR : + return WOLFSSL_TLSV1_1; + case TLSv1_2_MINOR : + return WOLFSSL_TLSV1_2; + case TLSv1_3_MINOR : + return WOLFSSL_TLSV1_3; + default: + break; + } + } +#ifdef WOLFSSL_DTLS + if (ssl->version.major == DTLS_MAJOR) { + switch (ssl->version.minor) { + case DTLS_MINOR : + return WOLFSSL_DTLSV1; + case DTLSv1_2_MINOR : + return WOLFSSL_DTLSV1_2; + case DTLSv1_3_MINOR : + return WOLFSSL_DTLSV1_3; + default: + break; + } + } +#endif /* WOLFSSL_DTLS */ - return WOLFSSL_SUCCESS; + return VERSION_ERROR; } -int wolfSSL_NoTicketTLSv12(WOLFSSL* ssl) +int wolfSSL_SetVersion(WOLFSSL* ssl, int version) { - if (ssl == NULL) - return BAD_FUNC_ARG; - - ssl->options.noTicketTls12 = 1; + word16 haveRSA = 1; + word16 havePSK = 0; + int keySz = 0; - return WOLFSSL_SUCCESS; -} + WOLFSSL_ENTER("wolfSSL_SetVersion"); -/* WOLFSSL_SUCCESS on ok */ -int wolfSSL_CTX_set_TicketEncCb(WOLFSSL_CTX* ctx, SessionTicketEncCb cb) -{ - if (ctx == NULL) + if (ssl == NULL) { + WOLFSSL_MSG("Bad function argument"); return BAD_FUNC_ARG; + } - ctx->ticketEncCb = cb; - - return WOLFSSL_SUCCESS; -} + switch (version) { +#if defined(WOLFSSL_ALLOW_SSLV3) && !defined(NO_OLD_TLS) + case WOLFSSL_SSLV3: + ssl->version = MakeSSLv3(); + break; +#endif -/* set hint interval, WOLFSSL_SUCCESS on ok */ -int wolfSSL_CTX_set_TicketHint(WOLFSSL_CTX* ctx, int hint) -{ - if (ctx == NULL) - return BAD_FUNC_ARG; +#ifndef NO_TLS + #ifndef NO_OLD_TLS + #ifdef WOLFSSL_ALLOW_TLSV10 + case WOLFSSL_TLSV1: + ssl->version = MakeTLSv1(); + break; + #endif - /* RFC8446 Section 4.6.1: Servers MUST NOT use any value greater than - * 604800 seconds (7 days). */ - if (hint < 0 || hint > 604800) - return BAD_FUNC_ARG; + case WOLFSSL_TLSV1_1: + ssl->version = MakeTLSv1_1(); + break; + #endif + #ifndef WOLFSSL_NO_TLS12 + case WOLFSSL_TLSV1_2: + ssl->version = MakeTLSv1_2(); + break; + #endif - ctx->ticketHint = hint; + #ifdef WOLFSSL_TLS13 + case WOLFSSL_TLSV1_3: + ssl->version = MakeTLSv1_3(); + break; + #endif /* WOLFSSL_TLS13 */ +#endif - return WOLFSSL_SUCCESS; -} + default: + WOLFSSL_MSG("Bad function argument"); + return BAD_FUNC_ARG; + } -/* set user context, WOLFSSL_SUCCESS on ok */ -int wolfSSL_CTX_set_TicketEncCtx(WOLFSSL_CTX* ctx, void* userCtx) -{ - if (ctx == NULL) - return BAD_FUNC_ARG; + ssl->options.downgrade = 0; - ctx->ticketEncCtx = userCtx; + #ifdef NO_RSA + haveRSA = 0; + #endif + #ifndef NO_PSK + havePSK = ssl->options.havePSK; + #endif + #ifndef NO_CERTS + keySz = ssl->buffers.keySz; + #endif + if (AllocateSuites(ssl) != 0) + return WOLFSSL_FAILURE; + InitSuites(ssl->suites, ssl->version, keySz, haveRSA, havePSK, + ssl->options.haveDH, ssl->options.haveECDSAsig, + ssl->options.haveECC, TRUE, ssl->options.haveStaticECC, + ssl->options.useAnon, TRUE, TRUE, TRUE, TRUE, ssl->options.side); return WOLFSSL_SUCCESS; } +#endif /* !leanpsk */ -/* get user context - returns userCtx on success, NULL on failure */ -void* wolfSSL_CTX_get_TicketEncCtx(WOLFSSL_CTX* ctx) -{ - if (ctx == NULL) - return NULL; - - return ctx->ticketEncCtx; -} +#if defined(OPENSSL_EXTRA) && !defined(WOLFSSL_NO_OPENSSL_RAND_CB) +static int wolfSSL_RAND_InitMutex(void); +#endif -#ifdef WOLFSSL_TLS13 -/* set the maximum number of tickets to send - * return WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on fail +/* 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. + * + * See further explanation below in wolfSSL_Init(). */ -int wolfSSL_CTX_set_num_tickets(WOLFSSL_CTX* ctx, size_t mxTickets) -{ - if (ctx == NULL) - return WOLFSSL_FAILURE; +#ifndef WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS + #if !defined(WOLFSSL_MUTEX_INITIALIZER) && !defined(SINGLE_THREADED) && \ + defined(WOLFSSL_ATOMIC_OPS) && defined(WOLFSSL_ATOMIC_INITIALIZER) + #define WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS 1 + #else + #define WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS 0 + #endif +#elif defined(WOLFSSL_MUTEX_INITIALIZER) || defined(SINGLE_THREADED) + #undef WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS + #define WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS 0 +#endif - ctx->maxTicketTls13 = (unsigned int)mxTickets; - return WOLFSSL_SUCCESS; -} +#if WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS + #ifndef WOLFSSL_ATOMIC_OPS + #error WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS requires WOLFSSL_ATOMIC_OPS + #endif + #ifndef WOLFSSL_ATOMIC_INITIALIZER + #error WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS requires WOLFSSL_ATOMIC_INITIALIZER + #endif + static wolfSSL_Atomic_Int inits_count_mutex_atomic_initing_flag = + WOLFSSL_ATOMIC_INITIALIZER(0); +#endif /* WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS && !WOLFSSL_MUTEX_INITIALIZER */ -/* get the maximum number of tickets to send - * return number of tickets set to be sent - */ -size_t wolfSSL_CTX_get_num_tickets(WOLFSSL_CTX* ctx) +#if defined(OPENSSL_EXTRA) && defined(HAVE_ATEXIT) +static void AtExitCleanup(void) { - if (ctx == NULL) - return 0; - - return (size_t)ctx->maxTicketTls13; + if (initRefCount > 0) { + initRefCount = 1; + (void)wolfSSL_Cleanup(); +#if WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS + if (inits_count_mutex_valid == 1) { + (void)wc_FreeMutex(&inits_count_mutex); + inits_count_mutex_valid = 0; + inits_count_mutex_atomic_initing_flag = 0; + } +#endif + } } -#endif /* WOLFSSL_TLS13 */ -#endif /* !NO_WOLFSSL_SERVER */ +#endif -#if !defined(NO_WOLFSSL_CLIENT) -int wolfSSL_UseSessionTicket(WOLFSSL* ssl) +WOLFSSL_ABI +int wolfSSL_Init(void) { - if (ssl == NULL) - return BAD_FUNC_ARG; + int ret = WOLFSSL_SUCCESS; +#if !defined(NO_SESSION_CACHE) && defined(ENABLE_SESSION_CACHE_ROW_LOCK) + int i; +#endif - return TLSX_UseSessionTicket(&ssl->extensions, NULL, ssl->heap); -} + WOLFSSL_ENTER("wolfSSL_Init"); -int wolfSSL_CTX_UseSessionTicket(WOLFSSL_CTX* ctx) -{ - if (ctx == NULL) - return BAD_FUNC_ARG; +#if defined(LIBWOLFSSL_CMAKE_OUTPUT) + WOLFSSL_MSG(LIBWOLFSSL_CMAKE_OUTPUT); +#else + WOLFSSL_MSG("No extra wolfSSL cmake messages found"); +#endif - return TLSX_UseSessionTicket(&ctx->extensions, NULL, ctx->heap); -} +#ifndef WOLFSSL_MUTEX_INITIALIZER + if (inits_count_mutex_valid == 0) { + #if WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS -int wolfSSL_get_SessionTicket(WOLFSSL* ssl, byte* buf, word32* bufSz) -{ - if (ssl == NULL || bufSz == NULL) - return BAD_FUNC_ARG; + /* Without this mitigation, if two threads enter wolfSSL_Init() at the + * same time, and both see zero inits_count_mutex_valid, then both will + * run wc_InitMutex(&inits_count_mutex), leading to process corruption + * or (best case) a resource leak. + * + * When WOLFSSL_ATOMIC_INITIALIZER() is available, we can mitigate this + * by use an atomic counting int as a mutex. + */ - if (*bufSz == 0 && buf == NULL) { - *bufSz = ssl->session->ticketLen; - return LENGTH_ONLY_E; + if (wolfSSL_Atomic_Int_FetchAdd(&inits_count_mutex_atomic_initing_flag, + 1) != 0) + { + (void)wolfSSL_Atomic_Int_FetchSub( + &inits_count_mutex_atomic_initing_flag, 1); + return DEADLOCK_AVERTED_E; + } + #endif /* WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS */ + if (wc_InitMutex(&inits_count_mutex) != 0) { + WOLFSSL_MSG("Bad Init Mutex count"); + #if WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS + (void)wolfSSL_Atomic_Int_FetchSub( + &inits_count_mutex_atomic_initing_flag, 1); + #endif + return BAD_MUTEX_E; + } + else { + inits_count_mutex_valid = 1; + } } +#endif /* !WOLFSSL_MUTEX_INITIALIZER */ - if (buf == NULL) - return BAD_FUNC_ARG; - - if (ssl->session->ticketLen <= *bufSz) { - XMEMCPY(buf, ssl->session->ticket, ssl->session->ticketLen); - *bufSz = ssl->session->ticketLen; + if (wc_LockMutex(&inits_count_mutex) != 0) { + WOLFSSL_MSG("Bad Lock Mutex count"); + return BAD_MUTEX_E; } - else - *bufSz = 0; - return WOLFSSL_SUCCESS; -} +#if FIPS_VERSION_GE(5,1) + if ((ret == WOLFSSL_SUCCESS) && (initRefCount == 0)) { + ret = wolfCrypt_SetPrivateKeyReadEnable_fips(1, WC_KEYTYPE_ALL); + if (ret == 0) + ret = WOLFSSL_SUCCESS; + } +#endif -int wolfSSL_set_SessionTicket(WOLFSSL* ssl, const byte* buf, - word32 bufSz) -{ - if (ssl == NULL || (buf == NULL && bufSz > 0)) - return BAD_FUNC_ARG; + if ((ret == WOLFSSL_SUCCESS) && (initRefCount == 0)) { + /* Initialize crypto for use with TLS connection */ - if (bufSz > 0) { - /* Ticket will fit into static ticket */ - if (bufSz <= SESSION_TICKET_LEN) { - if (ssl->session->ticketLenAlloc > 0) { - XFREE(ssl->session->ticket, ssl->session->heap, - DYNAMIC_TYPE_SESSION_TICK); - ssl->session->ticketLenAlloc = 0; - ssl->session->ticket = ssl->session->staticTicket; - } + if (wolfCrypt_Init() != 0) { + WOLFSSL_MSG("Bad wolfCrypt Init"); + ret = WC_INIT_E; } - else { /* Ticket requires dynamic ticket storage */ - /* is dyn buffer big enough */ - if (ssl->session->ticketLen < bufSz) { - if (ssl->session->ticketLenAlloc > 0) { - XFREE(ssl->session->ticket, ssl->session->heap, - DYNAMIC_TYPE_SESSION_TICK); - } - ssl->session->ticket = (byte*)XMALLOC(bufSz, ssl->session->heap, - DYNAMIC_TYPE_SESSION_TICK); - if(ssl->session->ticket == NULL) { - ssl->session->ticket = ssl->session->staticTicket; - ssl->session->ticketLenAlloc = 0; - return MEMORY_ERROR; - } - ssl->session->ticketLenAlloc = (word16)bufSz; + +#if defined(HAVE_GLOBAL_RNG) && !defined(WOLFSSL_MUTEX_INITIALIZER) + if (ret == WOLFSSL_SUCCESS) { + if (wc_InitMutex(&globalRNGMutex) != 0) { + WOLFSSL_MSG("Bad Init Mutex rng"); + ret = BAD_MUTEX_E; + } + else { + globalRNGMutex_valid = 1; } } - XMEMCPY(ssl->session->ticket, buf, bufSz); - } - ssl->session->ticketLen = (word16)bufSz; - - return WOLFSSL_SUCCESS; -} - - -int wolfSSL_set_SessionTicket_cb(WOLFSSL* ssl, - CallbackSessionTicket cb, void* ctx) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - - ssl->session_ticket_cb = cb; - ssl->session_ticket_ctx = ctx; - - return WOLFSSL_SUCCESS; -} -#endif /* !NO_WOLFSSL_CLIENT */ - -#endif /* HAVE_SESSION_TICKET */ - - -#ifdef HAVE_EXTENDED_MASTER -#ifndef NO_WOLFSSL_CLIENT - -int wolfSSL_CTX_DisableExtendedMasterSecret(WOLFSSL_CTX* ctx) -{ - if (ctx == NULL) - return BAD_FUNC_ARG; - - ctx->haveEMS = 0; - - return WOLFSSL_SUCCESS; -} - - -int wolfSSL_DisableExtendedMasterSecret(WOLFSSL* ssl) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - - ssl->options.haveEMS = 0; - - return WOLFSSL_SUCCESS; -} - -#endif -#endif - - -#ifndef WOLFSSL_LEANPSK - -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; -} - - -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 -int wolfSSL_SendUserCanceled(WOLFSSL* ssl) -{ - int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); - WOLFSSL_ENTER("wolfSSL_recv"); + #ifdef WC_RNG_SEED_CB + wc_SetSeed_Cb(WC_GENERATE_SEED_DEFAULT); + #endif - if (ssl != NULL) { - ssl->error = SendAlert(ssl, alert_warning, user_canceled); - if (ssl->error < 0) { - WOLFSSL_ERROR(ssl->error); +#ifdef OPENSSL_EXTRA + #ifndef WOLFSSL_NO_OPENSSL_RAND_CB + if ((ret == WOLFSSL_SUCCESS) && (wolfSSL_RAND_InitMutex() != 0)) { + ret = BAD_MUTEX_E; } - else { - ret = wolfSSL_shutdown(ssl); + #endif + if ((ret == WOLFSSL_SUCCESS) && + (wolfSSL_RAND_seed(NULL, 0) != WOLFSSL_SUCCESS)) { + WOLFSSL_MSG("wolfSSL_RAND_seed failed"); + ret = WC_INIT_E; } - } - - 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; - } +#endif - 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; - } - } +#ifndef NO_SESSION_CACHE + #ifdef ENABLE_SESSION_CACHE_ROW_LOCK + for (i = 0; i < SESSION_ROWS; ++i) { + SessionCache[i].lock_valid = 0; } - - /* 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; + for (i = 0; (ret == WOLFSSL_SUCCESS) && (i < SESSION_ROWS); ++i) { + if (wc_InitRwLock(&SessionCache[i].row_lock) != 0) { + WOLFSSL_MSG("Bad Init Mutex session"); + ret = BAD_MUTEX_E; } else { - ret = WOLFSSL_SHUTDOWN_NOT_DONE; - WOLFSSL_LEAVE("wolfSSL_shutdown", ret); - return ret; + SessionCache[i].lock_valid = 1; } } - -#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) { - 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 == WOLFSSL_SUCCESS) { + if (wc_InitRwLock(&session_lock) != 0) { + WOLFSSL_MSG("Bad Init Mutex session"); + ret = BAD_MUTEX_E; } - else if (ret == WC_NO_ERR_TRACE(WANT_READ)) { - ssl->error = ret; - ret = WOLFSSL_FATAL_ERROR; + else { + session_lock_valid = 1; } - else if (ssl->error == WOLFSSL_ERROR_NONE) { - ret = WOLFSSL_SHUTDOWN_NOT_DONE; + } + #endif + #ifndef NO_CLIENT_CACHE + #ifndef WOLFSSL_MUTEX_INITIALIZER + if (ret == WOLFSSL_SUCCESS) { + if (wc_InitMutex(&clisession_mutex) != 0) { + WOLFSSL_MSG("Bad Init Mutex session"); + ret = BAD_MUTEX_E; } else { - WOLFSSL_ERROR(ssl->error); - ret = WOLFSSL_FATAL_ERROR; + clisession_mutex_valid = 1; } } + #endif + #endif +#endif +#if defined(OPENSSL_EXTRA) && defined(HAVE_ATEXIT) + /* OpenSSL registers cleanup using atexit */ + if ((ret == WOLFSSL_SUCCESS) && (atexit(AtExitCleanup) != 0)) { + WOLFSSL_MSG("Bad atexit registration"); + ret = WC_INIT_E; + } +#endif } -#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 */ - -/* get current error state value */ -int wolfSSL_state(WOLFSSL* ssl) -{ - if (ssl == NULL) { - return BAD_FUNC_ARG; - } - - return ssl->error; -} - - -WOLFSSL_ABI -int wolfSSL_get_error(WOLFSSL* ssl, int ret) -{ - 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); - - /* 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; -} - - -/* 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; - } - return WOLFSSL_SUCCESS; -} - -#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; -} - -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; - } -} - - -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'; - } - } -} - - -/* don't free temporary arrays at end of handshake */ -void wolfSSL_KeepArrays(WOLFSSL* ssl) -{ - if (ssl) - ssl->options.saveArrays = 1; -} - - -/* user doesn't need temporary arrays anymore, Free */ -void wolfSSL_FreeArrays(WOLFSSL* ssl) -{ - if (ssl && ssl->options.handShakeState == HANDSHAKE_DONE) { - ssl->options.saveArrays = 0; - FreeArrays(ssl, 1); - } -} - -/* 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) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - - ssl->options.keepResources = 1; - - return 0; -} - -/* 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; - - FreeHandshakeResources(ssl); - - return 0; -} - -/* 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->useClientOrder = 1; - - return 0; -} - -/* 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) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - - ssl->options.useClientOrder = 1; - - return 0; -} - -#ifdef WOLFSSL_DTLS -const byte* wolfSSL_GetDtlsMacSecret(WOLFSSL* ssl, int verify, int epochOrder) -{ -#ifndef WOLFSSL_AEAD_ONLY - Keys* keys = NULL; - - (void)epochOrder; - - if (ssl == NULL) - return NULL; - -#ifdef HAVE_SECURE_RENEGOTIATION - switch (epochOrder) { - case PEER_ORDER: - if (IsDtlsMsgSCRKeys(ssl)) - keys = &ssl->secure_renegotiation->tmp_keys; - else - keys = &ssl->keys; - break; - case PREV_ORDER: - keys = &ssl->keys; - break; - case CUR_ORDER: - if (DtlsUseSCRKeys(ssl)) - keys = &ssl->secure_renegotiation->tmp_keys; - else - keys = &ssl->keys; - break; - default: - WOLFSSL_MSG("Unknown epoch order"); - return NULL; - } -#else - keys = &ssl->keys; -#endif - - if ( (ssl->options.side == WOLFSSL_CLIENT_END && !verify) || - (ssl->options.side == WOLFSSL_SERVER_END && verify) ) - return keys->client_write_MAC_secret; - else - return keys->server_write_MAC_secret; -#else - (void)ssl; - (void)verify; - (void)epochOrder; - - return NULL; -#endif -} -#endif /* WOLFSSL_DTLS */ - -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) -{ - if (ssl) - return ssl->options.side; - - return BAD_FUNC_ARG; -} - -#ifdef ATOMIC_USER - -void wolfSSL_CTX_SetMacEncryptCb(WOLFSSL_CTX* ctx, CallbackMacEncrypt cb) -{ - if (ctx) - ctx->MacEncryptCb = cb; -} - - -void wolfSSL_SetMacEncryptCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->MacEncryptCtx = ctx; -} - - -void* wolfSSL_GetMacEncryptCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->MacEncryptCtx; - - return NULL; -} - - -void wolfSSL_CTX_SetDecryptVerifyCb(WOLFSSL_CTX* ctx, CallbackDecryptVerify cb) -{ - if (ctx) - ctx->DecryptVerifyCb = cb; -} - - -void wolfSSL_SetDecryptVerifyCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->DecryptVerifyCtx = ctx; -} - - -void* wolfSSL_GetDecryptVerifyCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->DecryptVerifyCtx; - - return NULL; -} - -#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; -} - -/** - * 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; -} - -/** - * 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; - - return NULL; -} - - -/** - * 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; -} - -/** - * 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) -{ - if (ssl) - return ssl->VerifyDecryptCtx; - - return NULL; -} -#endif /* HAVE_ENCRYPT_THEN_MAC !WOLFSSL_AEAD_ONLY */ - - - -const byte* wolfSSL_GetClientWriteKey(WOLFSSL* ssl) -{ - if (ssl) - return ssl->keys.client_write_key; - - return NULL; -} - - -const byte* wolfSSL_GetClientWriteIV(WOLFSSL* ssl) -{ - if (ssl) - return ssl->keys.client_write_IV; - - return NULL; -} - - -const byte* wolfSSL_GetServerWriteKey(WOLFSSL* ssl) -{ - if (ssl) - return ssl->keys.server_write_key; - - return NULL; -} - - -const byte* wolfSSL_GetServerWriteIV(WOLFSSL* ssl) -{ - if (ssl) - return ssl->keys.server_write_IV; - - return NULL; -} - -int wolfSSL_GetKeySize(WOLFSSL* ssl) -{ - if (ssl) - return ssl->specs.key_size; - - return BAD_FUNC_ARG; -} - - -int wolfSSL_GetIVSize(WOLFSSL* ssl) -{ - if (ssl) - return ssl->specs.iv_size; - - return BAD_FUNC_ARG; -} - - -int wolfSSL_GetBulkCipher(WOLFSSL* ssl) -{ - if (ssl) - return ssl->specs.bulk_cipher_algorithm; - - return BAD_FUNC_ARG; -} - - -int wolfSSL_GetCipherType(WOLFSSL* ssl) -{ - if (ssl == NULL) - 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; - - return WOLFSSL_FATAL_ERROR; -} - - -int wolfSSL_GetCipherBlockSize(WOLFSSL* ssl) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - - return ssl->specs.block_size; -} - - -int wolfSSL_GetAeadMacSize(WOLFSSL* ssl) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - - return ssl->specs.aead_mac_size; -} - - -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) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - - if (ssl->version.major == SSLv3_MAJOR) { - switch (ssl->version.minor) { - case SSLv3_MINOR : - return WOLFSSL_SSLV3; - case TLSv1_MINOR : - return WOLFSSL_TLSV1; - case TLSv1_1_MINOR : - return WOLFSSL_TLSV1_1; - case TLSv1_2_MINOR : - return WOLFSSL_TLSV1_2; - case TLSv1_3_MINOR : - return WOLFSSL_TLSV1_3; - default: - break; - } - } -#ifdef WOLFSSL_DTLS - if (ssl->version.major == DTLS_MAJOR) { - switch (ssl->version.minor) { - case DTLS_MINOR : - return WOLFSSL_DTLSV1; - case DTLSv1_2_MINOR : - return WOLFSSL_DTLSV1_2; - case DTLSv1_3_MINOR : - return WOLFSSL_DTLSV1_3; - default: - break; - } - } -#endif /* WOLFSSL_DTLS */ - - return VERSION_ERROR; -} - -int wolfSSL_SetVersion(WOLFSSL* ssl, int version) -{ - word16 haveRSA = 1; - word16 havePSK = 0; - int keySz = 0; - - WOLFSSL_ENTER("wolfSSL_SetVersion"); - - if (ssl == NULL) { - WOLFSSL_MSG("Bad function argument"); - return BAD_FUNC_ARG; - } - - switch (version) { -#if defined(WOLFSSL_ALLOW_SSLV3) && !defined(NO_OLD_TLS) - case WOLFSSL_SSLV3: - ssl->version = MakeSSLv3(); - break; -#endif - -#ifndef NO_TLS - #ifndef NO_OLD_TLS - #ifdef WOLFSSL_ALLOW_TLSV10 - case WOLFSSL_TLSV1: - ssl->version = MakeTLSv1(); - break; - #endif - - case WOLFSSL_TLSV1_1: - ssl->version = MakeTLSv1_1(); - break; - #endif - #ifndef WOLFSSL_NO_TLS12 - case WOLFSSL_TLSV1_2: - ssl->version = MakeTLSv1_2(); - break; - #endif - - #ifdef WOLFSSL_TLS13 - case WOLFSSL_TLSV1_3: - ssl->version = MakeTLSv1_3(); - break; - #endif /* WOLFSSL_TLS13 */ -#endif - - default: - WOLFSSL_MSG("Bad function argument"); - return BAD_FUNC_ARG; - } - - ssl->options.downgrade = 0; - - #ifdef NO_RSA - haveRSA = 0; - #endif - #ifndef NO_PSK - havePSK = ssl->options.havePSK; - #endif - #ifndef NO_CERTS - keySz = ssl->buffers.keySz; - #endif - - if (AllocateSuites(ssl) != 0) - return WOLFSSL_FAILURE; - InitSuites(ssl->suites, ssl->version, keySz, haveRSA, havePSK, - ssl->options.haveDH, ssl->options.haveECDSAsig, - ssl->options.haveECC, TRUE, ssl->options.haveStaticECC, - ssl->options.useAnon, TRUE, TRUE, TRUE, TRUE, ssl->options.side); - return WOLFSSL_SUCCESS; -} -#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. - * - * See further explanation below in wolfSSL_Init(). - */ -#ifndef WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS - #if !defined(WOLFSSL_MUTEX_INITIALIZER) && !defined(SINGLE_THREADED) && \ - defined(WOLFSSL_ATOMIC_OPS) && defined(WOLFSSL_ATOMIC_INITIALIZER) - #define WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS 1 - #else - #define WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS 0 - #endif -#elif defined(WOLFSSL_MUTEX_INITIALIZER) || defined(SINGLE_THREADED) - #undef WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS - #define WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS 0 -#endif - -#if WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS - #ifndef WOLFSSL_ATOMIC_OPS - #error WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS requires WOLFSSL_ATOMIC_OPS - #endif - #ifndef WOLFSSL_ATOMIC_INITIALIZER - #error WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS requires WOLFSSL_ATOMIC_INITIALIZER - #endif - static wolfSSL_Atomic_Int inits_count_mutex_atomic_initing_flag = - WOLFSSL_ATOMIC_INITIALIZER(0); -#endif /* WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS && !WOLFSSL_MUTEX_INITIALIZER */ - -#if defined(OPENSSL_EXTRA) && defined(HAVE_ATEXIT) -static void AtExitCleanup(void) -{ - if (initRefCount > 0) { - initRefCount = 1; - (void)wolfSSL_Cleanup(); -#if WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS - if (inits_count_mutex_valid == 1) { - (void)wc_FreeMutex(&inits_count_mutex); - inits_count_mutex_valid = 0; - inits_count_mutex_atomic_initing_flag = 0; - } -#endif - } -} -#endif - -WOLFSSL_ABI -int wolfSSL_Init(void) -{ - int ret = WOLFSSL_SUCCESS; -#if !defined(NO_SESSION_CACHE) && defined(ENABLE_SESSION_CACHE_ROW_LOCK) - int i; -#endif - - WOLFSSL_ENTER("wolfSSL_Init"); - -#if defined(LIBWOLFSSL_CMAKE_OUTPUT) - WOLFSSL_MSG(LIBWOLFSSL_CMAKE_OUTPUT); -#else - WOLFSSL_MSG("No extra wolfSSL cmake messages found"); -#endif - -#ifndef WOLFSSL_MUTEX_INITIALIZER - if (inits_count_mutex_valid == 0) { - #if WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS - - /* Without this mitigation, if two threads enter wolfSSL_Init() at the - * same time, and both see zero inits_count_mutex_valid, then both will - * run wc_InitMutex(&inits_count_mutex), leading to process corruption - * or (best case) a resource leak. - * - * When WOLFSSL_ATOMIC_INITIALIZER() is available, we can mitigate this - * by use an atomic counting int as a mutex. - */ - - if (wolfSSL_Atomic_Int_FetchAdd(&inits_count_mutex_atomic_initing_flag, - 1) != 0) - { - (void)wolfSSL_Atomic_Int_FetchSub( - &inits_count_mutex_atomic_initing_flag, 1); - return DEADLOCK_AVERTED_E; - } - #endif /* WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS */ - if (wc_InitMutex(&inits_count_mutex) != 0) { - WOLFSSL_MSG("Bad Init Mutex count"); - #if WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS - (void)wolfSSL_Atomic_Int_FetchSub( - &inits_count_mutex_atomic_initing_flag, 1); - #endif - return BAD_MUTEX_E; - } - else { - inits_count_mutex_valid = 1; - } - } -#endif /* !WOLFSSL_MUTEX_INITIALIZER */ - - if (wc_LockMutex(&inits_count_mutex) != 0) { - WOLFSSL_MSG("Bad Lock Mutex count"); - return BAD_MUTEX_E; - } - -#if FIPS_VERSION_GE(5,1) - if ((ret == WOLFSSL_SUCCESS) && (initRefCount == 0)) { - ret = wolfCrypt_SetPrivateKeyReadEnable_fips(1, WC_KEYTYPE_ALL); - if (ret == 0) - ret = WOLFSSL_SUCCESS; - } -#endif - - if ((ret == WOLFSSL_SUCCESS) && (initRefCount == 0)) { - /* Initialize crypto for use with TLS connection */ - - if (wolfCrypt_Init() != 0) { - WOLFSSL_MSG("Bad wolfCrypt Init"); - ret = WC_INIT_E; - } - -#if defined(HAVE_GLOBAL_RNG) && !defined(WOLFSSL_MUTEX_INITIALIZER) - if (ret == WOLFSSL_SUCCESS) { - if (wc_InitMutex(&globalRNGMutex) != 0) { - WOLFSSL_MSG("Bad Init Mutex rng"); - ret = BAD_MUTEX_E; - } - else { - globalRNGMutex_valid = 1; - } - } -#endif - - #ifdef WC_RNG_SEED_CB - wc_SetSeed_Cb(WC_GENERATE_SEED_DEFAULT); - #endif - -#ifdef OPENSSL_EXTRA - #ifndef WOLFSSL_NO_OPENSSL_RAND_CB - if ((ret == WOLFSSL_SUCCESS) && (wolfSSL_RAND_InitMutex() != 0)) { - ret = BAD_MUTEX_E; - } - #endif - if ((ret == WOLFSSL_SUCCESS) && - (wolfSSL_RAND_seed(NULL, 0) != WOLFSSL_SUCCESS)) { - WOLFSSL_MSG("wolfSSL_RAND_seed failed"); - ret = WC_INIT_E; - } -#endif - -#ifndef NO_SESSION_CACHE - #ifdef ENABLE_SESSION_CACHE_ROW_LOCK - for (i = 0; i < SESSION_ROWS; ++i) { - SessionCache[i].lock_valid = 0; - } - for (i = 0; (ret == WOLFSSL_SUCCESS) && (i < SESSION_ROWS); ++i) { - if (wc_InitRwLock(&SessionCache[i].row_lock) != 0) { - WOLFSSL_MSG("Bad Init Mutex session"); - ret = BAD_MUTEX_E; - } - else { - SessionCache[i].lock_valid = 1; - } - } - #else - if (ret == WOLFSSL_SUCCESS) { - if (wc_InitRwLock(&session_lock) != 0) { - WOLFSSL_MSG("Bad Init Mutex session"); - ret = BAD_MUTEX_E; - } - else { - session_lock_valid = 1; - } - } - #endif - #ifndef NO_CLIENT_CACHE - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (ret == WOLFSSL_SUCCESS) { - if (wc_InitMutex(&clisession_mutex) != 0) { - WOLFSSL_MSG("Bad Init Mutex session"); - ret = BAD_MUTEX_E; - } - else { - clisession_mutex_valid = 1; - } - } - #endif - #endif -#endif -#if defined(OPENSSL_EXTRA) && defined(HAVE_ATEXIT) - /* OpenSSL registers cleanup using atexit */ - if ((ret == WOLFSSL_SUCCESS) && (atexit(AtExitCleanup) != 0)) { - WOLFSSL_MSG("Bad atexit registration"); - ret = WC_INIT_E; - } -#endif - } - -#if defined(WOLFSSL_SYS_CRYPTO_POLICY) - /* System wide crypto policy disabled by default. */ - XMEMSET(&crypto_policy, 0, sizeof(crypto_policy)); -#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - - if (ret == WOLFSSL_SUCCESS) { - initRefCount = initRefCount + 1; - } - else { - initRefCount = 1; /* Force cleanup */ - } - - wc_UnLockMutex(&inits_count_mutex); - - if (ret != WOLFSSL_SUCCESS) { - (void)wolfSSL_Cleanup(); /* Ignore any error from cleanup */ - } - - return ret; -} - -#if defined(WOLFSSL_SYS_CRYPTO_POLICY) -/* Helper function for wolfSSL_crypto_policy_enable and - * wolfSSL_crypto_policy_enable_buffer. - * - * Parses the crypto policy string, verifies values, - * and sets in global crypto policy struct. Not thread - * safe. String length has already been verified. - * - * Returns WOLFSSL_SUCCESS on success. - * Returns CRYPTO_POLICY_FORBIDDEN if already enabled. - * Returns < 0 on misc error. - * */ -static int crypto_policy_parse(void) -{ - const char * hdr = WOLFSSL_SECLEVEL_STR; - int sec_level = 0; - size_t i = 0; - - /* All policies should begin with "@SECLEVEL=" (N={0..5}) followed - * by bulk cipher list. */ - if (XMEMCMP(crypto_policy.str, hdr, strlen(hdr)) != 0) { - WOLFSSL_MSG("error: crypto policy: invalid header"); - return WOLFSSL_BAD_FILE; - } - - { - /* Extract the security level. */ - char * policy_mem = crypto_policy.str; - policy_mem += strlen(hdr); - sec_level = (int) (*policy_mem - '0'); - } - - if (sec_level < MIN_WOLFSSL_SEC_LEVEL || - sec_level > MAX_WOLFSSL_SEC_LEVEL) { - WOLFSSL_MSG_EX("error: invalid SECLEVEL: %d", sec_level); - return WOLFSSL_BAD_FILE; - } - - /* Remove trailing '\r' or '\n'. */ - for (i = 0; i < MAX_WOLFSSL_CRYPTO_POLICY_SIZE; ++i) { - if (crypto_policy.str[i] == '\0') { - break; - } - - if (crypto_policy.str[i] == '\r' || crypto_policy.str[i] == '\n') { - crypto_policy.str[i] = '\0'; - break; - } - } - - #if defined(DEBUG_WOLFSSL_VERBOSE) - WOLFSSL_MSG_EX("info: SECLEVEL=%d", sec_level); - WOLFSSL_MSG_EX("info: using crypto-policy file: %s, %ld", policy_file, sz); - #endif /* DEBUG_WOLFSSL_VERBOSE */ - - crypto_policy.secLevel = sec_level; - crypto_policy.enabled = 1; - - return WOLFSSL_SUCCESS; -} - -#ifndef NO_FILESYSTEM -/* Enables wolfSSL system wide crypto-policy, using the given policy - * file arg. If NULL is passed, then the default system crypto-policy - * file that was set at configure time will be used instead. - * - * While enabled: - * - TLS methods, min key sizes, and cipher lists are all configured - * automatically by the policy. - * - Attempting to use lesser strength parameters will fail with - * error CRYPTO_POLICY_FORBIDDEN. - * - * Disable with wolfSSL_crypto_policy_disable. - * - * Note: the wolfSSL_crypto_policy_X API are not thread safe, and should - * only be called at program init time. - * - * Returns WOLFSSL_SUCCESS on success. - * Returns CRYPTO_POLICY_FORBIDDEN if already enabled. - * Returns < 0 on misc error. - * */ -int wolfSSL_crypto_policy_enable(const char * policy_file) -{ - XFILE file; - long sz = 0; - size_t n_read = 0; - - WOLFSSL_ENTER("wolfSSL_crypto_policy_enable"); - - if (wolfSSL_crypto_policy_is_enabled()) { - WOLFSSL_MSG_EX("error: crypto policy already enabled: %s", - policy_file); - return CRYPTO_POLICY_FORBIDDEN; - } - - if (policy_file == NULL) { - /* Use the configure-time default if NULL passed. */ - policy_file = WC_STRINGIFY(WOLFSSL_CRYPTO_POLICY_FILE); - } - - if (policy_file == NULL || *policy_file == '\0') { - WOLFSSL_MSG("error: crypto policy empty file"); - return BAD_FUNC_ARG; - } - +#if defined(WOLFSSL_SYS_CRYPTO_POLICY) + /* System wide crypto policy disabled by default. */ XMEMSET(&crypto_policy, 0, sizeof(crypto_policy)); +#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - file = XFOPEN(policy_file, "rb"); - - if (file == XBADFILE) { - WOLFSSL_MSG_EX("error: crypto policy file open failed: %s", - policy_file); - return WOLFSSL_BAD_FILE; - } - - if (XFSEEK(file, 0, XSEEK_END) != 0) { - WOLFSSL_MSG_EX("error: crypto policy file seek end failed: %s", - policy_file); - XFCLOSE(file); - return WOLFSSL_BAD_FILE; - } - - sz = XFTELL(file); - - if (XFSEEK(file, 0, XSEEK_SET) != 0) { - WOLFSSL_MSG_EX("error: crypto policy file seek failed: %s", - policy_file); - XFCLOSE(file); - return WOLFSSL_BAD_FILE; + if (ret == WOLFSSL_SUCCESS) { + initRefCount = initRefCount + 1; } - - if (sz <= 0 || sz > MAX_WOLFSSL_CRYPTO_POLICY_SIZE) { - WOLFSSL_MSG_EX("error: crypto policy file %s, invalid size: %ld", - policy_file, sz); - XFCLOSE(file); - return WOLFSSL_BAD_FILE; + else { + initRefCount = 1; /* Force cleanup */ } - n_read = XFREAD(crypto_policy.str, 1, sz, file); - XFCLOSE(file); + wc_UnLockMutex(&inits_count_mutex); - if (n_read != (size_t) sz) { - WOLFSSL_MSG_EX("error: crypto policy file %s: read %zu, " - "expected %ld", policy_file, n_read, sz); - return WOLFSSL_BAD_FILE; + if (ret != WOLFSSL_SUCCESS) { + (void)wolfSSL_Cleanup(); /* Ignore any error from cleanup */ } - crypto_policy.str[n_read] = '\0'; - - return crypto_policy_parse(); + return ret; } -#endif /* ! NO_FILESYSTEM */ -/* Same behavior as wolfSSL_crypto_policy_enable, but loads - * via memory buf instead of file. +#if defined(WOLFSSL_SYS_CRYPTO_POLICY) +/* Helper function for wolfSSL_crypto_policy_enable and + * wolfSSL_crypto_policy_enable_buffer. + * + * Parses the crypto policy string, verifies values, + * and sets in global crypto policy struct. Not thread + * safe. String length has already been verified. * * Returns WOLFSSL_SUCCESS on success. * Returns CRYPTO_POLICY_FORBIDDEN if already enabled. * Returns < 0 on misc error. * */ -int wolfSSL_crypto_policy_enable_buffer(const char * buf) -{ - size_t sz = 0; - - WOLFSSL_ENTER("wolfSSL_crypto_policy_enable_buffer"); - - if (wolfSSL_crypto_policy_is_enabled()) { - WOLFSSL_MSG_EX("error: crypto policy already enabled"); - return CRYPTO_POLICY_FORBIDDEN; - } - - if (buf == NULL || *buf == '\0') { - return BAD_FUNC_ARG; - } - - sz = XSTRLEN(buf); - - if (sz == 0 || sz > MAX_WOLFSSL_CRYPTO_POLICY_SIZE) { - return BAD_FUNC_ARG; - } - - XMEMSET(&crypto_policy, 0, sizeof(crypto_policy)); - XMEMCPY(crypto_policy.str, buf, sz); - - return crypto_policy_parse(); -} - -/* Returns whether the system wide crypto-policy is enabled. - * - * Returns 1 if enabled. - * 0 if disabled. - * */ -int wolfSSL_crypto_policy_is_enabled(void) -{ - WOLFSSL_ENTER("wolfSSL_crypto_policy_is_enabled"); - - return crypto_policy.enabled == 1; -} - -/* Disables the system wide crypto-policy. - * note: SSL and CTX structures already instantiated will - * keep their security policy parameters. This will only - * affect new instantiations. - * */ -void wolfSSL_crypto_policy_disable(void) -{ - WOLFSSL_ENTER("wolfSSL_crypto_policy_disable"); - crypto_policy.enabled = 0; - XMEMSET(&crypto_policy, 0, sizeof(crypto_policy)); - return; -} - -/* Get the crypto-policy bulk cipher list string. - * String is not owned by caller, should not be freed. - * - * Returns pointer to bulk cipher list string. - * Returns NULL if NOT enabled, or on error. - * */ -const char * wolfSSL_crypto_policy_get_ciphers(void) -{ - WOLFSSL_ENTER("wolfSSL_crypto_policy_get_ciphers"); - - if (crypto_policy.enabled == 1) { - /* The crypto policy config will have - * this form: - * "@SECLEVEL=2:kEECDH:kRSA..." */ - return crypto_policy.str; - } - - return NULL; -} - -/* Get the configured crypto-policy security level. - * A security level of 0 does not impose any additional - * restrictions. - * - * Returns 1 - 5 if enabled. - * Returns 0 if NOT enabled. - * */ -int wolfSSL_crypto_policy_get_level(void) -{ - if (crypto_policy.enabled == 1) { - return crypto_policy.secLevel; - } - - return 0; -} - -/* Get security level from ssl structure. - * @param ssl a pointer to WOLFSSL structure - */ -int wolfSSL_get_security_level(const WOLFSSL * ssl) -{ - if (ssl == NULL) { - return BAD_FUNC_ARG; - } - - return ssl->secLevel; -} - -#ifndef NO_WOLFSSL_STUB -/* - * 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 ssl a pointer to WOLFSSL structure - * @param level security level - */ -void wolfSSL_set_security_level(WOLFSSL * ssl, int level) -{ - WOLFSSL_ENTER("wolfSSL_set_security_level"); - (void)ssl; - (void)level; -} -#endif /* !NO_WOLFSSL_STUB */ - -#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - - -#define WOLFSSL_SSL_LOAD_INCLUDED -#include - -#define WOLFSSL_SSL_API_CRL_OCSP_INCLUDED -#include "src/ssl_api_crl_ocsp.c" - - -void wolfSSL_load_error_strings(void) -{ - /* compatibility only */ -} - - -int wolfSSL_library_init(void) -{ - WOLFSSL_ENTER("wolfSSL_library_init"); - if (wolfSSL_Init() == WOLFSSL_SUCCESS) - return WOLFSSL_SUCCESS; - else - return WOLFSSL_FATAL_ERROR; -} - - -#ifdef HAVE_SECRET_CALLBACK - -int wolfSSL_set_session_secret_cb(WOLFSSL* ssl, SessionSecretCb cb, void* ctx) +static int crypto_policy_parse(void) { - WOLFSSL_ENTER("wolfSSL_set_session_secret_cb"); - if (ssl == NULL) - return WOLFSSL_FAILURE; - - ssl->sessionSecretCb = cb; - ssl->sessionSecretCtx = ctx; - if (cb != NULL) { - /* If using a pre-set key, assume session resumption. */ - ssl->session->sessionIDSz = 0; - ssl->options.resuming = 1; + const char * hdr = WOLFSSL_SECLEVEL_STR; + int sec_level = 0; + size_t i = 0; + + /* All policies should begin with "@SECLEVEL=" (N={0..5}) followed + * by bulk cipher list. */ + if (XMEMCMP(crypto_policy.str, hdr, strlen(hdr)) != 0) { + WOLFSSL_MSG("error: crypto policy: invalid header"); + return WOLFSSL_BAD_FILE; } - return WOLFSSL_SUCCESS; -} + { + /* Extract the security level. */ + char * policy_mem = crypto_policy.str; + policy_mem += strlen(hdr); + sec_level = (int) (*policy_mem - '0'); + } -int wolfSSL_set_session_ticket_ext_cb(WOLFSSL* ssl, TicketParseCb cb, - void *ctx) -{ - WOLFSSL_ENTER("wolfSSL_set_session_ticket_ext_cb"); - if (ssl == NULL) - return WOLFSSL_FAILURE; + if (sec_level < MIN_WOLFSSL_SEC_LEVEL || + sec_level > MAX_WOLFSSL_SEC_LEVEL) { + WOLFSSL_MSG_EX("error: invalid SECLEVEL: %d", sec_level); + return WOLFSSL_BAD_FILE; + } - ssl->ticketParseCb = cb; - ssl->ticketParseCtx = ctx; + /* Remove trailing '\r' or '\n'. */ + for (i = 0; i < MAX_WOLFSSL_CRYPTO_POLICY_SIZE; ++i) { + if (crypto_policy.str[i] == '\0') { + break; + } - return WOLFSSL_SUCCESS; -} + if (crypto_policy.str[i] == '\r' || crypto_policy.str[i] == '\n') { + crypto_policy.str[i] = '\0'; + break; + } + } -int wolfSSL_set_secret_cb(WOLFSSL* ssl, TlsSecretCb cb, void* ctx) -{ - WOLFSSL_ENTER("wolfSSL_set_secret_cb"); - if (ssl == NULL) - return WOLFSSL_FATAL_ERROR; + #if defined(DEBUG_WOLFSSL_VERBOSE) + WOLFSSL_MSG_EX("info: SECLEVEL=%d", sec_level); + WOLFSSL_MSG_EX("info: using crypto-policy file: %s, %ld", policy_file, sz); + #endif /* DEBUG_WOLFSSL_VERBOSE */ - ssl->tlsSecretCb = cb; - ssl->tlsSecretCtx = ctx; + crypto_policy.secLevel = sec_level; + crypto_policy.enabled = 1; return WOLFSSL_SUCCESS; } -#ifdef SHOW_SECRETS -int tlsShowSecrets(WOLFSSL* ssl, void* secret, int secretSz, - void* ctx) +#ifndef NO_FILESYSTEM +/* Enables wolfSSL system wide crypto-policy, using the given policy + * file arg. If NULL is passed, then the default system crypto-policy + * file that was set at configure time will be used instead. + * + * While enabled: + * - TLS methods, min key sizes, and cipher lists are all configured + * automatically by the policy. + * - Attempting to use lesser strength parameters will fail with + * error CRYPTO_POLICY_FORBIDDEN. + * + * Disable with wolfSSL_crypto_policy_disable. + * + * Note: the wolfSSL_crypto_policy_X API are not thread safe, and should + * only be called at program init time. + * + * Returns WOLFSSL_SUCCESS on success. + * Returns CRYPTO_POLICY_FORBIDDEN if already enabled. + * Returns < 0 on misc error. + * */ +int wolfSSL_crypto_policy_enable(const char * policy_file) { - /* Wireshark Pre-Master-Secret Format: - * CLIENT_RANDOM - */ - const char* CLIENT_RANDOM_LABEL = "CLIENT_RANDOM"; - int i, pmsPos = 0; - char pmsBuf[13 + 1 + 64 + 1 + 96 + 1 + 1]; - byte clientRandom[RAN_LEN]; - int clientRandomSz; + XFILE file; + long sz = 0; + size_t n_read = 0; - (void)ctx; + WOLFSSL_ENTER("wolfSSL_crypto_policy_enable"); - clientRandomSz = (int)wolfSSL_get_client_random(ssl, clientRandom, - sizeof(clientRandom)); + if (wolfSSL_crypto_policy_is_enabled()) { + WOLFSSL_MSG_EX("error: crypto policy already enabled: %s", + policy_file); + return CRYPTO_POLICY_FORBIDDEN; + } - if (clientRandomSz <= 0) { - printf("Error getting server random %d\n", clientRandomSz); + if (policy_file == NULL) { + /* Use the configure-time default if NULL passed. */ + policy_file = WC_STRINGIFY(WOLFSSL_CRYPTO_POLICY_FILE); + } + + if (policy_file == NULL || *policy_file == '\0') { + WOLFSSL_MSG("error: crypto policy empty file"); return BAD_FUNC_ARG; } - XSNPRINTF(&pmsBuf[pmsPos], sizeof(pmsBuf) - pmsPos, "%s ", - CLIENT_RANDOM_LABEL); - pmsPos += XSTRLEN(CLIENT_RANDOM_LABEL) + 1; - for (i = 0; i < clientRandomSz; i++) { - XSNPRINTF(&pmsBuf[pmsPos], sizeof(pmsBuf) - pmsPos, "%02x", - clientRandom[i]); - pmsPos += 2; + XMEMSET(&crypto_policy, 0, sizeof(crypto_policy)); + + file = XFOPEN(policy_file, "rb"); + + if (file == XBADFILE) { + WOLFSSL_MSG_EX("error: crypto policy file open failed: %s", + policy_file); + return WOLFSSL_BAD_FILE; } - XSNPRINTF(&pmsBuf[pmsPos], sizeof(pmsBuf) - pmsPos, " "); - pmsPos += 1; - for (i = 0; i < secretSz; i++) { - XSNPRINTF(&pmsBuf[pmsPos], sizeof(pmsBuf) - pmsPos, "%02x", - ((byte*)secret)[i]); - pmsPos += 2; + + if (XFSEEK(file, 0, XSEEK_END) != 0) { + WOLFSSL_MSG_EX("error: crypto policy file seek end failed: %s", + policy_file); + XFCLOSE(file); + return WOLFSSL_BAD_FILE; } - XSNPRINTF(&pmsBuf[pmsPos], sizeof(pmsBuf) - pmsPos, "\n"); - pmsPos += 1; - /* print master secret */ - puts(pmsBuf); + sz = XFTELL(file); - #if !defined(NO_FILESYSTEM) && defined(WOLFSSL_SSLKEYLOGFILE) - { - FILE* f = XFOPEN(WOLFSSL_SSLKEYLOGFILE_OUTPUT, "a"); - if (f != XBADFILE) { - XFWRITE(pmsBuf, 1, pmsPos, f); - XFCLOSE(f); - } + if (XFSEEK(file, 0, XSEEK_SET) != 0) { + WOLFSSL_MSG_EX("error: crypto policy file seek failed: %s", + policy_file); + XFCLOSE(file); + return WOLFSSL_BAD_FILE; } - #endif - return 0; -} -#endif /* SHOW_SECRETS */ -#endif + if (sz <= 0 || sz > MAX_WOLFSSL_CRYPTO_POLICY_SIZE) { + WOLFSSL_MSG_EX("error: crypto policy file %s, invalid size: %ld", + policy_file, sz); + XFCLOSE(file); + return WOLFSSL_BAD_FILE; + } + n_read = XFREAD(crypto_policy.str, 1, sz, file); + XFCLOSE(file); -#ifdef OPENSSL_EXTRA + if (n_read != (size_t) sz) { + WOLFSSL_MSG_EX("error: crypto policy file %s: read %zu, " + "expected %ld", policy_file, n_read, sz); + return WOLFSSL_BAD_FILE; + } -/* - * check if the list has TLS13 and pre-TLS13 suites - * @param list cipher suite list that user want to set - * (caller required to check for NULL) - * @return mixed: 0, only pre-TLS13: 1, only TLS13: 2 - */ -static int CheckcipherList(const char* list) -{ - int ret; - int findTLSv13Suites = 0; - int findbeforeSuites = 0; - byte cipherSuite0; - byte cipherSuite1; - int flags; - char* next = (char*)list; + crypto_policy.str[n_read] = '\0'; - do { - char* current = next; - char name[MAX_SUITE_NAME + 1]; - word32 length = MAX_SUITE_NAME; - word32 current_length; - byte major = INVALID_BYTE; - byte minor = INVALID_BYTE; + return crypto_policy_parse(); +} +#endif /* ! NO_FILESYSTEM */ - next = XSTRSTR(next, ":"); +/* Same behavior as wolfSSL_crypto_policy_enable, but loads + * via memory buf instead of file. + * + * Returns WOLFSSL_SUCCESS on success. + * Returns CRYPTO_POLICY_FORBIDDEN if already enabled. + * Returns < 0 on misc error. + * */ +int wolfSSL_crypto_policy_enable_buffer(const char * buf) +{ + size_t sz = 0; - if (next) { - current_length = (word32)(next - current); - ++next; /* increment to skip ':' */ - } - else { - current_length = (word32)XSTRLEN(current); - } + WOLFSSL_ENTER("wolfSSL_crypto_policy_enable_buffer"); - if (current_length == 0) { - break; - } + if (wolfSSL_crypto_policy_is_enabled()) { + WOLFSSL_MSG_EX("error: crypto policy already enabled"); + return CRYPTO_POLICY_FORBIDDEN; + } - if (current_length < length) { - length = current_length; - } - XMEMCPY(name, current, length); - name[length] = 0; + if (buf == NULL || *buf == '\0') { + return BAD_FUNC_ARG; + } - if (XSTRCMP(name, "ALL") == 0 || - XSTRCMP(name, "DEFAULT") == 0 || - XSTRCMP(name, "HIGH") == 0) - { - findTLSv13Suites = 1; - findbeforeSuites = 1; - break; - } + sz = XSTRLEN(buf); - ret = GetCipherSuiteFromName(name, &cipherSuite0, - &cipherSuite1, &major, &minor, &flags); - if (ret == 0) { - if (cipherSuite0 == TLS13_BYTE || minor == TLSv1_3_MINOR) { - /* TLSv13 suite */ - findTLSv13Suites = 1; - } - else { - findbeforeSuites = 1; - } - } + if (sz == 0 || sz > MAX_WOLFSSL_CRYPTO_POLICY_SIZE) { + return BAD_FUNC_ARG; + } + + XMEMSET(&crypto_policy, 0, sizeof(crypto_policy)); + XMEMCPY(crypto_policy.str, buf, sz); - #if defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) - /* check if mixed due to names like RSA:ECDHE+AESGCM etc. */ - if (ret != 0) { - char* subStr = name; - char* subStrNext; + return crypto_policy_parse(); +} - do { - subStrNext = XSTRSTR(subStr, "+"); +/* Returns whether the system wide crypto-policy is enabled. + * + * Returns 1 if enabled. + * 0 if disabled. + * */ +int wolfSSL_crypto_policy_is_enabled(void) +{ + WOLFSSL_ENTER("wolfSSL_crypto_policy_is_enabled"); - if ((XSTRCMP(subStr, "ECDHE") == 0) || - (XSTRCMP(subStr, "RSA") == 0)) { - return 0; - } + return crypto_policy.enabled == 1; +} - if (subStrNext && (XSTRLEN(subStrNext) > 0)) { - subStr = subStrNext + 1; /* +1 to skip past '+' */ - } - } while (subStrNext != NULL); - } - #endif +/* Disables the system wide crypto-policy. + * note: SSL and CTX structures already instantiated will + * keep their security policy parameters. This will only + * affect new instantiations. + * */ +void wolfSSL_crypto_policy_disable(void) +{ + WOLFSSL_ENTER("wolfSSL_crypto_policy_disable"); + crypto_policy.enabled = 0; + XMEMSET(&crypto_policy, 0, sizeof(crypto_policy)); + return; +} - if (findTLSv13Suites == 1 && findbeforeSuites == 1) { - /* list has mixed suites */ - return 0; - } - } while (next); +/* Get the crypto-policy bulk cipher list string. + * String is not owned by caller, should not be freed. + * + * Returns pointer to bulk cipher list string. + * Returns NULL if NOT enabled, or on error. + * */ +const char * wolfSSL_crypto_policy_get_ciphers(void) +{ + WOLFSSL_ENTER("wolfSSL_crypto_policy_get_ciphers"); - if (findTLSv13Suites == 0 && findbeforeSuites == 1) { - ret = 1;/* only before TLSv13 suites */ + if (crypto_policy.enabled == 1) { + /* The crypto policy config will have + * this form: + * "@SECLEVEL=2:kEECDH:kRSA..." */ + return crypto_policy.str; } - else if (findTLSv13Suites == 1 && findbeforeSuites == 0) { - ret = 2;/* only TLSv13 suties */ + + return NULL; +} + +/* Get the configured crypto-policy security level. + * A security level of 0 does not impose any additional + * restrictions. + * + * Returns 1 - 5 if enabled. + * Returns 0 if NOT enabled. + * */ +int wolfSSL_crypto_policy_get_level(void) +{ + if (crypto_policy.enabled == 1) { + return crypto_policy.secLevel; } - else { - ret = 0;/* handle as mixed */ + + return 0; +} + +/* Get security level from ssl structure. + * @param ssl a pointer to WOLFSSL structure + */ +int wolfSSL_get_security_level(const WOLFSSL * ssl) +{ + if (ssl == NULL) { + return BAD_FUNC_ARG; } - return ret; + + return ssl->secLevel; } -/* parse some bulk lists like !eNULL / !aNULL +#ifndef NO_WOLFSSL_STUB +/* + * Set security level (wolfSSL doesn't support setting the security level). * - * returns WOLFSSL_SUCCESS on success and sets the cipher suite list + * The security level can only be set through a system wide crypto-policy + * with wolfSSL_crypto_policy_enable(). + * + * @param ssl a pointer to WOLFSSL structure + * @param level security level */ -static int wolfSSL_parse_cipher_list(WOLFSSL_CTX* ctx, WOLFSSL* ssl, - Suites* suites, const char* list) +void wolfSSL_set_security_level(WOLFSSL * ssl, int level) { - int ret = 0; - int listattribute = 0; - int tls13Only = 0; - WC_DECLARE_VAR(suitesCpy, byte, WOLFSSL_MAX_SUITE_SZ, 0); - word16 suitesCpySz = 0; - word16 i = 0; - word16 j = 0; + WOLFSSL_ENTER("wolfSSL_set_security_level"); + (void)ssl; + (void)level; +} +#endif /* !NO_WOLFSSL_STUB */ - if (suites == NULL || list == NULL) { - WOLFSSL_MSG("NULL argument"); - return WOLFSSL_FAILURE; - } +#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - listattribute = CheckcipherList(list); - if (listattribute == 0) { - /* list has mixed(pre-TLSv13 and TLSv13) suites - * update cipher suites the same as before - */ - return (SetCipherList_ex(ctx, ssl, suites, list)) ? WOLFSSL_SUCCESS : - WOLFSSL_FAILURE; - } - else if (listattribute == 1) { - /* list has only pre-TLSv13 suites. - * Only update before TLSv13 suites. - */ - tls13Only = 0; - } - else if (listattribute == 2) { - /* list has only TLSv13 suites. Only update TLv13 suites - * simulate set_ciphersuites() compatibility layer API - */ - tls13Only = 1; - if ((ctx != NULL && !IsAtLeastTLSv1_3(ctx->method->version)) || - (ssl != NULL && !IsAtLeastTLSv1_3(ssl->version))) { - /* Silently ignore TLS 1.3 ciphers if we don't support it. */ - return WOLFSSL_SUCCESS; - } - } +#define WOLFSSL_SSL_LOAD_INCLUDED +#include - /* list contains ciphers either only for TLS 1.3 or <= TLS 1.2 */ -#ifdef WOLFSSL_SMALL_STACK - if (suites->suiteSz > 0) { - suitesCpy = (byte*)XMALLOC(suites->suiteSz, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (suitesCpy == NULL) { - return WOLFSSL_FAILURE; - } +#define WOLFSSL_SSL_API_CRL_OCSP_INCLUDED +#include "src/ssl_api_crl_ocsp.c" - XMEMSET(suitesCpy, 0, suites->suiteSz); - } -#else - XMEMSET(suitesCpy, 0, sizeof(suitesCpy)); -#endif - if (suites->suiteSz > 0) - XMEMCPY(suitesCpy, suites->suites, suites->suiteSz); - suitesCpySz = suites->suiteSz; +void wolfSSL_load_error_strings(void) +{ + /* compatibility only */ +} - ret = SetCipherList_ex(ctx, ssl, suites, list); - if (ret != 1) { - WC_FREE_VAR_EX(suitesCpy, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return WOLFSSL_FAILURE; - } - /* The idea in this section is that OpenSSL has two API to set ciphersuites. - * - SSL_CTX_set_cipher_list for setting TLS <= 1.2 suites - * - SSL_CTX_set_ciphersuites for setting TLS 1.3 suites - * Since we direct both API here we attempt to provide API compatibility. If - * we only get suites from <= 1.2 or == 1.3 then we will only update those - * suites and keep the suites from the other group. - * If downgrade is disabled, skip preserving the other group's suites. */ - if ((ssl != NULL && !ssl->options.downgrade) || - (ctx != NULL && !ctx->method->downgrade)) { - /* Downgrade disabled - don't preserve other group's suites */ - WC_FREE_VAR_EX(suitesCpy, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return ret; - } +int wolfSSL_library_init(void) +{ + WOLFSSL_ENTER("wolfSSL_library_init"); + if (wolfSSL_Init() == WOLFSSL_SUCCESS) + return WOLFSSL_SUCCESS; + else + return WOLFSSL_FATAL_ERROR; +} - for (i = 0; i < suitesCpySz && - suites->suiteSz <= (WOLFSSL_MAX_SUITE_SZ - SUITE_LEN); i += 2) { - /* Check for duplicates */ - int duplicate = 0; - for (j = 0; j < suites->suiteSz; j += 2) { - if (suitesCpy[i] == suites->suites[j] && - suitesCpy[i+1] == suites->suites[j+1]) { - duplicate = 1; - break; - } - } - if (!duplicate) { - if (tls13Only) { - /* Updating TLS 1.3 ciphers */ - if (suitesCpy[i] != TLS13_BYTE) { - /* Only copy over <= TLS 1.2 ciphers */ - /* TLS 1.3 ciphers take precedence */ - suites->suites[suites->suiteSz++] = suitesCpy[i]; - suites->suites[suites->suiteSz++] = suitesCpy[i+1]; - } - } - else { - /* Updating <= TLS 1.2 ciphers */ - if (suitesCpy[i] == TLS13_BYTE) { - /* Only copy over TLS 1.3 ciphers */ - /* TLS 1.3 ciphers take precedence */ - XMEMMOVE(suites->suites + SUITE_LEN, suites->suites, - suites->suiteSz); - suites->suites[0] = suitesCpy[i]; - suites->suites[1] = suitesCpy[i+1]; - suites->suiteSz += 2; - } - } - } - } - WC_FREE_VAR_EX(suitesCpy, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return ret; -} +#ifdef HAVE_SECRET_CALLBACK -#endif +int wolfSSL_set_session_secret_cb(WOLFSSL* ssl, SessionSecretCb cb, void* ctx) +{ + WOLFSSL_ENTER("wolfSSL_set_session_secret_cb"); + if (ssl == NULL) + return WOLFSSL_FAILURE; + + ssl->sessionSecretCb = cb; + ssl->sessionSecretCtx = ctx; + if (cb != NULL) { + /* If using a pre-set key, assume session resumption. */ + ssl->session->sessionIDSz = 0; + ssl->options.resuming = 1; + } + return WOLFSSL_SUCCESS; +} -int wolfSSL_CTX_set_cipher_list(WOLFSSL_CTX* ctx, const char* list) +int wolfSSL_set_session_ticket_ext_cb(WOLFSSL* ssl, TicketParseCb cb, + void *ctx) { - WOLFSSL_ENTER("wolfSSL_CTX_set_cipher_list"); - - if (ctx == NULL) + WOLFSSL_ENTER("wolfSSL_set_session_ticket_ext_cb"); + if (ssl == NULL) return WOLFSSL_FAILURE; - if (AllocateCtxSuites(ctx) != 0) - return WOLFSSL_FAILURE; + ssl->ticketParseCb = cb; + ssl->ticketParseCtx = ctx; -#ifdef OPENSSL_EXTRA - return wolfSSL_parse_cipher_list(ctx, NULL, ctx->suites, list); -#else - return (SetCipherList(ctx, ctx->suites, list)) ? - WOLFSSL_SUCCESS : WOLFSSL_FAILURE; -#endif + return WOLFSSL_SUCCESS; } -#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_SET_CIPHER_BYTES) -int wolfSSL_CTX_set_cipher_list_bytes(WOLFSSL_CTX* ctx, const byte* list, - const int listSz) +int wolfSSL_set_secret_cb(WOLFSSL* ssl, TlsSecretCb cb, void* ctx) { - WOLFSSL_ENTER("wolfSSL_CTX_set_cipher_list_bytes"); - - if (ctx == NULL) - return WOLFSSL_FAILURE; + WOLFSSL_ENTER("wolfSSL_set_secret_cb"); + if (ssl == NULL) + return WOLFSSL_FATAL_ERROR; - if (AllocateCtxSuites(ctx) != 0) - return WOLFSSL_FAILURE; + ssl->tlsSecretCb = cb; + ssl->tlsSecretCtx = ctx; - return (SetCipherListFromBytes(ctx, ctx->suites, list, listSz)) ? - WOLFSSL_SUCCESS : WOLFSSL_FAILURE; + return WOLFSSL_SUCCESS; } -#endif /* OPENSSL_EXTRA || WOLFSSL_SET_CIPHER_BYTES */ -int wolfSSL_set_cipher_list(WOLFSSL* ssl, const char* list) +#ifdef SHOW_SECRETS +int tlsShowSecrets(WOLFSSL* ssl, void* secret, int secretSz, + void* ctx) { - WOLFSSL_ENTER("wolfSSL_set_cipher_list"); - - if (ssl == NULL || ssl->ctx == NULL) { - return WOLFSSL_FAILURE; - } + /* Wireshark Pre-Master-Secret Format: + * CLIENT_RANDOM + */ + const char* CLIENT_RANDOM_LABEL = "CLIENT_RANDOM"; + int i, pmsPos = 0; + char pmsBuf[13 + 1 + 64 + 1 + 96 + 1 + 1]; + byte clientRandom[RAN_LEN]; + int clientRandomSz; - if (AllocateSuites(ssl) != 0) - return WOLFSSL_FAILURE; + (void)ctx; -#ifdef OPENSSL_EXTRA - return wolfSSL_parse_cipher_list(NULL, ssl, ssl->suites, list); -#else - return (SetCipherList_ex(NULL, ssl, ssl->suites, list)) ? - WOLFSSL_SUCCESS : - WOLFSSL_FAILURE; -#endif -} + clientRandomSz = (int)wolfSSL_get_client_random(ssl, clientRandom, + sizeof(clientRandom)); -#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_SET_CIPHER_BYTES) -int wolfSSL_set_cipher_list_bytes(WOLFSSL* ssl, const byte* list, - const int listSz) -{ - WOLFSSL_ENTER("wolfSSL_set_cipher_list_bytes"); + if (clientRandomSz <= 0) { + printf("Error getting server random %d\n", clientRandomSz); + return BAD_FUNC_ARG; + } - if (ssl == NULL || ssl->ctx == NULL) { - return WOLFSSL_FAILURE; + XSNPRINTF(&pmsBuf[pmsPos], sizeof(pmsBuf) - pmsPos, "%s ", + CLIENT_RANDOM_LABEL); + pmsPos += XSTRLEN(CLIENT_RANDOM_LABEL) + 1; + for (i = 0; i < clientRandomSz; i++) { + XSNPRINTF(&pmsBuf[pmsPos], sizeof(pmsBuf) - pmsPos, "%02x", + clientRandom[i]); + pmsPos += 2; + } + XSNPRINTF(&pmsBuf[pmsPos], sizeof(pmsBuf) - pmsPos, " "); + pmsPos += 1; + for (i = 0; i < secretSz; i++) { + XSNPRINTF(&pmsBuf[pmsPos], sizeof(pmsBuf) - pmsPos, "%02x", + ((byte*)secret)[i]); + pmsPos += 2; } + XSNPRINTF(&pmsBuf[pmsPos], sizeof(pmsBuf) - pmsPos, "\n"); + pmsPos += 1; - if (AllocateSuites(ssl) != 0) - return WOLFSSL_FAILURE; + /* print master secret */ + puts(pmsBuf); - return (SetCipherListFromBytes(ssl->ctx, ssl->suites, list, listSz)) - ? WOLFSSL_SUCCESS - : WOLFSSL_FAILURE; + #if !defined(NO_FILESYSTEM) && defined(WOLFSSL_SSLKEYLOGFILE) + { + FILE* f = XFOPEN(WOLFSSL_SSLKEYLOGFILE_OUTPUT, "a"); + if (f != XBADFILE) { + XFWRITE(pmsBuf, 1, pmsPos, f); + XFCLOSE(f); + } + } + #endif + return 0; } -#endif /* OPENSSL_EXTRA || WOLFSSL_SET_CIPHER_BYTES */ - +#endif /* SHOW_SECRETS */ -#ifdef HAVE_KEYING_MATERIAL +#endif -#define TLS_PRF_LABEL_CLIENT_FINISHED "client finished" -#define TLS_PRF_LABEL_SERVER_FINISHED "server finished" -#define TLS_PRF_LABEL_MASTER_SECRET "master secret" -#define TLS_PRF_LABEL_EXT_MASTER_SECRET "extended master secret" -#define TLS_PRF_LABEL_KEY_EXPANSION "key expansion" -static const struct ForbiddenLabels { - const char* label; - size_t labelLen; -} forbiddenLabels[] = { - {TLS_PRF_LABEL_CLIENT_FINISHED, XSTR_SIZEOF(TLS_PRF_LABEL_CLIENT_FINISHED)}, - {TLS_PRF_LABEL_SERVER_FINISHED, XSTR_SIZEOF(TLS_PRF_LABEL_SERVER_FINISHED)}, - {TLS_PRF_LABEL_MASTER_SECRET, XSTR_SIZEOF(TLS_PRF_LABEL_MASTER_SECRET)}, - {TLS_PRF_LABEL_EXT_MASTER_SECRET, - XSTR_SIZEOF(TLS_PRF_LABEL_EXT_MASTER_SECRET)}, - {TLS_PRF_LABEL_KEY_EXPANSION, XSTR_SIZEOF(TLS_PRF_LABEL_KEY_EXPANSION)}, - {NULL, 0}, -}; +#ifdef OPENSSL_EXTRA -/** - * Implement RFC 5705 - * TLS 1.3 uses a different exporter definition (section 7.5 of RFC 8446) - * @return WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on error +/* + * check if the list has TLS13 and pre-TLS13 suites + * @param list cipher suite list that user want to set + * (caller required to check for NULL) + * @return mixed: 0, only pre-TLS13: 1, only TLS13: 2 */ -int wolfSSL_export_keying_material(WOLFSSL *ssl, - unsigned char *out, size_t outLen, - const char *label, size_t labelLen, - const unsigned char *context, size_t contextLen, - int use_context) +static int CheckcipherList(const char* list) { - byte* seed = NULL; - word32 seedLen; - const struct ForbiddenLabels* fl; - - WOLFSSL_ENTER("wolfSSL_export_keying_material"); - - if (ssl == NULL || out == NULL || label == NULL || - (use_context && contextLen && context == NULL)) { - WOLFSSL_MSG("Bad argument"); - return WOLFSSL_FAILURE; - } - - /* Sanity check contextLen to prevent integer overflow when cast to word32 - * and to ensure it fits in the 2-byte length encoding (max 65535). */ - if (use_context && contextLen > WOLFSSL_MAX_16BIT) { - WOLFSSL_MSG("contextLen too large"); - return WOLFSSL_FAILURE; - } + int ret; + int findTLSv13Suites = 0; + int findbeforeSuites = 0; + byte cipherSuite0; + byte cipherSuite1; + int flags; + char* next = (char*)list; - /* clientRandom + serverRandom - * OR - * clientRandom + serverRandom + ctx len encoding + ctx */ - seedLen = !use_context ? (word32)SEED_LEN : - (word32)SEED_LEN + 2 + (word32)contextLen; + do { + char* current = next; + char name[MAX_SUITE_NAME + 1]; + word32 length = MAX_SUITE_NAME; + word32 current_length; + byte major = INVALID_BYTE; + byte minor = INVALID_BYTE; - if (ssl->options.saveArrays == 0 || ssl->arrays == NULL) { - WOLFSSL_MSG("To export keying material wolfSSL needs to keep handshake " - "data. Call wolfSSL_KeepArrays before attempting to " - "export keyid material."); - return WOLFSSL_FAILURE; - } + next = XSTRSTR(next, ":"); - /* check forbidden labels */ - for (fl = &forbiddenLabels[0]; fl->label != NULL; fl++) { - if (labelLen >= fl->labelLen && - XMEMCMP(label, fl->label, fl->labelLen) == 0) { - WOLFSSL_MSG("Forbidden label"); - return WOLFSSL_FAILURE; + if (next) { + current_length = (word32)(next - current); + ++next; /* increment to skip ':' */ } - } - -#ifdef WOLFSSL_TLS13 - if (IsAtLeastTLSv1_3(ssl->version)) { - /* Path for TLS 1.3 */ - if (!use_context) { - contextLen = 0; - context = (byte*)""; /* Give valid pointer for 0 length memcpy */ + else { + current_length = (word32)XSTRLEN(current); } - if (Tls13_Exporter(ssl, out, (word32)outLen, label, labelLen, - context, contextLen) != 0) { - WOLFSSL_MSG("Tls13_Exporter error"); - return WOLFSSL_FAILURE; + if (current_length == 0) { + break; } - return WOLFSSL_SUCCESS; - } -#endif - /* Path for <=TLS 1.2 */ - seed = (byte*)XMALLOC(seedLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (seed == NULL) { - WOLFSSL_MSG("malloc error"); - return WOLFSSL_FAILURE; - } + if (current_length < length) { + length = current_length; + } + XMEMCPY(name, current, length); + name[length] = 0; - XMEMCPY(seed, ssl->arrays->clientRandom, RAN_LEN); - XMEMCPY(seed + RAN_LEN, ssl->arrays->serverRandom, RAN_LEN); + if (XSTRCMP(name, "ALL") == 0 || + XSTRCMP(name, "DEFAULT") == 0 || + XSTRCMP(name, "HIGH") == 0) + { + findTLSv13Suites = 1; + findbeforeSuites = 1; + break; + } - if (use_context) { - /* Encode len in big endian */ - seed[SEED_LEN ] = (contextLen >> 8) & 0xFF; - seed[SEED_LEN + 1] = (contextLen) & 0xFF; - if (contextLen) { - /* 0 length context is allowed */ - XMEMCPY(seed + SEED_LEN + 2, context, contextLen); + ret = GetCipherSuiteFromName(name, &cipherSuite0, + &cipherSuite1, &major, &minor, &flags); + if (ret == 0) { + if (cipherSuite0 == TLS13_BYTE || minor == TLSv1_3_MINOR) { + /* TLSv13 suite */ + findTLSv13Suites = 1; + } + else { + findbeforeSuites = 1; + } } - } - PRIVATE_KEY_UNLOCK(); - if (wc_PRF_TLS(out, (word32)outLen, ssl->arrays->masterSecret, SECRET_LEN, - (byte*)label, (word32)labelLen, seed, seedLen, - IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm, ssl->heap, - ssl->devId) != 0) { - WOLFSSL_MSG("wc_PRF_TLS error"); - PRIVATE_KEY_LOCK(); - XFREE(seed, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return WOLFSSL_FAILURE; - } - PRIVATE_KEY_LOCK(); + #if defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) + /* check if mixed due to names like RSA:ECDHE+AESGCM etc. */ + if (ret != 0) { + char* subStr = name; + char* subStrNext; - XFREE(seed, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return WOLFSSL_SUCCESS; -} -#endif /* HAVE_KEYING_MATERIAL */ + do { + subStrNext = XSTRSTR(subStr, "+"); -int wolfSSL_dtls_get_using_nonblock(WOLFSSL* ssl) -{ - int useNb = 0; + if ((XSTRCMP(subStr, "ECDHE") == 0) || + (XSTRCMP(subStr, "RSA") == 0)) { + return 0; + } - if (ssl == NULL) - return WOLFSSL_FAILURE; + if (subStrNext && (XSTRLEN(subStrNext) > 0)) { + subStr = subStrNext + 1; /* +1 to skip past '+' */ + } + } while (subStrNext != NULL); + } + #endif - WOLFSSL_ENTER("wolfSSL_dtls_get_using_nonblock"); - if (ssl->options.dtls) { -#ifdef WOLFSSL_DTLS - useNb = ssl->options.dtlsUseNonblock; -#endif + if (findTLSv13Suites == 1 && findbeforeSuites == 1) { + /* list has mixed suites */ + return 0; + } + } while (next); + + if (findTLSv13Suites == 0 && findbeforeSuites == 1) { + ret = 1;/* only before TLSv13 suites */ + } + else if (findTLSv13Suites == 1 && findbeforeSuites == 0) { + ret = 2;/* only TLSv13 suties */ } else { - WOLFSSL_MSG("wolfSSL_dtls_get_using_nonblock() is " - "DEPRECATED for non-DTLS use."); + ret = 0;/* handle as mixed */ } - return useNb; + return ret; } - -#ifndef WOLFSSL_LEANPSK - -void wolfSSL_dtls_set_using_nonblock(WOLFSSL* ssl, int nonblock) +/* parse some bulk lists like !eNULL / !aNULL + * + * returns WOLFSSL_SUCCESS on success and sets the cipher suite list + */ +static int wolfSSL_parse_cipher_list(WOLFSSL_CTX* ctx, WOLFSSL* ssl, + Suites* suites, const char* list) { - (void)nonblock; + int ret = 0; + int listattribute = 0; + int tls13Only = 0; + WC_DECLARE_VAR(suitesCpy, byte, WOLFSSL_MAX_SUITE_SZ, 0); + word16 suitesCpySz = 0; + word16 i = 0; + word16 j = 0; - WOLFSSL_ENTER("wolfSSL_dtls_set_using_nonblock"); + if (suites == NULL || list == NULL) { + WOLFSSL_MSG("NULL argument"); + return WOLFSSL_FAILURE; + } - if (ssl == NULL) - return; + listattribute = CheckcipherList(list); - if (ssl->options.dtls) { -#ifdef WOLFSSL_DTLS - ssl->options.dtlsUseNonblock = (nonblock != 0); -#endif + if (listattribute == 0) { + /* list has mixed(pre-TLSv13 and TLSv13) suites + * update cipher suites the same as before + */ + return (SetCipherList_ex(ctx, ssl, suites, list)) ? WOLFSSL_SUCCESS : + WOLFSSL_FAILURE; } - else { - WOLFSSL_MSG("wolfSSL_dtls_set_using_nonblock() is " - "DEPRECATED for non-DTLS use."); + else if (listattribute == 1) { + /* list has only pre-TLSv13 suites. + * Only update before TLSv13 suites. + */ + tls13Only = 0; + } + else if (listattribute == 2) { + /* list has only TLSv13 suites. Only update TLv13 suites + * simulate set_ciphersuites() compatibility layer API + */ + tls13Only = 1; + if ((ctx != NULL && !IsAtLeastTLSv1_3(ctx->method->version)) || + (ssl != NULL && !IsAtLeastTLSv1_3(ssl->version))) { + /* Silently ignore TLS 1.3 ciphers if we don't support it. */ + return WOLFSSL_SUCCESS; + } } -} - - -#ifdef WOLFSSL_DTLS -int wolfSSL_dtls_get_current_timeout(WOLFSSL* ssl) -{ - int timeout = 0; - if (ssl) - timeout = ssl->dtls_timeout; + /* list contains ciphers either only for TLS 1.3 or <= TLS 1.2 */ +#ifdef WOLFSSL_SMALL_STACK + if (suites->suiteSz > 0) { + suitesCpy = (byte*)XMALLOC(suites->suiteSz, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (suitesCpy == NULL) { + return WOLFSSL_FAILURE; + } - WOLFSSL_LEAVE("wolfSSL_dtls_get_current_timeout", timeout); - return timeout; -} + XMEMSET(suitesCpy, 0, suites->suiteSz); + } +#else + XMEMSET(suitesCpy, 0, sizeof(suitesCpy)); +#endif -#ifdef WOLFSSL_DTLS13 + if (suites->suiteSz > 0) + XMEMCPY(suitesCpy, suites->suites, suites->suiteSz); + suitesCpySz = suites->suiteSz; -/* - * This API returns 1 when the user should set a short timeout for receiving - * data. It is recommended that it is at most 1/4 the value returned by - * wolfSSL_dtls_get_current_timeout(). - */ -int wolfSSL_dtls13_use_quick_timeout(WOLFSSL* ssl) -{ - return ssl != NULL && ssl->dtls13FastTimeout; -} + ret = SetCipherList_ex(ctx, ssl, suites, list); + if (ret != 1) { + WC_FREE_VAR_EX(suitesCpy, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_FAILURE; + } -/* - * When this is set, a DTLS 1.3 connection will send acks immediately when a - * disruption is detected to shortcut timeouts. This results in potentially - * more traffic but may make the handshake quicker. - */ -void wolfSSL_dtls13_set_send_more_acks(WOLFSSL* ssl, int value) -{ - if (ssl != NULL) - ssl->options.dtls13SendMoreAcks = !!value; -} -#endif /* WOLFSSL_DTLS13 */ + /* The idea in this section is that OpenSSL has two API to set ciphersuites. + * - SSL_CTX_set_cipher_list for setting TLS <= 1.2 suites + * - SSL_CTX_set_ciphersuites for setting TLS 1.3 suites + * Since we direct both API here we attempt to provide API compatibility. If + * we only get suites from <= 1.2 or == 1.3 then we will only update those + * suites and keep the suites from the other group. + * If downgrade is disabled, skip preserving the other group's suites. */ + if ((ssl != NULL && !ssl->options.downgrade) || + (ctx != NULL && !ctx->method->downgrade)) { + /* Downgrade disabled - don't preserve other group's suites */ + WC_FREE_VAR_EX(suitesCpy, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return ret; + } -int wolfSSL_DTLSv1_get_timeout(WOLFSSL* ssl, WOLFSSL_TIMEVAL* timeleft) -{ - if (ssl && timeleft) { - XMEMSET(timeleft, 0, sizeof(WOLFSSL_TIMEVAL)); - timeleft->tv_sec = ssl->dtls_timeout; + for (i = 0; i < suitesCpySz && + suites->suiteSz <= (WOLFSSL_MAX_SUITE_SZ - SUITE_LEN); i += 2) { + /* Check for duplicates */ + int duplicate = 0; + for (j = 0; j < suites->suiteSz; j += 2) { + if (suitesCpy[i] == suites->suites[j] && + suitesCpy[i+1] == suites->suites[j+1]) { + duplicate = 1; + break; + } + } + if (!duplicate) { + if (tls13Only) { + /* Updating TLS 1.3 ciphers */ + if (suitesCpy[i] != TLS13_BYTE) { + /* Only copy over <= TLS 1.2 ciphers */ + /* TLS 1.3 ciphers take precedence */ + suites->suites[suites->suiteSz++] = suitesCpy[i]; + suites->suites[suites->suiteSz++] = suitesCpy[i+1]; + } + } + else { + /* Updating <= TLS 1.2 ciphers */ + if (suitesCpy[i] == TLS13_BYTE) { + /* Only copy over TLS 1.3 ciphers */ + /* TLS 1.3 ciphers take precedence */ + XMEMMOVE(suites->suites + SUITE_LEN, suites->suites, + suites->suiteSz); + suites->suites[0] = suitesCpy[i]; + suites->suites[1] = suitesCpy[i+1]; + suites->suiteSz += 2; + } + } + } } - return 0; -} -#ifndef NO_WOLFSSL_STUB -int wolfSSL_DTLSv1_handle_timeout(WOLFSSL* ssl) -{ - WOLFSSL_STUB("SSL_DTLSv1_handle_timeout"); - (void)ssl; - return 0; + WC_FREE_VAR_EX(suitesCpy, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return ret; } -#endif -#ifndef NO_WOLFSSL_STUB -void wolfSSL_DTLSv1_set_initial_timeout_duration(WOLFSSL* ssl, - word32 duration_ms) -{ - WOLFSSL_STUB("SSL_DTLSv1_set_initial_timeout_duration"); - (void)ssl; - (void)duration_ms; -} #endif -/* user may need to alter init dtls recv timeout, WOLFSSL_SUCCESS on ok */ -int wolfSSL_dtls_set_timeout_init(WOLFSSL* ssl, int timeout) + +int wolfSSL_CTX_set_cipher_list(WOLFSSL_CTX* ctx, const char* list) { - if (ssl == NULL || timeout < 0) - return BAD_FUNC_ARG; + WOLFSSL_ENTER("wolfSSL_CTX_set_cipher_list"); - if (timeout > ssl->dtls_timeout_max) { - WOLFSSL_MSG("Can't set dtls timeout init greater than dtls timeout " - "max"); - return BAD_FUNC_ARG; - } + if (ctx == NULL) + return WOLFSSL_FAILURE; - ssl->dtls_timeout_init = timeout; - ssl->dtls_timeout = timeout; + if (AllocateCtxSuites(ctx) != 0) + return WOLFSSL_FAILURE; - return WOLFSSL_SUCCESS; +#ifdef OPENSSL_EXTRA + return wolfSSL_parse_cipher_list(ctx, NULL, ctx->suites, list); +#else + return (SetCipherList(ctx, ctx->suites, list)) ? + WOLFSSL_SUCCESS : WOLFSSL_FAILURE; +#endif } - -/* user may need to alter max dtls recv timeout, WOLFSSL_SUCCESS on ok */ -int wolfSSL_dtls_set_timeout_max(WOLFSSL* ssl, int timeout) +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_SET_CIPHER_BYTES) +int wolfSSL_CTX_set_cipher_list_bytes(WOLFSSL_CTX* ctx, const byte* list, + const int listSz) { - if (ssl == NULL || timeout < 0) - return BAD_FUNC_ARG; + WOLFSSL_ENTER("wolfSSL_CTX_set_cipher_list_bytes"); - if (timeout < ssl->dtls_timeout_init) { - WOLFSSL_MSG("Can't set dtls timeout max less than dtls timeout init"); - return BAD_FUNC_ARG; - } + if (ctx == NULL) + return WOLFSSL_FAILURE; - ssl->dtls_timeout_max = timeout; + if (AllocateCtxSuites(ctx) != 0) + return WOLFSSL_FAILURE; - return WOLFSSL_SUCCESS; + return (SetCipherListFromBytes(ctx, ctx->suites, list, listSz)) ? + WOLFSSL_SUCCESS : WOLFSSL_FAILURE; } +#endif /* OPENSSL_EXTRA || WOLFSSL_SET_CIPHER_BYTES */ - -int wolfSSL_dtls_got_timeout(WOLFSSL* ssl) +int wolfSSL_set_cipher_list(WOLFSSL* ssl, const char* list) { - int result = WOLFSSL_SUCCESS; - WOLFSSL_ENTER("wolfSSL_dtls_got_timeout"); - - if (ssl == NULL || !ssl->options.dtls) - return WOLFSSL_FATAL_ERROR; - -#ifdef WOLFSSL_DTLS13 - if (IsAtLeastTLSv1_3(ssl->version)) { - result = Dtls13RtxTimeout(ssl); - if (result < 0) { - if (result == WC_NO_ERR_TRACE(WANT_WRITE)) - ssl->dtls13SendingAckOrRtx = 1; - ssl->error = result; - WOLFSSL_ERROR(result); - return WOLFSSL_FATAL_ERROR; - } - - return WOLFSSL_SUCCESS; - } -#endif /* WOLFSSL_DTLS13 */ + WOLFSSL_ENTER("wolfSSL_set_cipher_list"); - /* Do we have any 1.2 messages stored? */ - if (ssl->dtls_tx_msg_list != NULL || ssl->dtls_tx_msg != NULL) { - if (DtlsMsgPoolTimeout(ssl) < 0){ - ssl->error = SOCKET_ERROR_E; - WOLFSSL_ERROR(ssl->error); - result = WOLFSSL_FATAL_ERROR; - } - else if ((result = DtlsMsgPoolSend(ssl, 0)) < 0) { - ssl->error = result; - WOLFSSL_ERROR(result); - result = WOLFSSL_FATAL_ERROR; - } - else { - /* Reset return value to success */ - result = WOLFSSL_SUCCESS; - } + if (ssl == NULL || ssl->ctx == NULL) { + return WOLFSSL_FAILURE; } - WOLFSSL_LEAVE("wolfSSL_dtls_got_timeout", result); - return result; -} + if (AllocateSuites(ssl) != 0) + return WOLFSSL_FAILURE; +#ifdef OPENSSL_EXTRA + return wolfSSL_parse_cipher_list(NULL, ssl, ssl->suites, list); +#else + return (SetCipherList_ex(NULL, ssl, ssl->suites, list)) ? + WOLFSSL_SUCCESS : + WOLFSSL_FAILURE; +#endif +} -/* retransmit all the saves messages, WOLFSSL_SUCCESS on ok */ -int wolfSSL_dtls_retransmit(WOLFSSL* ssl) +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_SET_CIPHER_BYTES) +int wolfSSL_set_cipher_list_bytes(WOLFSSL* ssl, const byte* list, + const int listSz) { - WOLFSSL_ENTER("wolfSSL_dtls_retransmit"); - - if (ssl == NULL) - return WOLFSSL_FATAL_ERROR; + WOLFSSL_ENTER("wolfSSL_set_cipher_list_bytes"); - if (!ssl->options.handShakeDone) { - int result; -#ifdef WOLFSSL_DTLS13 - if (IsAtLeastTLSv1_3(ssl->version)) - result = Dtls13DoScheduledWork(ssl); - else -#endif - result = DtlsMsgPoolSend(ssl, 0); - if (result < 0) { - ssl->error = result; - WOLFSSL_ERROR(result); - return WOLFSSL_FATAL_ERROR; - } + if (ssl == NULL || ssl->ctx == NULL) { + return WOLFSSL_FAILURE; } - return WOLFSSL_SUCCESS; + if (AllocateSuites(ssl) != 0) + return WOLFSSL_FAILURE; + + return (SetCipherListFromBytes(ssl->ctx, ssl->suites, list, listSz)) + ? WOLFSSL_SUCCESS + : WOLFSSL_FAILURE; } +#endif /* OPENSSL_EXTRA || WOLFSSL_SET_CIPHER_BYTES */ -#endif /* DTLS */ -#endif /* LEANPSK */ +#ifdef HAVE_KEYING_MATERIAL -#if defined(WOLFSSL_DTLS) && !defined(NO_WOLFSSL_SERVER) +#define TLS_PRF_LABEL_CLIENT_FINISHED "client finished" +#define TLS_PRF_LABEL_SERVER_FINISHED "server finished" +#define TLS_PRF_LABEL_MASTER_SECRET "master secret" +#define TLS_PRF_LABEL_EXT_MASTER_SECRET "extended master secret" +#define TLS_PRF_LABEL_KEY_EXPANSION "key expansion" + +static const struct ForbiddenLabels { + const char* label; + size_t labelLen; +} forbiddenLabels[] = { + {TLS_PRF_LABEL_CLIENT_FINISHED, XSTR_SIZEOF(TLS_PRF_LABEL_CLIENT_FINISHED)}, + {TLS_PRF_LABEL_SERVER_FINISHED, XSTR_SIZEOF(TLS_PRF_LABEL_SERVER_FINISHED)}, + {TLS_PRF_LABEL_MASTER_SECRET, XSTR_SIZEOF(TLS_PRF_LABEL_MASTER_SECRET)}, + {TLS_PRF_LABEL_EXT_MASTER_SECRET, + XSTR_SIZEOF(TLS_PRF_LABEL_EXT_MASTER_SECRET)}, + {TLS_PRF_LABEL_KEY_EXPANSION, XSTR_SIZEOF(TLS_PRF_LABEL_KEY_EXPANSION)}, + {NULL, 0}, +}; -/* Not an SSL function, return 0 for success, error code otherwise */ -/* Prereq: ssl's RNG needs to be initialized. */ -int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, - const byte* secret, word32 secretSz) +/** + * Implement RFC 5705 + * TLS 1.3 uses a different exporter definition (section 7.5 of RFC 8446) + * @return WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on error + */ +int wolfSSL_export_keying_material(WOLFSSL *ssl, + unsigned char *out, size_t outLen, + const char *label, size_t labelLen, + const unsigned char *context, size_t contextLen, + int use_context) { - int ret = 0; + byte* seed = NULL; + word32 seedLen; + const struct ForbiddenLabels* fl; - WOLFSSL_ENTER("wolfSSL_DTLS_SetCookieSecret"); + WOLFSSL_ENTER("wolfSSL_export_keying_material"); - if (ssl == NULL) { - WOLFSSL_MSG("need a SSL object"); - return BAD_FUNC_ARG; + if (ssl == NULL || out == NULL || label == NULL || + (use_context && contextLen && context == NULL)) { + WOLFSSL_MSG("Bad argument"); + return WOLFSSL_FAILURE; } - if (secret != NULL && secretSz == 0) { - WOLFSSL_MSG("can't have a new secret without a size"); - return BAD_FUNC_ARG; + /* Sanity check contextLen to prevent integer overflow when cast to word32 + * and to ensure it fits in the 2-byte length encoding (max 65535). */ + if (use_context && contextLen > WOLFSSL_MAX_16BIT) { + WOLFSSL_MSG("contextLen too large"); + return WOLFSSL_FAILURE; } - /* If secretSz is 0, use the default size. */ - if (secretSz == 0) - secretSz = COOKIE_SECRET_SZ; + /* clientRandom + serverRandom + * OR + * clientRandom + serverRandom + ctx len encoding + ctx */ + seedLen = !use_context ? (word32)SEED_LEN : + (word32)SEED_LEN + 2 + (word32)contextLen; + + if (ssl->options.saveArrays == 0 || ssl->arrays == NULL) { + WOLFSSL_MSG("To export keying material wolfSSL needs to keep handshake " + "data. Call wolfSSL_KeepArrays before attempting to " + "export keyid material."); + return WOLFSSL_FAILURE; + } - if (secretSz != ssl->buffers.dtlsCookieSecret.length) { - byte* newSecret; + /* check forbidden labels */ + for (fl = &forbiddenLabels[0]; fl->label != NULL; fl++) { + if (labelLen >= fl->labelLen && + XMEMCMP(label, fl->label, fl->labelLen) == 0) { + WOLFSSL_MSG("Forbidden label"); + return WOLFSSL_FAILURE; + } + } - if (ssl->buffers.dtlsCookieSecret.buffer != NULL) { - ForceZero(ssl->buffers.dtlsCookieSecret.buffer, - ssl->buffers.dtlsCookieSecret.length); - XFREE(ssl->buffers.dtlsCookieSecret.buffer, - ssl->heap, DYNAMIC_TYPE_COOKIE_PWD); +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version)) { + /* Path for TLS 1.3 */ + if (!use_context) { + contextLen = 0; + context = (byte*)""; /* Give valid pointer for 0 length memcpy */ } - newSecret = (byte*)XMALLOC(secretSz, ssl->heap,DYNAMIC_TYPE_COOKIE_PWD); - if (newSecret == NULL) { - ssl->buffers.dtlsCookieSecret.buffer = NULL; - ssl->buffers.dtlsCookieSecret.length = 0; - WOLFSSL_MSG("couldn't allocate new cookie secret"); - return MEMORY_ERROR; + if (Tls13_Exporter(ssl, out, (word32)outLen, label, labelLen, + context, contextLen) != 0) { + WOLFSSL_MSG("Tls13_Exporter error"); + return WOLFSSL_FAILURE; } - ssl->buffers.dtlsCookieSecret.buffer = newSecret; - ssl->buffers.dtlsCookieSecret.length = secretSz; - #ifdef WOLFSSL_CHECK_MEM_ZERO - wc_MemZero_Add("wolfSSL_DTLS_SetCookieSecret secret", - ssl->buffers.dtlsCookieSecret.buffer, - ssl->buffers.dtlsCookieSecret.length); - #endif + return WOLFSSL_SUCCESS; } +#endif - /* If the supplied secret is NULL, randomly generate a new secret. */ - if (secret == NULL) { - ret = wc_RNG_GenerateBlock(ssl->rng, - ssl->buffers.dtlsCookieSecret.buffer, secretSz); + /* Path for <=TLS 1.2 */ + seed = (byte*)XMALLOC(seedLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (seed == NULL) { + WOLFSSL_MSG("malloc error"); + return WOLFSSL_FAILURE; } - else - XMEMCPY(ssl->buffers.dtlsCookieSecret.buffer, secret, secretSz); - WOLFSSL_LEAVE("wolfSSL_DTLS_SetCookieSecret", 0); - return ret; -} + XMEMCPY(seed, ssl->arrays->clientRandom, RAN_LEN); + XMEMCPY(seed + RAN_LEN, ssl->arrays->serverRandom, RAN_LEN); + + if (use_context) { + /* Encode len in big endian */ + seed[SEED_LEN ] = (contextLen >> 8) & 0xFF; + seed[SEED_LEN + 1] = (contextLen) & 0xFF; + if (contextLen) { + /* 0 length context is allowed */ + XMEMCPY(seed + SEED_LEN + 2, context, contextLen); + } + } + + PRIVATE_KEY_UNLOCK(); + if (wc_PRF_TLS(out, (word32)outLen, ssl->arrays->masterSecret, SECRET_LEN, + (byte*)label, (word32)labelLen, seed, seedLen, + IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm, ssl->heap, + ssl->devId) != 0) { + WOLFSSL_MSG("wc_PRF_TLS error"); + PRIVATE_KEY_LOCK(); + XFREE(seed, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_FAILURE; + } + PRIVATE_KEY_LOCK(); -#endif /* WOLFSSL_DTLS && !NO_WOLFSSL_SERVER */ + XFREE(seed, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_SUCCESS; +} +#endif /* HAVE_KEYING_MATERIAL */ /* EITHER SIDE METHODS */ @@ -10464,8 +8224,7 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out, #endif /* OPENSSL_EXTRA */ -#if (defined(KEEP_PEER_CERT) && defined(SESSION_CERTS)) || \ - (defined(OPENSSL_EXTRA) && defined(SESSION_CERTS)) +#ifdef SESSION_CERTS /* Decode the X509 DER encoded certificate into a WOLFSSL_X509 object. * * x509 WOLFSSL_X509 object to decode into. @@ -10497,7 +8256,7 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out, return ret; } -#endif /* (KEEP_PEER_CERT & SESSION_CERTS) || (OPENSSL_EXTRA & SESSION_CERTS) */ +#endif /* SESSION_CERTS */ #ifdef KEEP_PEER_CERT @@ -11987,19 +9746,6 @@ WOLFSSL_X509_VERIFY_PARAM* wolfSSL_get0_param(WOLFSSL* ssl) #endif /* OPENSSL_EXTRA */ -#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) -/* Gets an index to store SSL structure at. - * - * Returns positive index on success and negative values on failure - */ -int wolfSSL_get_ex_data_X509_STORE_CTX_idx(void) -{ - WOLFSSL_ENTER("wolfSSL_get_ex_data_X509_STORE_CTX_idx"); - - /* store SSL at index 0 */ - return 0; -} -#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */ #ifdef OPENSSL_EXTRA /* Sets a function callback that will send information about the state of all @@ -12847,70 +10593,6 @@ long wolfSSL_clear_options(WOLFSSL* ssl, long opt) return (long)ssl->options.mask; } -#ifdef HAVE_PK_CALLBACKS -long wolfSSL_set_tlsext_debug_arg(WOLFSSL* ssl, void *arg) -{ - if (ssl == NULL) { - return WOLFSSL_FAILURE; - } - - ssl->loggingCtx = arg; - return WOLFSSL_SUCCESS; -} -#endif /* HAVE_PK_CALLBACKS */ - -#ifndef NO_WOLFSSL_STUB -long wolfSSL_get_tlsext_status_exts(WOLFSSL *s, void *arg) -{ - (void)s; - (void)arg; - WOLFSSL_STUB("wolfSSL_get_tlsext_status_exts"); - return WOLFSSL_FAILURE; -} -#endif - -/*** TBD ***/ -#ifndef NO_WOLFSSL_STUB -long wolfSSL_set_tlsext_status_exts(WOLFSSL *s, void *arg) -{ - (void)s; - (void)arg; - WOLFSSL_STUB("wolfSSL_set_tlsext_status_exts"); - return WOLFSSL_FAILURE; -} -#endif - -/*** TBD ***/ -#ifndef NO_WOLFSSL_STUB -long wolfSSL_get_tlsext_status_ids(WOLFSSL *s, void *arg) -{ - (void)s; - (void)arg; - WOLFSSL_STUB("wolfSSL_get_tlsext_status_ids"); - return WOLFSSL_FAILURE; -} -#endif - -/*** TBD ***/ -#ifndef NO_WOLFSSL_STUB -long wolfSSL_set_tlsext_status_ids(WOLFSSL *s, void *arg) -{ - (void)s; - (void)arg; - WOLFSSL_STUB("wolfSSL_set_tlsext_status_ids"); - return WOLFSSL_FAILURE; -} -#endif - -#ifndef NO_WOLFSSL_STUB -/*** TBD ***/ -WOLFSSL_EVP_PKEY *wolfSSL_get_privatekey(const WOLFSSL *ssl) -{ - (void)ssl; - WOLFSSL_STUB("SSL_get_privatekey"); - return NULL; -} -#endif #ifndef NO_WOLFSSL_STUB /*** TBD ***/ @@ -12940,37 +10622,6 @@ void wolfSSL_ERR_load_SSL_strings(void) } #endif -#ifdef HAVE_MAX_FRAGMENT -#if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS) -/** - * Set max fragment tls extension - * @param c a pointer to WOLFSSL_CTX object - * @param mode maximum fragment length mode - * @return 1 on success, otherwise 0 or negative error code - */ -int wolfSSL_CTX_set_tlsext_max_fragment_length(WOLFSSL_CTX *c, - unsigned char mode) -{ - if (c == NULL || (mode < WOLFSSL_MFL_2_9 || mode > WOLFSSL_MFL_2_12 )) - return BAD_FUNC_ARG; - - return wolfSSL_CTX_UseMaxFragment(c, mode); -} -/** - * Set max fragment tls extension - * @param c a pointer to WOLFSSL object - * @param mode maximum fragment length mode - * @return 1 on success, otherwise 0 or negative error code - */ -int wolfSSL_set_tlsext_max_fragment_length(WOLFSSL *s, unsigned char mode) -{ - if (s == NULL || (mode < WOLFSSL_MFL_2_9 || mode > WOLFSSL_MFL_2_12 )) - return BAD_FUNC_ARG; - - return wolfSSL_UseMaxFragment(s, mode); -} -#endif /* !NO_WOLFSSL_CLIENT && !NO_TLS */ -#endif /* HAVE_MAX_FRAGMENT */ #endif /* OPENSSL_EXTRA */ @@ -13020,17 +10671,6 @@ size_t wolfSSL_get_peer_finished(const WOLFSSL *ssl, void *buf, size_t count) } #endif /* WOLFSSL_HAVE_TLS_UNIQUE */ -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) || \ - defined(OPENSSL_ALL) -long wolfSSL_get_verify_result(const WOLFSSL *ssl) -{ - if (ssl == NULL) { - return WOLFSSL_FAILURE; - } - - return (long)ssl->peerVerifyRet; -} -#endif #ifdef OPENSSL_EXTRA @@ -13193,90 +10833,18 @@ int wolfSSL_CTX_set_read_ahead(WOLFSSL_CTX* ctx, int v) long wolfSSL_CTX_set_tlsext_opaque_prf_input_callback_arg(WOLFSSL_CTX* ctx, - void* arg) -{ - if (ctx == NULL) { - return WOLFSSL_FAILURE; - } - - ctx->userPRFArg = arg; - return WOLFSSL_SUCCESS; -} - -#endif /* OPENSSL_EXTRA */ - -#if defined(OPENSSL_EXTRA) && defined(KEEP_PEER_CERT) && \ - defined(HAVE_EX_DATA) && !defined(NO_FILESYSTEM) -int wolfSSL_cmp_peer_cert_to_file(WOLFSSL* ssl, const char *fname) -{ - int ret = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR); - - WOLFSSL_ENTER("wolfSSL_cmp_peer_cert_to_file"); - if (ssl != NULL && fname != NULL) - { - #ifdef WOLFSSL_SMALL_STACK - byte staticBuffer[1]; /* force heap usage */ - #else - byte staticBuffer[FILE_BUFFER_SIZE]; - #endif - byte* myBuffer = staticBuffer; - int dynamic = 0; - XFILE file; - long sz = 0; - WOLFSSL_CTX* ctx = ssl->ctx; - WOLFSSL_X509* peer_cert = &ssl->peerCert; - DerBuffer* fileDer = NULL; - - file = XFOPEN(fname, "rb"); - if (file == XBADFILE) - return WOLFSSL_BAD_FILE; - - if (XFSEEK(file, 0, XSEEK_END) != 0) { - XFCLOSE(file); - return WOLFSSL_BAD_FILE; - } - sz = XFTELL(file); - if (XFSEEK(file, 0, XSEEK_SET) != 0) { - XFCLOSE(file); - return WOLFSSL_BAD_FILE; - } - - if (sz > MAX_WOLFSSL_FILE_SIZE || sz < 0) { - WOLFSSL_MSG("cmp_peer_cert_to_file size error"); - XFCLOSE(file); - return WOLFSSL_BAD_FILE; - } - - if (sz > (long)sizeof(staticBuffer)) { - WOLFSSL_MSG("Getting dynamic buffer"); - myBuffer = (byte*)XMALLOC((size_t)sz, ctx->heap, DYNAMIC_TYPE_FILE); - dynamic = 1; - } - - if ((myBuffer != NULL) && - (sz > 0) && - (XFREAD(myBuffer, 1, (size_t)sz, file) == (size_t)sz) && - (PemToDer(myBuffer, (long)sz, CERT_TYPE, - &fileDer, ctx->heap, NULL, NULL) == 0) && - (fileDer->length != 0) && - (fileDer->length == peer_cert->derCert->length) && - (XMEMCMP(peer_cert->derCert->buffer, fileDer->buffer, - fileDer->length) == 0)) - { - ret = 0; - } - - FreeDer(&fileDer); - - if (dynamic) - XFREE(myBuffer, ctx->heap, DYNAMIC_TYPE_FILE); - - XFCLOSE(file); + void* arg) +{ + if (ctx == NULL) { + return WOLFSSL_FAILURE; } - return ret; + ctx->userPRFArg = arg; + return WOLFSSL_SUCCESS; } -#endif + +#endif /* OPENSSL_EXTRA */ + #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) const WOLFSSL_ObjectInfo wolfssl_object_info[] = { @@ -13850,416 +11418,8 @@ int wolfSSL_OPENSSL_init_crypto(word64 opts, return wolfSSL_library_init(); } -/* Colon separated list of + algorithms. - * Replaces list in context. - */ -int wolfSSL_CTX_set1_sigalgs_list(WOLFSSL_CTX* ctx, const char* list) -{ - WOLFSSL_MSG("wolfSSL_CTX_set1_sigalg_list"); - - if (ctx == NULL || list == NULL) { - WOLFSSL_MSG("Bad function arguments"); - return WOLFSSL_FAILURE; - } - - if (AllocateCtxSuites(ctx) != 0) - return WOLFSSL_FAILURE; - - return SetSuitesHashSigAlgo(ctx->suites, list); -} - -/* Colon separated list of + algorithms. - * Replaces list in SSL. - */ -int wolfSSL_set1_sigalgs_list(WOLFSSL* ssl, const char* list) -{ - WOLFSSL_MSG("wolfSSL_set1_sigalg_list"); - - if (ssl == NULL || list == NULL) { - WOLFSSL_MSG("Bad function arguments"); - return WOLFSSL_FAILURE; - } - - if (AllocateSuites(ssl) != 0) - return WOLFSSL_FAILURE; - - return SetSuitesHashSigAlgo(ssl->suites, list); -} - -static int HashToNid(byte hashAlgo, int* nid) -{ - int ret = WOLFSSL_SUCCESS; - - /* Cast for compiler to check everything is implemented */ - switch ((enum wc_MACAlgorithm)hashAlgo) { - case no_mac: - case rmd_mac: - *nid = WC_NID_undef; - break; - case md5_mac: - *nid = WC_NID_md5; - break; - case sha_mac: - *nid = WC_NID_sha1; - break; - case sha224_mac: - *nid = WC_NID_sha224; - break; - case sha256_mac: - *nid = WC_NID_sha256; - break; - case sha384_mac: - *nid = WC_NID_sha384; - break; - case sha512_mac: - *nid = WC_NID_sha512; - break; - case blake2b_mac: - *nid = WC_NID_blake2b512; - break; - case sm3_mac: - *nid = WC_NID_sm3; - break; - default: - ret = WOLFSSL_FAILURE; - break; - } - - return ret; -} - -static int SaToNid(byte sa, int* nid) -{ - int ret = WOLFSSL_SUCCESS; - /* Cast for compiler to check everything is implemented */ - switch ((enum SignatureAlgorithm)sa) { - case anonymous_sa_algo: - *nid = WC_NID_undef; - break; - case rsa_sa_algo: - *nid = WC_NID_rsaEncryption; - break; - case dsa_sa_algo: - *nid = WC_NID_dsa; - break; - case ecc_dsa_sa_algo: - case ecc_brainpool_sa_algo: - *nid = WC_NID_X9_62_id_ecPublicKey; - break; - case rsa_pss_sa_algo: - *nid = WC_NID_rsassaPss; - break; - case ed25519_sa_algo: -#ifdef HAVE_ED25519 - *nid = WC_NID_ED25519; -#else - ret = WOLFSSL_FAILURE; -#endif - break; - case rsa_pss_pss_algo: - *nid = WC_NID_rsassaPss; - break; - case ed448_sa_algo: -#ifdef HAVE_ED448 - *nid = WC_NID_ED448; -#else - ret = WOLFSSL_FAILURE; -#endif - break; - case falcon_level1_sa_algo: - *nid = CTC_FALCON_LEVEL1; - break; - case falcon_level5_sa_algo: - *nid = CTC_FALCON_LEVEL5; - break; - case mldsa_44_sa_algo: - *nid = CTC_ML_DSA_44; - break; - case mldsa_65_sa_algo: - *nid = CTC_ML_DSA_65; - break; - case mldsa_87_sa_algo: - *nid = CTC_ML_DSA_87; - break; - case sm2_sa_algo: - *nid = WC_NID_sm2; - break; - case invalid_sa_algo: - case any_sa_algo: - default: - ret = WOLFSSL_FAILURE; - break; - } - return ret; -} - -/* This API returns the hash selected. */ -int wolfSSL_get_signature_nid(WOLFSSL *ssl, int* nid) -{ - WOLFSSL_MSG("wolfSSL_get_signature_nid"); - - if (ssl == NULL || nid == NULL) { - WOLFSSL_MSG("Bad function arguments"); - return WOLFSSL_FAILURE; - } - - return HashToNid(ssl->options.hashAlgo, nid); -} - -/* This API returns the signature selected. */ -int wolfSSL_get_signature_type_nid(const WOLFSSL* ssl, int* nid) -{ - WOLFSSL_MSG("wolfSSL_get_signature_type_nid"); - - if (ssl == NULL || nid == NULL) { - WOLFSSL_MSG("Bad function arguments"); - return WOLFSSL_FAILURE; - } - - return SaToNid(ssl->options.sigAlgo, nid); -} - -int wolfSSL_get_peer_signature_nid(WOLFSSL* ssl, int* nid) -{ - WOLFSSL_MSG("wolfSSL_get_peer_signature_nid"); - - if (ssl == NULL || nid == NULL) { - WOLFSSL_MSG("Bad function arguments"); - return WOLFSSL_FAILURE; - } - - return HashToNid(ssl->options.peerHashAlgo, nid); -} - -int wolfSSL_get_peer_signature_type_nid(const WOLFSSL* ssl, int* nid) -{ - WOLFSSL_MSG("wolfSSL_get_peer_signature_type_nid"); - - if (ssl == NULL || nid == NULL) { - WOLFSSL_MSG("Bad function arguments"); - return WOLFSSL_FAILURE; - } - - return SaToNid(ssl->options.peerSigAlgo, nid); -} - -#ifdef HAVE_ECC - -#if defined(WOLFSSL_TLS13) && defined(HAVE_SUPPORTED_CURVES) -int wolfSSL_CTX_set1_groups_list(WOLFSSL_CTX *ctx, const char *list) -{ - if (!ctx || !list) { - return WOLFSSL_FAILURE; - } - - return set_curves_list(NULL, ctx, list, 0); -} - -int wolfSSL_set1_groups_list(WOLFSSL *ssl, const char *list) -{ - if (!ssl || !list) { - return WOLFSSL_FAILURE; - } - - return set_curves_list(ssl, NULL, list, 0); -} -#endif /* WOLFSSL_TLS13 */ - -#endif /* HAVE_ECC */ - #endif /* OPENSSL_EXTRA */ -#ifdef WOLFSSL_ALT_CERT_CHAINS -int wolfSSL_is_peer_alt_cert_chain(const WOLFSSL* ssl) -{ - int isUsing = 0; - if (ssl) - isUsing = ssl->options.usingAltCertChain; - return isUsing; -} -#endif /* WOLFSSL_ALT_CERT_CHAINS */ - - -#ifdef SESSION_CERTS - -#ifdef WOLFSSL_ALT_CERT_CHAINS -/* Get peer's alternate certificate chain */ -WOLFSSL_X509_CHAIN* wolfSSL_get_peer_alt_chain(WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_get_peer_alt_chain"); - if (ssl) - return &ssl->session->altChain; - - return 0; -} -#endif /* WOLFSSL_ALT_CERT_CHAINS */ - - -/* Get peer's certificate chain */ -WOLFSSL_X509_CHAIN* wolfSSL_get_peer_chain(WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_get_peer_chain"); - if (ssl) - return &ssl->session->chain; - - return 0; -} - - -/* Get peer's certificate chain total count */ -int wolfSSL_get_chain_count(WOLFSSL_X509_CHAIN* chain) -{ - WOLFSSL_ENTER("wolfSSL_get_chain_count"); - if (chain) - return chain->count; - - return 0; -} - - -/* Get peer's ASN.1 DER certificate at index (idx) length in bytes */ -int wolfSSL_get_chain_length(WOLFSSL_X509_CHAIN* chain, int idx) -{ - WOLFSSL_ENTER("wolfSSL_get_chain_length"); - if (chain) - return chain->certs[idx].length; - - return 0; -} - - -/* Get peer's ASN.1 DER certificate at index (idx) */ -byte* wolfSSL_get_chain_cert(WOLFSSL_X509_CHAIN* chain, int idx) -{ - WOLFSSL_ENTER("wolfSSL_get_chain_cert"); - if (chain) - return chain->certs[idx].buffer; - - return 0; -} - - -/* Get peer's wolfSSL X509 certificate at index (idx) */ -WOLFSSL_X509* wolfSSL_get_chain_X509(WOLFSSL_X509_CHAIN* chain, int idx) -{ - int ret = 0; - WOLFSSL_X509* x509 = NULL; - WC_DECLARE_VAR(cert, DecodedCert, 1, 0); - - WOLFSSL_ENTER("wolfSSL_get_chain_X509"); - if (chain != NULL && idx < MAX_CHAIN_DEPTH) { - #ifdef WOLFSSL_SMALL_STACK - cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, - DYNAMIC_TYPE_DCERT); - if (cert != NULL) - #endif - { - InitDecodedCert(cert, chain->certs[idx].buffer, - (word32)chain->certs[idx].length, NULL); - - if ((ret = ParseCertRelative(cert, CERT_TYPE, 0, NULL, NULL)) != 0) { - WOLFSSL_MSG("Failed to parse cert"); - } - else { - x509 = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), NULL, - DYNAMIC_TYPE_X509); - if (x509 == NULL) { - WOLFSSL_MSG("Failed alloc X509"); - } - else { - InitX509(x509, 1, NULL); - - if ((ret = CopyDecodedToX509(x509, cert)) != 0) { - WOLFSSL_MSG("Failed to copy decoded"); - wolfSSL_X509_free(x509); - x509 = NULL; - } - } - } - - FreeDecodedCert(cert); - WC_FREE_VAR_EX(cert, NULL, DYNAMIC_TYPE_DCERT); - } - } - (void)ret; - - return x509; -} - - -/* Get peer's PEM certificate at index (idx), output to buffer if inLen big - enough else return error (-1). If buffer is NULL only calculate - outLen. Output length is in *outLen WOLFSSL_SUCCESS on ok */ -int wolfSSL_get_chain_cert_pem(WOLFSSL_X509_CHAIN* chain, int idx, - unsigned char* buf, int inLen, int* outLen) -{ -#if defined(WOLFSSL_PEM_TO_DER) || defined(WOLFSSL_DER_TO_PEM) - const char* header = NULL; - const char* footer = NULL; - int headerLen; - int footerLen; - int i; - int err; - word32 szNeeded = 0; - - WOLFSSL_ENTER("wolfSSL_get_chain_cert_pem"); - if (!chain || !outLen || idx < 0 || idx >= wolfSSL_get_chain_count(chain)) - return BAD_FUNC_ARG; - - err = wc_PemGetHeaderFooter(CERT_TYPE, &header, &footer); - if (err != 0) - return err; - - headerLen = (int)XSTRLEN(header); - footerLen = (int)XSTRLEN(footer); - - /* Null output buffer return size needed in outLen */ - if(!buf) { - if(Base64_Encode(chain->certs[idx].buffer, - (word32)chain->certs[idx].length, - NULL, &szNeeded) != WC_NO_ERR_TRACE(LENGTH_ONLY_E)) - return WOLFSSL_FAILURE; - *outLen = (int)szNeeded + headerLen + footerLen; - return WC_NO_ERR_TRACE(LENGTH_ONLY_E); - } - - /* don't even try if inLen too short */ - if (inLen < headerLen + footerLen + chain->certs[idx].length) - return BAD_FUNC_ARG; - - /* header */ - if (XMEMCPY(buf, header, (size_t)headerLen) == NULL) - return WOLFSSL_FATAL_ERROR; - - i = headerLen; - - /* body */ - *outLen = inLen; /* input to Base64_Encode */ - if ( (err = Base64_Encode(chain->certs[idx].buffer, - (word32)chain->certs[idx].length, buf + i, - (word32*)outLen)) < 0) - return err; - i += *outLen; - - /* footer */ - if ( (i + footerLen) > inLen) - return BAD_FUNC_ARG; - if (XMEMCPY(buf + i, footer, (size_t)footerLen) == NULL) - return WOLFSSL_FATAL_ERROR; - *outLen += headerLen + footerLen; - - return WOLFSSL_SUCCESS; -#else - (void)chain; - (void)idx; - (void)buf; - (void)inLen; - (void)outLen; - return WOLFSSL_FAILURE; -#endif /* WOLFSSL_PEM_TO_DER || WOLFSSL_DER_TO_PEM */ -} - -#endif /* SESSION_CERTS */ #ifdef HAVE_FUZZER void wolfSSL_SetFuzzerCb(WOLFSSL* ssl, CallbackFuzzer cbf, void* fCtx) @@ -15736,27 +12896,10 @@ long wolfSSL_CTX_callback_ctrl(WOLFSSL_CTX* ctx, int cmd, void (*fp)(void)) (void) fp; WOLFSSL_STUB("wolfSSL_CTX_callback_ctrl"); return WOLFSSL_FAILURE; - -} -#endif /* NO_WOLFSSL_STUB */ - -#ifndef NO_WOLFSSL_STUB -long wolfSSL_CTX_clear_extra_chain_certs(WOLFSSL_CTX* ctx) -{ - return wolfSSL_CTX_ctrl(ctx, SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS, 0L, NULL); -} -#endif - -/* Returns the verifyCallback from the ssl structure if successful. -Returns NULL otherwise. */ -VerifyCallback wolfSSL_get_verify_callback(WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_get_verify_callback"); - if (ssl) { - return ssl->verifyCallback; - } - return NULL; + } +#endif /* NO_WOLFSSL_STUB */ + #endif /* OPENSSL_ALL || WOLFSSL_ASIO || WOLFSSL_HAPROXY || WOLFSSL_QT */ @@ -15910,32 +13053,6 @@ int wolfSSL_CIPHER_get_bits(const WOLFSSL_CIPHER *c, int *alg_bits) return ret; } -#ifdef HAVE_SNI -int wolfSSL_set_tlsext_host_name(WOLFSSL* ssl, const char* host_name) -{ - int ret; - WOLFSSL_ENTER("wolfSSL_set_tlsext_host_name"); - ret = wolfSSL_UseSNI(ssl, WOLFSSL_SNI_HOST_NAME, - host_name, (word16)XSTRLEN(host_name)); - WOLFSSL_LEAVE("wolfSSL_set_tlsext_host_name", ret); - return ret; -} - -#ifndef NO_WOLFSSL_SERVER -/* May be called by server to get the requested accepted name and by the client - * to get the requested name. */ -const char * wolfSSL_get_servername(WOLFSSL* ssl, byte type) -{ - void * serverName = NULL; - if (ssl == NULL) - return NULL; - TLSX_SNI_GetRequest(ssl->extensions, type, &serverName, - !wolfSSL_is_server(ssl)); - return (const char *)serverName; -} -#endif - -#endif /* HAVE_SNI */ WOLFSSL_CTX* wolfSSL_set_SSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx) { @@ -16117,30 +13234,6 @@ WOLFSSL_CTX* wolfSSL_set_SSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx) } -VerifyCallback wolfSSL_CTX_get_verify_callback(WOLFSSL_CTX* ctx) -{ - WOLFSSL_ENTER("wolfSSL_CTX_get_verify_callback"); - if(ctx) - return ctx->verifyCallback; - return NULL; -} - -#ifdef HAVE_SNI -/* this is a compatibility function, consider using - * wolfSSL_CTX_set_servername_callback */ -int wolfSSL_CTX_set_tlsext_servername_callback(WOLFSSL_CTX* ctx, - CallbackSniRecv cb) -{ - WOLFSSL_ENTER("wolfSSL_CTX_set_tlsext_servername_callback"); - if (ctx) { - ctx->sniRecvCb = cb; - return WOLFSSL_SUCCESS; - } - return WOLFSSL_FAILURE; -} - -#endif /* HAVE_SNI */ - #ifndef NO_BIO void wolfSSL_ERR_load_BIO_strings(void) { WOLFSSL_ENTER("wolfSSL_ERR_load_BIO_strings"); @@ -16173,27 +13266,6 @@ void wolfSSL_THREADID_set_numeric(void* id, unsigned long val) #endif /* OPENSSL_ALL || OPENSSL_EXTRA */ -#ifdef HAVE_SNI - -void wolfSSL_CTX_set_servername_callback(WOLFSSL_CTX* ctx, CallbackSniRecv cb) -{ - WOLFSSL_ENTER("wolfSSL_CTX_set_servername_callback"); - if (ctx) - ctx->sniRecvCb = cb; -} - - -int wolfSSL_CTX_set_servername_arg(WOLFSSL_CTX* ctx, void* arg) -{ - WOLFSSL_ENTER("wolfSSL_CTX_set_servername_arg"); - if (ctx) { - ctx->sniRecvCbArg = arg; - return WOLFSSL_SUCCESS; - } - return WOLFSSL_FAILURE; -} - -#endif /* HAVE_SNI */ #if defined(OPENSSL_EXTRA) @@ -16271,77 +13343,6 @@ WOLFSSL_CTX* wolfSSL_get_SSL_CTX(const WOLFSSL* ssl) return ssl->ctx; } -#if defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) || defined(HAVE_STUNNEL) || \ - defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(WOLFSSL_NGINX) - -/* TODO: Doesn't currently track SSL_VERIFY_CLIENT_ONCE */ -int wolfSSL_get_verify_mode(const WOLFSSL* ssl) -{ - int mode = 0; - WOLFSSL_ENTER("wolfSSL_get_verify_mode"); - - if (!ssl) { - return WOLFSSL_FAILURE; - } - - if (ssl->options.verifyNone) { - mode = WOLFSSL_VERIFY_NONE; - } - else { - if (ssl->options.verifyPeer) { - mode |= WOLFSSL_VERIFY_PEER; - } - if (ssl->options.failNoCert) { - mode |= WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT; - } - if (ssl->options.failNoCertxPSK) { - mode |= WOLFSSL_VERIFY_FAIL_EXCEPT_PSK; - } -#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) - if (ssl->options.verifyPostHandshake) { - mode |= WOLFSSL_VERIFY_POST_HANDSHAKE; - } -#endif - } - - WOLFSSL_LEAVE("wolfSSL_get_verify_mode", mode); - return mode; -} - -int wolfSSL_CTX_get_verify_mode(const WOLFSSL_CTX* ctx) -{ - int mode = 0; - WOLFSSL_ENTER("wolfSSL_CTX_get_verify_mode"); - - if (!ctx) { - return WOLFSSL_FAILURE; - } - - if (ctx->verifyNone) { - mode = WOLFSSL_VERIFY_NONE; - } - else { - if (ctx->verifyPeer) { - mode |= WOLFSSL_VERIFY_PEER; - } - if (ctx->failNoCert) { - mode |= WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT; - } - if (ctx->failNoCertxPSK) { - mode |= WOLFSSL_VERIFY_FAIL_EXCEPT_PSK; - } -#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) - if (ctx->verifyPostHandshake) { - mode |= WOLFSSL_VERIFY_POST_HANDSHAKE; - } -#endif - } - - WOLFSSL_LEAVE("wolfSSL_CTX_get_verify_mode", mode); - return mode; -} - -#endif #ifdef WOLFSSL_JNI @@ -16717,19 +13718,6 @@ long wolfSSL_get_timeout(WOLFSSL* ssl) #if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) \ || defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) -#ifdef HAVE_ECC -int wolfSSL_SSL_CTX_set_tmp_ecdh(WOLFSSL_CTX *ctx, WOLFSSL_EC_KEY *ecdh) -{ - WOLFSSL_ENTER("wolfSSL_SSL_CTX_set_tmp_ecdh"); - - if (ctx == NULL || ecdh == NULL) - return BAD_FUNC_ARG; - - ctx->ecdhCurveOID = (word32)ecdh->group->curve_oid; - - return WOLFSSL_SUCCESS; -} -#endif #ifndef NO_BIO WOLFSSL_BIO *wolfSSL_SSL_get_rbio(const WOLFSSL *s) { @@ -16829,331 +13817,14 @@ int wolfSSL_SSL_in_connect_init(WOLFSSL* ssl) ssl->options.acceptState < ACCEPT_THIRD_REPLY_DONE; } -#if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_SERVER) -/* Expected return values from implementations of OpenSSL ticket key callback. - */ -#define TICKET_KEY_CB_RET_FAILURE (-1) -#define TICKET_KEY_CB_RET_NOT_FOUND 0 -#define TICKET_KEY_CB_RET_OK 1 -#define TICKET_KEY_CB_RET_RENEW 2 - -/* Implementation of session ticket encryption/decryption using OpenSSL - * callback to initialize the cipher and HMAC. - * - * ssl The SSL/TLS object. - * keyName The key name - used to identify the key to be used. - * iv The IV to use. - * mac The MAC of the encrypted data. - * enc Encrypt ticket. - * encTicket The ticket data. - * encTicketLen The length of the ticket data. - * encLen The encrypted/decrypted ticket length - output length. - * ctx Ignored. Application specific data. - * returns WOLFSSL_TICKET_RET_OK to indicate success, - * WOLFSSL_TICKET_RET_CREATE if a new ticket is required and - * WOLFSSL_TICKET_RET_FATAL on error. - */ -static int wolfSSL_TicketKeyCb(WOLFSSL* ssl, - unsigned char keyName[WOLFSSL_TICKET_NAME_SZ], - unsigned char iv[WOLFSSL_TICKET_IV_SZ], - unsigned char mac[WOLFSSL_TICKET_MAC_SZ], - int enc, unsigned char* encTicket, - int encTicketLen, int* encLen, void* ctx) -{ - byte digest[WC_MAX_DIGEST_SIZE]; - WC_DECLARE_VAR(evpCtx, WOLFSSL_EVP_CIPHER_CTX, 1, 0); - WOLFSSL_HMAC_CTX hmacCtx; - unsigned int mdSz = 0; - int len = 0; - int ret = WOLFSSL_TICKET_RET_FATAL; - int res; - int totalSz = 0; - - (void)ctx; - - WOLFSSL_ENTER("wolfSSL_TicketKeyCb"); - - if (ssl == NULL || ssl->ctx == NULL || ssl->ctx->ticketEncWrapCb == NULL) { - WOLFSSL_MSG("Bad parameter"); - return WOLFSSL_TICKET_RET_FATAL; - } - -#ifdef WOLFSSL_SMALL_STACK - evpCtx = (WOLFSSL_EVP_CIPHER_CTX *)XMALLOC(sizeof(*evpCtx), ssl->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (evpCtx == NULL) { - WOLFSSL_MSG("out of memory"); - return WOLFSSL_TICKET_RET_FATAL; - } -#endif - - /* Initialize the cipher and HMAC. */ - wolfSSL_EVP_CIPHER_CTX_init(evpCtx); - if (wolfSSL_HMAC_CTX_Init(&hmacCtx) != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("wolfSSL_HMAC_CTX_Init error"); - WC_FREE_VAR_EX(evpCtx, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); - return WOLFSSL_TICKET_RET_FATAL; - } - res = ssl->ctx->ticketEncWrapCb(ssl, keyName, - iv, evpCtx, &hmacCtx, enc); - if (res != TICKET_KEY_CB_RET_OK && res != TICKET_KEY_CB_RET_RENEW) { - WOLFSSL_MSG("Ticket callback error"); - ret = WOLFSSL_TICKET_RET_FATAL; - goto end; - } - - if (wolfSSL_HMAC_size(&hmacCtx) > WOLFSSL_TICKET_MAC_SZ) { - WOLFSSL_MSG("Ticket cipher MAC size error"); - goto end; - } - - if (enc) - { - /* Encrypt in place. */ - if (!wolfSSL_EVP_CipherUpdate(evpCtx, encTicket, &len, - encTicket, encTicketLen)) - goto end; - totalSz = len; - if (totalSz > *encLen) - goto end; - if (!wolfSSL_EVP_EncryptFinal(evpCtx, &encTicket[len], &len)) - goto end; - /* Total length of encrypted data. */ - totalSz += len; - if (totalSz > *encLen) - goto end; - - /* HMAC the encrypted data into the parameter 'mac'. */ - if (!wolfSSL_HMAC_Update(&hmacCtx, encTicket, totalSz)) - goto end; - if (!wolfSSL_HMAC_Final(&hmacCtx, mac, &mdSz)) - goto end; - } - else - { - /* HMAC the encrypted data and compare it to the passed in data. */ - if (!wolfSSL_HMAC_Update(&hmacCtx, encTicket, encTicketLen)) - goto end; - if (!wolfSSL_HMAC_Final(&hmacCtx, digest, &mdSz)) - goto end; - if (ConstantCompare(mac, digest, (int)mdSz) != 0) - goto end; - - /* Decrypt the ticket data in place. */ - if (!wolfSSL_EVP_CipherUpdate(evpCtx, encTicket, &len, - encTicket, encTicketLen)) - goto end; - totalSz = len; - if (totalSz > encTicketLen) - goto end; - if (!wolfSSL_EVP_DecryptFinal(evpCtx, &encTicket[len], &len)) - goto end; - /* Total length of decrypted data. */ - totalSz += len; - if (totalSz > encTicketLen) - goto end; - } - *encLen = totalSz; - - if (res == TICKET_KEY_CB_RET_RENEW && !IsAtLeastTLSv1_3(ssl->version) - && !enc) - ret = WOLFSSL_TICKET_RET_CREATE; - else - ret = WOLFSSL_TICKET_RET_OK; -end: - - (void)wc_HmacFree(&hmacCtx.hmac); - (void)wolfSSL_EVP_CIPHER_CTX_cleanup(evpCtx); - - WC_FREE_VAR_EX(evpCtx, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); - - return ret; -} - -/* Set the callback to use when encrypting/decrypting tickets. - * - * ctx The SSL/TLS context object. - * cb The OpenSSL session ticket callback. - * returns WOLFSSL_SUCCESS to indicate success. - */ -int wolfSSL_CTX_set_tlsext_ticket_key_cb(WOLFSSL_CTX *ctx, ticketCompatCb cb) -{ - - /* Set the ticket encryption callback to be a wrapper around OpenSSL - * callback. - */ - ctx->ticketEncCb = wolfSSL_TicketKeyCb; - ctx->ticketEncWrapCb = cb; - - return WOLFSSL_SUCCESS; -} - -#endif /* HAVE_SESSION_TICKET */ #endif /* OPENSSL_ALL || WOLFSSL_NGINX || WOLFSSL_HAPROXY || OPENSSL_EXTRA || HAVE_LIGHTY */ -#if defined(HAVE_SESSION_TICKET) && !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \ - !defined(NO_WOLFSSL_SERVER) -/* Serialize the session ticket encryption keys. - * - * @param [in] ctx SSL/TLS context object. - * @param [in] keys Buffer to hold session ticket keys. - * @param [in] keylen Length of buffer. - * @return WOLFSSL_SUCCESS on success. - * @return WOLFSSL_FAILURE when ctx is NULL, keys is NULL or keylen is not the - * correct length. - */ -long wolfSSL_CTX_get_tlsext_ticket_keys(WOLFSSL_CTX *ctx, - unsigned char *keys, int keylen) -{ - if (ctx == NULL || keys == NULL) { - return WOLFSSL_FAILURE; - } - if (keylen != WOLFSSL_TICKET_KEYS_SZ) { - return WOLFSSL_FAILURE; - } - - XMEMCPY(keys, ctx->ticketKeyCtx.name, WOLFSSL_TICKET_NAME_SZ); - keys += WOLFSSL_TICKET_NAME_SZ; - XMEMCPY(keys, ctx->ticketKeyCtx.key[0], WOLFSSL_TICKET_KEY_SZ); - keys += WOLFSSL_TICKET_KEY_SZ; - XMEMCPY(keys, ctx->ticketKeyCtx.key[1], WOLFSSL_TICKET_KEY_SZ); - keys += WOLFSSL_TICKET_KEY_SZ; - c32toa(ctx->ticketKeyCtx.expirary[0], keys); - keys += OPAQUE32_LEN; - c32toa(ctx->ticketKeyCtx.expirary[1], keys); - - return WOLFSSL_SUCCESS; -} - -/* Deserialize the session ticket encryption keys. - * - * @param [in] ctx SSL/TLS context object. - * @param [in] keys Session ticket keys. - * @param [in] keylen Length of data. - * @return WOLFSSL_SUCCESS on success. - * @return WOLFSSL_FAILURE when ctx is NULL, keys is NULL or keylen is not the - * correct length. - */ -long wolfSSL_CTX_set_tlsext_ticket_keys(WOLFSSL_CTX *ctx, - const void *keys_vp, int keylen) -{ - const byte* keys = (const byte*)keys_vp; - if (ctx == NULL || keys == NULL) { - return WOLFSSL_FAILURE; - } - if (keylen != WOLFSSL_TICKET_KEYS_SZ) { - return WOLFSSL_FAILURE; - } - - XMEMCPY(ctx->ticketKeyCtx.name, keys, WOLFSSL_TICKET_NAME_SZ); - keys += WOLFSSL_TICKET_NAME_SZ; - XMEMCPY(ctx->ticketKeyCtx.key[0], keys, WOLFSSL_TICKET_KEY_SZ); - keys += WOLFSSL_TICKET_KEY_SZ; - XMEMCPY(ctx->ticketKeyCtx.key[1], keys, WOLFSSL_TICKET_KEY_SZ); - keys += WOLFSSL_TICKET_KEY_SZ; - ato32(keys, &ctx->ticketKeyCtx.expirary[0]); - keys += OPAQUE32_LEN; - ato32(keys, &ctx->ticketKeyCtx.expirary[1]); - - return WOLFSSL_SUCCESS; -} -#endif #if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || \ defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) -int wolfSSL_CTX_get_extra_chain_certs(WOLFSSL_CTX* ctx, - WOLF_STACK_OF(X509)** chain) -{ - word32 idx; - word32 length; - WOLFSSL_STACK* node; - WOLFSSL_STACK* last = NULL; - - if (ctx == NULL || chain == NULL) { - chain = NULL; - return WOLFSSL_FAILURE; - } - if (ctx->x509Chain != NULL) { - *chain = ctx->x509Chain; - return WOLFSSL_SUCCESS; - } - - /* If there are no chains then success! */ - *chain = NULL; - if (ctx->certChain == NULL || ctx->certChain->length == 0) { - return WOLFSSL_SUCCESS; - } - /* Create a new stack of WOLFSSL_X509 object from chain buffer. */ - for (idx = 0; idx < ctx->certChain->length; ) { - node = wolfSSL_sk_X509_new_null(); - if (node == NULL) - return WOLFSSL_FAILURE; - node->next = NULL; - - /* 3 byte length | X509 DER data */ - ato24(ctx->certChain->buffer + idx, &length); - idx += 3; - - /* Create a new X509 from DER encoded data. */ - node->data.x509 = wolfSSL_X509_d2i_ex(NULL, - ctx->certChain->buffer + idx, (int)length, ctx->heap); - if (node->data.x509 == NULL) { - XFREE(node, NULL, DYNAMIC_TYPE_OPENSSL); - /* Return as much of the chain as we created. */ - ctx->x509Chain = *chain; - return WOLFSSL_FAILURE; - } - idx += length; - - /* Add object to the end of the stack. */ - if (last == NULL) { - node->num = 1; - *chain = node; - } - else { - (*chain)->num++; - last->next = node; - } - - last = node; - } - - ctx->x509Chain = *chain; - - return WOLFSSL_SUCCESS; -} - -int wolfSSL_CTX_get0_chain_certs(WOLFSSL_CTX *ctx, - WOLF_STACK_OF(WOLFSSL_X509) **sk) -{ - WOLFSSL_ENTER("wolfSSL_CTX_get0_chain_certs"); - if (ctx == NULL || sk == NULL) { - WOLFSSL_MSG("Bad parameter"); - return WOLFSSL_FAILURE; - } - - /* This function should return ctx->x509Chain if it is populated, otherwise - it should be populated from ctx->certChain. This matches the behavior of - wolfSSL_CTX_get_extra_chain_certs, so it is used directly. */ - return wolfSSL_CTX_get_extra_chain_certs(ctx, sk); -} - -#ifdef KEEP_OUR_CERT -int wolfSSL_get0_chain_certs(WOLFSSL *ssl, - WOLF_STACK_OF(WOLFSSL_X509) **sk) -{ - WOLFSSL_ENTER("wolfSSL_get0_chain_certs"); - if (ssl == NULL || sk == NULL) { - WOLFSSL_MSG("Bad parameter"); - return WOLFSSL_FAILURE; - } - *sk = ssl->ourCertChain; - return WOLFSSL_SUCCESS; -} -#endif void wolfSSL_WOLFSSL_STRING_free(WOLFSSL_STRING s) { @@ -17164,157 +13835,8 @@ void wolfSSL_WOLFSSL_STRING_free(WOLFSSL_STRING s) #endif /* WOLFSSL_NGINX || WOLFSSL_HAPROXY || OPENSSL_EXTRA || OPENSSL_ALL */ -#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || \ - defined(WOLFSSL_HAPROXY) || defined(HAVE_LIGHTY) || \ - defined(WOLFSSL_QUIC) -#ifdef HAVE_ALPN -void wolfSSL_get0_alpn_selected(const WOLFSSL *ssl, const unsigned char **data, - unsigned int *len) -{ - word16 nameLen = 0; - - if (ssl != NULL && data != NULL && len != NULL) { - TLSX_ALPN_GetRequest(ssl->extensions, (void **)data, &nameLen); - *len = nameLen; - } -} - -int wolfSSL_select_next_proto(unsigned char **out, unsigned char *outLen, - const unsigned char *in, unsigned int inLen, - const unsigned char *clientNames, - unsigned int clientLen) -{ - unsigned int i, j; - byte lenIn, lenClient; - - if (out == NULL || outLen == NULL || in == NULL || clientNames == NULL) - return WOLFSSL_NPN_UNSUPPORTED; - - for (i = 0; i < inLen; i += lenIn) { - lenIn = in[i++]; - if (lenIn == 0 || i + lenIn > inLen) - break; - for (j = 0; j < clientLen; j += lenClient) { - lenClient = clientNames[j++]; - if (lenClient == 0 || j + lenClient > clientLen) - break; - - if (lenIn != lenClient) - continue; - - if (XMEMCMP(in + i, clientNames + j, lenIn) == 0) { - *out = (unsigned char *)(in + i); - *outLen = lenIn; - return WOLFSSL_NPN_NEGOTIATED; - } - } - } - - if (clientLen > 0 && (unsigned int)clientNames[0] + 1 <= clientLen) { - *out = (unsigned char *)clientNames + 1; - *outLen = clientNames[0]; - } - else { - *out = (unsigned char *)clientNames; - *outLen = 0; - } - return WOLFSSL_NPN_NO_OVERLAP; -} - -void wolfSSL_set_alpn_select_cb(WOLFSSL *ssl, - int (*cb) (WOLFSSL *ssl, - const unsigned char **out, - unsigned char *outlen, - const unsigned char *in, - unsigned int inlen, - void *arg), void *arg) -{ - if (ssl != NULL) { - ssl->alpnSelect = cb; - ssl->alpnSelectArg = arg; - } -} - -void wolfSSL_CTX_set_alpn_select_cb(WOLFSSL_CTX *ctx, - int (*cb) (WOLFSSL *ssl, - const unsigned char **out, - unsigned char *outlen, - const unsigned char *in, - unsigned int inlen, - void *arg), void *arg) -{ - if (ctx != NULL) { - ctx->alpnSelect = cb; - ctx->alpnSelectArg = arg; - } -} - -void wolfSSL_CTX_set_next_protos_advertised_cb(WOLFSSL_CTX *s, - int (*cb) (WOLFSSL *ssl, - const unsigned char - **out, - unsigned int *outlen, - void *arg), void *arg) -{ - (void)s; - (void)cb; - (void)arg; - WOLFSSL_STUB("wolfSSL_CTX_set_next_protos_advertised_cb"); -} - -void wolfSSL_CTX_set_next_proto_select_cb(WOLFSSL_CTX *s, - int (*cb) (WOLFSSL *ssl, - unsigned char **out, - unsigned char *outlen, - const unsigned char *in, - unsigned int inlen, - void *arg), void *arg) -{ - (void)s; - (void)cb; - (void)arg; - WOLFSSL_STUB("wolfSSL_CTX_set_next_proto_select_cb"); -} - -void wolfSSL_get0_next_proto_negotiated(const WOLFSSL *s, - const unsigned char **data, unsigned *len) -{ - (void)s; - (void)data; - (void)len; - WOLFSSL_STUB("wolfSSL_get0_next_proto_negotiated"); -} -#endif /* HAVE_ALPN */ - -#endif /* WOLFSSL_NGINX / WOLFSSL_HAPROXY */ #if defined(OPENSSL_EXTRA) || defined(HAVE_CURL) -int wolfSSL_curve_is_disabled(const WOLFSSL* ssl, word16 curve_id) -{ - int ret = 0; - - WOLFSSL_ENTER("wolfSSL_curve_is_disabled"); - WOLFSSL_MSG_EX("wolfSSL_curve_is_disabled checking for %d", curve_id); - - /* (curve_id >= WOLFSSL_FFDHE_START) - DH parameters are never disabled. */ - if (curve_id < WOLFSSL_FFDHE_START) { - if (curve_id > WOLFSSL_ECC_MAX_AVAIL) { - WOLFSSL_MSG("Curve id out of supported range"); - /* Disabled if not in valid range. */ - ret = 1; - } - else if (curve_id >= 32) { - /* 0 is for invalid and 1-14 aren't used otherwise. */ - ret = (ssl->disabledCurves & (1U << (curve_id - 32))) != 0; - } - else { - ret = (ssl->disabledCurves & (1U << curve_id)) != 0; - } - } - - WOLFSSL_LEAVE("wolfSSL_curve_is_disabled", ret); - return ret; -} #if (defined(HAVE_ECC) || \ defined(HAVE_CURVE25519) || defined(HAVE_CURVE448)) @@ -17553,30 +14075,11 @@ int set_curves_list(WOLFSSL* ssl, WOLFSSL_CTX *ctx, const char* names, leave: #ifdef WOLFSSL_SMALL_STACK if (groups) - XFREE((void*)groups, heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; -} - -int wolfSSL_CTX_set1_curves_list(WOLFSSL_CTX* ctx, const char* names) -{ - WOLFSSL_ENTER("wolfSSL_CTX_set1_curves_list"); - if (ctx == NULL || names == NULL) { - WOLFSSL_MSG("ctx or names was NULL"); - return WOLFSSL_FAILURE; - } - return set_curves_list(NULL, ctx, names, 1); + XFREE((void*)groups, heap, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ret; } -int wolfSSL_set1_curves_list(WOLFSSL* ssl, const char* names) -{ - WOLFSSL_ENTER("wolfSSL_set1_curves_list"); - if (ssl == NULL || names == NULL) { - WOLFSSL_MSG("ssl or names was NULL"); - return WOLFSSL_FAILURE; - } - return set_curves_list(ssl, NULL, names, 1); -} #endif /* (HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448) */ #endif /* OPENSSL_EXTRA || HAVE_CURL */ @@ -17675,142 +14178,11 @@ void wolfSSL_OPENSSL_cleanse(void *ptr, size_t len) ForceZero(ptr, (word32)len); } -int wolfSSL_CTX_set_alpn_protos(WOLFSSL_CTX *ctx, const unsigned char *p, - unsigned int p_len) -{ - WOLFSSL_ENTER("wolfSSL_CTX_set_alpn_protos"); - if (ctx == NULL || p == NULL) - return BAD_FUNC_ARG; - if (ctx->alpn_cli_protos != NULL) { - XFREE((void*)ctx->alpn_cli_protos, ctx->heap, DYNAMIC_TYPE_OPENSSL); - } - - ctx->alpn_cli_protos = (const unsigned char*)XMALLOC(p_len, - ctx->heap, DYNAMIC_TYPE_OPENSSL); - if (ctx->alpn_cli_protos == NULL) { -#if defined(WOLFSSL_ERROR_CODE_OPENSSL) - /* 0 on success in OpenSSL, non-0 on failure in OpenSSL - * the function reverses the return value convention. - */ - return 1; -#else - return WOLFSSL_FAILURE; -#endif - } - XMEMCPY((void*)ctx->alpn_cli_protos, p, p_len); - ctx->alpn_cli_protos_len = p_len; - -#if defined(WOLFSSL_ERROR_CODE_OPENSSL) - /* 0 on success in OpenSSL, non-0 on failure in OpenSSL - * the function reverses the return value convention. - */ - return 0; -#else - return WOLFSSL_SUCCESS; -#endif -} - - -#ifdef HAVE_ALPN -#ifndef NO_BIO -/* Sets the ALPN extension protos - * - * example format is - * unsigned char p[] = { - * 8, 'h', 't', 't', 'p', '/', '1', '.', '1' - * }; - * - * returns WOLFSSL_SUCCESS on success */ -int wolfSSL_set_alpn_protos(WOLFSSL* ssl, - const unsigned char* p, unsigned int p_len) -{ - char* pt = NULL; - unsigned int ptIdx; - unsigned int sz; - unsigned int idx = 0; - /* RFC 7301: a server that does not select any of the client's offered - * protocols MUST send no_application_protocol. Match that contract on - * the OpenSSL-compat surface rather than silently continuing. */ - int alpn_opt = WOLFSSL_ALPN_FAILED_ON_MISMATCH; - int ret; - - WOLFSSL_ENTER("wolfSSL_set_alpn_protos"); - - if (ssl == NULL || p_len <= 1 || p == NULL) { -#if defined(WOLFSSL_ERROR_CODE_OPENSSL) - /* 0 on success in OpenSSL, non-0 on failure in OpenSSL - * the function reverses the return value convention. - */ - return 1; -#else - return WOLFSSL_FAILURE; -#endif - } - - /* Replacing leading number with trailing ',' and adding '\0'. */ - pt = (char*)XMALLOC(p_len + 1, ssl->heap, DYNAMIC_TYPE_OPENSSL); - if (pt == NULL) { -#if defined(WOLFSSL_ERROR_CODE_OPENSSL) - /* 0 on success in OpenSSL, non-0 on failure in OpenSSL - * the function reverses the return value convention. - */ - return 1; -#else - return WOLFSSL_FAILURE; -#endif - } - - ptIdx = 0; - /* convert into comma separated list */ - while (idx < p_len - 1) { - unsigned int i; - - sz = p[idx++]; - if (idx + sz > p_len) { - WOLFSSL_MSG("Bad list format"); - XFREE(pt, ssl->heap, DYNAMIC_TYPE_OPENSSL); - #if defined(WOLFSSL_ERROR_CODE_OPENSSL) - /* 0 on success in OpenSSL, non-0 on failure in OpenSSL - * the function reverses the return value convention. - */ - return 1; - #else - return WOLFSSL_FAILURE; - #endif - } - if (sz > 0) { - for (i = 0; i < sz; i++) { - pt[ptIdx++] = p[idx++]; - } - if (idx < p_len - 1) { - pt[ptIdx++] = ','; - } - } - } - pt[ptIdx++] = '\0'; - - /* clears out all current ALPN extensions set */ - TLSX_Remove(&ssl->extensions, TLSX_APPLICATION_LAYER_PROTOCOL, ssl->heap); - - ret = wolfSSL_UseALPN(ssl, pt, ptIdx, (byte)alpn_opt); - XFREE(pt, ssl->heap, DYNAMIC_TYPE_OPENSSL); -#if defined(WOLFSSL_ERROR_CODE_OPENSSL) - /* 0 on success in OpenSSL, non-0 on failure in OpenSSL - * the function reverses the return value convention. - */ - if (ret != WOLFSSL_SUCCESS) - return 1; - return 0; -#else - if (ret != WOLFSSL_SUCCESS) - return WOLFSSL_FAILURE; - return WOLFSSL_SUCCESS; -#endif -} -#endif /* !NO_BIO */ -#endif /* HAVE_ALPN */ #endif /* OPENSSL_EXTRA */ +#define WOLFSSL_SSL_API_EXT_INCLUDED +#include "src/ssl_api_ext.c" + #if defined(OPENSSL_EXTRA) #ifndef NO_BIO @@ -18641,421 +15013,6 @@ void wolfSSL_ERR_remove_state(unsigned long id) #endif /* OPENSSL_EXTRA */ -#ifdef WOLFSSL_STATIC_EPHEMERAL -int wolfSSL_StaticEphemeralKeyLoad(WOLFSSL* ssl, int keyAlgo, void* keyPtr) -{ - int ret; - word32 idx = 0; - DerBuffer* der = NULL; - - if (ssl == NULL || ssl->ctx == NULL || keyPtr == NULL) { - return BAD_FUNC_ARG; - } - -#ifndef SINGLE_THREADED - if (!ssl->ctx->staticKELockInit) { - return BUFFER_E; /* no keys set */ - } - ret = wc_LockMutex(&ssl->ctx->staticKELock); - if (ret != 0) { - return ret; - } -#endif - - ret = BUFFER_E; /* set default error */ - switch (keyAlgo) { - #ifndef NO_DH - case WC_PK_TYPE_DH: - if (ssl != NULL) - der = ssl->staticKE.dhKey; - if (der == NULL) - der = ssl->ctx->staticKE.dhKey; - if (der != NULL) { - DhKey* key = (DhKey*)keyPtr; - WOLFSSL_MSG("Using static DH key"); - ret = wc_DhKeyDecode(der->buffer, &idx, key, der->length); - } - break; - #endif - #ifdef HAVE_ECC - case WC_PK_TYPE_ECDH: - if (ssl != NULL) - der = ssl->staticKE.ecKey; - if (der == NULL) - der = ssl->ctx->staticKE.ecKey; - if (der != NULL) { - ecc_key* key = (ecc_key*)keyPtr; - WOLFSSL_MSG("Using static ECDH key"); - ret = wc_EccPrivateKeyDecode(der->buffer, &idx, key, - der->length); - } - break; - #endif - #ifdef HAVE_CURVE25519 - case WC_PK_TYPE_CURVE25519: - if (ssl != NULL) - der = ssl->staticKE.x25519Key; - if (der == NULL) - der = ssl->ctx->staticKE.x25519Key; - if (der != NULL) { - curve25519_key* key = (curve25519_key*)keyPtr; - WOLFSSL_MSG("Using static X25519 key"); - - #ifdef WOLFSSL_CURVE25519_BLINDING - ret = wc_curve25519_set_rng(key, ssl->rng); - if (ret == 0) - #endif - ret = wc_Curve25519PrivateKeyDecode(der->buffer, &idx, key, - der->length); - } - break; - #endif - #ifdef HAVE_CURVE448 - case WC_PK_TYPE_CURVE448: - if (ssl != NULL) - der = ssl->staticKE.x448Key; - if (der == NULL) - der = ssl->ctx->staticKE.x448Key; - if (der != NULL) { - curve448_key* key = (curve448_key*)keyPtr; - WOLFSSL_MSG("Using static X448 key"); - ret = wc_Curve448PrivateKeyDecode(der->buffer, &idx, key, - der->length); - } - break; - #endif - default: - /* not supported */ - ret = NOT_COMPILED_IN; - break; - } - -#ifndef SINGLE_THREADED - wc_UnLockMutex(&ssl->ctx->staticKELock); -#endif - return ret; -} - -static int SetStaticEphemeralKey(WOLFSSL_CTX* ctx, - StaticKeyExchangeInfo_t* staticKE, int keyAlgo, const char* key, - unsigned int keySz, int format, void* heap) -{ - int ret = 0; - DerBuffer* der = NULL; - byte* keyBuf = NULL; -#ifndef NO_FILESYSTEM - const char* keyFile = NULL; -#endif - - /* allow empty key to free buffer */ - if (staticKE == NULL || (key == NULL && keySz > 0)) { - return BAD_FUNC_ARG; - } - - WOLFSSL_ENTER("SetStaticEphemeralKey"); - - /* if just free'ing key then skip loading */ - if (key != NULL) { - #ifndef NO_FILESYSTEM - /* load file from filesystem */ - if (key != NULL && keySz == 0) { - size_t keyBufSz = 0; - keyFile = (const char*)key; - ret = wc_FileLoad(keyFile, &keyBuf, &keyBufSz, heap); - if (ret != 0) { - return ret; - } - keySz = (unsigned int)keyBufSz; - } - else - #endif - { - /* use as key buffer directly */ - keyBuf = (byte*)key; - } - - if (format == WOLFSSL_FILETYPE_PEM) { - #ifdef WOLFSSL_PEM_TO_DER - int keyFormat = 0; - ret = PemToDer(keyBuf, keySz, PRIVATEKEY_TYPE, &der, - heap, NULL, &keyFormat); - /* auto detect key type */ - if (ret == 0 && keyAlgo == WC_PK_TYPE_NONE) { - if (keyFormat == ECDSAk) - keyAlgo = WC_PK_TYPE_ECDH; - else if (keyFormat == X25519k) - keyAlgo = WC_PK_TYPE_CURVE25519; - else - keyAlgo = WC_PK_TYPE_DH; - } - #else - ret = NOT_COMPILED_IN; - #endif - } - else { - /* Detect PK type (if required) */ - #ifdef HAVE_ECC - if (keyAlgo == WC_PK_TYPE_NONE) { - word32 idx = 0; - WC_DECLARE_VAR(eccKey, ecc_key, 1, heap); - WC_ALLOC_VAR_EX(eccKey, ecc_key, 1, heap, DYNAMIC_TYPE_ECC, - ret = MEMORY_E); - if (ret == 0) - ret = wc_ecc_init_ex(eccKey, heap, INVALID_DEVID); - if (ret == 0) { - ret = wc_EccPrivateKeyDecode(keyBuf, &idx, eccKey, keySz); - if (ret == 0) - keyAlgo = WC_PK_TYPE_ECDH; - wc_ecc_free(eccKey); - ret = 0; /* clear error to enable key-type detect cascade */ - } - WC_FREE_VAR_EX(eccKey, heap, DYNAMIC_TYPE_ECC); - } - #endif - #if !defined(NO_DH) && defined(WOLFSSL_DH_EXTRA) - if (keyAlgo == WC_PK_TYPE_NONE) { - word32 idx = 0; - WC_DECLARE_VAR(dhKey, DhKey, 1, heap); - WC_ALLOC_VAR_EX(dhKey, DhKey, 1, heap, DYNAMIC_TYPE_DH, - ret = MEMORY_E); - if (ret == 0) - ret = wc_InitDhKey_ex(dhKey, heap, INVALID_DEVID); - if (ret == 0) { - ret = wc_DhKeyDecode(keyBuf, &idx, dhKey, keySz); - if (ret == 0) - keyAlgo = WC_PK_TYPE_DH; - wc_FreeDhKey(dhKey); - ret = 0; /* clear error to enable key-type detect cascade */ - } - WC_FREE_VAR_EX(dhKey, heap, DYNAMIC_TYPE_DH); - } - #endif - #ifdef HAVE_CURVE25519 - if (keyAlgo == WC_PK_TYPE_NONE) { - word32 idx = 0; - WC_DECLARE_VAR(x25519Key, curve25519_key, 1, heap); - WC_ALLOC_VAR_EX(x25519Key, curve25519_key, 1, heap, - DYNAMIC_TYPE_CURVE25519, ret = MEMORY_E); - if (ret == 0) - ret = wc_curve25519_init_ex(x25519Key, heap, INVALID_DEVID); - if (ret == 0) { - ret = wc_Curve25519PrivateKeyDecode(keyBuf, &idx, - x25519Key, keySz); - if (ret == 0) - keyAlgo = WC_PK_TYPE_CURVE25519; - wc_curve25519_free(x25519Key); - ret = 0; /* clear error to enable key-type detect cascade */ - } - WC_FREE_VAR_EX(x25519Key, heap, DYNAMIC_TYPE_CURVE25519); - } - #endif - #ifdef HAVE_CURVE448 - if (keyAlgo == WC_PK_TYPE_NONE) { - word32 idx = 0; - WC_DECLARE_VAR(x448Key, curve448_key, 1, heap); - WC_ALLOC_VAR_EX(x448Key, curve448_key, 1, heap, - DYNAMIC_TYPE_CURVE448, ret = MEMORY_E); - if (ret == 0) - ret = wc_curve448_init(x448Key); - if (ret == 0) { - ret = wc_Curve448PrivateKeyDecode(keyBuf, &idx, x448Key, - keySz); - if (ret == 0) - keyAlgo = WC_PK_TYPE_CURVE448; - wc_curve448_free(x448Key); - ret = 0; /* clear error to enable key-type detect cascade */ - } - WC_FREE_VAR_EX(x448Key, heap, DYNAMIC_TYPE_CURVE448); - } - #endif - - if (keyAlgo != WC_PK_TYPE_NONE) { - ret = AllocDer(&der, keySz, PRIVATEKEY_TYPE, heap); - if (ret == 0) { - XMEMCPY(der->buffer, keyBuf, keySz); - } - } - } - } - -#ifndef NO_FILESYSTEM - /* done with keyFile buffer */ - if (keyFile && keyBuf) { - ForceZero(keyBuf, keySz); - XFREE(keyBuf, heap, DYNAMIC_TYPE_TMP_BUFFER); - } -#endif - -#ifndef SINGLE_THREADED - if (ret == 0 && !ctx->staticKELockInit) { - ret = wc_InitMutex(&ctx->staticKELock); - if (ret == 0) { - ctx->staticKELockInit = 1; - } - } -#endif - if (ret == 0 - #ifndef SINGLE_THREADED - && (ret = wc_LockMutex(&ctx->staticKELock)) == 0 - #endif - ) { - switch (keyAlgo) { - #ifndef NO_DH - case WC_PK_TYPE_DH: - FreeDer(&staticKE->dhKey); - staticKE->dhKey = der; der = NULL; - break; - #endif - #ifdef HAVE_ECC - case WC_PK_TYPE_ECDH: - FreeDer(&staticKE->ecKey); - staticKE->ecKey = der; der = NULL; - break; - #endif - #ifdef HAVE_CURVE25519 - case WC_PK_TYPE_CURVE25519: - FreeDer(&staticKE->x25519Key); - staticKE->x25519Key = der; der = NULL; - break; - #endif - #ifdef HAVE_CURVE448 - case WC_PK_TYPE_CURVE448: - FreeDer(&staticKE->x448Key); - staticKE->x448Key = der; der = NULL; - break; - #endif - default: - /* not supported */ - ret = NOT_COMPILED_IN; - break; - } - - #ifndef SINGLE_THREADED - wc_UnLockMutex(&ctx->staticKELock); - #endif - } - - if (ret != 0) { - FreeDer(&der); - } - - (void)ctx; /* not used for single threaded */ - - WOLFSSL_LEAVE("SetStaticEphemeralKey", ret); - - return ret; -} - -int wolfSSL_CTX_set_ephemeral_key(WOLFSSL_CTX* ctx, int keyAlgo, - const char* key, unsigned int keySz, int format) -{ - if (ctx == NULL) { - return BAD_FUNC_ARG; - } - return SetStaticEphemeralKey(ctx, &ctx->staticKE, keyAlgo, - key, keySz, format, ctx->heap); -} -int wolfSSL_set_ephemeral_key(WOLFSSL* ssl, int keyAlgo, - const char* key, unsigned int keySz, int format) -{ - if (ssl == NULL || ssl->ctx == NULL) { - return BAD_FUNC_ARG; - } - return SetStaticEphemeralKey(ssl->ctx, &ssl->staticKE, keyAlgo, - key, keySz, format, ssl->heap); -} - -static int GetStaticEphemeralKey(WOLFSSL_CTX* ctx, WOLFSSL* ssl, - int keyAlgo, const unsigned char** key, unsigned int* keySz) -{ - int ret = 0; - DerBuffer* der = NULL; - - if (key) *key = NULL; - if (keySz) *keySz = 0; - -#ifndef SINGLE_THREADED - if (ctx->staticKELockInit && - (ret = wc_LockMutex(&ctx->staticKELock)) != 0) { - return ret; - } -#endif - - switch (keyAlgo) { - #ifndef NO_DH - case WC_PK_TYPE_DH: - if (ssl != NULL) - der = ssl->staticKE.dhKey; - if (der == NULL) - der = ctx->staticKE.dhKey; - break; - #endif - #ifdef HAVE_ECC - case WC_PK_TYPE_ECDH: - if (ssl != NULL) - der = ssl->staticKE.ecKey; - if (der == NULL) - der = ctx->staticKE.ecKey; - break; - #endif - #ifdef HAVE_CURVE25519 - case WC_PK_TYPE_CURVE25519: - if (ssl != NULL) - der = ssl->staticKE.x25519Key; - if (der == NULL) - der = ctx->staticKE.x25519Key; - break; - #endif - #ifdef HAVE_CURVE448 - case WC_PK_TYPE_CURVE448: - if (ssl != NULL) - der = ssl->staticKE.x448Key; - if (der == NULL) - der = ctx->staticKE.x448Key; - break; - #endif - default: - /* not supported */ - ret = NOT_COMPILED_IN; - break; - } - - if (der) { - if (key) - *key = der->buffer; - if (keySz) - *keySz = der->length; - } - -#ifndef SINGLE_THREADED - wc_UnLockMutex(&ctx->staticKELock); -#endif - - return ret; -} - -/* returns pointer to currently loaded static ephemeral as ASN.1 */ -/* this can be converted to PEM using wc_DerToPem */ -int wolfSSL_CTX_get_ephemeral_key(WOLFSSL_CTX* ctx, int keyAlgo, - const unsigned char** key, unsigned int* keySz) -{ - if (ctx == NULL) { - return BAD_FUNC_ARG; - } - - return GetStaticEphemeralKey(ctx, NULL, keyAlgo, key, keySz); -} -int wolfSSL_get_ephemeral_key(WOLFSSL* ssl, int keyAlgo, - const unsigned char** key, unsigned int* keySz) -{ - if (ssl == NULL || ssl->ctx == NULL) { - return BAD_FUNC_ARG; - } - - return GetStaticEphemeralKey(ssl->ctx, ssl, keyAlgo, key, keySz); -} - -#endif /* WOLFSSL_STATIC_EPHEMERAL */ #if defined(OPENSSL_EXTRA) /* wolfSSL_THREADID_current is provided as a compat API with @@ -19081,40 +15038,6 @@ unsigned long wolfSSL_THREADID_hash(const WOLFSSL_CRYPTO_THREADID* id) (void)id; return 0UL; } -/* wolfSSL_set_ecdh_auto is provided as compatible API with - * SSL_set_ecdh_auto to enable auto ecdh curve selection functionality. - * Since this functionality is enabled by default in wolfSSL, - * this API exists as a stub. - */ -int wolfSSL_set_ecdh_auto(WOLFSSL* ssl, int onoff) -{ - (void)ssl; - (void)onoff; - return WOLFSSL_SUCCESS; -} -/* wolfSSL_CTX_set_ecdh_auto is provided as compatible API with - * SSL_CTX_set_ecdh_auto to enable auto ecdh curve selection functionality. - * Since this functionality is enabled by default in wolfSSL, - * this API exists as a stub. - */ -int wolfSSL_CTX_set_ecdh_auto(WOLFSSL_CTX* ctx, int onoff) -{ - (void)ctx; - (void)onoff; - return WOLFSSL_SUCCESS; -} - -/* wolfSSL_CTX_set_dh_auto is provided as compatible API with - * SSL_CTX_set_dh_auto to enable auto dh selection functionality. - * Since this functionality is enabled by default in wolfSSL, - * this API exists as a stub. - */ -int wolfSSL_CTX_set_dh_auto(WOLFSSL_CTX* ctx, int onoff) -{ - (void)ctx; - (void)onoff; - return WOLFSSL_SUCCESS; -} /** * Set security level (wolfSSL doesn't support setting the security level). diff --git a/src/ssl_api_cert.c b/src/ssl_api_cert.c index ed471be105..2d2559c64b 100644 --- a/src/ssl_api_cert.c +++ b/src/ssl_api_cert.c @@ -42,6 +42,7 @@ int wolfSSL_CTX_mutual_auth(WOLFSSL_CTX* ctx, int req) { if (ctx == NULL) return BAD_FUNC_ARG; + /* Mutual authentication is a server-side only setting. */ if (ctx->method->side != WOLFSSL_SERVER_END) return SIDE_ERROR; @@ -63,6 +64,7 @@ int wolfSSL_mutual_auth(WOLFSSL* ssl, int req) { if (ssl == NULL) return BAD_FUNC_ARG; + /* Mutual authentication is a server-side only setting. */ if (ssl->options.side != WOLFSSL_SERVER_END) return SIDE_ERROR; @@ -81,7 +83,8 @@ WOLFSSL_CERT_MANAGER* wolfSSL_CTX_GetCertManager(WOLFSSL_CTX* ctx) { WOLFSSL_CERT_MANAGER* cm = NULL; - if (ctx) + /* The certificate manager is owned by the context. */ + if (ctx != NULL) cm = ctx->cm; return cm; @@ -98,6 +101,7 @@ void wolfSSL_CTX_set_verify_depth(WOLFSSL_CTX *ctx, int depth) { WOLFSSL_ENTER("wolfSSL_CTX_set_verify_depth"); + /* Reject out-of-range depths; valid range is 0 to MAX_CHAIN_DEPTH. */ if ((ctx == NULL) || (depth < 0) || (depth > MAX_CHAIN_DEPTH)) { WOLFSSL_MSG("Bad depth argument, too large or less than 0"); } @@ -121,6 +125,8 @@ long wolfSSL_CTX_get_verify_depth(WOLFSSL_CTX* ctx) ret = BAD_FUNC_ARG; } else { + /* A configurable depth is only tracked with the OpenSSL extra APIs; + * otherwise the fixed maximum chain depth applies. */ #ifndef OPENSSL_EXTRA ret = MAX_CHAIN_DEPTH; #else @@ -145,6 +151,8 @@ long wolfSSL_get_verify_depth(WOLFSSL* ssl) ret = BAD_FUNC_ARG; } else { + /* A configurable depth is only tracked with the OpenSSL extra APIs; + * otherwise the fixed maximum chain depth applies. */ #ifndef OPENSSL_EXTRA ret = MAX_CHAIN_DEPTH; #else @@ -168,7 +176,7 @@ long wolfSSL_get_verify_depth(WOLFSSL* ssl) static int isArrayUnique(const char* buf, size_t len) { size_t i; - /* check the array is unique */ + /* Check the array is unique. */ for (i = 0; i < len - 1; ++i) { size_t j; for (j = i + 1; j < len; ++j) { @@ -260,6 +268,7 @@ int wolfSSL_CTX_set_client_cert_type(WOLFSSL_CTX* ctx, const char* buf, int len) ret = BAD_FUNC_ARG; } else { + /* A side value of 1 records these as the client certificate types. */ ret = set_cert_type(&ctx->rpkConfig, 1, buf, len); } @@ -284,6 +293,7 @@ int wolfSSL_CTX_set_server_cert_type(WOLFSSL_CTX* ctx, const char* buf, int len) ret = BAD_FUNC_ARG; } else { + /* A side value of 0 records these as the server certificate types. */ ret = set_cert_type(&ctx->rpkConfig, 0, buf, len); } @@ -308,6 +318,7 @@ int wolfSSL_set_client_cert_type(WOLFSSL* ssl, const char* buf, int len) ret = BAD_FUNC_ARG; } else { + /* A side value of 1 records these as the client certificate types. */ ret = set_cert_type(&ssl->options.rpkConfig, 1, buf, len); } @@ -332,6 +343,7 @@ int wolfSSL_set_server_cert_type(WOLFSSL* ssl, const char* buf, int len) ret = BAD_FUNC_ARG; } else { + /* A side value of 0 records these as the server certificate types. */ ret = set_cert_type(&ssl->options.rpkConfig, 0, buf, len); } @@ -627,7 +639,7 @@ int wolfSSL_verify_client_post_handshake(WOLFSSL* ssl) ret = wolfSSL_request_certificate(ssl); if (ret != 1) { /* Special logging for wrong protocol version. */ - if ((ssl != NULL) && !IsAtLeastTLSv1_3(ssl->version)) { + if ((ssl != NULL) && (!IsAtLeastTLSv1_3(ssl->version))) { WOLFSSL_ERROR(UNSUPPORTED_PROTO_VERSION); } else { @@ -851,7 +863,7 @@ int wolfSSL_UnloadCertsKeys(WOLFSSL* ssl) ret = BAD_FUNC_ARG; } else { - if (ssl->buffers.weOwnCert && !ssl->keepCert) { + if (ssl->buffers.weOwnCert && (!ssl->keepCert)) { WOLFSSL_MSG("Unloading cert"); FreeDer(&ssl->buffers.certificate); #ifdef KEEP_OUR_CERT @@ -869,7 +881,7 @@ int wolfSSL_UnloadCertsKeys(WOLFSSL* ssl) if (ssl->buffers.weOwnKey) { WOLFSSL_MSG("Unloading key"); - if (ssl->buffers.key != NULL && ssl->buffers.key->buffer != NULL) + if ((ssl->buffers.key != NULL) && (ssl->buffers.key->buffer != NULL)) ForceZero(ssl->buffers.key->buffer, ssl->buffers.key->length); FreeDer(&ssl->buffers.key); #ifdef WOLFSSL_BLIND_PRIVATE_KEY @@ -881,8 +893,8 @@ int wolfSSL_UnloadCertsKeys(WOLFSSL* ssl) #ifdef WOLFSSL_DUAL_ALG_CERTS if (ssl->buffers.weOwnAltKey) { WOLFSSL_MSG("Unloading alt key"); - if (ssl->buffers.altKey != NULL && - ssl->buffers.altKey->buffer != NULL) { + if ((ssl->buffers.altKey != NULL) && + (ssl->buffers.altKey->buffer != NULL)) { ForceZero(ssl->buffers.altKey->buffer, ssl->buffers.altKey->length); } @@ -1028,11 +1040,13 @@ static int add_to_ca_names_list(WOLFSSL_STACK* ca_names, WOLFSSL_X509* x509) int ret = 1; WOLFSSL_X509_NAME *nameCopy = NULL; + /* The list owns its names, so push a copy of the subject name. */ nameCopy = wolfSSL_X509_NAME_dup(wolfSSL_X509_get_subject_name(x509)); if (nameCopy == NULL) { WOLFSSL_MSG("wolfSSL_X509_NAME_dup error"); ret = 0; } + /* On push failure the copy is not owned by the list - free it here. */ else if (wolfSSL_sk_X509_NAME_push(ca_names, nameCopy) <= 0) { WOLFSSL_MSG("wolfSSL_sk_X509_NAME_push error"); wolfSSL_X509_NAME_free(nameCopy); @@ -1435,7 +1449,7 @@ WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_load_client_CA_file(const char* fname) } /* Read each certificate in the chain out of the file. */ - while (!err && wolfSSL_PEM_read_bio_X509(bio, &cert, NULL, NULL) != NULL) { + while ((!err) && (wolfSSL_PEM_read_bio_X509(bio, &cert, NULL, NULL) != NULL)) { WOLFSSL_X509_NAME *nameCopy; /* Need a persistent copy of the subject name. */ @@ -1730,15 +1744,15 @@ WOLFSSL_X509* wolfSSL_get_certificate(WOLFSSL* ssl) * a new X509. This maintains pointer compatibility with * applications (like nginx OCSP stapling) that use the X509 pointer * from SSL_CTX_use_certificate as a lookup key. */ - if (ssl->ctx != NULL && ssl->ctx->ourCert != NULL) { + if ((ssl->ctx != NULL) && (ssl->ctx->ourCert != NULL)) { /* Compare cert buffers to make sure they are the same */ - if (ssl->buffers.certificate == NULL || - ssl->buffers.certificate->buffer == NULL || - (ssl->buffers.certificate->length == - ssl->ctx->certificate->length && - XMEMCMP(ssl->buffers.certificate->buffer, + if ((ssl->buffers.certificate == NULL) || + (ssl->buffers.certificate->buffer == NULL) || + ((ssl->buffers.certificate->length == + ssl->ctx->certificate->length) && + (XMEMCMP(ssl->buffers.certificate->buffer, ssl->ctx->certificate->buffer, - ssl->buffers.certificate->length) == 0)) { + ssl->buffers.certificate->length) == 0))) { return ssl->ctx->ourCert; } } @@ -1769,4 +1783,744 @@ WOLFSSL_X509* wolfSSL_get_certificate(WOLFSSL* ssl) #endif /* !NO_CERTS */ +#ifndef WOLFCRYPT_ONLY + +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) +/* Get the index at which the object is stored in an X509 store context's + * external data. + * + * @return Index of the SSL/TLS object (0). + */ +int wolfSSL_get_ex_data_X509_STORE_CTX_idx(void) +{ + WOLFSSL_ENTER("wolfSSL_get_ex_data_X509_STORE_CTX_idx"); + + /* store SSL at index 0 */ + return 0; +} +#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */ + + +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) || \ + defined(OPENSSL_ALL) +/* Get the result of peer certificate verification. + * + * @param [in] ssl SSL/TLS object. + * @return Verification result code on success. + * @return WOLFSSL_FAILURE when ssl is NULL. + */ +long wolfSSL_get_verify_result(const WOLFSSL *ssl) +{ + long ret; + + if (ssl == NULL) { + ret = WOLFSSL_FAILURE; + } + else { + /* Result of verifying the peer's certificate chain. */ + ret = (long)ssl->peerVerifyRet; + } + + return ret; +} +#endif + + +#if defined(OPENSSL_EXTRA) && defined(KEEP_PEER_CERT) && \ + defined(HAVE_EX_DATA) && !defined(NO_FILESYSTEM) +/* Compare the peer's certificate against a PEM certificate file. + * + * @param [in] ssl SSL/TLS object. + * @param [in] fname Path to a PEM certificate file. + * @return 0 when the certificates match. + * @return WOLFSSL_FATAL_ERROR when arguments are NULL or they do not match. + * @return WOLFSSL_BAD_FILE when the file cannot be read. + */ +int wolfSSL_cmp_peer_cert_to_file(WOLFSSL* ssl, const char *fname) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_cmp_peer_cert_to_file"); + + if ((ssl == NULL) || (fname == NULL)) { + ret = WOLFSSL_FATAL_ERROR; + } + else { + #ifdef WOLFSSL_SMALL_STACK + byte staticBuffer[1]; /* force heap usage */ + #else + byte staticBuffer[FILE_BUFFER_SIZE]; + #endif + byte* myBuf = staticBuffer; + XFILE file; + long sz = 0; + void* heap = ssl->ctx->heap; + WOLFSSL_X509* peer_cert = &ssl->peerCert; + DerBuffer* fileDer = NULL; + + /* Open the file and determine its size. From here, ret == 0 + * indicates processing is still on track. */ + file = XFOPEN(fname, "rb"); + ret = wolfssl_file_len(file, &sz); + /* Use a heap buffer when the file is bigger than the stack buffer. */ + if ((ret == 0) && (sz > (long)sizeof(staticBuffer))) { + WOLFSSL_MSG("Getting dynamic buffer"); + myBuf = (byte*)XMALLOC((size_t)sz, heap, DYNAMIC_TYPE_FILE); + if (myBuf == NULL) { + ret = WOLFSSL_FATAL_ERROR; + } + } + /* Read the whole file into the buffer. */ + if ((ret == 0) && (XFREAD(myBuf, 1, (size_t)sz, file) != (size_t)sz)) { + ret = WOLFSSL_FATAL_ERROR; + } + /* Convert the PEM file contents to DER. */ + if ((ret == 0) && (PemToDer(myBuf, sz, CERT_TYPE, &fileDer, heap, NULL, + NULL) != 0)) { + ret = WOLFSSL_FATAL_ERROR; + } + /* Peer certificate matches when the DER lengths and bytes are equal. */ + if ((ret == 0) && ((fileDer->length == 0) || + (fileDer->length != peer_cert->derCert->length) || + (XMEMCMP(peer_cert->derCert->buffer, fileDer->buffer, + fileDer->length) != 0))) { + ret = WOLFSSL_FATAL_ERROR; + } + + /* Dispose of the DER, any heap buffer and close the file. */ + FreeDer(&fileDer); + if (myBuf != staticBuffer) { + XFREE(myBuf, heap, DYNAMIC_TYPE_FILE); + } + if (file != XBADFILE) { + XFCLOSE(file); + } + } + + return ret; +} +#endif + + +#ifdef WOLFSSL_ALT_CERT_CHAINS +/* Determine whether the peer was verified using an alternate cert chain. + * + * @param [in] ssl SSL/TLS object. + * @return 1 when an alternate certificate chain was used. + * @return 0 otherwise, or when ssl is NULL. + */ +int wolfSSL_is_peer_alt_cert_chain(const WOLFSSL* ssl) +{ + return (ssl != NULL) && ssl->options.usingAltCertChain; +} +#endif /* WOLFSSL_ALT_CERT_CHAINS */ + + +#ifdef SESSION_CERTS + +#ifdef WOLFSSL_ALT_CERT_CHAINS +/* Get the peer's alternate certificate chain. + * + * @param [in] ssl SSL/TLS object. + * @return Alternate certificate chain on success. + * @return NULL when ssl is NULL. + */ +WOLFSSL_X509_CHAIN* wolfSSL_get_peer_alt_chain(WOLFSSL* ssl) +{ + WOLFSSL_X509_CHAIN* chain = NULL; + + WOLFSSL_ENTER("wolfSSL_get_peer_alt_chain"); + + if (ssl != NULL) { + /* The alternate chain is held within the session. */ + chain = &ssl->session->altChain; + } + + return chain; +} +#endif /* WOLFSSL_ALT_CERT_CHAINS */ + + +/* Get the peer's certificate chain. + * + * @param [in] ssl SSL/TLS object. + * @return Certificate chain on success. + * @return NULL when ssl is NULL. + */ +WOLFSSL_X509_CHAIN* wolfSSL_get_peer_chain(WOLFSSL* ssl) +{ + WOLFSSL_X509_CHAIN* chain = NULL; + + WOLFSSL_ENTER("wolfSSL_get_peer_chain"); + + if (ssl != NULL) { + /* The peer chain is held within the session. */ + chain = &ssl->session->chain; + } + + return chain; +} + + +/* Get the number of certificates in a certificate chain. + * + * @param [in] chain Certificate chain object. + * @return Number of certificates on success. + * @return 0 when chain is NULL. + */ +int wolfSSL_get_chain_count(WOLFSSL_X509_CHAIN* chain) +{ + int count = 0; + + WOLFSSL_ENTER("wolfSSL_get_chain_count"); + + if (chain != NULL) { + /* Number of certificates captured in the chain. */ + count = chain->count; + } + + return count; +} + + +/* Get the length, in bytes, of the DER certificate at an index in a chain. + * + * @param [in] chain Certificate chain object. + * @param [in] idx Index of the certificate in the chain. + * @return Length of the DER certificate in bytes on success. + * @return 0 when chain is NULL. + */ +int wolfSSL_get_chain_length(WOLFSSL_X509_CHAIN* chain, int idx) +{ + int length = 0; + + WOLFSSL_ENTER("wolfSSL_get_chain_length"); + + if (chain != NULL) { + /* DER length of the certificate stored at the given index. */ + length = chain->certs[idx].length; + } + + return length; +} + + +/* Get the DER certificate at an index in a certificate chain. + * + * @param [in] chain Certificate chain object. + * @param [in] idx Index of the certificate in the chain. + * @return Buffer holding the DER certificate on success. + * @return 0 when chain is NULL. + */ +byte* wolfSSL_get_chain_cert(WOLFSSL_X509_CHAIN* chain, int idx) +{ + byte* cert = NULL; + + WOLFSSL_ENTER("wolfSSL_get_chain_cert"); + + if (chain != NULL) { + /* DER buffer of the certificate stored at the given index. */ + cert = chain->certs[idx].buffer; + } + + return cert; +} + + +/* Decode DER certificate data into a WOLFSSL_X509 object. Defined in + * src/ssl.c. */ +static int DecodeToX509(WOLFSSL_X509* x509, const byte* in, int len); + +/* Get the certificate at an index in a chain as a new X509 object. + * + * The returned object must be freed by the caller with wolfSSL_X509_free(). + * + * @param [in] chain Certificate chain object. + * @param [in] idx Index of the certificate in the chain. + * @return Newly allocated X509 certificate object on success. + * @return NULL when chain is NULL, idx is out of range or on error. + */ +WOLFSSL_X509* wolfSSL_get_chain_X509(WOLFSSL_X509_CHAIN* chain, int idx) +{ + WOLFSSL_X509* x509 = NULL; + + WOLFSSL_ENTER("wolfSSL_get_chain_X509"); + + if ((chain != NULL) && (idx < MAX_CHAIN_DEPTH)) { + x509 = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), NULL, + DYNAMIC_TYPE_X509); + if (x509 == NULL) { + WOLFSSL_MSG("Failed alloc X509"); + } + else { + /* Pre-init with dynamicMemory=1 so DecodeToX509 skips its own + * InitX509 (and we still own the buffer for X509_free). */ + InitX509(x509, 1, NULL); + if (DecodeToX509(x509, chain->certs[idx].buffer, + chain->certs[idx].length) != 0) { + WOLFSSL_MSG("Failed to decode cert"); + wolfSSL_X509_free(x509); + x509 = NULL; + } + } + } + + return x509; +} + + +/* Get the certificate at an index in a chain as PEM. + * + * When buf is NULL, the length required is returned in outLen. + * + * @param [in] chain Certificate chain object. + * @param [in] idx Index of the certificate in the chain. + * @param [out] buf Buffer to hold PEM. May be NULL to get the length. + * @param [in] inLen Length of buffer in bytes. + * @param [out] outLen Length of PEM data in bytes. + * @return WOLFSSL_SUCCESS on success. + * @return LENGTH_ONLY_E when buf is NULL and outLen has been set. + * @return BAD_FUNC_ARG when a required argument is NULL or idx is invalid. + * @return WOLFSSL_FAILURE on error. + */ +int wolfSSL_get_chain_cert_pem(WOLFSSL_X509_CHAIN* chain, int idx, + unsigned char* buf, int inLen, int* outLen) +{ +#ifdef WOLFSSL_DER_TO_PEM + int ret = WOLFSSL_SUCCESS; + + WOLFSSL_ENTER("wolfSSL_get_chain_cert_pem"); + if ((chain == NULL) || (outLen == NULL) || (idx < 0) || + (idx >= wolfSSL_get_chain_count(chain))) { + ret = BAD_FUNC_ARG; + } + /* Delegate to wc_DerToPem when DER-to-PEM is available. */ + if (ret == WOLFSSL_SUCCESS) { + if (buf == NULL) { + inLen = 0; + } + else if (inLen < 0) { + ret = BAD_FUNC_ARG; + } + } + if (ret == WOLFSSL_SUCCESS) { + int n = wc_DerToPem(chain->certs[idx].buffer, + (word32)chain->certs[idx].length, buf, (word32)inLen, CERT_TYPE); + if (n < 0) { + if (buf == NULL) { + ret = WOLFSSL_FAILURE; + } + else { + ret = n; + } + } + else { + *outLen = n; + if (buf == NULL) { + ret = WC_NO_ERR_TRACE(LENGTH_ONLY_E); + } + } + } + + return ret; +#elif defined(WOLFSSL_PEM_TO_DER) + int ret = WOLFSSL_SUCCESS; + const char* header = NULL; + const char* footer = NULL; + int headerLen; + int footerLen; + int i; + int err; + + WOLFSSL_ENTER("wolfSSL_get_chain_cert_pem"); + if ((chain == NULL) || (outLen == NULL) || (idx < 0) || + (idx >= wolfSSL_get_chain_count(chain))) { + ret = BAD_FUNC_ARG; + } + if (ret == WOLFSSL_SUCCESS) { + if ((err = wc_PemGetHeaderFooter(CERT_TYPE, &header, &footer)) != 0) { + ret = err; + } + } + if (ret == WOLFSSL_SUCCESS) { + headerLen = (int)XSTRLEN(header); + footerLen = (int)XSTRLEN(footer); + + /* Null output buffer returns size needed in outLen. */ + if (buf == NULL) { + word32 szNeeded = 0; + + if (Base64_Encode(chain->certs[idx].buffer, + (word32)chain->certs[idx].length, NULL, + &szNeeded) != WC_NO_ERR_TRACE(LENGTH_ONLY_E)) { + ret = WOLFSSL_FAILURE; + } + else { + *outLen = (int)szNeeded + headerLen + footerLen; + ret = WC_NO_ERR_TRACE(LENGTH_ONLY_E); + } + } + /* buf == NULL, ret will not be WOLFSSL_SUCCESS. */ + } + /* Don't even try when inLen is too short. */ + if ((ret == WOLFSSL_SUCCESS) && + (inLen < headerLen + footerLen + chain->certs[idx].length)) { + ret = BAD_FUNC_ARG; + } + if (ret == WOLFSSL_SUCCESS) { + /* Write the PEM header. */ + XMEMCPY(buf, header, (size_t)headerLen); + i = headerLen; + + /* Space left for Base64 data after header and before footer. */ + *outLen = inLen - headerLen - footerLen; + if ((err = Base64_Encode(chain->certs[idx].buffer, + (word32)chain->certs[idx].length, buf + i, + (word32*)outLen)) < 0) { + ret = err; + } + } + if (ret == WOLFSSL_SUCCESS) { + i += *outLen; + + /* Write the PEM footer. */ + XMEMCPY(buf + i, footer, (size_t)footerLen); + *outLen += headerLen + footerLen; + } + + return ret; +#else + (void)chain; + (void)idx; + (void)buf; + (void)inLen; + (void)outLen; + return WOLFSSL_FAILURE; +#endif /* WOLFSSL_PEM_TO_DER || WOLFSSL_DER_TO_PEM */ +} + +#endif /* SESSION_CERTS */ + + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || defined(WOLFSSL_HAPROXY) \ + || defined(WOLFSSL_NGINX) || defined(WOLFSSL_QT) +#ifndef NO_WOLFSSL_STUB +/* Clear the extra certificate chain set on the context. + * + * Not implemented - stub for OpenSSL compatibility. + * + * @param [in] ctx SSL/TLS context object. + * @return Result of the SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS control command. + */ +long wolfSSL_CTX_clear_extra_chain_certs(WOLFSSL_CTX* ctx) +{ + return wolfSSL_CTX_ctrl(ctx, SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS, 0L, NULL); +} +#endif + +/* Get the verify callback set on the object. + * + * @param [in] ssl SSL/TLS object. + * @return Verify callback on success. + * @return NULL when ssl is NULL or no callback is set. + */ +VerifyCallback wolfSSL_get_verify_callback(WOLFSSL* ssl) +{ + VerifyCallback cb = NULL; + + WOLFSSL_ENTER("wolfSSL_get_verify_callback"); + + if (ssl != NULL) { + /* Verify callback configured on the object. */ + cb = ssl->verifyCallback; + } + + return cb; +} + +#endif + +#if defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) +/* Get the verify callback set on the context. + * + * @param [in] ctx SSL/TLS context object. + * @return Verify callback on success. + * @return NULL when ctx is NULL or no callback is set. + */ +VerifyCallback wolfSSL_CTX_get_verify_callback(WOLFSSL_CTX* ctx) +{ + VerifyCallback cb = NULL; + + WOLFSSL_ENTER("wolfSSL_CTX_get_verify_callback"); + + if (ctx != NULL) { + /* Verify callback configured on the context. */ + cb = ctx->verifyCallback; + } + + return cb; +} + +#endif + +#if defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) || defined(HAVE_STUNNEL) || \ + defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(WOLFSSL_NGINX) + +/* Get the verification mode set on the object. + * + * TODO: Doesn't currently track SSL_VERIFY_CLIENT_ONCE. + * + * @param [in] ssl SSL/TLS object. + * @return Bitmask of WOLFSSL_VERIFY_* flags on success. + * @return WOLFSSL_FAILURE when ssl is NULL. + */ +int wolfSSL_get_verify_mode(const WOLFSSL* ssl) +{ + int mode = 0; + + WOLFSSL_ENTER("wolfSSL_get_verify_mode"); + + if (ssl == NULL) { + mode = WOLFSSL_FAILURE; + } + else if (ssl->options.verifyNone) { + /* VERIFY_NONE is exclusive of the other verify flags. */ + mode = WOLFSSL_VERIFY_NONE; + } + else { + /* Build the mode as a bitmask of the enabled verify flags. */ + if (ssl->options.verifyPeer) { + mode |= WOLFSSL_VERIFY_PEER; + } + if (ssl->options.failNoCert) { + mode |= WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT; + } + if (ssl->options.failNoCertxPSK) { + mode |= WOLFSSL_VERIFY_FAIL_EXCEPT_PSK; + } +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) + if (ssl->options.verifyPostHandshake) { + mode |= WOLFSSL_VERIFY_POST_HANDSHAKE; + } +#endif + } + + WOLFSSL_LEAVE("wolfSSL_get_verify_mode", mode); + return mode; +} + +/* Get the verification mode set on the context. + * + * @param [in] ctx SSL/TLS context object. + * @return Bitmask of WOLFSSL_VERIFY_* flags on success. + * @return WOLFSSL_FAILURE when ctx is NULL. + */ +int wolfSSL_CTX_get_verify_mode(const WOLFSSL_CTX* ctx) +{ + int mode = 0; + + WOLFSSL_ENTER("wolfSSL_CTX_get_verify_mode"); + + if (ctx == NULL) { + mode = WOLFSSL_FAILURE; + } + else if (ctx->verifyNone) { + /* VERIFY_NONE is exclusive of the other verify flags. */ + mode = WOLFSSL_VERIFY_NONE; + } + else { + /* Build the mode as a bitmask of the enabled verify flags. */ + if (ctx->verifyPeer) { + mode |= WOLFSSL_VERIFY_PEER; + } + if (ctx->failNoCert) { + mode |= WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT; + } + if (ctx->failNoCertxPSK) { + mode |= WOLFSSL_VERIFY_FAIL_EXCEPT_PSK; + } +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) + if (ctx->verifyPostHandshake) { + mode |= WOLFSSL_VERIFY_POST_HANDSHAKE; + } +#endif + } + + WOLFSSL_LEAVE("wolfSSL_CTX_get_verify_mode", mode); + return mode; +} + +#endif + + +#if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || \ + defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) +/* Create a stack of X509 certificates from a DER encoded certificate chain. + * + * The chain buffer holds each certificate as: 3 byte length | X509 DER data. + * + * @param [in] der DER encoded certificate chain. + * @param [in] derLen Length of certificate chain buffer in bytes. + * @param [in] heap Dynamic memory hint. + * @param [out] chain Stack of X509 certificates. Holds as much of the + * chain as was created on failure. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE on allocation or decode error. + */ +static int wolfssl_certchain_to_x509_stack(byte* der, word32 derLen, + void* heap, WOLF_STACK_OF(X509)** chain) +{ + int ret = WOLFSSL_SUCCESS; + word32 idx; + word32 length; + WOLFSSL_STACK* node; + WOLFSSL_STACK* last = NULL; + + /* Create a new stack of WOLFSSL_X509 object from chain buffer. */ + for (idx = 0; idx < derLen; ) { + /* Need 3 bytes for the length of the DER encoded certificate. */ + if ((derLen - idx) < 3) { + ret = WOLFSSL_FAILURE; + break; + } + + /* Format: 3 byte length | X509 DER data. */ + ato24(der + idx, &length); + idx += 3; + + /* Ensure the DER encoded certificate is contained in the buffer. */ + if (length > (derLen - idx)) { + ret = WOLFSSL_FAILURE; + break; + } + + node = wolfSSL_sk_X509_new_null(); + if (node == NULL) { + ret = WOLFSSL_FAILURE; + break; + } + node->next = NULL; + + /* Create a new X509 from DER encoded data. */ + node->data.x509 = wolfSSL_X509_d2i_ex(NULL, der + idx, (int)length, + heap); + if (node->data.x509 == NULL) { + XFREE(node, NULL, DYNAMIC_TYPE_OPENSSL); + /* Return as much of the chain as we created. */ + ret = WOLFSSL_FAILURE; + break; + } + idx += length; + + /* Add object to the end of the stack. */ + if (last == NULL) { + node->num = 1; + *chain = node; + } + else { + (*chain)->num++; + last->next = node; + } + + last = node; + } + + return ret; +} + +/* Get the extra certificate chain set on the context as a stack of X509. + * + * Builds the stack from the context's certificate chain buffer when needed. + * + * @param [in] ctx SSL/TLS context object. + * @param [out] chain Stack of X509 certificates. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ctx or chain is NULL, or on allocation error. + */ +int wolfSSL_CTX_get_extra_chain_certs(WOLFSSL_CTX* ctx, + WOLF_STACK_OF(X509)** chain) +{ + int ret = WOLFSSL_SUCCESS; + + if ((ctx == NULL) || (chain == NULL)) { + ret = WOLFSSL_FAILURE; + } + else if (ctx->x509Chain != NULL) { + *chain = ctx->x509Chain; + } + else { + /* If there are no chains then success! */ + *chain = NULL; + if ((ctx->certChain != NULL) && (ctx->certChain->length != 0)) { + /* Build a stack of X509 from the DER certificate chain buffer. */ + ret = wolfssl_certchain_to_x509_stack(ctx->certChain->buffer, + ctx->certChain->length, ctx->heap, chain); + /* Cache the chain - holds as much as was created on failure. */ + ctx->x509Chain = *chain; + } + } + + return ret; +} + +/* Get the certificate chain set on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [out] sk Stack of X509 certificates. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ctx or sk is NULL. + */ +int wolfSSL_CTX_get0_chain_certs(WOLFSSL_CTX *ctx, + WOLF_STACK_OF(WOLFSSL_X509) **sk) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_get0_chain_certs"); + + if ((ctx == NULL) || (sk == NULL)) { + WOLFSSL_MSG("Bad parameter"); + ret = WOLFSSL_FAILURE; + } + else { + /* This function should return ctx->x509Chain if it is populated, + * otherwise it should be populated from ctx->certChain. This matches + * the behavior of wolfSSL_CTX_get_extra_chain_certs, so it is used + * directly. */ + ret = wolfSSL_CTX_get_extra_chain_certs(ctx, sk); + } + + return ret; +} + +#ifdef KEEP_OUR_CERT +/* Get our certificate chain set on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [out] sk Stack of X509 certificates. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ssl or sk is NULL. + */ +int wolfSSL_get0_chain_certs(WOLFSSL *ssl, WOLF_STACK_OF(WOLFSSL_X509) **sk) +{ + int ret = WOLFSSL_SUCCESS; + + WOLFSSL_ENTER("wolfSSL_get0_chain_certs"); + + if ((ssl == NULL) || (sk == NULL)) { + WOLFSSL_MSG("Bad parameter"); + ret = WOLFSSL_FAILURE; + } + else { + /* Return our own certificate chain held on the object. */ + *sk = ssl->ourCertChain; + } + + return ret; +} +#endif + +#endif + +#endif /* !WOLFCRYPT_ONLY */ + #endif /* !WOLFSSL_SSL_API_CERT_INCLUDED */ diff --git a/src/ssl_api_dtls.c b/src/ssl_api_dtls.c new file mode 100644 index 0000000000..46ea02b567 --- /dev/null +++ b/src/ssl_api_dtls.c @@ -0,0 +1,1462 @@ +/* ssl_api_dtls.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_DTLS_INCLUDED) + #ifndef WOLFSSL_IGNORE_FILE_WARN + #warning ssl_api_dtls.c does not need to be compiled separately from ssl.c + #endif +#else + +#ifndef WOLFCRYPT_ONLY + +#ifdef WOLFSSL_DTLS +/* Set the file descriptor for an already connected DTLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] fd Connected socket file descriptor. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + */ +int wolfSSL_set_dtls_fd_connected(WOLFSSL* ssl, int fd) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_set_dtls_fd_connected"); + + if (ssl == NULL) { + return BAD_FUNC_ARG; + } + + ret = wolfSSL_set_fd(ssl, fd); + if (ret == WOLFSSL_SUCCESS) + ssl->buffers.dtlsCtx.connected = 1; + + return ret; +} +#endif + + +/* Determine whether the object is configured for DTLS. + * + * @param [in] ssl SSL/TLS object. + * @return 1 when using DTLS. + * @return 0 otherwise, or when ssl is NULL. + */ +int wolfSSL_dtls(WOLFSSL* ssl) +{ + int dtlsOpt = 0; + if (ssl) + dtlsOpt = ssl->options.dtls; + return dtlsOpt; +} + + +#ifndef WOLFSSL_LEANPSK +#if defined(WOLFSSL_DTLS) && defined(XINET_PTON) && \ + !defined(WOLFSSL_NO_SOCK) && defined(HAVE_SOCKADDR) +/* Create a DTLS peer address from a port and IPv4 address string. + * + * The returned object must be freed with wolfSSL_dtls_free_peer(). + * + * @param [in] port Port number. + * @param [in] ip Dotted-decimal IPv4 address string. + * @return Newly allocated peer address on success. + * @return NULL on allocation error or when the address is invalid. + */ +void* wolfSSL_dtls_create_peer(int port, char* ip) +{ + SOCKADDR_IN *addr; + addr = (SOCKADDR_IN*)XMALLOC(sizeof(*addr), NULL, + DYNAMIC_TYPE_SOCKADDR); + if (addr == NULL) { + return NULL; + } + + addr->sin_family = AF_INET; + addr->sin_port = XHTONS((word16)port); + if (XINET_PTON(AF_INET, ip, &addr->sin_addr) < 1) { + XFREE(addr, NULL, DYNAMIC_TYPE_SOCKADDR); + return NULL; + } + + return addr; +} + +/* Free a DTLS peer address created with wolfSSL_dtls_create_peer(). + * + * @param [in] addr Peer address to free. + * @return WOLFSSL_SUCCESS always. + */ +int wolfSSL_dtls_free_peer(void* addr) +{ + XFREE(addr, NULL, DYNAMIC_TYPE_SOCKADDR); + return WOLFSSL_SUCCESS; +} +#endif + +#ifdef WOLFSSL_DTLS +/* Store a socket address into a socket address holder, resizing as needed. + * + * A NULL or zero-length peer frees the holder's buffer. + * + * @param [in, out] sockAddr Socket address holder. + * @param [in] peer Socket address data, may be NULL to free. + * @param [in] peerSz Length of socket address data in bytes. + * @param [in] heap Heap hint for dynamic memory allocation. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE on allocation error. + */ +static int SockAddrSet(WOLFSSL_SOCKADDR* sockAddr, void* peer, + unsigned int peerSz, void* heap) +{ + if (peer == NULL || peerSz == 0) { + if (sockAddr->sa != NULL) + XFREE(sockAddr->sa, heap, DYNAMIC_TYPE_SOCKADDR); + sockAddr->sa = NULL; + sockAddr->sz = 0; + sockAddr->bufSz = 0; + return WOLFSSL_SUCCESS; + } + + if (peerSz > sockAddr->bufSz) { + if (sockAddr->sa != NULL) + XFREE(sockAddr->sa, heap, DYNAMIC_TYPE_SOCKADDR); + sockAddr->sa = + (void*)XMALLOC(peerSz, heap, DYNAMIC_TYPE_SOCKADDR); + if (sockAddr->sa == NULL) { + sockAddr->sz = 0; + sockAddr->bufSz = 0; + return WOLFSSL_FAILURE; + } + sockAddr->bufSz = peerSz; + } + XMEMCPY(sockAddr->sa, peer, peerSz); + sockAddr->sz = peerSz; + return WOLFSSL_SUCCESS; +} +#endif + +/* Set the DTLS peer address on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] peer Peer socket address, may be NULL to clear. + * @param [in] peerSz Length of peer address in bytes. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ssl is NULL or on error. + * @return WOLFSSL_NOT_IMPLEMENTED when DTLS is not compiled in. + */ +int wolfSSL_dtls_set_peer(WOLFSSL* ssl, void* peer, unsigned int peerSz) +{ +#ifdef WOLFSSL_DTLS + int ret; + + if (ssl == NULL) + return WOLFSSL_FAILURE; +#ifdef WOLFSSL_RW_THREADED + if (wc_LockRwLock_Wr(&ssl->buffers.dtlsCtx.peerLock) != 0) + return WOLFSSL_FAILURE; +#endif + ret = SockAddrSet(&ssl->buffers.dtlsCtx.peer, peer, peerSz, ssl->heap); + if (ret == WOLFSSL_SUCCESS && !(peer == NULL || peerSz == 0)) + ssl->buffers.dtlsCtx.userSet = 1; + else + ssl->buffers.dtlsCtx.userSet = 0; +#ifdef WOLFSSL_RW_THREADED + if (wc_UnLockRwLock(&ssl->buffers.dtlsCtx.peerLock) != 0) + ret = WOLFSSL_FAILURE; +#endif + return ret; +#else + (void)ssl; + (void)peer; + (void)peerSz; + return WOLFSSL_NOT_IMPLEMENTED; +#endif +} + +#if defined(WOLFSSL_DTLS_CID) && !defined(WOLFSSL_NO_SOCK) +/* Set the pending DTLS peer address on the object. + * + * Used with connection ID to stage a change of peer address. + * + * @param [in] ssl SSL/TLS object. + * @param [in] peer Peer socket address. + * @param [in] peerSz Length of peer address in bytes. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ssl is NULL or on error. + * @return WOLFSSL_NOT_IMPLEMENTED when DTLS is not compiled in. + */ +int wolfSSL_dtls_set_pending_peer(WOLFSSL* ssl, void* peer, unsigned int peerSz) +{ +#ifdef WOLFSSL_DTLS + int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); + + if (ssl == NULL) + return WOLFSSL_FAILURE; +#ifdef WOLFSSL_RW_THREADED + if (wc_LockRwLock_Rd(&ssl->buffers.dtlsCtx.peerLock) != 0) + return WOLFSSL_FAILURE; +#endif + if (ssl->buffers.dtlsCtx.peer.sa != NULL && + ssl->buffers.dtlsCtx.peer.sz == peerSz && + sockAddrEqual((SOCKADDR_S*)ssl->buffers.dtlsCtx.peer.sa, + (XSOCKLENT)ssl->buffers.dtlsCtx.peer.sz, (SOCKADDR_S*)peer, + (XSOCKLENT)peerSz)) { + /* Already the current peer. */ + if (ssl->buffers.dtlsCtx.pendingPeer.sa != NULL) { + /* Clear any other pendingPeer */ + XFREE(ssl->buffers.dtlsCtx.pendingPeer.sa, ssl->heap, + DYNAMIC_TYPE_SOCKADDR); + ssl->buffers.dtlsCtx.pendingPeer.sa = NULL; + ssl->buffers.dtlsCtx.pendingPeer.sz = 0; + ssl->buffers.dtlsCtx.pendingPeer.bufSz = 0; + } + ret = WOLFSSL_SUCCESS; + } + else { + ret = SockAddrSet(&ssl->buffers.dtlsCtx.pendingPeer, peer, peerSz, + ssl->heap); + } + if (ret == WOLFSSL_SUCCESS) + ssl->buffers.dtlsCtx.processingPendingRecord = 0; +#ifdef WOLFSSL_RW_THREADED + if (wc_UnLockRwLock(&ssl->buffers.dtlsCtx.peerLock) != 0) + ret = WOLFSSL_FAILURE; +#endif + return ret; +#else + (void)ssl; + (void)peer; + (void)peerSz; + return WOLFSSL_NOT_IMPLEMENTED; +#endif +} +#endif /* WOLFSSL_DTLS_CID && !WOLFSSL_NO_SOCK */ + +/* Get a copy of the DTLS peer address from the object. + * + * @param [in] ssl SSL/TLS object. + * @param [out] peer Buffer to hold the peer address. + * @param [in, out] peerSz In: size of buffer. Out: length of address. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ssl is NULL or the buffer is too small. + * @return WOLFSSL_NOT_IMPLEMENTED when DTLS is not compiled in. + */ +int wolfSSL_dtls_get_peer(WOLFSSL* ssl, void* peer, unsigned int* peerSz) +{ +#ifdef WOLFSSL_DTLS + int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); + if (ssl == NULL) + return WOLFSSL_FAILURE; +#ifdef WOLFSSL_RW_THREADED + if (wc_LockRwLock_Rd(&ssl->buffers.dtlsCtx.peerLock) != 0) + return WOLFSSL_FAILURE; +#endif + if (peer != NULL && peerSz != NULL + && *peerSz >= ssl->buffers.dtlsCtx.peer.sz + && ssl->buffers.dtlsCtx.peer.sa != NULL) { + *peerSz = ssl->buffers.dtlsCtx.peer.sz; + XMEMCPY(peer, ssl->buffers.dtlsCtx.peer.sa, *peerSz); + ret = WOLFSSL_SUCCESS; + } +#ifdef WOLFSSL_RW_THREADED + if (wc_UnLockRwLock(&ssl->buffers.dtlsCtx.peerLock) != 0) + ret = WOLFSSL_FAILURE; +#endif + return ret; +#else + (void)ssl; + (void)peer; + (void)peerSz; + return WOLFSSL_NOT_IMPLEMENTED; +#endif +} + +/* Get a pointer to the DTLS peer address stored on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [out] peer Pointer to the stored peer address. + * @param [out] peerSz Length of the peer address in bytes. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when an argument is NULL. + * @return WOLFSSL_NOT_IMPLEMENTED when DTLS is not compiled in or threaded. + */ +int wolfSSL_dtls_get0_peer(WOLFSSL* ssl, const void** peer, + unsigned int* peerSz) +{ +#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_RW_THREADED) + if (ssl == NULL) + return WOLFSSL_FAILURE; + + if (peer == NULL || peerSz == NULL) + return WOLFSSL_FAILURE; + + *peer = ssl->buffers.dtlsCtx.peer.sa; + *peerSz = ssl->buffers.dtlsCtx.peer.sz; + return WOLFSSL_SUCCESS; +#else + (void)ssl; + (void)peer; + (void)peerSz; + return WOLFSSL_NOT_IMPLEMENTED; +#endif +} + + +#if defined(WOLFSSL_SCTP) && defined(WOLFSSL_DTLS) + +/* Enable DTLS over SCTP mode on the context. + * + * @param [in] ctx SSL/TLS context object. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx is NULL. + */ +int wolfSSL_CTX_dtls_set_sctp(WOLFSSL_CTX* ctx) +{ + WOLFSSL_ENTER("wolfSSL_CTX_dtls_set_sctp"); + + if (ctx == NULL) + return BAD_FUNC_ARG; + + ctx->dtlsSctp = 1; + return WOLFSSL_SUCCESS; +} + + +/* Enable DTLS over SCTP mode on the object. + * + * @param [in] ssl SSL/TLS object. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + */ +int wolfSSL_dtls_set_sctp(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_dtls_set_sctp"); + + if (ssl == NULL) + return BAD_FUNC_ARG; + + ssl->options.dtlsSctp = 1; + return WOLFSSL_SUCCESS; +} + +#endif /* WOLFSSL_DTLS && WOLFSSL_SCTP */ + +#if (defined(WOLFSSL_SCTP) || defined(WOLFSSL_DTLS_MTU)) && \ + defined(WOLFSSL_DTLS) + +/* Set the DTLS path MTU on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] newMtu Maximum transmission unit in bytes. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx is NULL or newMtu is too large. + */ +int wolfSSL_CTX_dtls_set_mtu(WOLFSSL_CTX* ctx, word16 newMtu) +{ + if (ctx == NULL || newMtu > MAX_RECORD_SIZE) + return BAD_FUNC_ARG; + + ctx->dtlsMtuSz = newMtu; + return WOLFSSL_SUCCESS; +} + + +/* Set the DTLS path MTU on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] newMtu Maximum transmission unit in bytes. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + * @return WOLFSSL_FAILURE when newMtu is too large. + */ +int wolfSSL_dtls_set_mtu(WOLFSSL* ssl, word16 newMtu) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + + if (newMtu > MAX_RECORD_SIZE) { + ssl->error = BAD_FUNC_ARG; + return WOLFSSL_FAILURE; + } + + ssl->dtlsMtuSz = newMtu; + return WOLFSSL_SUCCESS; +} + +#ifdef OPENSSL_EXTRA +/* Set the DTLS path MTU on the object. + * + * Maps to the compatibility API SSL_set_mtu. Same as wolfSSL_dtls_set_mtu() + * but returns only success or failure. + * + * @param [in] ssl SSL/TLS object. + * @param [in] mtu Maximum transmission unit in bytes. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE on error. + */ +int wolfSSL_set_mtu_compat(WOLFSSL* ssl, unsigned short mtu) +{ + if (wolfSSL_dtls_set_mtu(ssl, mtu) == WOLFSSL_SUCCESS) + return WOLFSSL_SUCCESS; + else + return WOLFSSL_FAILURE; +} +#endif /* OPENSSL_EXTRA */ + +#endif /* WOLFSSL_DTLS && (WOLFSSL_SCTP || WOLFSSL_DTLS_MTU) */ + +#ifdef WOLFSSL_SRTP + +static const WOLFSSL_SRTP_PROTECTION_PROFILE gSrtpProfiles[] = { + /* AES CCM 128, Salt:112-bits, Auth HMAC-SHA1 Tag: 80-bits + * (master_key:128bits + master_salt:112bits) * 2 = 480 bits (60) */ + {"SRTP_AES128_CM_SHA1_80", SRTP_AES128_CM_SHA1_80, + (((128 + 112) * 2) / 8) }, + /* AES CCM 128, Salt:112-bits, Auth HMAC-SHA1 Tag: 32-bits + * (master_key:128bits + master_salt:112bits) * 2 = 480 bits (60) */ + {"SRTP_AES128_CM_SHA1_32", SRTP_AES128_CM_SHA1_32, + (((128 + 112) * 2) / 8) }, + /* NULL Cipher, Salt:112-bits, Auth HMAC-SHA1 Tag 80-bits */ + {"SRTP_NULL_SHA1_80", SRTP_NULL_SHA1_80, ((112 * 2) / 8)}, + /* NULL Cipher, Salt:112-bits, Auth HMAC-SHA1 Tag 32-bits */ + {"SRTP_NULL_SHA1_32", SRTP_NULL_SHA1_32, ((112 * 2) / 8)}, + /* AES GCM 128, Salt: 96-bits, Auth GCM Tag 128-bits + * (master_key:128bits + master_salt:96bits) * 2 = 448 bits (56) */ + {"SRTP_AEAD_AES_128_GCM", SRTP_AEAD_AES_128_GCM, (((128 + 96) * 2) / 8) }, + /* AES GCM 256, Salt: 96-bits, Auth GCM Tag 128-bits + * (master_key:256bits + master_salt:96bits) * 2 = 704 bits (88) */ + {"SRTP_AEAD_AES_256_GCM", SRTP_AEAD_AES_256_GCM, (((256 + 96) * 2) / 8) }, +}; + +/* Find an SRTP protection profile by name or by id. + * + * @param [in] profile_str Profile name, or NULL to search by id. + * @param [in] profile_str_len Length of profile name in bytes. + * @param [in] id Profile id to search for when name is NULL. + * @return Matching SRTP protection profile on success. + * @return NULL when no profile matches. + */ +static const WOLFSSL_SRTP_PROTECTION_PROFILE* DtlsSrtpFindProfile( + const char* profile_str, word32 profile_str_len, unsigned long id) +{ + int i; + const WOLFSSL_SRTP_PROTECTION_PROFILE* profile = NULL; + for (i=0; + i<(int)(sizeof(gSrtpProfiles)/sizeof(WOLFSSL_SRTP_PROTECTION_PROFILE)); + i++) { + if (profile_str != NULL) { + word32 srtp_profile_len = (word32)XSTRLEN(gSrtpProfiles[i].name); + if (srtp_profile_len == profile_str_len && + XMEMCMP(gSrtpProfiles[i].name, profile_str, profile_str_len) + == 0) { + profile = &gSrtpProfiles[i]; + break; + } + } + else if (id != 0 && gSrtpProfiles[i].id == id) { + profile = &gSrtpProfiles[i]; + break; + } + } + return profile; +} + +/* Select SRTP protection profiles from a colon-separated name list. + * + * @param [out] id Bitmask of selected profile ids. + * @param [in] profile_str Colon-separated list of SRTP profile names. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when profile_str is NULL. + */ +static int DtlsSrtpSelProfiles(word16* id, const char* profile_str) +{ + const WOLFSSL_SRTP_PROTECTION_PROFILE* profile; + const char *current, *next = NULL; + word32 length = 0, current_length; + + *id = 0; /* reset destination ID's */ + + if (profile_str == NULL) { + return WOLFSSL_FAILURE; + } + + /* loop on end of line or colon ":" */ + next = profile_str; + length = (word32)XSTRLEN(profile_str); + do { + current = next; + next = XSTRSTR(current, ":"); + if (next) { + current_length = (word32)(next - current); + ++next; /* ++ needed to skip ':' */ + } else { + current_length = (word32)XSTRLEN(current); + } + if (current_length < length) + length = current_length; + profile = DtlsSrtpFindProfile(current, current_length, 0); + if (profile != NULL) { + *id |= (1 << profile->id); /* selected bit based on ID */ + } + } while (next != NULL); + return WOLFSSL_SUCCESS; +} + +/* Set the SRTP protection profiles for DTLS on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] profile_str Colon-separated list of SRTP profile names. + * @return 0 on success, to match OpenSSL. + * @return 1 on error, to match OpenSSL. + */ +int wolfSSL_CTX_set_tlsext_use_srtp(WOLFSSL_CTX* ctx, const char* profile_str) +{ + int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); + if (ctx != NULL) { + ret = DtlsSrtpSelProfiles(&ctx->dtlsSrtpProfiles, profile_str); + } + + if (ret == WC_NO_ERR_TRACE(WOLFSSL_FAILURE)) { + ret = 1; + } else { + ret = 0; + } + + return ret; +} + +/* Set the SRTP protection profiles for DTLS on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] profile_str Colon-separated list of SRTP profile names. + * @return 0 on success, to match OpenSSL. + * @return 1 on error, to match OpenSSL. + */ +int wolfSSL_set_tlsext_use_srtp(WOLFSSL* ssl, const char* profile_str) +{ + int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); + if (ssl != NULL) { + ret = DtlsSrtpSelProfiles(&ssl->dtlsSrtpProfiles, profile_str); + } + + if (ret == WC_NO_ERR_TRACE(WOLFSSL_FAILURE)) { + ret = 1; + } else { + ret = 0; + } + + return ret; +} + +/* Get the SRTP protection profile selected for the object. + * + * @param [in] ssl SSL/TLS object. + * @return Selected SRTP protection profile on success. + * @return NULL when ssl is NULL or none is selected. + */ +const WOLFSSL_SRTP_PROTECTION_PROFILE* wolfSSL_get_selected_srtp_profile( + WOLFSSL* ssl) +{ + const WOLFSSL_SRTP_PROTECTION_PROFILE* profile = NULL; + if (ssl) { + profile = DtlsSrtpFindProfile(NULL, 0, ssl->dtlsSrtpId); + } + return profile; +} +#ifndef NO_WOLFSSL_STUB +/* Get the list of SRTP protection profiles set on the object. + * + * Not implemented - stub. + * + * @param [in] ssl SSL/TLS object. + * @return NULL always. + */ +WOLF_STACK_OF(WOLFSSL_SRTP_PROTECTION_PROFILE)* wolfSSL_get_srtp_profiles( + WOLFSSL* ssl) +{ + /* Not yet implemented - should return list of available SRTP profiles + * ssl->dtlsSrtpProfiles */ + (void)ssl; + return NULL; +} +#endif + +#define DTLS_SRTP_KEYING_MATERIAL_LABEL "EXTRACTOR-dtls_srtp" + +/* Export the DTLS-SRTP keying material for the object. + * + * When out is NULL, the length required is returned in olen. + * + * @param [in] ssl SSL/TLS object. + * @param [out] out Buffer to hold keying material. May be NULL. + * @param [in, out] olen In: size of buffer. Out: length of keying material. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl or olen is NULL. + * @return EXT_MISSING when DTLS-SRTP is not in use. + * @return LENGTH_ONLY_E when out is NULL and olen has been set. + * @return BUFFER_E when the buffer is too small. + */ +int wolfSSL_export_dtls_srtp_keying_material(WOLFSSL* ssl, + unsigned char* out, size_t* olen) +{ + const WOLFSSL_SRTP_PROTECTION_PROFILE* profile = NULL; + + if (ssl == NULL || olen == NULL) { + return BAD_FUNC_ARG; + } + + profile = DtlsSrtpFindProfile(NULL, 0, ssl->dtlsSrtpId); + if (profile == NULL) { + WOLFSSL_MSG("Not using DTLS SRTP"); + return EXT_MISSING; + } + if (out == NULL) { + *olen = (size_t)profile->kdfBits; + return WC_NO_ERR_TRACE(LENGTH_ONLY_E); + } + + if (*olen < (size_t)profile->kdfBits) { + return BUFFER_E; + } + + return wolfSSL_export_keying_material(ssl, out, (size_t)profile->kdfBits, + DTLS_SRTP_KEYING_MATERIAL_LABEL, + XSTR_SIZEOF(DTLS_SRTP_KEYING_MATERIAL_LABEL), NULL, 0, 0); +} + +#endif /* WOLFSSL_SRTP */ + + +#ifdef WOLFSSL_DTLS_DROP_STATS + +/* Get the DTLS dropped-record statistics for the object. + * + * @param [in] ssl SSL/TLS object. + * @param [out] macDropCount Number of records dropped on MAC failure. + * @param [out] replayDropCount Number of records dropped as replays. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + */ +int wolfSSL_dtls_get_drop_stats(WOLFSSL* ssl, + word32* macDropCount, word32* replayDropCount) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_dtls_get_drop_stats"); + + if (ssl == NULL) + ret = BAD_FUNC_ARG; + else { + ret = WOLFSSL_SUCCESS; + if (macDropCount != NULL) + *macDropCount = ssl->macDropCount; + if (replayDropCount != NULL) + *replayDropCount = ssl->replayDropCount; + } + + WOLFSSL_LEAVE("wolfSSL_dtls_get_drop_stats", ret); + return ret; +} + +#endif /* WOLFSSL_DTLS_DROP_STATS */ + + +#if defined(WOLFSSL_MULTICAST) + +/* Set the multicast member id on the context and enable multicast. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] id Multicast member id. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx is NULL or id is out of range. + */ +int wolfSSL_CTX_mcast_set_member_id(WOLFSSL_CTX* ctx, word16 id) +{ + int ret = 0; + + WOLFSSL_ENTER("wolfSSL_CTX_mcast_set_member_id"); + + if (ctx == NULL || id > WOLFSSL_MAX_8BIT) + ret = BAD_FUNC_ARG; + + if (ret == 0) { + ctx->haveEMS = 0; + ctx->haveMcast = 1; + ctx->mcastID = (byte)id; +#ifndef WOLFSSL_USER_IO + ctx->CBIORecv = EmbedReceiveFromMcast; +#endif /* WOLFSSL_USER_IO */ + + ret = WOLFSSL_SUCCESS; + } + WOLFSSL_LEAVE("wolfSSL_CTX_mcast_set_member_id", ret); + return ret; +} + +/* Get the maximum number of multicast peers supported. + * + * @return Maximum number of multicast peers. + */ +int wolfSSL_mcast_get_max_peers(void) +{ + return WOLFSSL_MULTICAST_PEERS; +} + +#ifdef WOLFSSL_DTLS +/* Determine the next highwater mark from the current sequence number. + * + * @param [in] cur Current sequence number. + * @param [in] first First highwater threshold. + * @param [in] second Second highwater threshold. + * @param [in] high Maximum highwater threshold. + * @return Next highwater mark, or 0 when cur is at or above high. + */ +static WC_INLINE word32 UpdateHighwaterMark(word32 cur, word32 first, + word32 second, word32 high) +{ + word32 newCur = 0; + + if (cur < first) + newCur = first; + else if (cur < second) + newCur = second; + else if (cur < high) + newCur = high; + + return newCur; +} +#endif /* WOLFSSL_DTLS */ + + +/* Set the master secret and derived keys directly on the object. + * + * Used with multicast to install externally derived keys. + * + * @param [in] ssl SSL/TLS object. + * @param [in] epoch DTLS epoch to use. + * @param [in] preMasterSecret Pre-master secret data. + * @param [in] preMasterSz Length of pre-master secret in bytes. + * @param [in] clientRandom Client random data (RAN_LEN bytes). + * @param [in] serverRandom Server random data (RAN_LEN bytes). + * @param [in] suite Cipher suite bytes (2). + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FATAL_ERROR on error, including invalid arguments. + */ +int wolfSSL_set_secret(WOLFSSL* ssl, word16 epoch, + const byte* preMasterSecret, word32 preMasterSz, + const byte* clientRandom, const byte* serverRandom, + const byte* suite) +{ + int ret = 0; + + WOLFSSL_ENTER("wolfSSL_set_secret"); + + if (ssl == NULL || preMasterSecret == NULL || + preMasterSz == 0 || preMasterSz > ENCRYPT_LEN || + clientRandom == NULL || serverRandom == NULL || suite == NULL) { + + ret = BAD_FUNC_ARG; + } + + if (ret == 0 && ssl->arrays->preMasterSecret == NULL) { + ssl->arrays->preMasterSz = ENCRYPT_LEN; + ssl->arrays->preMasterSecret = (byte*)XMALLOC(ENCRYPT_LEN, ssl->heap, + DYNAMIC_TYPE_SECRET); + if (ssl->arrays->preMasterSecret == NULL) { + ret = MEMORY_E; + } + } + + if (ret == 0) { + XMEMCPY(ssl->arrays->preMasterSecret, preMasterSecret, preMasterSz); + XMEMSET(ssl->arrays->preMasterSecret + preMasterSz, 0, + ENCRYPT_LEN - preMasterSz); + ssl->arrays->preMasterSz = preMasterSz; + XMEMCPY(ssl->arrays->clientRandom, clientRandom, RAN_LEN); + XMEMCPY(ssl->arrays->serverRandom, serverRandom, RAN_LEN); + ssl->options.cipherSuite0 = suite[0]; + ssl->options.cipherSuite = suite[1]; + + ret = SetCipherSpecs(ssl); + } + + if (ret == 0) + ret = MakeTlsMasterSecret(ssl); + + if (ret == 0) { + ssl->keys.encryptionOn = 1; + ret = SetKeysSide(ssl, ENCRYPT_AND_DECRYPT_SIDE); + } + + if (ret == 0) { + if (ssl->options.dtls) { + #ifdef WOLFSSL_DTLS + WOLFSSL_DTLS_PEERSEQ* peerSeq; + int i; + + ssl->keys.dtls_epoch = epoch; + for (i = 0, peerSeq = ssl->keys.peerSeq; + i < WOLFSSL_DTLS_PEERSEQ_SZ; + i++, peerSeq++) { + + peerSeq->nextEpoch = epoch; + peerSeq->prevSeq_lo = peerSeq->nextSeq_lo; + peerSeq->prevSeq_hi = peerSeq->nextSeq_hi; + peerSeq->nextSeq_lo = 0; + peerSeq->nextSeq_hi = 0; + XMEMCPY(peerSeq->prevWindow, peerSeq->window, DTLS_SEQ_SZ); + XMEMSET(peerSeq->window, 0, DTLS_SEQ_SZ); + peerSeq->highwaterMark = UpdateHighwaterMark(0, + ssl->ctx->mcastFirstSeq, + ssl->ctx->mcastSecondSeq, + ssl->ctx->mcastMaxSeq); + } + #else + (void)epoch; + #endif + } + FreeHandshakeResources(ssl); + ret = WOLFSSL_SUCCESS; + } + else { + if (ssl) + ssl->error = ret; + ret = WOLFSSL_FATAL_ERROR; + } + WOLFSSL_LEAVE("wolfSSL_set_secret", ret); + return ret; +} + + +#ifdef WOLFSSL_DTLS + +/* Add or remove a peer from the multicast peer list. + * + * @param [in] ssl SSL/TLS object. + * @param [in] peerId Peer id to add or remove. + * @param [in] sub 0 to add the peer, non-zero to remove it. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL or peerId is out of range. + * @return WOLFSSL_FATAL_ERROR when the peer list is full. + */ +int wolfSSL_mcast_peer_add(WOLFSSL* ssl, word16 peerId, int sub) +{ + WOLFSSL_DTLS_PEERSEQ* p = NULL; + int ret = WOLFSSL_SUCCESS; + int i; + + WOLFSSL_ENTER("wolfSSL_mcast_peer_add"); + if (ssl == NULL || peerId > WOLFSSL_MAX_8BIT) + return BAD_FUNC_ARG; + + if (!sub) { + /* Make sure it isn't already present, while keeping the first + * open spot. */ + for (i = 0; i < WOLFSSL_DTLS_PEERSEQ_SZ; i++) { + if (ssl->keys.peerSeq[i].peerId == INVALID_PEER_ID) + p = &ssl->keys.peerSeq[i]; + if (ssl->keys.peerSeq[i].peerId == peerId) { + WOLFSSL_MSG("Peer ID already in multicast peer list."); + p = NULL; + } + } + + if (p != NULL) { + XMEMSET(p, 0, sizeof(WOLFSSL_DTLS_PEERSEQ)); + p->peerId = peerId; + p->highwaterMark = UpdateHighwaterMark(0, + ssl->ctx->mcastFirstSeq, + ssl->ctx->mcastSecondSeq, + ssl->ctx->mcastMaxSeq); + } + else { + WOLFSSL_MSG("No room in peer list."); + ret = WOLFSSL_FATAL_ERROR; + } + } + else { + for (i = 0; i < WOLFSSL_DTLS_PEERSEQ_SZ; i++) { + if (ssl->keys.peerSeq[i].peerId == peerId) + p = &ssl->keys.peerSeq[i]; + } + + if (p != NULL) { + p->peerId = INVALID_PEER_ID; + } + else { + WOLFSSL_MSG("Peer not found in list."); + } + } + + WOLFSSL_LEAVE("wolfSSL_mcast_peer_add", ret); + return ret; +} + + +/* Determine whether a multicast peer is known and active. + * + * @param [in] ssl SSL/TLS object. + * @param [in] peerId Peer id to look up. + * @return 1 when the peer is in the list with a non-zero sequence number. + * @return 0 when the peer is not known or has not sent data. + * @return BAD_FUNC_ARG when ssl is NULL or peerId is out of range. + */ +int wolfSSL_mcast_peer_known(WOLFSSL* ssl, unsigned short peerId) +{ + int known = 0; + int i; + + WOLFSSL_ENTER("wolfSSL_mcast_peer_known"); + + if (ssl == NULL || peerId > WOLFSSL_MAX_8BIT) { + return BAD_FUNC_ARG; + } + + for (i = 0; i < WOLFSSL_DTLS_PEERSEQ_SZ; i++) { + if (ssl->keys.peerSeq[i].peerId == peerId) { + if (ssl->keys.peerSeq[i].nextSeq_hi || + ssl->keys.peerSeq[i].nextSeq_lo) { + + known = 1; + } + break; + } + } + + WOLFSSL_LEAVE("wolfSSL_mcast_peer_known", known); + return known; +} + + +/* Set the multicast highwater callback and thresholds on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] maxSeq Maximum sequence number threshold. + * @param [in] first First sequence number threshold. + * @param [in] second Second sequence number threshold. + * @param [in] cb Highwater callback. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when an argument is NULL or thresholds are invalid. + */ +int wolfSSL_CTX_mcast_set_highwater_cb(WOLFSSL_CTX* ctx, word32 maxSeq, + word32 first, word32 second, + CallbackMcastHighwater cb) +{ + if (ctx == NULL || (second && first > second) || + first > maxSeq || second > maxSeq || cb == NULL) { + + return BAD_FUNC_ARG; + } + + ctx->mcastHwCb = cb; + ctx->mcastFirstSeq = first; + ctx->mcastSecondSeq = second; + ctx->mcastMaxSeq = maxSeq; + + return WOLFSSL_SUCCESS; +} + + +/* Set the user context passed to the multicast highwater callback. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx User context for the highwater callback. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl or ctx is NULL. + */ +int wolfSSL_mcast_set_highwater_ctx(WOLFSSL* ssl, void* ctx) +{ + if (ssl == NULL || ctx == NULL) + return BAD_FUNC_ARG; + + ssl->mcastHwCbCtx = ctx; + + return WOLFSSL_SUCCESS; +} + +#endif /* WOLFSSL_DTLS */ + +#endif /* WOLFSSL_MULTICAST */ + + +#endif /* WOLFSSL_LEANPSK */ + + +#ifndef NO_TLS +#ifdef WOLFSSL_MULTICAST + +/* Read application data from a multicast DTLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [out] id Peer id the data was received from. May be NULL. + * @param [out] data Buffer to hold the data read. + * @param [in] sz Size of the buffer in bytes. + * @return Number of bytes read on success. + * @return BAD_FUNC_ARG when ssl is NULL or sz is negative. + * @return Negative value on error. + */ +int wolfSSL_mcast_read(WOLFSSL* ssl, word16* id, void* data, int sz) +{ + int ret = 0; + + WOLFSSL_ENTER("wolfSSL_mcast_read"); + + if ((ssl == NULL) || (sz < 0)) + return BAD_FUNC_ARG; + + ret = wolfSSL_read_internal(ssl, data, (size_t)sz, FALSE); + if (ssl->options.dtls && ssl->options.haveMcast && id != NULL) + *id = ssl->keys.curPeerId; + return ret; +} + +#endif /* WOLFSSL_MULTICAST */ +#endif /* !NO_TLS */ + + +#ifdef WOLFSSL_DTLS +/* Get the DTLS MAC secret for the requested side and epoch. + * + * @param [in] ssl SSL/TLS object. + * @param [in] verify 1 for the verify (read) secret, 0 for the write one. + * @param [in] epochOrder Epoch order: PEER_ORDER, PREV_ORDER or CUR_ORDER. + * @return MAC secret on success. + * @return NULL when ssl is NULL, AEAD-only build, or epoch order is unknown. + */ +const byte* wolfSSL_GetDtlsMacSecret(WOLFSSL* ssl, int verify, int epochOrder) +{ +#ifndef WOLFSSL_AEAD_ONLY + Keys* keys = NULL; + + (void)epochOrder; + + if (ssl == NULL) + return NULL; + +#ifdef HAVE_SECURE_RENEGOTIATION + switch (epochOrder) { + case PEER_ORDER: + if (IsDtlsMsgSCRKeys(ssl)) + keys = &ssl->secure_renegotiation->tmp_keys; + else + keys = &ssl->keys; + break; + case PREV_ORDER: + keys = &ssl->keys; + break; + case CUR_ORDER: + if (DtlsUseSCRKeys(ssl)) + keys = &ssl->secure_renegotiation->tmp_keys; + else + keys = &ssl->keys; + break; + default: + WOLFSSL_MSG("Unknown epoch order"); + return NULL; + } +#else + keys = &ssl->keys; +#endif + + if ( (ssl->options.side == WOLFSSL_CLIENT_END && !verify) || + (ssl->options.side == WOLFSSL_SERVER_END && verify) ) + return keys->client_write_MAC_secret; + else + return keys->server_write_MAC_secret; +#else + (void)ssl; + (void)verify; + (void)epochOrder; + + return NULL; +#endif +} +#endif /* WOLFSSL_DTLS */ + + +/* Get whether the DTLS object is using non-blocking I/O. + * + * @param [in] ssl SSL/TLS object. + * @return 1 when non-blocking I/O is enabled. + * @return 0 when disabled or not a DTLS object. + * @return WOLFSSL_FAILURE when ssl is NULL. + */ +int wolfSSL_dtls_get_using_nonblock(WOLFSSL* ssl) +{ + int useNb = 0; + + if (ssl == NULL) + return WOLFSSL_FAILURE; + + WOLFSSL_ENTER("wolfSSL_dtls_get_using_nonblock"); + if (ssl->options.dtls) { +#ifdef WOLFSSL_DTLS + useNb = ssl->options.dtlsUseNonblock; +#endif + } + else { + WOLFSSL_MSG("wolfSSL_dtls_get_using_nonblock() is " + "DEPRECATED for non-DTLS use."); + } + return useNb; +} + + +#ifndef WOLFSSL_LEANPSK + +/* Set whether the DTLS object uses non-blocking I/O. + * + * @param [in] ssl SSL/TLS object. + * @param [in] nonblock 1 to use non-blocking I/O, 0 otherwise. + */ +void wolfSSL_dtls_set_using_nonblock(WOLFSSL* ssl, int nonblock) +{ + (void)nonblock; + + WOLFSSL_ENTER("wolfSSL_dtls_set_using_nonblock"); + + if (ssl == NULL) + return; + + if (ssl->options.dtls) { +#ifdef WOLFSSL_DTLS + ssl->options.dtlsUseNonblock = (nonblock != 0); +#endif + } + else { + WOLFSSL_MSG("wolfSSL_dtls_set_using_nonblock() is " + "DEPRECATED for non-DTLS use."); + } +} + + +#ifdef WOLFSSL_DTLS + +/* Get the current DTLS receive timeout, in seconds. + * + * @param [in] ssl SSL/TLS object. + * @return Current timeout in seconds, or 0 when ssl is NULL. + */ +int wolfSSL_dtls_get_current_timeout(WOLFSSL* ssl) +{ + int timeout = 0; + if (ssl) + timeout = ssl->dtls_timeout; + + WOLFSSL_LEAVE("wolfSSL_dtls_get_current_timeout", timeout); + return timeout; +} + +#ifdef WOLFSSL_DTLS13 + +/* Determine whether a short receive timeout should be used. + * + * Recommended to be at most 1/4 of wolfSSL_dtls_get_current_timeout(). + * + * @param [in] ssl SSL/TLS object. + * @return 1 when a short timeout should be used. + * @return 0 otherwise, or when ssl is NULL. + */ +int wolfSSL_dtls13_use_quick_timeout(WOLFSSL* ssl) +{ + return ssl != NULL && ssl->dtls13FastTimeout; +} + +/* Set whether a DTLS 1.3 connection sends acks immediately on a disruption. + * + * Sending more acks may increase traffic but can speed up the handshake. + * + * @param [in] ssl SSL/TLS object. + * @param [in] value Non-zero to send more acks, 0 otherwise. + */ +void wolfSSL_dtls13_set_send_more_acks(WOLFSSL* ssl, int value) +{ + if (ssl != NULL) + ssl->options.dtls13SendMoreAcks = !!value; +} +#endif /* WOLFSSL_DTLS13 */ + +/* Get the time left until the next DTLS timeout. + * + * @param [in] ssl SSL/TLS object. + * @param [out] timeleft Time left until the next timeout. + * @return 0 always. + */ +int wolfSSL_DTLSv1_get_timeout(WOLFSSL* ssl, WOLFSSL_TIMEVAL* timeleft) +{ + if (ssl && timeleft) { + XMEMSET(timeleft, 0, sizeof(WOLFSSL_TIMEVAL)); + timeleft->tv_sec = ssl->dtls_timeout; + } + return 0; +} + +#ifndef NO_WOLFSSL_STUB +/* Handle a DTLS timeout. + * + * Not implemented - stub for OpenSSL compatibility. + * + * @param [in] ssl SSL/TLS object. + * @return 0 always. + */ +int wolfSSL_DTLSv1_handle_timeout(WOLFSSL* ssl) +{ + WOLFSSL_STUB("SSL_DTLSv1_handle_timeout"); + (void)ssl; + return 0; +} +#endif + +#ifndef NO_WOLFSSL_STUB +/* Set the initial DTLS timeout duration. + * + * Not implemented - stub for OpenSSL compatibility. + * + * @param [in] ssl SSL/TLS object. + * @param [in] duration_ms Initial timeout duration in milliseconds. + */ +void wolfSSL_DTLSv1_set_initial_timeout_duration(WOLFSSL* ssl, + word32 duration_ms) +{ + WOLFSSL_STUB("SSL_DTLSv1_set_initial_timeout_duration"); + (void)ssl; + (void)duration_ms; +} +#endif + +/* Set the initial DTLS receive timeout, in seconds, on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] timeout Initial timeout in seconds. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL, timeout is negative or greater than + * the maximum timeout. + */ +int wolfSSL_dtls_set_timeout_init(WOLFSSL* ssl, int timeout) +{ + if (ssl == NULL || timeout < 0) + return BAD_FUNC_ARG; + + if (timeout > ssl->dtls_timeout_max) { + WOLFSSL_MSG("Can't set dtls timeout init greater than dtls timeout " + "max"); + return BAD_FUNC_ARG; + } + + ssl->dtls_timeout_init = timeout; + ssl->dtls_timeout = timeout; + + return WOLFSSL_SUCCESS; +} + + +/* Set the maximum DTLS receive timeout, in seconds, on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] timeout Maximum timeout in seconds. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL, timeout is negative or less than + * the initial timeout. + */ +int wolfSSL_dtls_set_timeout_max(WOLFSSL* ssl, int timeout) +{ + if (ssl == NULL || timeout < 0) + return BAD_FUNC_ARG; + + if (timeout < ssl->dtls_timeout_init) { + WOLFSSL_MSG("Can't set dtls timeout max less than dtls timeout init"); + return BAD_FUNC_ARG; + } + + ssl->dtls_timeout_max = timeout; + + return WOLFSSL_SUCCESS; +} + + +/* Process a DTLS timeout, retransmitting messages as needed. + * + * @param [in] ssl SSL/TLS object. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FATAL_ERROR when ssl is NULL, not DTLS, or on error. + */ +int wolfSSL_dtls_got_timeout(WOLFSSL* ssl) +{ + int result = WOLFSSL_SUCCESS; + WOLFSSL_ENTER("wolfSSL_dtls_got_timeout"); + + if (ssl == NULL || !ssl->options.dtls) + return WOLFSSL_FATAL_ERROR; + +#ifdef WOLFSSL_DTLS13 + if (IsAtLeastTLSv1_3(ssl->version)) { + result = Dtls13RtxTimeout(ssl); + if (result < 0) { + if (result == WC_NO_ERR_TRACE(WANT_WRITE)) + ssl->dtls13SendingAckOrRtx = 1; + ssl->error = result; + WOLFSSL_ERROR(result); + return WOLFSSL_FATAL_ERROR; + } + + return WOLFSSL_SUCCESS; + } +#endif /* WOLFSSL_DTLS13 */ + + /* Do we have any 1.2 messages stored? */ + if (ssl->dtls_tx_msg_list != NULL || ssl->dtls_tx_msg != NULL) { + if (DtlsMsgPoolTimeout(ssl) < 0){ + ssl->error = SOCKET_ERROR_E; + WOLFSSL_ERROR(ssl->error); + result = WOLFSSL_FATAL_ERROR; + } + else if ((result = DtlsMsgPoolSend(ssl, 0)) < 0) { + ssl->error = result; + WOLFSSL_ERROR(result); + result = WOLFSSL_FATAL_ERROR; + } + else { + /* Reset return value to success */ + result = WOLFSSL_SUCCESS; + } + } + + WOLFSSL_LEAVE("wolfSSL_dtls_got_timeout", result); + return result; +} + + +/* Retransmit all stored DTLS handshake messages. + * + * @param [in] ssl SSL/TLS object. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FATAL_ERROR when ssl is NULL or on error. + */ +int wolfSSL_dtls_retransmit(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_dtls_retransmit"); + + if (ssl == NULL) + return WOLFSSL_FATAL_ERROR; + + if (!ssl->options.handShakeDone) { + int result; +#ifdef WOLFSSL_DTLS13 + if (IsAtLeastTLSv1_3(ssl->version)) + result = Dtls13DoScheduledWork(ssl); + else +#endif + result = DtlsMsgPoolSend(ssl, 0); + if (result < 0) { + ssl->error = result; + WOLFSSL_ERROR(result); + return WOLFSSL_FATAL_ERROR; + } + } + + return WOLFSSL_SUCCESS; +} + +#endif /* DTLS */ +#endif /* LEANPSK */ + + +#if defined(WOLFSSL_DTLS) && !defined(NO_WOLFSSL_SERVER) + +/* Set the DTLS cookie secret used to generate HelloVerifyRequest cookies. + * + * When secret is NULL a new secret is randomly generated. The object's RNG + * must be initialized. This is not an SSL function. + * + * @param [in] ssl SSL/TLS object. + * @param [in] secret Cookie secret data, or NULL to generate one. + * @param [in] secretSz Length of secret in bytes, 0 to use the default. + * @return 0 on success. + * @return BAD_FUNC_ARG when ssl is NULL or secret is set with size 0. + * @return MEMORY_ERROR on allocation failure. + */ +int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, + const byte* secret, word32 secretSz) +{ + int ret = 0; + + WOLFSSL_ENTER("wolfSSL_DTLS_SetCookieSecret"); + + if (ssl == NULL) { + WOLFSSL_MSG("need a SSL object"); + return BAD_FUNC_ARG; + } + + if (secret != NULL && secretSz == 0) { + WOLFSSL_MSG("can't have a new secret without a size"); + return BAD_FUNC_ARG; + } + + /* If secretSz is 0, use the default size. */ + if (secretSz == 0) + secretSz = COOKIE_SECRET_SZ; + + if (secretSz != ssl->buffers.dtlsCookieSecret.length) { + byte* newSecret; + + if (ssl->buffers.dtlsCookieSecret.buffer != NULL) { + ForceZero(ssl->buffers.dtlsCookieSecret.buffer, + ssl->buffers.dtlsCookieSecret.length); + XFREE(ssl->buffers.dtlsCookieSecret.buffer, + ssl->heap, DYNAMIC_TYPE_COOKIE_PWD); + } + + newSecret = (byte*)XMALLOC(secretSz, ssl->heap,DYNAMIC_TYPE_COOKIE_PWD); + if (newSecret == NULL) { + ssl->buffers.dtlsCookieSecret.buffer = NULL; + ssl->buffers.dtlsCookieSecret.length = 0; + WOLFSSL_MSG("couldn't allocate new cookie secret"); + return MEMORY_ERROR; + } + ssl->buffers.dtlsCookieSecret.buffer = newSecret; + ssl->buffers.dtlsCookieSecret.length = secretSz; + #ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("wolfSSL_DTLS_SetCookieSecret secret", + ssl->buffers.dtlsCookieSecret.buffer, + ssl->buffers.dtlsCookieSecret.length); + #endif + } + + /* If the supplied secret is NULL, randomly generate a new secret. */ + if (secret == NULL) { + ret = wc_RNG_GenerateBlock(ssl->rng, + ssl->buffers.dtlsCookieSecret.buffer, secretSz); + } + else + XMEMCPY(ssl->buffers.dtlsCookieSecret.buffer, secret, secretSz); + + WOLFSSL_LEAVE("wolfSSL_DTLS_SetCookieSecret", 0); + return ret; +} + +#endif /* WOLFSSL_DTLS && !NO_WOLFSSL_SERVER */ + +#endif /* !WOLFCRYPT_ONLY */ + +#endif /* !WOLFSSL_SSL_API_DTLS_INCLUDED */ diff --git a/src/ssl_api_ext.c b/src/ssl_api_ext.c new file mode 100644 index 0000000000..f212c67d96 --- /dev/null +++ b/src/ssl_api_ext.c @@ -0,0 +1,2725 @@ +/* ssl_api_ext.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_EXT_INCLUDED) + #ifndef WOLFSSL_IGNORE_FILE_WARN + #warning ssl_api_ext.c does not need to be compiled separately from ssl.c + #endif +#else + +#ifndef WOLFCRYPT_ONLY +#ifndef NO_TLS + +#ifdef HAVE_SNI + +/* Set the Server Name Indication extension data on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] type SNI type, e.g. WOLFSSL_SNI_HOST_NAME. + * @param [in] data SNI data. + * @param [in] size Length of SNI data in bytes. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + * @return Negative value on error. + */ +WOLFSSL_ABI +int wolfSSL_UseSNI(WOLFSSL* ssl, byte type, const void* data, word16 size) +{ + int ret; + + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = TLSX_UseSNI(&ssl->extensions, type, data, size, ssl->heap); + } + + return ret; +} + + +/* Set the Server Name Indication extension data on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] type SNI type, e.g. WOLFSSL_SNI_HOST_NAME. + * @param [in] data SNI data. + * @param [in] size Length of SNI data in bytes. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx is NULL. + * @return Negative value on error. + */ +WOLFSSL_ABI +int wolfSSL_CTX_UseSNI(WOLFSSL_CTX* ctx, byte type, const void* data, + word16 size) +{ + int ret; + + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = TLSX_UseSNI(&ctx->extensions, type, data, size, ctx->heap); + } + + return ret; +} + +#ifndef NO_WOLFSSL_SERVER + +/* Set options for the Server Name Indication extension on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] type SNI type. + * @param [in] options Bitmask of SNI options. + */ +void wolfSSL_SNI_SetOptions(WOLFSSL* ssl, byte type, byte options) +{ + if ((ssl != NULL) && (ssl->extensions != NULL)) { + TLSX_SNI_SetOptions(ssl->extensions, type, options); + } +} + + +/* Set options for the Server Name Indication extension on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] type SNI type. + * @param [in] options Bitmask of SNI options. + */ +void wolfSSL_CTX_SNI_SetOptions(WOLFSSL_CTX* ctx, byte type, byte options) +{ + if ((ctx != NULL) && (ctx->extensions != NULL)) { + TLSX_SNI_SetOptions(ctx->extensions, type, options); + } +} + + +/* Get the status of the Server Name Indication extension on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] type SNI type. + * @return SNI status for the type. + */ +byte wolfSSL_SNI_Status(WOLFSSL* ssl, byte type) +{ + return TLSX_SNI_Status((ssl != NULL) ? ssl->extensions : NULL, type); +} + + +/* Get the Server Name Indication request data received from the peer. + * + * @param [in] ssl SSL/TLS object. + * @param [in] type SNI type. + * @param [out] data Pointer to the SNI request data. May be NULL. + * @return Length of the SNI request data in bytes, or 0 when none. + */ +word16 wolfSSL_SNI_GetRequest(WOLFSSL* ssl, byte type, void** data) +{ + word16 ret = 0; + + /* Default the output to no request data. */ + if (data != NULL) { + *data = NULL; + } + + /* Only query when SNI extensions are present on the object. */ + if ((ssl != NULL) && (ssl->extensions != NULL)) { + ret = TLSX_SNI_GetRequest(ssl->extensions, type, data, 0); + } + + return ret; +} + + +/* Get the Server Name Indication data from a raw ClientHello buffer. + * + * @param [in] clientHello ClientHello message buffer. + * @param [in] helloSz Length of the ClientHello in bytes. + * @param [in] type SNI type. + * @param [out] sni Buffer to hold the SNI data. + * @param [in, out] inOutSz In: size of buffer. Out: length of SNI data. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when an argument is NULL or a size is zero. + */ +int wolfSSL_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz, + byte type, byte* sni, word32* inOutSz) +{ + int ret; + + /* All arguments are required and the sizes must be non-zero. */ + if ((clientHello == NULL) || (helloSz == 0) || (sni == NULL) || + (inOutSz == NULL) || (*inOutSz == 0)) { + ret = BAD_FUNC_ARG; + } + else { + ret = TLSX_SNI_GetFromBuffer(clientHello, helloSz, type, sni, inOutSz); + } + + return ret; +} + +#endif /* !NO_WOLFSSL_SERVER */ + +#endif /* HAVE_SNI */ + + +#ifdef HAVE_TRUSTED_CA + +/* Set the Trusted CA Indication extension on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] type Trusted CA identifier type. + * @param [in] certId Certificate identifier data. + * @param [in] certIdSz Length of certificate identifier in bytes. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL or arguments are inconsistent with + * the type. + */ +int wolfSSL_UseTrustedCA(WOLFSSL* ssl, byte type, + const byte* certId, word32 certIdSz) +{ + int ret = 0; + + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + /* Pre-agreed type carries no identifier. */ + else if (type == WOLFSSL_TRUSTED_CA_PRE_AGREED) { + if ((certId != NULL) || (certIdSz != 0)) { + ret = BAD_FUNC_ARG; + } + } + /* X.509 name type requires a non-empty identifier. */ + else if (type == WOLFSSL_TRUSTED_CA_X509_NAME) { + if ((certId == NULL) || (certIdSz == 0)) { + ret = BAD_FUNC_ARG; + } + } +#ifndef NO_SHA + /* SHA-1 hash types require a SHA-1 digest sized identifier. */ + else if ((type == WOLFSSL_TRUSTED_CA_KEY_SHA1) || + (type == WOLFSSL_TRUSTED_CA_CERT_SHA1)) { + if ((certId == NULL) || (certIdSz != WC_SHA_DIGEST_SIZE)) { + ret = BAD_FUNC_ARG; + } + } +#endif + /* Any other identifier type is not supported. */ + else { + ret = BAD_FUNC_ARG; + } + + /* Add the extension once the identifier has been validated. */ + if (ret == 0) { + ret = TLSX_UseTrustedCA(&ssl->extensions, type, certId, certIdSz, + ssl->heap); + } + + return ret; +} + +#endif /* HAVE_TRUSTED_CA */ + + +#ifdef HAVE_MAX_FRAGMENT +#ifndef NO_WOLFSSL_CLIENT + +/* Set the Maximum Fragment Length extension on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] mfl Maximum fragment length code, e.g. WOLFSSL_MFL_2_9. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + * @return Negative value on error. + */ +int wolfSSL_UseMaxFragment(WOLFSSL* ssl, byte mfl) +{ + int ret; + + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } +#ifdef WOLFSSL_ALLOW_MAX_FRAGMENT_ADJUST + /* The following is a non-standard way to reconfigure the max packet size + * post-handshake for wolfSSL_write/wolfSSL_read */ + else if (ssl->options.handShakeState == HANDSHAKE_DONE) { + switch (mfl) { + case WOLFSSL_MFL_2_8 : ssl->max_fragment = 256; break; + case WOLFSSL_MFL_2_9 : ssl->max_fragment = 512; break; + case WOLFSSL_MFL_2_10: ssl->max_fragment = 1024; break; + case WOLFSSL_MFL_2_11: ssl->max_fragment = 2048; break; + case WOLFSSL_MFL_2_12: ssl->max_fragment = 4096; break; + case WOLFSSL_MFL_2_13: ssl->max_fragment = 8192; break; + default: ssl->max_fragment = MAX_RECORD_SIZE; break; + } + ret = WOLFSSL_SUCCESS; + } +#endif /* WOLFSSL_MAX_FRAGMENT_ADJUST */ + else { + /* This call sets the max fragment TLS extension, which gets sent to + * server. The server_hello response is what sets the + * `ssl->max_fragment` in TLSX_MFL_Parse */ + ret = TLSX_UseMaxFragment(&ssl->extensions, mfl, ssl->heap); + } + + return ret; +} + + +/* Set the Maximum Fragment Length extension on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] mfl Maximum fragment length code, e.g. WOLFSSL_MFL_2_9. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx is NULL. + * @return Negative value on error. + */ +int wolfSSL_CTX_UseMaxFragment(WOLFSSL_CTX* ctx, byte mfl) +{ + int ret; + + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = TLSX_UseMaxFragment(&ctx->extensions, mfl, ctx->heap); + } + + return ret; +} + +#endif /* NO_WOLFSSL_CLIENT */ +#endif /* HAVE_MAX_FRAGMENT */ + +#ifdef HAVE_TRUNCATED_HMAC +#ifndef NO_WOLFSSL_CLIENT + +/* Set the Truncated HMAC extension on the object. + * + * @param [in] ssl SSL/TLS object. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + * @return Negative value on error. + */ +int wolfSSL_UseTruncatedHMAC(WOLFSSL* ssl) +{ + int ret; + + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = TLSX_UseTruncatedHMAC(&ssl->extensions, ssl->heap); + } + + return ret; +} + + +/* Set the Truncated HMAC extension on the context. + * + * @param [in] ctx SSL/TLS context object. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx is NULL. + * @return Negative value on error. + */ +int wolfSSL_CTX_UseTruncatedHMAC(WOLFSSL_CTX* ctx) +{ + int ret; + + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = TLSX_UseTruncatedHMAC(&ctx->extensions, ctx->heap); + } + + return ret; +} + +#endif /* NO_WOLFSSL_CLIENT */ +#endif /* HAVE_TRUNCATED_HMAC */ + +/* Elliptic Curves */ +#if defined(HAVE_SUPPORTED_CURVES) + +/* Determine whether a named group is a supported curve or FFDHE group. + * + * @param [in] name Named group identifier. + * @return 1 when the named group is valid. + * @return 0 otherwise. + */ +static int isValidCurveGroup(word16 name) +{ + int ret; + + switch (name) { + case WOLFSSL_ECC_SECP160K1: + case WOLFSSL_ECC_SECP160R1: + case WOLFSSL_ECC_SECP160R2: + case WOLFSSL_ECC_SECP192K1: + case WOLFSSL_ECC_SECP192R1: + case WOLFSSL_ECC_SECP224K1: + case WOLFSSL_ECC_SECP224R1: + case WOLFSSL_ECC_SECP256K1: + case WOLFSSL_ECC_SECP256R1: + case WOLFSSL_ECC_SECP384R1: + case WOLFSSL_ECC_SECP521R1: + case WOLFSSL_ECC_BRAINPOOLP256R1: + case WOLFSSL_ECC_BRAINPOOLP384R1: + case WOLFSSL_ECC_BRAINPOOLP512R1: + case WOLFSSL_ECC_SM2P256V1: + case WOLFSSL_ECC_X25519: + case WOLFSSL_ECC_X448: + case WOLFSSL_ECC_BRAINPOOLP256R1TLS13: + case WOLFSSL_ECC_BRAINPOOLP384R1TLS13: + case WOLFSSL_ECC_BRAINPOOLP512R1TLS13: + + case WOLFSSL_FFDHE_2048: + case WOLFSSL_FFDHE_3072: + case WOLFSSL_FFDHE_4096: + case WOLFSSL_FFDHE_6144: + case WOLFSSL_FFDHE_8192: + +#ifdef WOLFSSL_HAVE_MLKEM +#ifndef WOLFSSL_NO_ML_KEM + #ifndef WOLFSSL_TLS_NO_MLKEM_STANDALONE + case WOLFSSL_ML_KEM_512: + case WOLFSSL_ML_KEM_768: + case WOLFSSL_ML_KEM_1024: + #endif /* !WOLFSSL_TLS_NO_MLKEM_STANDALONE */ + #ifdef WOLFSSL_PQC_HYBRIDS + case WOLFSSL_SECP384R1MLKEM1024: + case WOLFSSL_X25519MLKEM768: + case WOLFSSL_SECP256R1MLKEM768: + #endif /* WOLFSSL_PQC_HYBRIDS */ + #ifdef WOLFSSL_EXTRA_PQC_HYBRIDS + case WOLFSSL_SECP256R1MLKEM512: + case WOLFSSL_SECP384R1MLKEM768: + case WOLFSSL_SECP521R1MLKEM1024: + case WOLFSSL_X25519MLKEM512: + case WOLFSSL_X448MLKEM768: + #endif /* WOLFSSL_EXTRA_PQC_HYBRIDS */ +#endif /* !WOLFSSL_NO_ML_KEM */ +#ifdef WOLFSSL_MLKEM_KYBER + case WOLFSSL_KYBER_LEVEL1: + case WOLFSSL_KYBER_LEVEL3: + case WOLFSSL_KYBER_LEVEL5: + case WOLFSSL_P256_KYBER_LEVEL1: + case WOLFSSL_P384_KYBER_LEVEL3: + case WOLFSSL_P521_KYBER_LEVEL5: + case WOLFSSL_X25519_KYBER_LEVEL1: + case WOLFSSL_X448_KYBER_LEVEL3: + case WOLFSSL_X25519_KYBER_LEVEL3: + case WOLFSSL_P256_KYBER_LEVEL3: +#endif /* WOLFSSL_MLKEM_KYBER */ +#endif /* WOLFSSL_HAVE_MLKEM*/ + ret = 1; + break; + + default: + ret = 0; + break; + } + + return ret; +} + +/* Set a named group in the Supported Groups extension on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] name Named group identifier. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL or the group is invalid. + * @return WOLFSSL_FAILURE when TLS is not compiled in. + */ +int wolfSSL_UseSupportedCurve(WOLFSSL* ssl, word16 name) +{ + int ret; + + if ((ssl == NULL) || (!isValidCurveGroup(name))) { + ret = BAD_FUNC_ARG; + } + else { + ssl->options.userCurves = 1; + #if defined(NO_TLS) + ret = WOLFSSL_FAILURE; + #else + ret = TLSX_UseSupportedCurve(&ssl->extensions, name, ssl->heap); + #endif /* NO_TLS */ + } + + return ret; +} + + +/* Set a named group in the Supported Groups extension on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] name Named group identifier. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx is NULL or the group is invalid. + * @return WOLFSSL_FAILURE when TLS is not compiled in. + */ +int wolfSSL_CTX_UseSupportedCurve(WOLFSSL_CTX* ctx, word16 name) +{ + int ret; + + if ((ctx == NULL) || (!isValidCurveGroup(name))) { + ret = BAD_FUNC_ARG; + } + else { + ctx->userCurves = 1; + #if defined(NO_TLS) + ret = WOLFSSL_FAILURE; + #else + ret = TLSX_UseSupportedCurve(&ctx->extensions, name, ctx->heap); + #endif /* NO_TLS */ + } + + return ret; +} + +#if defined(OPENSSL_EXTRA) +/* Validate a list of group identifiers and translate them into named groups. + * + * Group values may be wolfSSL named groups or curve NIDs (when ECC is + * available). + * + * @param [in] groups Array of group identifiers. + * @param [in] count Number of groups in the array. + * @param [out] outGroups Array to hold the named groups. Must have at least + * count entries. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when a group is not recognized. + */ +static int wolfssl_validate_groups(const int* groups, int count, int* outGroups) +{ + int i; + int ret = WOLFSSL_SUCCESS; + + for (i = 0; i < count; i++) { + if (isValidCurveGroup((word16)groups[i])) { + outGroups[i] = groups[i]; + } +#ifdef HAVE_ECC + else { + /* Groups may be populated with curve NIDs. */ + int oid = (int)nid2oid(groups[i], oidCurveType); + int name = (int)GetCurveByOID(oid); + if (name == 0) { + WOLFSSL_MSG("Invalid group name"); + ret = WOLFSSL_FAILURE; + break; + } + outGroups[i] = name; + } +#else + else { + WOLFSSL_MSG("Invalid group name"); + ret = WOLFSSL_FAILURE; + break; + } +#endif + } + + return ret; +} + +/* Set the list of supported groups on the context. + * + * Group values may be wolfSSL named groups or curve NIDs. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] groups Array of group identifiers. + * @param [in] count Number of groups in the array. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when count is invalid or a group is not recognized. + */ +int wolfSSL_CTX_set1_groups(WOLFSSL_CTX* ctx, int* groups, int count) +{ + int _groups[WOLFSSL_MAX_GROUP_COUNT]; + int ret = WOLFSSL_SUCCESS; + + WOLFSSL_ENTER("wolfSSL_CTX_set1_groups"); + if (count == 0) { + WOLFSSL_MSG("Group count is zero"); + ret = WOLFSSL_FAILURE; + } + else if (count > WOLFSSL_MAX_GROUP_COUNT) { + WOLFSSL_MSG("Group count exceeds maximum"); + ret = WOLFSSL_FAILURE; + } + else { + /* Translate the input list into named groups, then apply it. */ + ret = wolfssl_validate_groups(groups, count, _groups); + if (ret == WOLFSSL_SUCCESS) { + ret = wolfSSL_CTX_set_groups(ctx, _groups, count); + /* Normalize any non-success result to WOLFSSL_FAILURE. */ + if (ret != WOLFSSL_SUCCESS) { + ret = WOLFSSL_FAILURE; + } + } + } + + return ret; +} + +/* Set the list of supported groups on the object. + * + * Group values may be wolfSSL named groups or curve NIDs. + * + * @param [in] ssl SSL/TLS object. + * @param [in] groups Array of group identifiers. + * @param [in] count Number of groups in the array. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when count is invalid or a group is not recognized. + */ +int wolfSSL_set1_groups(WOLFSSL* ssl, int* groups, int count) +{ + int _groups[WOLFSSL_MAX_GROUP_COUNT]; + int ret = WOLFSSL_SUCCESS; + + WOLFSSL_ENTER("wolfSSL_CTX_set1_groups"); + if (count == 0) { + WOLFSSL_MSG("Group count is zero"); + ret = WOLFSSL_FAILURE; + } + else if (count > WOLFSSL_MAX_GROUP_COUNT) { + WOLFSSL_MSG("Group count exceeds maximum"); + ret = WOLFSSL_FAILURE; + } + else { + /* Translate the input list into named groups, then apply it. */ + ret = wolfssl_validate_groups(groups, count, _groups); + if (ret == WOLFSSL_SUCCESS) { + ret = wolfSSL_set_groups(ssl, _groups, count); + /* Normalize any non-success result to WOLFSSL_FAILURE. */ + if (ret != WOLFSSL_SUCCESS) { + ret = WOLFSSL_FAILURE; + } + } + } + + return ret; +} +#endif /* OPENSSL_EXTRA */ +#endif /* HAVE_SUPPORTED_CURVES */ + +/* Application-Layer Protocol Negotiation */ +#ifdef HAVE_ALPN + +/* Set the Application-Layer Protocol Negotiation extension on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] protocol_name_list Comma-separated list of protocol names. + * @param [in] protocol_name_listSz Length of the list in bytes. + * @param [in] options Bitmask of ALPN options. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when an argument is NULL, the list is too long or + * options are unsupported. + * @return MEMORY_ERROR on allocation failure. + */ +WOLFSSL_ABI +int wolfSSL_UseALPN(WOLFSSL* ssl, char *protocol_name_list, + word32 protocol_name_listSz, byte options) +{ + char* list = NULL; + char* ptr = NULL; + char** token = NULL; + word16 len; + int idx = 0; + int ret = WOLFSSL_SUCCESS; + + WOLFSSL_ENTER("wolfSSL_UseALPN"); + + if ((ssl == NULL) || (protocol_name_list == NULL)) { + ret = BAD_FUNC_ARG; + } + else if (protocol_name_listSz > (WOLFSSL_MAX_ALPN_NUMBER * + WOLFSSL_MAX_ALPN_PROTO_NAME_LEN + WOLFSSL_MAX_ALPN_NUMBER)) { + WOLFSSL_MSG("Invalid arguments, protocol name list too long"); + ret = BAD_FUNC_ARG; + } + else if ((!(options & WOLFSSL_ALPN_CONTINUE_ON_MISMATCH)) && + (!(options & WOLFSSL_ALPN_FAILED_ON_MISMATCH))) { + WOLFSSL_MSG("Invalid arguments, options not supported"); + ret = BAD_FUNC_ARG; + } + if (ret == WOLFSSL_SUCCESS) { + list = (char *)XMALLOC(protocol_name_listSz + 1, ssl->heap, + DYNAMIC_TYPE_ALPN); + token = (char **)XMALLOC(sizeof(char*) * (WOLFSSL_MAX_ALPN_NUMBER + 1), + ssl->heap, DYNAMIC_TYPE_ALPN); + if ((list == NULL) || (token == NULL)) { + WOLFSSL_MSG("Memory failure"); + ret = MEMORY_ERROR; + } + } + if (ret == WOLFSSL_SUCCESS) { + XMEMSET(token, 0, sizeof(char *) * (WOLFSSL_MAX_ALPN_NUMBER+1)); + + XSTRNCPY(list, protocol_name_list, protocol_name_listSz); + list[protocol_name_listSz] = '\0'; + + /* Read all protocol names from the list. */ + token[idx] = XSTRTOK(list, ",", &ptr); + while ((idx < WOLFSSL_MAX_ALPN_NUMBER) && (token[idx] != NULL)) { + token[++idx] = XSTRTOK(NULL, ",", &ptr); + } + + /* Add the protocol name list to the TLS extension in reverse order. */ + while ((idx--) > 0) { + len = (word16)XSTRLEN(token[idx]); + + ret = TLSX_UseALPN(&ssl->extensions, token[idx], len, options, + ssl->heap); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("TLSX_UseALPN failure"); + break; + } + } + } + + XFREE(token, ssl->heap, DYNAMIC_TYPE_ALPN); + XFREE(list, ssl->heap, DYNAMIC_TYPE_ALPN); + + return ret; +} + +/* Get the ALPN protocol negotiated for the object. + * + * @param [in] ssl SSL/TLS object. + * @param [out] protocol_name Negotiated protocol name. + * @param [out] size Length of the protocol name in bytes. + * @return WOLFSSL_SUCCESS on success. + * @return Negative value on error. + */ +int wolfSSL_ALPN_GetProtocol(WOLFSSL* ssl, char **protocol_name, word16 *size) +{ + return TLSX_ALPN_GetRequest((ssl != NULL) ? ssl->extensions : NULL, + (void **)protocol_name, size); +} + +/* Get the ALPN protocol list offered by the peer as a comma-separated string. + * + * The returned list must be freed with wolfSSL_ALPN_FreePeerProtocol(). + * + * @param [in] ssl SSL/TLS object. + * @param [out] list Newly allocated comma-separated protocol list. + * @param [out] listSz Length of the list string. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when an argument is NULL. + * @return BUFFER_ERROR when the peer offered no protocols. + * @return MEMORY_ERROR on allocation failure. + */ +int wolfSSL_ALPN_GetPeerProtocol(WOLFSSL* ssl, char **list, word16 *listSz) +{ + int i, len; + char *p; + byte *s; + int ret = WOLFSSL_SUCCESS; + + if ((ssl == NULL) || (list == NULL) || (listSz == NULL)) { + ret = BAD_FUNC_ARG; + } + else if ((ssl->alpn_peer_requested == NULL) || + (ssl->alpn_peer_requested_length == 0)) { + ret = BUFFER_ERROR; + } + if (ret == WOLFSSL_SUCCESS) { + /* ssl->alpn_peer_requested are the original bytes sent in a + * ClientHello, formatted as (len-byte chars+)+. To turn n protocols + * into a comma-separated C string, one needs (n-1) commas and a final + * 0 byte which has the same length as the original. + * The returned length is the strlen() of the C string, so -1 of + * that. */ + *listSz = ssl->alpn_peer_requested_length-1; + *list = p = (char *)XMALLOC(ssl->alpn_peer_requested_length, ssl->heap, + DYNAMIC_TYPE_TLSX); + if (p == NULL) { + ret = MEMORY_ERROR; + } + } + if (ret == WOLFSSL_SUCCESS) { + s = ssl->alpn_peer_requested; + for (i = 0; i < ssl->alpn_peer_requested_length; p += len, i += len) { + if (i != 0) { + *p++ = ','; + } + len = s[i++]; + /* Guard against bad length bytes. */ + if ((i + len) > ssl->alpn_peer_requested_length) { + XFREE(*list, ssl->heap, DYNAMIC_TYPE_TLSX); + *list = NULL; + ret = WOLFSSL_FAILURE; + break; + } + XMEMCPY(p, s + i, (size_t)len); + } + if (ret == WOLFSSL_SUCCESS) { + *p = 0; + } + } + + return ret; +} + + +/* Free a peer protocol list returned by wolfSSL_ALPN_GetPeerProtocol(). + * + * @param [in] ssl SSL/TLS object. + * @param [in, out] list Protocol list to free; set to NULL on return. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + */ +int wolfSSL_ALPN_FreePeerProtocol(WOLFSSL* ssl, char **list) +{ + int ret; + + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else { + XFREE(*list, ssl->heap, DYNAMIC_TYPE_TLSX); + *list = NULL; + ret = WOLFSSL_SUCCESS; + } + + return ret; +} + +#endif /* HAVE_ALPN */ + +/* Secure Renegotiation */ +#ifdef HAVE_SERVER_RENEGOTIATION_INFO + +/* Enable the Secure Renegotiation extension on the object. + * + * Use of secure renegotiation is discouraged. + * + * @param [in] ssl SSL/TLS object. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + * @return Negative value on error. + */ +int wolfSSL_UseSecureRenegotiation(WOLFSSL* ssl) +{ + int ret = WC_NO_ERR_TRACE(BAD_FUNC_ARG); +#if defined(NO_TLS) + (void)ssl; +#else + if (ssl != NULL) { + ret = TLSX_UseSecureRenegotiation(&ssl->extensions, ssl->heap); + } + else { + ret = BAD_FUNC_ARG; + } + + if (ret == WOLFSSL_SUCCESS) { + TLSX* extension = TLSX_Find(ssl->extensions, TLSX_RENEGOTIATION_INFO); + if (extension != NULL) { + ssl->secure_renegotiation = (SecureRenegotiation*)extension->data; + } + } +#endif /* !NO_TLS */ + return ret; +} + +/* Enable the Secure Renegotiation extension on the context. + * + * Use of secure renegotiation is discouraged. + * + * @param [in] ctx SSL/TLS context object. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx is NULL. + */ +int wolfSSL_CTX_UseSecureRenegotiation(WOLFSSL_CTX* ctx) +{ + int ret; + + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ctx->useSecureReneg = 1; + ret = WOLFSSL_SUCCESS; + } + + return ret; +} + +#ifdef HAVE_SECURE_RENEGOTIATION +/* Perform a secure renegotiation handshake on the object. + * + * User forced; use of secure renegotiation is discouraged. + * + * @param [in] ssl SSL/TLS object. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + * @return SECURE_RENEGOTIATION_E when renegotiation is not allowed. + * @return WOLFSSL_FATAL_ERROR on error. + */ +static int _Rehandshake(WOLFSSL* ssl) +{ + int ret; + + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + goto end; + } + + if (IsAtLeastTLSv1_3(ssl->version)) { + WOLFSSL_MSG("Secure Renegotiation not supported in TLS 1.3"); + ret = SECURE_RENEGOTIATION_E; + goto end; + } + + if (ssl->secure_renegotiation == NULL) { + WOLFSSL_MSG("Secure Renegotiation not forced on by user"); + ret = SECURE_RENEGOTIATION_E; + goto end; + } + + if (ssl->secure_renegotiation->enabled == 0) { + WOLFSSL_MSG("Secure Renegotiation not enabled at extension level"); + ret = SECURE_RENEGOTIATION_E; + goto end; + } + +#ifdef WOLFSSL_DTLS + if (ssl->options.dtls && (ssl->keys.dtls_epoch == 0xFFFF)) { + WOLFSSL_MSG("Secure Renegotiation not allowed. Epoch would wrap"); + ret = SECURE_RENEGOTIATION_E; + goto end; + } +#endif + + /* If the client started the renegotiation, the server will already + * have processed the client's hello. */ + if ((ssl->options.side != WOLFSSL_SERVER_END) || + (ssl->options.acceptState != ACCEPT_FIRST_REPLY_DONE)) { + + if (ssl->options.handShakeState != HANDSHAKE_DONE) { + if (!ssl->options.handShakeDone) { + WOLFSSL_MSG("Can't renegotiate until initial " + "handshake complete"); + ret = SECURE_RENEGOTIATION_E; + goto end; + } + else { + WOLFSSL_MSG("Renegotiation already started. " + "Moving it forward."); + ret = wolfSSL_negotiate(ssl); + if (ret == WOLFSSL_SUCCESS) { + ssl->secure_rene_count++; + } + goto end; + } + } + + /* Reset handshake states. */ + ssl->options.sendVerify = 0; + ssl->options.serverState = NULL_STATE; + ssl->options.clientState = NULL_STATE; + ssl->options.connectState = CONNECT_BEGIN; + ssl->options.acceptState = ACCEPT_BEGIN_RENEG; + ssl->options.handShakeState = NULL_STATE; + ssl->options.processReply = 0; /* TODO, move states in internal.h */ + + XMEMSET(&ssl->msgsReceived, 0, sizeof(ssl->msgsReceived)); + + ssl->secure_renegotiation->cache_status = SCR_CACHE_NEEDED; + +#if !defined(NO_WOLFSSL_SERVER) && !defined(WOLFSSL_NO_TLS12) + if (ssl->options.side == WOLFSSL_SERVER_END) { + ret = SendHelloRequest(ssl); + if (ret != 0) { + ssl->error = ret; + ret = WOLFSSL_FATAL_ERROR; + goto end; + } + } +#endif /* !NO_WOLFSSL_SERVER && !WOLFSSL_NO_TLS12 */ + + ret = InitHandshakeHashes(ssl); + if (ret != 0) { + ssl->error = ret; + ret = WOLFSSL_FATAL_ERROR; + goto end; + } + } + ret = wolfSSL_negotiate(ssl); + if (ret == WOLFSSL_SUCCESS) { + ssl->secure_rene_count++; + } + +end: + return ret; +} + + +/* Perform a secure renegotiation handshake on the object. + * + * User forced; use of secure renegotiation is discouraged. + * + * @param [in] ssl SSL/TLS object. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ssl is NULL. + * @return Negative value on error. + */ +int wolfSSL_Rehandshake(WOLFSSL* ssl) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_Rehandshake"); + + if (ssl == NULL) { + ret = WOLFSSL_FAILURE; + } + else { +#ifdef HAVE_SESSION_TICKET + ret = WOLFSSL_SUCCESS; +#endif + + if (ssl->options.side == WOLFSSL_SERVER_END) { + /* Reset option to send certificate verify. */ + ssl->options.sendVerify = 0; + /* Reset resuming flag to do full secure handshake. */ + ssl->options.resuming = 0; + } + else { + /* Reset resuming flag to do full secure handshake. */ + ssl->options.resuming = 0; + #if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_CLIENT) + /* Clearing the ticket. */ + ret = wolfSSL_UseSessionTicket(ssl); + #endif + } + /* CLIENT/SERVER: Reset peer authentication for full secure + * handshake. */ + ssl->options.peerAuthGood = 0; + +#ifdef HAVE_SESSION_TICKET + if (ret == WOLFSSL_SUCCESS) +#endif + { + ret = _Rehandshake(ssl); + } + } + + return ret; +} + + +#ifndef NO_WOLFSSL_CLIENT + +/* Perform a secure resumption handshake on the object. + * + * Client side only. User forced; use of secure renegotiation is discouraged. + * + * @param [in] ssl SSL/TLS object. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + * @return WOLFSSL_FATAL_ERROR when called on a server. + */ +int wolfSSL_SecureResume(WOLFSSL* ssl) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_SecureResume"); + + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else if (ssl->options.side == WOLFSSL_SERVER_END) { + ssl->error = SIDE_ERROR; + ret = WOLFSSL_FATAL_ERROR; + } + else { + ret = _Rehandshake(ssl); + } + + return ret; +} + +#endif /* NO_WOLFSSL_CLIENT */ + +#endif /* HAVE_SECURE_RENEGOTIATION */ + +/* Get whether secure renegotiation is enabled for the object. + * + * @param [in] ssl SSL/TLS object. + * @return 1 when secure renegotiation is enabled. + * @return 0 when ssl is NULL or it is not enabled. + */ +long wolfSSL_SSL_get_secure_renegotiation_support(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_SSL_get_secure_renegotiation_support"); + + return (ssl != NULL) && (ssl->secure_renegotiation != NULL) && + ssl->secure_renegotiation->enabled; +} + +#endif /* HAVE_SECURE_RENEGOTIATION_INFO */ + +#if !defined(NO_WOLFSSL_CLIENT) && !defined(WOLFSSL_NO_TLS12) && \ + defined(WOLFSSL_HARDEN_TLS) && !defined(WOLFSSL_HARDEN_TLS_NO_SCR_CHECK) +/* Get whether the secure renegotiation check is enabled for the object. + * + * @param [in] ssl SSL/TLS object. + * @return Non-zero when the check is enabled, 0 otherwise. + * @return BAD_FUNC_ARG when ssl is NULL. + */ +WOLFSSL_API int wolfSSL_get_scr_check_enabled(const WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_get_scr_check_enabled"); + + return (ssl == NULL) ? BAD_FUNC_ARG : ssl->scr_check_enabled; +} + +/* Set whether the secure renegotiation check is enabled for the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] enabled Non-zero to enable the check, 0 to disable it. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + */ +WOLFSSL_API int wolfSSL_set_scr_check_enabled(WOLFSSL* ssl, byte enabled) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_set_scr_check_enabled"); + + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ssl->scr_check_enabled = !!enabled; + ret = WOLFSSL_SUCCESS; + } + + return ret; +} +#endif + +#if defined(HAVE_SESSION_TICKET) +/* Session Ticket */ + +#if !defined(NO_WOLFSSL_SERVER) +/* Disable use of session tickets with TLS 1.2 on the context. + * + * @param [in] ctx SSL/TLS context object. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx is NULL. + */ +int wolfSSL_CTX_NoTicketTLSv12(WOLFSSL_CTX* ctx) +{ + int ret; + + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ctx->noTicketTls12 = 1; + ret = WOLFSSL_SUCCESS; + } + + return ret; +} + +/* Disable use of session tickets with TLS 1.2 on the object. + * + * @param [in] ssl SSL/TLS object. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + */ +int wolfSSL_NoTicketTLSv12(WOLFSSL* ssl) +{ + int ret; + + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ssl->options.noTicketTls12 = 1; + ret = WOLFSSL_SUCCESS; + } + + return ret; +} + +/* Set the session ticket encryption callback on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] cb Session ticket encryption callback. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx is NULL. + */ +int wolfSSL_CTX_set_TicketEncCb(WOLFSSL_CTX* ctx, SessionTicketEncCb cb) +{ + int ret; + + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ctx->ticketEncCb = cb; + ret = WOLFSSL_SUCCESS; + } + + return ret; +} + +/* Set the session ticket lifetime hint, in seconds, on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] hint Lifetime hint in seconds. No more than 604800 (7 days). + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx is NULL or hint is out of range. + */ +int wolfSSL_CTX_set_TicketHint(WOLFSSL_CTX* ctx, int hint) +{ + int ret; + + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + /* RFC8446 Section 4.6.1: Servers MUST NOT use any value greater than + * 604800 seconds (7 days). */ + else if ((hint < 0) || (hint > 604800)) { + ret = BAD_FUNC_ARG; + } + else { + ctx->ticketHint = hint; + ret = WOLFSSL_SUCCESS; + } + + return ret; +} + +/* Set the user context passed to the session ticket encryption callback. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] userCtx User context for the ticket encryption callback. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx is NULL. + */ +int wolfSSL_CTX_set_TicketEncCtx(WOLFSSL_CTX* ctx, void* userCtx) +{ + int ret; + + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ctx->ticketEncCtx = userCtx; + ret = WOLFSSL_SUCCESS; + } + + return ret; +} + +/* Get the user context passed to the session ticket encryption callback. + * + * @param [in] ctx SSL/TLS context object. + * @return User context on success. + * @return NULL when ctx is NULL. + */ +void* wolfSSL_CTX_get_TicketEncCtx(WOLFSSL_CTX* ctx) +{ + void* ret; + + if (ctx == NULL) { + ret = NULL; + } + else { + ret = ctx->ticketEncCtx; + } + + return ret; +} + +#ifdef WOLFSSL_TLS13 +/* Set the maximum number of TLS 1.3 session tickets to send. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] mxTickets Maximum number of tickets to send. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ctx is NULL. + */ +int wolfSSL_CTX_set_num_tickets(WOLFSSL_CTX* ctx, size_t mxTickets) +{ + int ret; + + if (ctx == NULL) { + ret = WOLFSSL_FAILURE; + } + else { + ctx->maxTicketTls13 = (unsigned int)mxTickets; + ret = WOLFSSL_SUCCESS; + } + + return ret; +} + +/* Get the maximum number of TLS 1.3 session tickets to send. + * + * @param [in] ctx SSL/TLS context object. + * @return Maximum number of tickets to send, or 0 when ctx is NULL. + */ +size_t wolfSSL_CTX_get_num_tickets(WOLFSSL_CTX* ctx) +{ + size_t ret; + + if (ctx == NULL) { + ret = 0; + } + else { + ret = (size_t)ctx->maxTicketTls13; + } + + return ret; +} +#endif /* WOLFSSL_TLS13 */ +#endif /* !NO_WOLFSSL_SERVER */ + +#if !defined(NO_WOLFSSL_CLIENT) +/* Enable use of the session ticket extension on the object. + * + * @param [in] ssl SSL/TLS object. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + * @return Negative value on error. + */ +int wolfSSL_UseSessionTicket(WOLFSSL* ssl) +{ + int ret; + + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = TLSX_UseSessionTicket(&ssl->extensions, NULL, ssl->heap); + } + + return ret; +} + +/* Enable use of the session ticket extension on the context. + * + * @param [in] ctx SSL/TLS context object. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx is NULL. + * @return Negative value on error. + */ +int wolfSSL_CTX_UseSessionTicket(WOLFSSL_CTX* ctx) +{ + int ret; + + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = TLSX_UseSessionTicket(&ctx->extensions, NULL, ctx->heap); + } + + return ret; +} + +/* Get the session ticket stored on the object. + * + * When buf is NULL and *bufSz is 0, the length required is returned in bufSz. + * + * @param [in] ssl SSL/TLS object. + * @param [out] buf Buffer to hold the ticket. May be NULL for length. + * @param [in, out] bufSz In: size of buffer. Out: length of ticket. + * @return WOLFSSL_SUCCESS on success. + * @return LENGTH_ONLY_E when buf is NULL and bufSz has been set. + * @return BAD_FUNC_ARG when ssl or bufSz is NULL. + */ +int wolfSSL_get_SessionTicket(WOLFSSL* ssl, byte* buf, word32* bufSz) +{ + int ret; + + if ((ssl == NULL) || (bufSz == NULL)) { + ret = BAD_FUNC_ARG; + } + /* No buffer and zero size is a query for the required length. */ + else if ((*bufSz == 0) && (buf == NULL)) { + *bufSz = ssl->session->ticketLen; + ret = LENGTH_ONLY_E; + } + else if (buf == NULL) { + ret = BAD_FUNC_ARG; + } + else { + /* Copy the ticket when it fits, otherwise report zero length. */ + if (ssl->session->ticketLen <= *bufSz) { + XMEMCPY(buf, ssl->session->ticket, ssl->session->ticketLen); + *bufSz = ssl->session->ticketLen; + } + else { + *bufSz = 0; + } + ret = WOLFSSL_SUCCESS; + } + + return ret; +} + +/* Set the session ticket to use on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] buf Ticket data, may be NULL when bufSz is 0. + * @param [in] bufSz Length of ticket data in bytes. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL or buf is NULL with bufSz > 0. + * @return MEMORY_ERROR on allocation failure. + */ +int wolfSSL_set_SessionTicket(WOLFSSL* ssl, const byte* buf, word32 bufSz) +{ + int ret = WOLFSSL_SUCCESS; + + if ((ssl == NULL) || ((buf == NULL) && (bufSz > 0))) { + ret = BAD_FUNC_ARG; + } + else { + if (bufSz > 0) { + /* Ticket will fit into the static ticket buffer. */ + if (bufSz <= SESSION_TICKET_LEN) { + if (ssl->session->ticketLenAlloc > 0) { + XFREE(ssl->session->ticket, ssl->session->heap, + DYNAMIC_TYPE_SESSION_TICK); + ssl->session->ticketLenAlloc = 0; + ssl->session->ticket = ssl->session->staticTicket; + } + } + else { /* Ticket requires dynamic ticket storage */ + /* Is the dynamic buffer big enough? */ + if (ssl->session->ticketLen < bufSz) { + if (ssl->session->ticketLenAlloc > 0) { + XFREE(ssl->session->ticket, ssl->session->heap, + DYNAMIC_TYPE_SESSION_TICK); + } + ssl->session->ticket = (byte*)XMALLOC(bufSz, + ssl->session->heap, DYNAMIC_TYPE_SESSION_TICK); + if (ssl->session->ticket == NULL) { + ssl->session->ticket = ssl->session->staticTicket; + ssl->session->ticketLenAlloc = 0; + ret = MEMORY_ERROR; + } + else { + ssl->session->ticketLenAlloc = (word16)bufSz; + } + } + } + if (ret == WOLFSSL_SUCCESS) { + XMEMCPY(ssl->session->ticket, buf, bufSz); + } + } + if (ret == WOLFSSL_SUCCESS) { + ssl->session->ticketLen = (word16)bufSz; + } + } + + return ret; +} + + +/* Set the session ticket callback and user context on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] cb Session ticket callback. + * @param [in] ctx User context passed to the callback. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + */ +int wolfSSL_set_SessionTicket_cb(WOLFSSL* ssl, CallbackSessionTicket cb, + void* ctx) +{ + int ret; + + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ssl->session_ticket_cb = cb; + ssl->session_ticket_ctx = ctx; + ret = WOLFSSL_SUCCESS; + } + + return ret; +} +#endif /* !NO_WOLFSSL_CLIENT */ + +#endif /* HAVE_SESSION_TICKET */ + + +#ifdef HAVE_EXTENDED_MASTER +#ifndef NO_WOLFSSL_CLIENT + +/* Disable the Extended Master Secret extension on the context. + * + * @param [in] ctx SSL/TLS context object. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx is NULL. + */ +int wolfSSL_CTX_DisableExtendedMasterSecret(WOLFSSL_CTX* ctx) +{ + int ret; + + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ctx->haveEMS = 0; + ret = WOLFSSL_SUCCESS; + } + + return ret; +} + + +/* Disable the Extended Master Secret extension on the object. + * + * @param [in] ssl SSL/TLS object. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + */ +int wolfSSL_DisableExtendedMasterSecret(WOLFSSL* ssl) +{ + int ret; + + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ssl->options.haveEMS = 0; + ret = WOLFSSL_SUCCESS; + } + + return ret; +} + +#endif +#endif + +#endif /* !NO_TLS */ +/* ---- OpenSSL-compatibility TLS extension APIs (moved from ssl.c) ---- */ + +#ifdef OPENSSL_EXTRA + +#ifdef HAVE_PK_CALLBACKS +/* Set the debug argument passed to the logging callback on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] arg Debug argument. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ssl is NULL. + */ +long wolfSSL_set_tlsext_debug_arg(WOLFSSL* ssl, void *arg) +{ + long ret; + + if (ssl == NULL) { + ret = WOLFSSL_FAILURE; + } + else { + ssl->loggingCtx = arg; + ret = WOLFSSL_SUCCESS; + } + + return ret; +} +#endif /* HAVE_PK_CALLBACKS */ + +#ifndef NO_WOLFSSL_STUB +/* Get the certificate status request extensions on the object. + * + * Not implemented - stub for OpenSSL compatibility. + * + * @param [in] s SSL/TLS object. + * @param [in] arg Ignored. + * @return WOLFSSL_FAILURE always. + */ +long wolfSSL_get_tlsext_status_exts(WOLFSSL *s, void *arg) +{ + (void)s; + (void)arg; + WOLFSSL_STUB("wolfSSL_get_tlsext_status_exts"); + return WOLFSSL_FAILURE; +} +#endif + +/* Set the certificate status request extensions on the object. + * + * Not implemented - stub for OpenSSL compatibility. + * + * @param [in] s SSL/TLS object. + * @param [in] arg Ignored. + * @return WOLFSSL_FAILURE always. + */ +#ifndef NO_WOLFSSL_STUB +long wolfSSL_set_tlsext_status_exts(WOLFSSL *s, void *arg) +{ + (void)s; + (void)arg; + WOLFSSL_STUB("wolfSSL_set_tlsext_status_exts"); + return WOLFSSL_FAILURE; +} +#endif + +/* Get the certificate status request responder ids on the object. + * + * Not implemented - stub for OpenSSL compatibility. + * + * @param [in] s SSL/TLS object. + * @param [in] arg Ignored. + * @return WOLFSSL_FAILURE always. + */ +#ifndef NO_WOLFSSL_STUB +long wolfSSL_get_tlsext_status_ids(WOLFSSL *s, void *arg) +{ + (void)s; + (void)arg; + WOLFSSL_STUB("wolfSSL_get_tlsext_status_ids"); + return WOLFSSL_FAILURE; +} +#endif + +/* Set the certificate status request responder ids on the object. + * + * Not implemented - stub for OpenSSL compatibility. + * + * @param [in] s SSL/TLS object. + * @param [in] arg Ignored. + * @return WOLFSSL_FAILURE always. + */ +#ifndef NO_WOLFSSL_STUB +long wolfSSL_set_tlsext_status_ids(WOLFSSL *s, void *arg) +{ + (void)s; + (void)arg; + WOLFSSL_STUB("wolfSSL_set_tlsext_status_ids"); + return WOLFSSL_FAILURE; +} +#endif + +#ifdef HAVE_MAX_FRAGMENT +#if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS) +/* Set the Maximum Fragment Length extension on the context. + * + * @param [in] c SSL/TLS context object. + * @param [in] mode Maximum fragment length mode, e.g. WOLFSSL_MFL_2_9. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when c is NULL or mode is out of range. + */ +int wolfSSL_CTX_set_tlsext_max_fragment_length(WOLFSSL_CTX *c, + unsigned char mode) +{ + int ret; + + if ((c == NULL) || ((mode < WOLFSSL_MFL_2_9) || + (mode > WOLFSSL_MFL_2_12))) { + ret = BAD_FUNC_ARG; + } + else { + ret = wolfSSL_CTX_UseMaxFragment(c, mode); + } + + return ret; +} +/* Set the Maximum Fragment Length extension on the object. + * + * @param [in] s SSL/TLS object. + * @param [in] mode Maximum fragment length mode, e.g. WOLFSSL_MFL_2_9. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when s is NULL or mode is out of range. + */ +int wolfSSL_set_tlsext_max_fragment_length(WOLFSSL *s, unsigned char mode) +{ + int ret; + + if ((s == NULL) || ((mode < WOLFSSL_MFL_2_9) || + (mode > WOLFSSL_MFL_2_12))) { + ret = BAD_FUNC_ARG; + } + else { + ret = wolfSSL_UseMaxFragment(s, mode); + } + + return ret; +} +#endif /* !NO_WOLFSSL_CLIENT && !NO_TLS */ +#endif /* HAVE_MAX_FRAGMENT */ + +/* Set the signature algorithms list on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] list Colon-separated list of + algorithms. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ctx or list is NULL or on error. + */ +int wolfSSL_CTX_set1_sigalgs_list(WOLFSSL_CTX* ctx, const char* list) +{ + int ret; + + WOLFSSL_MSG("wolfSSL_CTX_set1_sigalg_list"); + + if ((ctx == NULL) || (list == NULL)) { + WOLFSSL_MSG("Bad function arguments"); + ret = WOLFSSL_FAILURE; + } + /* Cipher suites must exist before the sig algs can be stored on them. */ + else if (AllocateCtxSuites(ctx) != 0) { + ret = WOLFSSL_FAILURE; + } + else { + ret = SetSuitesHashSigAlgo(ctx->suites, list); + } + + return ret; +} + +/* Set the signature algorithms list on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] list Colon-separated list of + algorithms. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ssl or list is NULL or on error. + */ +int wolfSSL_set1_sigalgs_list(WOLFSSL* ssl, const char* list) +{ + int ret; + + WOLFSSL_MSG("wolfSSL_set1_sigalg_list"); + + if ((ssl == NULL) || (list == NULL)) { + WOLFSSL_MSG("Bad function arguments"); + ret = WOLFSSL_FAILURE; + } + /* Cipher suites must exist before the sig algs can be stored on them. */ + else if (AllocateSuites(ssl) != 0) { + ret = WOLFSSL_FAILURE; + } + else { + ret = SetSuitesHashSigAlgo(ssl->suites, list); + } + + return ret; +} + +#ifdef HAVE_ECC + +#if defined(WOLFSSL_TLS13) && defined(HAVE_SUPPORTED_CURVES) +/* Set the supported groups list, by name, on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] list Colon-separated list of group names. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ctx or list is NULL or on error. + */ +int wolfSSL_CTX_set1_groups_list(WOLFSSL_CTX *ctx, const char *list) +{ + int ret; + + if ((ctx == NULL) || (list == NULL)) { + ret = WOLFSSL_FAILURE; + } + else { + ret = set_curves_list(NULL, ctx, list, 0); + } + + return ret; +} + +/* Set the supported groups list, by name, on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] list Colon-separated list of group names. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ssl or list is NULL or on error. + */ +int wolfSSL_set1_groups_list(WOLFSSL *ssl, const char *list) +{ + int ret; + + if ((ssl == NULL) || (list == NULL)) { + ret = WOLFSSL_FAILURE; + } + else { + ret = set_curves_list(ssl, NULL, list, 0); + } + + return ret; +} +#endif /* WOLFSSL_TLS13 */ + +#endif /* HAVE_ECC */ + +#endif /* OPENSSL_EXTRA */ + +#if defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) + +#ifdef HAVE_SNI +/* Set the SNI host name extension on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] host_name Host name string. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + * @return Negative value on error. + */ +int wolfSSL_set_tlsext_host_name(WOLFSSL* ssl, const char* host_name) +{ + int ret; + WOLFSSL_ENTER("wolfSSL_set_tlsext_host_name"); + ret = wolfSSL_UseSNI(ssl, WOLFSSL_SNI_HOST_NAME, host_name, + (word16)XSTRLEN(host_name)); + WOLFSSL_LEAVE("wolfSSL_set_tlsext_host_name", ret); + return ret; +} + +#ifndef NO_WOLFSSL_SERVER +/* Get the SNI host name requested for the object. + * + * May be called by a server to get the accepted name or by a client to get + * the requested name. + * + * @param [in] ssl SSL/TLS object. + * @param [in] type SNI type. + * @return Requested server name on success. + * @return NULL when ssl is NULL or no name is set. + */ +const char * wolfSSL_get_servername(WOLFSSL* ssl, byte type) +{ + void * serverName = NULL; + + if (ssl != NULL) { + /* On a client request the name sent; on a server the name received. */ + TLSX_SNI_GetRequest(ssl->extensions, type, &serverName, + !wolfSSL_is_server(ssl)); + } + + return (const char *)serverName; +} +#endif + +#endif /* HAVE_SNI */ + +#ifdef HAVE_SNI +/* Set the SNI receive callback on the context. + * + * Compatibility function; consider using wolfSSL_CTX_set_servername_callback(). + * + * @param [in] ctx SSL/TLS context object. + * @param [in] cb SNI receive callback. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ctx is NULL. + */ +int wolfSSL_CTX_set_tlsext_servername_callback(WOLFSSL_CTX* ctx, + CallbackSniRecv cb) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_set_tlsext_servername_callback"); + + if (ctx == NULL) { + ret = WOLFSSL_FAILURE; + } + else { + ctx->sniRecvCb = cb; + ret = WOLFSSL_SUCCESS; + } + + return ret; +} + +#endif /* HAVE_SNI */ + +#endif /* OPENSSL_ALL || OPENSSL_EXTRA */ + +#ifdef HAVE_SNI + +/* Set the SNI receive callback on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] cb SNI receive callback. + */ +void wolfSSL_CTX_set_servername_callback(WOLFSSL_CTX* ctx, CallbackSniRecv cb) +{ + WOLFSSL_ENTER("wolfSSL_CTX_set_servername_callback"); + + if (ctx != NULL) { + ctx->sniRecvCb = cb; + } +} + + +/* Set the user argument passed to the SNI receive callback on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] arg User argument for the SNI receive callback. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ctx is NULL. + */ +int wolfSSL_CTX_set_servername_arg(WOLFSSL_CTX* ctx, void* arg) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_set_servername_arg"); + + if (ctx == NULL) { + ret = WOLFSSL_FAILURE; + } + else { + ctx->sniRecvCbArg = arg; + ret = WOLFSSL_SUCCESS; + } + + return ret; +} + +#endif /* HAVE_SNI */ + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) \ + || defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) + +#if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_SERVER) +/* Expected return values from implementations of OpenSSL ticket key callback. + */ +#define TICKET_KEY_CB_RET_FAILURE (-1) +#define TICKET_KEY_CB_RET_NOT_FOUND 0 +#define TICKET_KEY_CB_RET_OK 1 +#define TICKET_KEY_CB_RET_RENEW 2 + +/* Encrypt the ticket data in place and compute the HMAC over it. + * + * @param [in] evpCtx Cipher context initialized by the callback. + * @param [in] hmacCtx HMAC context initialized by the callback. + * @param [in, out] encTicket Ticket data, encrypted in place. + * @param [in] encTicketLen Length of the plaintext ticket data in bytes. + * @param [in] encSz Capacity of the ticket buffer in bytes. + * @param [out] mac HMAC of the encrypted data. + * @param [out] outSz Length of the encrypted data in bytes. + * @return 1 on success. + * @return 0 on error. + */ +static int wolfssl_ticket_key_enc(WOLFSSL_EVP_CIPHER_CTX* evpCtx, + WOLFSSL_HMAC_CTX* hmacCtx, unsigned char* encTicket, int encTicketLen, + int encSz, unsigned char* mac, int* outSz) +{ + int ret = 1; + int len = 0; + int totalSz = 0; + unsigned int mdSz = 0; + + /* Encrypt in place. */ + if (!wolfSSL_EVP_CipherUpdate(evpCtx, encTicket, &len, encTicket, + encTicketLen)) { + ret = 0; + } + if (ret == 1) { + totalSz = len; + /* Encrypted data must fit in the output buffer. */ + if (totalSz > encSz) { + ret = 0; + } + } + if ((ret == 1) && + (!wolfSSL_EVP_EncryptFinal(evpCtx, &encTicket[len], &len))) { + ret = 0; + } + if (ret == 1) { + /* Total length of encrypted data. */ + totalSz += len; + if (totalSz > encSz) { + ret = 0; + } + } + /* HMAC the encrypted data into the parameter 'mac'. */ + if ((ret == 1) && (!wolfSSL_HMAC_Update(hmacCtx, encTicket, totalSz))) { + ret = 0; + } + if ((ret == 1) && (!wolfSSL_HMAC_Final(hmacCtx, mac, &mdSz))) { + ret = 0; + } + if (ret == 1) { + *outSz = totalSz; + } + + return ret; +} + +/* Verify the ticket HMAC then decrypt the ticket data in place. + * + * @param [in] evpCtx Cipher context initialized by the callback. + * @param [in] hmacCtx HMAC context initialized by the callback. + * @param [in, out] encTicket Ticket data, decrypted in place. + * @param [in] encTicketLen Length of the encrypted ticket data in bytes. + * @param [in] mac Expected HMAC of the encrypted data. + * @param [out] outSz Length of the decrypted data in bytes. + * @return 1 on success. + * @return 0 on error or when the HMAC does not match. + */ +static int wolfssl_ticket_key_dec(WOLFSSL_EVP_CIPHER_CTX* evpCtx, + WOLFSSL_HMAC_CTX* hmacCtx, unsigned char* encTicket, int encTicketLen, + const unsigned char* mac, int* outSz) +{ + int ret = 1; + int len = 0; + int totalSz = 0; + unsigned int mdSz = 0; + byte digest[WC_MAX_DIGEST_SIZE]; + + /* HMAC the encrypted data and compare it to the passed in data. */ + if (!wolfSSL_HMAC_Update(hmacCtx, encTicket, encTicketLen)) { + ret = 0; + } + if ((ret == 1) && (!wolfSSL_HMAC_Final(hmacCtx, digest, &mdSz))) { + ret = 0; + } + if ((ret == 1) && (ConstantCompare(mac, digest, (int)mdSz) != 0)) { + ret = 0; + } + /* Decrypt the ticket data in place. */ + if ((ret == 1) && + (!wolfSSL_EVP_CipherUpdate(evpCtx, encTicket, &len, encTicket, + encTicketLen))) { + ret = 0; + } + if (ret == 1) { + totalSz = len; + /* Decrypted data must fit in the buffer. */ + if (totalSz > encTicketLen) { + ret = 0; + } + } + if ((ret == 1) && + (!wolfSSL_EVP_DecryptFinal(evpCtx, &encTicket[len], &len))) { + ret = 0; + } + if (ret == 1) { + /* Total length of decrypted data. */ + totalSz += len; + if (totalSz > encTicketLen) { + ret = 0; + } + } + if (ret == 1) { + *outSz = totalSz; + } + + return ret; +} + +/* Encrypt or decrypt a session ticket using the OpenSSL ticket key callback. + * + * Wraps the application's OpenSSL-style callback that initializes the cipher + * and HMAC. + * + * @param [in] ssl SSL/TLS object. + * @param [in] keyName Key name identifying the key to use. + * @param [in] iv IV to use. + * @param [in, out] mac MAC of the encrypted data. + * @param [in] enc 1 to encrypt the ticket, 0 to decrypt. + * @param [in, out] encTicket Ticket data, encrypted/decrypted in place. + * @param [in] encTicketLen Length of the ticket data in bytes. + * @param [out] encLen Output length of the ticket data. + * @param [in] ctx Ignored. Application specific data. + * @return WOLFSSL_TICKET_RET_OK on success. + * @return WOLFSSL_TICKET_RET_CREATE when a new ticket is required. + * @return WOLFSSL_TICKET_RET_FATAL on error. + */ +static int wolfSSL_TicketKeyCb(WOLFSSL* ssl, + unsigned char keyName[WOLFSSL_TICKET_NAME_SZ], + unsigned char iv[WOLFSSL_TICKET_IV_SZ], + unsigned char mac[WOLFSSL_TICKET_MAC_SZ], + int enc, unsigned char* encTicket, + int encTicketLen, int* encLen, void* ctx) +{ + WC_DECLARE_VAR(evpCtx, WOLFSSL_EVP_CIPHER_CTX, 1, 0); + int ret = WOLFSSL_TICKET_RET_OK; + + (void)ctx; + + WOLFSSL_ENTER("wolfSSL_TicketKeyCb"); + + if ((ssl == NULL) || (ssl->ctx == NULL) || + (ssl->ctx->ticketEncWrapCb == NULL)) { + WOLFSSL_MSG("Bad parameter"); + ret = WOLFSSL_TICKET_RET_FATAL; + } + +#ifdef WOLFSSL_SMALL_STACK + if (ret == WOLFSSL_TICKET_RET_OK) { + evpCtx = (WOLFSSL_EVP_CIPHER_CTX *)XMALLOC(sizeof(*evpCtx), ssl->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (evpCtx == NULL) { + WOLFSSL_MSG("out of memory"); + ret = WOLFSSL_TICKET_RET_FATAL; + } + } +#endif + + if (ret == WOLFSSL_TICKET_RET_OK) { + WOLFSSL_HMAC_CTX hmacCtx; + + /* Initialize the cipher and HMAC. */ + wolfSSL_EVP_CIPHER_CTX_init(evpCtx); + + if (wolfSSL_HMAC_CTX_Init(&hmacCtx) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("wolfSSL_HMAC_CTX_Init error"); + ret = WOLFSSL_TICKET_RET_FATAL; + } + + if (ret == WOLFSSL_TICKET_RET_OK) { + int res; + int totalSz = 0; + + res = ssl->ctx->ticketEncWrapCb(ssl, keyName, iv, evpCtx, &hmacCtx, + enc); + if ((res != TICKET_KEY_CB_RET_OK) && + (res != TICKET_KEY_CB_RET_RENEW)) { + WOLFSSL_MSG("Ticket callback error"); + ret = WOLFSSL_TICKET_RET_FATAL; + } + + if (ret == WOLFSSL_TICKET_RET_OK) { + if (wolfSSL_HMAC_size(&hmacCtx) > WOLFSSL_TICKET_MAC_SZ) { + WOLFSSL_MSG("Ticket cipher MAC size error"); + ret = WOLFSSL_TICKET_RET_FATAL; + } + } + + if (ret == WOLFSSL_TICKET_RET_OK) { + if (enc) { + if (!wolfssl_ticket_key_enc(evpCtx, &hmacCtx, encTicket, + encTicketLen, *encLen, mac, &totalSz)) { + ret = WOLFSSL_TICKET_RET_FATAL; + } + } + else { + if (!wolfssl_ticket_key_dec(evpCtx, &hmacCtx, encTicket, + encTicketLen, mac, &totalSz)) { + ret = WOLFSSL_TICKET_RET_FATAL; + } + } + } + + if (ret == WOLFSSL_TICKET_RET_OK) { + *encLen = totalSz; + + if ((res == TICKET_KEY_CB_RET_RENEW) && + (!IsAtLeastTLSv1_3(ssl->version)) && (!enc)) { + ret = WOLFSSL_TICKET_RET_CREATE; + } + else { + ret = WOLFSSL_TICKET_RET_OK; + } + } + + (void)wc_HmacFree(&hmacCtx.hmac); + } + (void)wolfSSL_EVP_CIPHER_CTX_cleanup(evpCtx); + WC_FREE_VAR_EX(evpCtx, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + } + + return ret; +} + +/* Set the OpenSSL-style session ticket key callback on the context. + * + * Installs a wrapper as the ticket encryption callback. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] cb OpenSSL session ticket key callback. + * @return WOLFSSL_SUCCESS on success. + */ +int wolfSSL_CTX_set_tlsext_ticket_key_cb(WOLFSSL_CTX *ctx, ticketCompatCb cb) +{ + + /* Set the ticket encryption callback to be a wrapper around OpenSSL + * callback. + */ + ctx->ticketEncCb = wolfSSL_TicketKeyCb; + ctx->ticketEncWrapCb = cb; + + return WOLFSSL_SUCCESS; +} + +#endif /* HAVE_SESSION_TICKET */ + +#endif /* OPENSSL_ALL || WOLFSSL_NGINX || WOLFSSL_HAPROXY || + OPENSSL_EXTRA || HAVE_LIGHTY */ + +#if defined(HAVE_SESSION_TICKET) && !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \ + !defined(NO_WOLFSSL_SERVER) +/* Serialize the session ticket encryption keys. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] keys Buffer to hold session ticket keys. + * @param [in] keylen Length of buffer. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ctx is NULL, keys is NULL or keylen is not the + * correct length. + */ +long wolfSSL_CTX_get_tlsext_ticket_keys(WOLFSSL_CTX *ctx, + unsigned char *keys, int keylen) +{ + long ret = WOLFSSL_SUCCESS; + + if ((ctx == NULL) || (keys == NULL)) { + ret = WOLFSSL_FAILURE; + } + else if (keylen != WOLFSSL_TICKET_KEYS_SZ) { + ret = WOLFSSL_FAILURE; + } + else { + /* Serialize as: name | key[0] | key[1] | expiry[0] | expiry[1]. */ + XMEMCPY(keys, ctx->ticketKeyCtx.name, WOLFSSL_TICKET_NAME_SZ); + keys += WOLFSSL_TICKET_NAME_SZ; + XMEMCPY(keys, ctx->ticketKeyCtx.key[0], WOLFSSL_TICKET_KEY_SZ); + keys += WOLFSSL_TICKET_KEY_SZ; + XMEMCPY(keys, ctx->ticketKeyCtx.key[1], WOLFSSL_TICKET_KEY_SZ); + keys += WOLFSSL_TICKET_KEY_SZ; + /* Expiry times are stored big-endian. */ + c32toa(ctx->ticketKeyCtx.expirary[0], keys); + keys += OPAQUE32_LEN; + c32toa(ctx->ticketKeyCtx.expirary[1], keys); + } + + return ret; +} + +/* Deserialize the session ticket encryption keys. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] keys Session ticket keys. + * @param [in] keylen Length of data. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ctx is NULL, keys is NULL or keylen is not the + * correct length. + */ +long wolfSSL_CTX_set_tlsext_ticket_keys(WOLFSSL_CTX *ctx, + const void *keys_vp, int keylen) +{ + const byte* keys = (const byte*)keys_vp; + long ret = WOLFSSL_SUCCESS; + + if ((ctx == NULL) || (keys == NULL)) { + ret = WOLFSSL_FAILURE; + } + else if (keylen != WOLFSSL_TICKET_KEYS_SZ) { + ret = WOLFSSL_FAILURE; + } + else { + /* Parse as: name | key[0] | key[1] | expiry[0] | expiry[1]. */ + XMEMCPY(ctx->ticketKeyCtx.name, keys, WOLFSSL_TICKET_NAME_SZ); + keys += WOLFSSL_TICKET_NAME_SZ; + XMEMCPY(ctx->ticketKeyCtx.key[0], keys, WOLFSSL_TICKET_KEY_SZ); + keys += WOLFSSL_TICKET_KEY_SZ; + XMEMCPY(ctx->ticketKeyCtx.key[1], keys, WOLFSSL_TICKET_KEY_SZ); + keys += WOLFSSL_TICKET_KEY_SZ; + /* Expiry times are stored big-endian. */ + ato32(keys, &ctx->ticketKeyCtx.expirary[0]); + keys += OPAQUE32_LEN; + ato32(keys, &ctx->ticketKeyCtx.expirary[1]); + } + + return ret; +} +#endif + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || \ + defined(WOLFSSL_HAPROXY) || defined(HAVE_LIGHTY) || \ + defined(WOLFSSL_QUIC) +#ifdef HAVE_ALPN +/* Get the ALPN protocol selected for the object. + * + * @param [in] ssl SSL/TLS object. + * @param [out] data Selected protocol data. + * @param [out] len Length of the protocol data in bytes. + */ +void wolfSSL_get0_alpn_selected(const WOLFSSL *ssl, const unsigned char **data, + unsigned int *len) +{ + word16 nameLen = 0; + + if ((ssl != NULL) && (data != NULL) && (len != NULL)) { + TLSX_ALPN_GetRequest(ssl->extensions, (void **)data, &nameLen); + *len = nameLen; + } +} + +/* Determine whether a protocol appears in the client's protocol list. + * + * The client's list is in wire format: each entry is a length byte followed + * by that many protocol-name bytes. + * + * @param [in] proto Protocol name to look for. + * @param [in] protoLen Length of the protocol name in bytes. + * @param [in] clientNames Client's protocol list. + * @param [in] clientLen Length of the client's list in bytes. + * @return 1 when the protocol is in the list. + * @return 0 when the protocol is not in the list. + */ +static int wolfssl_protocol_in_list(const unsigned char* proto, byte protoLen, + const unsigned char* clientNames, unsigned int clientLen) +{ + unsigned int j; + byte lenClient; + int found = 0; + + /* Compare against each of the client's length-prefixed names. */ + for (j = 0; j < clientLen; j += lenClient) { + lenClient = clientNames[j++]; + if ((lenClient == 0) || (j + lenClient > clientLen)) { + break; + } + + if ((protoLen == lenClient) && + (XMEMCMP(proto, clientNames + j, protoLen) == 0)) { + found = 1; + break; + } + } + + return found; +} + +/* Select the next protocol from the peer's list that matches the client's. + * + * On no overlap, the first client protocol is selected. + * + * @param [out] out Selected protocol data. + * @param [out] outLen Length of the selected protocol in bytes. + * @param [in] in Peer's protocol list. + * @param [in] inLen Length of the peer's list in bytes. + * @param [in] clientNames Client's protocol list. + * @param [in] clientLen Length of the client's list in bytes. + * @return WOLFSSL_NPN_NEGOTIATED when a match was found. + * @return WOLFSSL_NPN_NO_OVERLAP when no match was found. + * @return WOLFSSL_NPN_UNSUPPORTED when an argument is NULL. + */ +int wolfSSL_select_next_proto(unsigned char **out, unsigned char *outLen, + const unsigned char *in, unsigned int inLen, + const unsigned char *clientNames, unsigned int clientLen) +{ + unsigned int i; + byte lenIn; + int ret = WOLFSSL_NPN_NO_OVERLAP; + + if ((out == NULL) || (outLen == NULL) || (in == NULL) || + (clientNames == NULL)) { + ret = WOLFSSL_NPN_UNSUPPORTED; + } + else { + /* Walk the peer's list; each entry is a length byte then that many + * protocol-name bytes. */ + for (i = 0; i < inLen; i += lenIn) { + lenIn = in[i++]; + /* Stop on an empty entry or one that runs past the buffer. */ + if ((lenIn == 0) || (i + lenIn > inLen)) { + break; + } + /* Select this peer protocol if the client also offered it. */ + if (wolfssl_protocol_in_list(in + i, lenIn, clientNames, + clientLen)) { + *out = (unsigned char *)(in + i); + *outLen = lenIn; + ret = WOLFSSL_NPN_NEGOTIATED; + break; + } + } + + if (ret != WOLFSSL_NPN_NEGOTIATED) { + /* No overlap: fall back to the client's first protocol. */ + if ((clientLen > 0) && + ((unsigned int)clientNames[0] + 1 <= clientLen)) { + *out = (unsigned char *)clientNames + 1; + *outLen = clientNames[0]; + } + else { + *out = (unsigned char *)clientNames; + *outLen = 0; + } + ret = WOLFSSL_NPN_NO_OVERLAP; + } + } + + return ret; +} + +/* Set the ALPN selection callback on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] cb ALPN selection callback. + * @param [in] arg User argument passed to the callback. + */ +void wolfSSL_set_alpn_select_cb(WOLFSSL *ssl, + int (*cb)(WOLFSSL *ssl, const unsigned char **out, unsigned char *outlen, + const unsigned char *in, unsigned int inlen, void *arg), + void *arg) +{ + if (ssl != NULL) { + ssl->alpnSelect = cb; + ssl->alpnSelectArg = arg; + } +} + +/* Set the ALPN selection callback on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] cb ALPN selection callback. + * @param [in] arg User argument passed to the callback. + */ +void wolfSSL_CTX_set_alpn_select_cb(WOLFSSL_CTX *ctx, + int (*cb)(WOLFSSL *ssl, const unsigned char **out, unsigned char *outlen, + const unsigned char *in, unsigned int inlen, void *arg), + void *arg) +{ + if (ctx != NULL) { + ctx->alpnSelect = cb; + ctx->alpnSelectArg = arg; + } +} + +/* Set the NPN advertised-protocols callback on the context. + * + * Not implemented - stub for OpenSSL compatibility. + * + * @param [in] s SSL/TLS context object. + * @param [in] cb NPN advertised-protocols callback. + * @param [in] arg User argument passed to the callback. + */ +void wolfSSL_CTX_set_next_protos_advertised_cb(WOLFSSL_CTX *s, + int (*cb)(WOLFSSL *ssl, const unsigned char **out, unsigned int *outlen, + void *arg), void *arg) +{ + (void)s; + (void)cb; + (void)arg; + WOLFSSL_STUB("wolfSSL_CTX_set_next_protos_advertised_cb"); +} + +/* Set the NPN protocol-selection callback on the context. + * + * Not implemented - stub for OpenSSL compatibility. + * + * @param [in] s SSL/TLS context object. + * @param [in] cb NPN protocol-selection callback. + * @param [in] arg User argument passed to the callback. + */ +void wolfSSL_CTX_set_next_proto_select_cb(WOLFSSL_CTX *s, + int (*cb)(WOLFSSL *ssl, unsigned char **out, unsigned char *outlen, + const unsigned char *in, unsigned int inlen, void *arg), + void *arg) +{ + (void)s; + (void)cb; + (void)arg; + WOLFSSL_STUB("wolfSSL_CTX_set_next_proto_select_cb"); +} + +/* Get the NPN protocol negotiated for the object. + * + * Not implemented - stub for OpenSSL compatibility. + * + * @param [in] s SSL/TLS object. + * @param [out] data Negotiated protocol data. + * @param [out] len Length of the protocol data in bytes. + */ +void wolfSSL_get0_next_proto_negotiated(const WOLFSSL *s, + const unsigned char **data, unsigned *len) +{ + (void)s; + (void)data; + (void)len; + WOLFSSL_STUB("wolfSSL_get0_next_proto_negotiated"); +} +#endif /* HAVE_ALPN */ + +#endif /* WOLFSSL_NGINX / WOLFSSL_HAPROXY */ + +#if defined(OPENSSL_EXTRA) || defined(HAVE_CURL) + +/* Determine whether an elliptic curve is disabled for the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] curve_id Curve identifier. + * @return 1 when the curve is disabled or out of range. + * @return 0 when the curve is enabled or is an FFDHE group. + */ +int wolfSSL_curve_is_disabled(const WOLFSSL* ssl, word16 curve_id) +{ + int ret = 0; + + WOLFSSL_ENTER("wolfSSL_curve_is_disabled"); + WOLFSSL_MSG_EX("wolfSSL_curve_is_disabled checking for %d", curve_id); + + /* (curve_id >= WOLFSSL_FFDHE_START) - DH parameters are never disabled. */ + if (curve_id < WOLFSSL_FFDHE_START) { + if (curve_id > WOLFSSL_ECC_MAX_AVAIL) { + WOLFSSL_MSG("Curve id out of supported range"); + /* Disabled if not in valid range. */ + ret = 1; + } + else if (curve_id >= 32) { + /* 0 is for invalid and 1-14 aren't used otherwise. */ + ret = (ssl->disabledCurves & (1U << (curve_id - 32))) != 0; + } + else { + ret = (ssl->disabledCurves & (1U << curve_id)) != 0; + } + } + + WOLFSSL_LEAVE("wolfSSL_curve_is_disabled", ret); + return ret; +} + +#if (defined(HAVE_ECC) || \ + defined(HAVE_CURVE25519) || defined(HAVE_CURVE448)) + +/* Set the supported curves list, by name, on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] names Colon-separated list of curve names. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ctx or names is NULL or on error. + */ +int wolfSSL_CTX_set1_curves_list(WOLFSSL_CTX* ctx, const char* names) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_set1_curves_list"); + + if ((ctx == NULL) || (names == NULL)) { + WOLFSSL_MSG("ctx or names was NULL"); + ret = WOLFSSL_FAILURE; + } + else { + ret = set_curves_list(NULL, ctx, names, 1); + } + + return ret; +} + +/* Set the supported curves list, by name, on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] names Colon-separated list of curve names. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ssl or names is NULL or on error. + */ +int wolfSSL_set1_curves_list(WOLFSSL* ssl, const char* names) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_set1_curves_list"); + + if ((ssl == NULL) || (names == NULL)) { + WOLFSSL_MSG("ssl or names was NULL"); + ret = WOLFSSL_FAILURE; + } + else { + ret = set_curves_list(ssl, NULL, names, 1); + } + + return ret; +} + +#endif /* HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448 */ +#endif /* OPENSSL_EXTRA || HAVE_CURL */ + +#ifdef OPENSSL_EXTRA + +/* Set the ALPN protocol list, in wire format, on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] p ALPN protocol list in wire format (length-prefixed). + * @param [in] p_len Length of the protocol list in bytes. + * @return WOLFSSL_SUCCESS (or 0 with WOLFSSL_ERROR_CODE_OPENSSL) on success. + * @return BAD_FUNC_ARG when ctx or p is NULL. + * @return WOLFSSL_FAILURE (or 1 with WOLFSSL_ERROR_CODE_OPENSSL) on error. + */ +int wolfSSL_CTX_set_alpn_protos(WOLFSSL_CTX *ctx, const unsigned char *p, + unsigned int p_len) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_set_alpn_protos"); + + if ((ctx == NULL) || (p == NULL)) { + ret = BAD_FUNC_ARG; + } + else { + if (ctx->alpn_cli_protos != NULL) { + XFREE((void*)ctx->alpn_cli_protos, ctx->heap, DYNAMIC_TYPE_OPENSSL); + } + + ctx->alpn_cli_protos = (const unsigned char*)XMALLOC(p_len, + ctx->heap, DYNAMIC_TYPE_OPENSSL); + if (ctx->alpn_cli_protos == NULL) { +#if defined(WOLFSSL_ERROR_CODE_OPENSSL) + /* 0 on success in OpenSSL, non-0 on failure in OpenSSL + * the function reverses the return value convention. + */ + ret = 1; +#else + ret = WOLFSSL_FAILURE; +#endif + } + else { + XMEMCPY((void*)ctx->alpn_cli_protos, p, p_len); + ctx->alpn_cli_protos_len = p_len; + +#if defined(WOLFSSL_ERROR_CODE_OPENSSL) + /* 0 on success in OpenSSL, non-0 on failure in OpenSSL + * the function reverses the return value convention. + */ + ret = 0; +#else + ret = WOLFSSL_SUCCESS; +#endif + } + } + + return ret; +} + + +#ifdef HAVE_ALPN +#ifndef NO_BIO +/* Convert a wire-format ALPN protocol list into a comma-separated string. + * + * The wire format is a sequence of entries, each a length byte followed by + * that many protocol-name bytes. + * + * @param [in] p ALPN protocol list in wire format. + * @param [in] p_len Length of the protocol list in bytes. + * @param [out] pt Buffer to hold the comma-separated list. Must hold at + * least p_len bytes. + * @param [out] ptLen Length of the comma-separated list written. + * @return 1 on success. + * @return 0 when the wire format is invalid. + */ +static int wolfssl_alpn_protos_to_list(const unsigned char* p, + unsigned int p_len, char* pt, unsigned int* ptLen) +{ + unsigned int idx = 0; + unsigned int ptIdx = 0; + unsigned int sz; + int ret = 1; + + /* Convert into a comma separated list. */ + while (idx < p_len - 1) { + unsigned int i; + + sz = p[idx++]; + if (idx + sz > p_len) { + WOLFSSL_MSG("Bad list format"); + ret = 0; + break; + } + if (sz > 0) { + for (i = 0; i < sz; i++) { + pt[ptIdx++] = p[idx++]; + } + if (idx < p_len - 1) { + pt[ptIdx++] = ','; + } + } + } + + if (ret == 1) { + *ptLen = ptIdx; + } + + return ret; +} + +/* Set the ALPN protocol list, in wire format, on the object. + * + * The list is length-prefixed, e.g. + * unsigned char p[] = { 8, 'h','t','t','p','/','1','.','1' }; + * + * @param [in] ssl SSL/TLS object. + * @param [in] p ALPN protocol list in wire format (length-prefixed). + * @param [in] p_len Length of the protocol list in bytes. + * @return WOLFSSL_SUCCESS (or 0 with WOLFSSL_ERROR_CODE_OPENSSL) on success. + * @return WOLFSSL_FAILURE (or 1 with WOLFSSL_ERROR_CODE_OPENSSL) on error. + */ +int wolfSSL_set_alpn_protos(WOLFSSL* ssl, + const unsigned char* p, unsigned int p_len) +{ + char* pt = NULL; + unsigned int ptIdx = 0; + /* RFC 7301: a server that does not select any of the client's offered + * protocols MUST send no_application_protocol. Match that contract on + * the OpenSSL-compat surface rather than silently continuing. */ + int alpn_opt = WOLFSSL_ALPN_FAILED_ON_MISMATCH; +#if defined(WOLFSSL_ERROR_CODE_OPENSSL) + int ret = 1; +#else + int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); +#endif + + WOLFSSL_ENTER("wolfSSL_set_alpn_protos"); + + if ((ssl != NULL) && (p_len > 1) && (p != NULL)) { + /* Replacing leading number with trailing ',' and adding '\0'. */ + pt = (char*)XMALLOC(p_len + 1, ssl->heap, DYNAMIC_TYPE_OPENSSL); + if (pt != NULL) { + if (wolfssl_alpn_protos_to_list(p, p_len, pt, &ptIdx)) { + pt[ptIdx++] = '\0'; + + /* Clear out all currently set ALPN extensions. */ + TLSX_Remove(&ssl->extensions, TLSX_APPLICATION_LAYER_PROTOCOL, + ssl->heap); + + if (wolfSSL_UseALPN(ssl, pt, ptIdx, (byte)alpn_opt) == + WOLFSSL_SUCCESS) { + #if defined(WOLFSSL_ERROR_CODE_OPENSSL) + ret = 0; + #else + ret = WOLFSSL_SUCCESS; + #endif + } + } + + XFREE(pt, ssl->heap, DYNAMIC_TYPE_OPENSSL); + } + } + + return ret; +} +#endif /* !NO_BIO */ +#endif /* HAVE_ALPN */ + +#endif /* OPENSSL_EXTRA */ + +#endif /* !WOLFCRYPT_ONLY */ + +#endif /* !WOLFSSL_SSL_API_EXT_INCLUDED */ diff --git a/src/ssl_api_pk.c b/src/ssl_api_pk.c index 1b42ac1493..4722184ccd 100644 --- a/src/ssl_api_pk.c +++ b/src/ssl_api_pk.c @@ -137,7 +137,7 @@ static int check_cert_key_dev(word32 keyOID, byte* privKey, word32 privSz, } } #else - /* devId was set, don't check, for now */ + /* devId was set, so don't check for now. */ /* TODO: Add callback for private key check? */ (void) pubKey; (void) pubSz; @@ -242,7 +242,7 @@ static int check_cert_key(const DerBuffer* cert, const DerBuffer* key, } } else { - /* fall through if unavailable */ + /* Fall through if unavailable. */ ret = CRYPTOCB_UNAVAILABLE; } @@ -270,7 +270,7 @@ static int check_cert_key(const DerBuffer* cert, const DerBuffer* key, } #ifdef WOLF_PRIVATE_KEY_ID if (altDevId != INVALID_DEVID) { - /* We have to decode the public key first */ + /* We have to decode the public key first. */ /* Default to max pub key size. */ word32 pubKeyLen = MAX_PUBLIC_KEY_SZ; byte* decodedPubKey = (byte*)XMALLOC(pubKeyLen, heap, @@ -280,7 +280,7 @@ static int check_cert_key(const DerBuffer* cert, const DerBuffer* key, } if (ret == WOLFSSL_SUCCESS) { if ((der->sapkiOID == RSAk) || (der->sapkiOID == ECDSAk)) { - /* Simply copy the data */ + /* Simply copy the data. */ XMEMCPY(decodedPubKey, der->sapkiDer, der->sapkiLen); pubKeyLen = der->sapkiLen; ret = 0; @@ -307,7 +307,7 @@ static int check_cert_key(const DerBuffer* cert, const DerBuffer* key, } } else { - /* fall through if unavailable */ + /* Fall through if unavailable. */ ret = CRYPTOCB_UNAVAILABLE; } @@ -1606,4 +1606,1240 @@ void* wolfSSL_GetDhAgreeCtx(WOLFSSL* ssl) } #endif /* HAVE_PK_CALLBACKS && !NO_DH */ +#ifndef WOLFCRYPT_ONLY + +#ifndef NO_TLS +#ifdef HAVE_ECC +/* Set the minimum ECC key size, in bits, allowed with the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] keySz Minimum ECC key size in bits. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx is NULL or keySz is negative. + * @return CRYPTO_POLICY_FORBIDDEN when below the active crypto-policy minimum. + */ +int wolfSSL_CTX_SetMinEccKey_Sz(WOLFSSL_CTX* ctx, short keySz) +{ + int ret = WOLFSSL_SUCCESS; + + WOLFSSL_ENTER("wolfSSL_CTX_SetMinEccKey_Sz"); + + if ((ctx == NULL) || (keySz < 0)) { + WOLFSSL_MSG("Key size must be positive value or ctx was null"); + ret = BAD_FUNC_ARG; + } + else { + short keySzBytes = (keySz + 7) / 8; + + #if defined(WOLFSSL_SYS_CRYPTO_POLICY) + if (crypto_policy.enabled && (ctx->minEccKeySz > keySzBytes)) { + ret = CRYPTO_POLICY_FORBIDDEN; + } + else + #endif /* WOLFSSL_SYS_CRYPTO_POLICY */ + { + ctx->minEccKeySz = keySzBytes; + #ifndef NO_CERTS + ctx->cm->minEccKeySz = keySzBytes; + #endif + } + } + + return ret; +} + + +/* Set the minimum ECC key size, in bits, allowed with the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] keySz Minimum ECC key size in bits. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL or keySz is negative. + * @return CRYPTO_POLICY_FORBIDDEN when below the active crypto-policy minimum. + */ +int wolfSSL_SetMinEccKey_Sz(WOLFSSL* ssl, short keySz) +{ + int ret = WOLFSSL_SUCCESS; + + WOLFSSL_ENTER("wolfSSL_SetMinEccKey_Sz"); + + if ((ssl == NULL) || (keySz < 0)) { + WOLFSSL_MSG("Key size must be positive value or ctx was null"); + ret = BAD_FUNC_ARG; + } + else { + short keySzBytes = (keySz + 7) / 8; + + #if defined(WOLFSSL_SYS_CRYPTO_POLICY) + if (crypto_policy.enabled && (ssl->options.minEccKeySz > keySzBytes)) { + ret = CRYPTO_POLICY_FORBIDDEN; + } + else + #endif /* WOLFSSL_SYS_CRYPTO_POLICY */ + { + ssl->options.minEccKeySz = keySzBytes; + } + } + + return ret; +} + +#endif /* HAVE_ECC */ + +#ifndef NO_RSA +/* Set the minimum RSA key size, in bits, allowed with the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] keySz Minimum RSA key size in bits. Must be a multiple of 8. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx is NULL or keySz is negative or not a + * multiple of 8. + * @return CRYPTO_POLICY_FORBIDDEN when below the active crypto-policy minimum. + */ +int wolfSSL_CTX_SetMinRsaKey_Sz(WOLFSSL_CTX* ctx, short keySz) +{ + int ret = WOLFSSL_SUCCESS; + + if ((ctx == NULL) || (keySz < 0) || ((keySz % 8) != 0)) { + WOLFSSL_MSG("Key size must be divisible by 8 or ctx was null"); + ret = BAD_FUNC_ARG; + } +#if defined(WOLFSSL_SYS_CRYPTO_POLICY) + else if (crypto_policy.enabled && (ctx->minRsaKeySz > (keySz / 8))) { + ret = CRYPTO_POLICY_FORBIDDEN; + } +#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ + else { + ctx->minRsaKeySz = keySz / 8; + ctx->cm->minRsaKeySz = keySz / 8; + } + + return ret; +} + + +/* Set the minimum RSA key size, in bits, allowed with the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] keySz Minimum RSA key size in bits. Must be a multiple of 8. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL or keySz is negative or not a + * multiple of 8. + * @return CRYPTO_POLICY_FORBIDDEN when below the active crypto-policy minimum. + */ +int wolfSSL_SetMinRsaKey_Sz(WOLFSSL* ssl, short keySz) +{ + int ret = WOLFSSL_SUCCESS; + + if ((ssl == NULL) || (keySz < 0) || ((keySz % 8) != 0)) { + WOLFSSL_MSG("Key size must be divisible by 8 or ssl was null"); + ret = BAD_FUNC_ARG; + } +#if defined(WOLFSSL_SYS_CRYPTO_POLICY) + else if (crypto_policy.enabled && (ssl->options.minRsaKeySz > (keySz / 8))) { + ret = CRYPTO_POLICY_FORBIDDEN; + } +#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ + else { + ssl->options.minRsaKeySz = keySz / 8; + } + + return ret; +} +#endif /* !NO_RSA */ + +#ifndef NO_DH + +#if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \ + !defined(HAVE_SELFTEST) +/* Enable or disable the DH key prime test on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] enable 1 to enable the prime test and 0 to disable it. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + */ +int wolfSSL_SetEnableDhKeyTest(WOLFSSL* ssl, int enable) +{ + int ret = WOLFSSL_SUCCESS; + + WOLFSSL_ENTER("wolfSSL_SetEnableDhKeyTest"); + + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else { + /* Store the flag normalized to a boolean. */ + ssl->options.dhDoKeyTest = (enable != 0); + } + + WOLFSSL_LEAVE("wolfSSL_SetEnableDhKeyTest", ret); + return ret; +} +#endif + +/* Set the minimum DH key size, in bits, allowed with the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] keySz_bits Minimum DH key size in bits. No more than 16000 and + * a multiple of 8. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx is NULL or keySz_bits is invalid. + * @return CRYPTO_POLICY_FORBIDDEN when below the active crypto-policy minimum. + */ +int wolfSSL_CTX_SetMinDhKey_Sz(WOLFSSL_CTX* ctx, word16 keySz_bits) +{ + int ret = WOLFSSL_SUCCESS; + + if ((ctx == NULL) || (keySz_bits > 16000) || ((keySz_bits % 8) != 0)) { + ret = BAD_FUNC_ARG; + } +#if defined(WOLFSSL_SYS_CRYPTO_POLICY) + else if (crypto_policy.enabled && (ctx->minDhKeySz > (keySz_bits / 8))) { + ret = CRYPTO_POLICY_FORBIDDEN; + } +#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ + else { + ctx->minDhKeySz = keySz_bits / 8; + } + + return ret; +} + + +/* Set the minimum DH key size, in bits, allowed with the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] keySz_bits Minimum DH key size in bits. No more than 16000 and + * a multiple of 8. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL or keySz_bits is invalid. + * @return CRYPTO_POLICY_FORBIDDEN when below the active crypto-policy minimum. + */ +int wolfSSL_SetMinDhKey_Sz(WOLFSSL* ssl, word16 keySz_bits) +{ + int ret = WOLFSSL_SUCCESS; + + if ((ssl == NULL) || (keySz_bits > 16000) || ((keySz_bits % 8) != 0)) { + ret = BAD_FUNC_ARG; + } +#if defined(WOLFSSL_SYS_CRYPTO_POLICY) + else if (crypto_policy.enabled && + (ssl->options.minDhKeySz > (keySz_bits / 8))) { + ret = CRYPTO_POLICY_FORBIDDEN; + } +#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ + else { + ssl->options.minDhKeySz = keySz_bits / 8; + } + + return ret; +} + + +/* Set the maximum DH key size, in bits, allowed with the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] keySz_bits Maximum DH key size in bits. No more than 16000 and + * a multiple of 8. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx is NULL or keySz_bits is invalid. + */ +int wolfSSL_CTX_SetMaxDhKey_Sz(WOLFSSL_CTX* ctx, word16 keySz_bits) +{ + int ret = WOLFSSL_SUCCESS; + + if ((ctx == NULL) || (keySz_bits > 16000) || (keySz_bits % 8 != 0)) { + ret = BAD_FUNC_ARG; + } +#if defined(WOLFSSL_SYS_CRYPTO_POLICY) + else if (crypto_policy.enabled && (ctx->minDhKeySz > (keySz_bits / 8))) { + ret = CRYPTO_POLICY_FORBIDDEN; + } +#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ + else { + ctx->maxDhKeySz = keySz_bits / 8; + } + + return ret; +} + + +/* Set the maximum DH key size, in bits, allowed with the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] keySz_bits Maximum DH key size in bits. No more than 16000 and + * a multiple of 8. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL or keySz_bits is invalid. + */ +int wolfSSL_SetMaxDhKey_Sz(WOLFSSL* ssl, word16 keySz_bits) +{ + int ret = WOLFSSL_SUCCESS; + + if ((ssl == NULL) || (keySz_bits > 16000) || ((keySz_bits % 8) != 0)) { + ret = BAD_FUNC_ARG; + } +#if defined(WOLFSSL_SYS_CRYPTO_POLICY) + else if (crypto_policy.enabled && + (ssl->options.minDhKeySz > (keySz_bits / 8))) { + ret = CRYPTO_POLICY_FORBIDDEN; + } +#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ + else { + ssl->options.maxDhKeySz = keySz_bits / 8; + } + + return ret; +} + + +/* Get the size, in bits, of the DH key being used by the object. + * + * @param [in] ssl SSL/TLS object. + * @return DH key size in bits on success. + * @return BAD_FUNC_ARG when ssl is NULL. + */ +int wolfSSL_GetDhKey_Sz(WOLFSSL* ssl) +{ + int ret; + + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else { + /* Key size is stored in bytes; report it in bits. */ + ret = ssl->options.dhKeySz * 8; + } + + return ret; +} + +#endif /* !NO_DH */ + +#endif /* !NO_TLS */ + +#ifdef OPENSSL_EXTRA +#ifndef NO_WOLFSSL_STUB +/* Get the private key of the object. + * + * Not implemented - stub for OpenSSL compatibility. + * + * @param [in] ssl SSL/TLS object. + * @return NULL always. + */ +WOLFSSL_EVP_PKEY *wolfSSL_get_privatekey(const WOLFSSL *ssl) +{ + (void)ssl; + WOLFSSL_STUB("SSL_get_privatekey"); + return NULL; +} +#endif + +#endif /* OPENSSL_EXTRA */ + +#ifdef OPENSSL_EXTRA +/* Map a wolfSSL MAC/hash algorithm identifier to a NID. + * + * @param [in] hashAlgo MAC/hash algorithm identifier. + * @param [out] nid NID corresponding to the hash algorithm. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when the algorithm is not recognized. + */ +static int HashToNid(byte hashAlgo, int* nid) +{ + int ret = WOLFSSL_SUCCESS; + + /* Cast for compiler to check everything is implemented. */ + switch ((enum wc_MACAlgorithm)hashAlgo) { + case no_mac: + case rmd_mac: + *nid = WC_NID_undef; + break; + case md5_mac: + *nid = WC_NID_md5; + break; + case sha_mac: + *nid = WC_NID_sha1; + break; + case sha224_mac: + *nid = WC_NID_sha224; + break; + case sha256_mac: + *nid = WC_NID_sha256; + break; + case sha384_mac: + *nid = WC_NID_sha384; + break; + case sha512_mac: + *nid = WC_NID_sha512; + break; + case blake2b_mac: + *nid = WC_NID_blake2b512; + break; + case sm3_mac: + *nid = WC_NID_sm3; + break; + default: + ret = WOLFSSL_FAILURE; + break; + } + + return ret; +} + +/* Map a wolfSSL signature algorithm identifier to a NID. + * + * @param [in] sa Signature algorithm identifier. + * @param [out] nid NID corresponding to the signature algorithm. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when the algorithm is not recognized or not + * compiled in. + */ +static int SaToNid(byte sa, int* nid) +{ + int ret = WOLFSSL_SUCCESS; + + /* Cast for compiler to check everything is implemented. */ + switch ((enum SignatureAlgorithm)sa) { + case anonymous_sa_algo: + *nid = WC_NID_undef; + break; + case rsa_sa_algo: + *nid = WC_NID_rsaEncryption; + break; + case dsa_sa_algo: + *nid = WC_NID_dsa; + break; + case ecc_dsa_sa_algo: + case ecc_brainpool_sa_algo: + *nid = WC_NID_X9_62_id_ecPublicKey; + break; + case rsa_pss_sa_algo: + *nid = WC_NID_rsassaPss; + break; + case ed25519_sa_algo: +#ifdef HAVE_ED25519 + *nid = WC_NID_ED25519; +#else + ret = WOLFSSL_FAILURE; +#endif + break; + case rsa_pss_pss_algo: + *nid = WC_NID_rsassaPss; + break; + case ed448_sa_algo: +#ifdef HAVE_ED448 + *nid = WC_NID_ED448; +#else + ret = WOLFSSL_FAILURE; +#endif + break; + case falcon_level1_sa_algo: + *nid = CTC_FALCON_LEVEL1; + break; + case falcon_level5_sa_algo: + *nid = CTC_FALCON_LEVEL5; + break; + case mldsa_44_sa_algo: + *nid = CTC_ML_DSA_LEVEL2; + break; + case mldsa_65_sa_algo: + *nid = CTC_ML_DSA_LEVEL3; + break; + case mldsa_87_sa_algo: + *nid = CTC_ML_DSA_LEVEL5; + break; + case sm2_sa_algo: + *nid = WC_NID_sm2; + break; + case invalid_sa_algo: + case any_sa_algo: + default: + ret = WOLFSSL_FAILURE; + break; + } + return ret; +} + +/* Get the NID of the hash algorithm used for signing by this side. + * + * @param [in] ssl SSL/TLS object. + * @param [out] nid NID of the hash algorithm. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ssl or nid is NULL or the algorithm is not + * recognized. + */ +int wolfSSL_get_signature_nid(WOLFSSL *ssl, int* nid) +{ + int ret; + + WOLFSSL_MSG("wolfSSL_get_signature_nid"); + + if ((ssl == NULL) || (nid == NULL)) { + WOLFSSL_MSG("Bad function arguments"); + ret = WOLFSSL_FAILURE; + } + else { + /* Map this side's signing hash algorithm to its NID. */ + ret = HashToNid(ssl->options.hashAlgo, nid); + } + + return ret; +} + +/* Get the NID of the signature algorithm used for signing by this side. + * + * @param [in] ssl SSL/TLS object. + * @param [out] nid NID of the signature algorithm. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ssl or nid is NULL or the algorithm is not + * recognized. + */ +int wolfSSL_get_signature_type_nid(const WOLFSSL* ssl, int* nid) +{ + int ret; + + WOLFSSL_MSG("wolfSSL_get_signature_type_nid"); + + if ((ssl == NULL) || (nid == NULL)) { + WOLFSSL_MSG("Bad function arguments"); + ret = WOLFSSL_FAILURE; + } + else { + /* Map this side's signature algorithm to its NID. */ + ret = SaToNid(ssl->options.sigAlgo, nid); + } + + return ret; +} + +/* Get the NID of the hash algorithm used for signing by the peer. + * + * @param [in] ssl SSL/TLS object. + * @param [out] nid NID of the hash algorithm. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ssl or nid is NULL or the algorithm is not + * recognized. + */ +int wolfSSL_get_peer_signature_nid(WOLFSSL* ssl, int* nid) +{ + int ret; + + WOLFSSL_MSG("wolfSSL_get_peer_signature_nid"); + + if ((ssl == NULL) || (nid == NULL)) { + WOLFSSL_MSG("Bad function arguments"); + ret = WOLFSSL_FAILURE; + } + else { + /* Map the peer's signing hash algorithm to its NID. */ + ret = HashToNid(ssl->options.peerHashAlgo, nid); + } + + return ret; +} + +/* Get the NID of the signature algorithm used for signing by the peer. + * + * @param [in] ssl SSL/TLS object. + * @param [out] nid NID of the signature algorithm. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ssl or nid is NULL or the algorithm is not + * recognized. + */ +int wolfSSL_get_peer_signature_type_nid(const WOLFSSL* ssl, int* nid) +{ + int ret; + + WOLFSSL_MSG("wolfSSL_get_peer_signature_type_nid"); + + if ((ssl == NULL) || (nid == NULL)) { + WOLFSSL_MSG("Bad function arguments"); + ret = WOLFSSL_FAILURE; + } + else { + /* Map the peer's signature algorithm to its NID. */ + ret = SaToNid(ssl->options.peerSigAlgo, nid); + } + + return ret; +} + +#endif /* OPENSSL_EXTRA */ + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) \ + || defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) +#ifdef HAVE_ECC +/* Set the temporary ECDH key's curve on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] ecdh EC key whose curve is to be used. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx or ecdh is NULL. + */ +int wolfSSL_SSL_CTX_set_tmp_ecdh(WOLFSSL_CTX *ctx, WOLFSSL_EC_KEY *ecdh) +{ + int ret = WOLFSSL_SUCCESS; + + WOLFSSL_ENTER("wolfSSL_SSL_CTX_set_tmp_ecdh"); + + if ((ctx == NULL) || (ecdh == NULL)) { + ret = BAD_FUNC_ARG; + } + else { + /* Only the curve of the EC key is used for ephemeral ECDH. */ + ctx->ecdhCurveOID = (word32)ecdh->group->curve_oid; + } + + return ret; +} +#endif + +#endif + +#ifdef WOLFSSL_STATIC_EPHEMERAL +/* Decode the loaded static ephemeral key into the given key object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] keyAlgo Key algorithm: WC_PK_TYPE_DH, WC_PK_TYPE_ECDH, + * WC_PK_TYPE_CURVE25519 or WC_PK_TYPE_CURVE448. + * @param [out] keyPtr Key object to decode into. + * @return 0 on success. + * @return BAD_FUNC_ARG when ssl, its context or keyPtr is NULL. + * @return BUFFER_E when no static key has been set. + * @return NOT_COMPILED_IN when the key algorithm is not supported. + * @return Other negative value on error. + */ +int wolfSSL_StaticEphemeralKeyLoad(WOLFSSL* ssl, int keyAlgo, void* keyPtr) +{ + int ret = 0; + word32 idx = 0; + DerBuffer* der = NULL; + + if ((ssl == NULL) || (ssl->ctx == NULL) || (keyPtr == NULL)) { + ret = BAD_FUNC_ARG; + } +#ifndef SINGLE_THREADED + else if (!ssl->ctx->staticKELockInit) { + ret = BUFFER_E; /* no keys set */ + } + else { + ret = wc_LockMutex(&ssl->ctx->staticKELock); + } +#endif + + if (ret == 0) { + ret = BUFFER_E; /* set default error */ + switch (keyAlgo) { + #ifndef NO_DH + case WC_PK_TYPE_DH: + if (ssl != NULL) + der = ssl->staticKE.dhKey; + if (der == NULL) + der = ssl->ctx->staticKE.dhKey; + if (der != NULL) { + DhKey* key = (DhKey*)keyPtr; + WOLFSSL_MSG("Using static DH key"); + ret = wc_DhKeyDecode(der->buffer, &idx, key, der->length); + } + break; + #endif + #ifdef HAVE_ECC + case WC_PK_TYPE_ECDH: + if (ssl != NULL) + der = ssl->staticKE.ecKey; + if (der == NULL) + der = ssl->ctx->staticKE.ecKey; + if (der != NULL) { + ecc_key* key = (ecc_key*)keyPtr; + WOLFSSL_MSG("Using static ECDH key"); + ret = wc_EccPrivateKeyDecode(der->buffer, &idx, key, + der->length); + } + break; + #endif + #ifdef HAVE_CURVE25519 + case WC_PK_TYPE_CURVE25519: + if (ssl != NULL) + der = ssl->staticKE.x25519Key; + if (der == NULL) + der = ssl->ctx->staticKE.x25519Key; + if (der != NULL) { + curve25519_key* key = (curve25519_key*)keyPtr; + WOLFSSL_MSG("Using static X25519 key"); + #ifdef WOLFSSL_CURVE25519_BLINDING + ret = wc_curve25519_set_rng(key, ssl->rng); + if (ret == 0) + #endif + { + ret = wc_Curve25519PrivateKeyDecode(der->buffer, &idx, + key, der->length); + } + } + break; + #endif + #ifdef HAVE_CURVE448 + case WC_PK_TYPE_CURVE448: + if (ssl != NULL) + der = ssl->staticKE.x448Key; + if (der == NULL) + der = ssl->ctx->staticKE.x448Key; + if (der != NULL) { + curve448_key* key = (curve448_key*)keyPtr; + WOLFSSL_MSG("Using static X448 key"); + ret = wc_Curve448PrivateKeyDecode(der->buffer, &idx, key, + der->length); + } + break; + #endif + default: + /* Not supported. */ + ret = NOT_COMPILED_IN; + break; + } + + #ifndef SINGLE_THREADED + wc_UnLockMutex(&ssl->ctx->staticKELock); + #endif + } + + return ret; +} + +/* Detect the algorithm of an ASN.1 DER encoded private key. + * + * Attempts to decode the key as each supported algorithm in turn, setting + * keyAlgo to the first type that decodes successfully. Detection is only + * performed when keyAlgo is WC_PK_TYPE_NONE on entry. + * + * @param [in] keyBuf ASN.1 DER encoded private key data. + * @param [in] keySz Length of key data in bytes. + * @param [in] heap Heap hint for dynamic memory allocation. + * @param [in, out] keyAlgo Key algorithm. Detected when WC_PK_TYPE_NONE on + * entry; left unchanged otherwise. + * @return 0 on success. + * @return MEMORY_E when dynamic memory allocation fails. + * @return Other negative value on key initialization error. + */ +static int DetectStaticEphemeralKeyType(const byte* keyBuf, unsigned int keySz, + void* heap, int* keyAlgo) +{ + int ret = 0; + +#ifdef HAVE_ECC + { + word32 idx = 0; + WC_DECLARE_VAR(eccKey, ecc_key, 1, heap); + WC_ALLOC_VAR_EX(eccKey, ecc_key, 1, heap, DYNAMIC_TYPE_ECC, + ret = MEMORY_E); + if (ret == 0) { + ret = wc_ecc_init_ex(eccKey, heap, INVALID_DEVID); + } + if (ret == 0) { + ret = wc_EccPrivateKeyDecode(keyBuf, &idx, eccKey, keySz); + if (ret == 0) { + *keyAlgo = WC_PK_TYPE_ECDH; + } + wc_ecc_free(eccKey); + ret = 0; /* clear error to enable key-type detect cascade */ + } + WC_FREE_VAR_EX(eccKey, heap, DYNAMIC_TYPE_ECC); + } +#endif +#if !defined(NO_DH) && defined(WOLFSSL_DH_EXTRA) + if (*keyAlgo == WC_PK_TYPE_NONE) { + word32 idx = 0; + WC_DECLARE_VAR(dhKey, DhKey, 1, heap); + WC_ALLOC_VAR_EX(dhKey, DhKey, 1, heap, DYNAMIC_TYPE_DH, + ret = MEMORY_E); + if (ret == 0) { + ret = wc_InitDhKey_ex(dhKey, heap, INVALID_DEVID); + } + if (ret == 0) { + ret = wc_DhKeyDecode(keyBuf, &idx, dhKey, keySz); + if (ret == 0) { + *keyAlgo = WC_PK_TYPE_DH; + } + wc_FreeDhKey(dhKey); + ret = 0; /* clear error to enable key-type detect cascade */ + } + WC_FREE_VAR_EX(dhKey, heap, DYNAMIC_TYPE_DH); + } +#endif +#ifdef HAVE_CURVE25519 + if (*keyAlgo == WC_PK_TYPE_NONE) { + word32 idx = 0; + WC_DECLARE_VAR(x25519Key, curve25519_key, 1, heap); + WC_ALLOC_VAR_EX(x25519Key, curve25519_key, 1, heap, + DYNAMIC_TYPE_CURVE25519, ret = MEMORY_E); + if (ret == 0) { + ret = wc_curve25519_init_ex(x25519Key, heap, INVALID_DEVID); + } + if (ret == 0) { + ret = wc_Curve25519PrivateKeyDecode(keyBuf, &idx, + x25519Key, keySz); + if (ret == 0) { + *keyAlgo = WC_PK_TYPE_CURVE25519; + } + wc_curve25519_free(x25519Key); + ret = 0; /* clear error to enable key-type detect cascade */ + } + WC_FREE_VAR_EX(x25519Key, heap, DYNAMIC_TYPE_CURVE25519); + } +#endif +#ifdef HAVE_CURVE448 + if (*keyAlgo == WC_PK_TYPE_NONE) { + word32 idx = 0; + WC_DECLARE_VAR(x448Key, curve448_key, 1, heap); + WC_ALLOC_VAR_EX(x448Key, curve448_key, 1, heap, + DYNAMIC_TYPE_CURVE448, ret = MEMORY_E); + if (ret == 0) { + ret = wc_curve448_init(x448Key); + } + if (ret == 0) { + ret = wc_Curve448PrivateKeyDecode(keyBuf, &idx, x448Key, + keySz); + if (ret == 0) { + *keyAlgo = WC_PK_TYPE_CURVE448; + } + wc_curve448_free(x448Key); + ret = 0; /* clear error to enable key-type detect cascade */ + } + WC_FREE_VAR_EX(x448Key, heap, DYNAMIC_TYPE_CURVE448); + } +#endif + + (void)keyBuf; + (void)keySz; + (void)heap; + (void)keyAlgo; + + return ret; +} + +/* Load and store a static ephemeral key into the static key exchange info. + * + * An empty key (key NULL) frees the stored buffer. A file is loaded when key + * is a path and keySz is 0. The key algorithm is auto-detected when keyAlgo + * is WC_PK_TYPE_NONE. + * + * @param [in] ctx SSL/TLS context object (used for the mutex). + * @param [in, out] staticKE Static key exchange info to store the key in. + * @param [in] keyAlgo Key algorithm or WC_PK_TYPE_NONE to detect. + * @param [in] key Key data or file path, may be NULL to free. + * @param [in] keySz Length of key data in bytes, 0 to load a file. + * @param [in] format WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @param [in] heap Heap hint for dynamic memory allocation. + * @return 0 on success. + * @return BAD_FUNC_ARG when staticKE is NULL or key is NULL with keySz > 0. + * @return NOT_COMPILED_IN when the key algorithm is not supported. + * @return Other negative value on error. + */ +static int SetStaticEphemeralKey(WOLFSSL_CTX* ctx, + StaticKeyExchangeInfo_t* staticKE, int keyAlgo, const char* key, + unsigned int keySz, int format, void* heap) +{ + int ret = 0; + DerBuffer* der = NULL; + byte* keyBuf = NULL; +#ifndef NO_FILESYSTEM + const char* keyFile = NULL; +#endif + + WOLFSSL_ENTER("SetStaticEphemeralKey"); + + /* Allow an empty key to free the buffer. */ + if ((staticKE == NULL) || ((key == NULL) && (keySz > 0))) { + ret = BAD_FUNC_ARG; + } + + /* If just freeing the key then skip loading. */ + if ((ret == 0) && (key != NULL)) { + #ifndef NO_FILESYSTEM + /* Load the file from the filesystem. */ + if ((key != NULL) && (keySz == 0)) { + size_t keyBufSz = 0; + keyFile = (const char*)key; + ret = wc_FileLoad(keyFile, &keyBuf, &keyBufSz, heap); + if (ret == 0) { + keySz = (unsigned int)keyBufSz; + } + } + else + #endif + { + /* Use as the key buffer directly. */ + keyBuf = (byte*)key; + } + + if (ret != 0) { + /* File load failed - nothing more to process. */ + } + else if (format == WOLFSSL_FILETYPE_PEM) { + #ifdef WOLFSSL_PEM_TO_DER + int keyFormat = 0; + ret = PemToDer(keyBuf, keySz, PRIVATEKEY_TYPE, &der, + heap, NULL, &keyFormat); + /* Auto-detect the key type. */ + if ((ret == 0) && (keyAlgo == WC_PK_TYPE_NONE)) { + if (keyFormat == ECDSAk) { + keyAlgo = WC_PK_TYPE_ECDH; + } + else if (keyFormat == X25519k) { + keyAlgo = WC_PK_TYPE_CURVE25519; + } + else { + keyAlgo = WC_PK_TYPE_DH; + } + } + #else + ret = NOT_COMPILED_IN; + #endif + } + else { + /* Detect the key type if not specified. */ + if (keyAlgo == WC_PK_TYPE_NONE) { + ret = DetectStaticEphemeralKeyType(keyBuf, keySz, heap, + &keyAlgo); + } + if ((ret == 0) && (keyAlgo != WC_PK_TYPE_NONE)) { + ret = AllocDer(&der, keySz, PRIVATEKEY_TYPE, heap); + if (ret == 0) { + XMEMCPY(der->buffer, keyBuf, keySz); + } + } + } + } + +#ifndef NO_FILESYSTEM + /* Done with the keyFile buffer. */ + if ((keyFile != NULL) && (keyBuf != NULL)) { + ForceZero(keyBuf, keySz); + XFREE(keyBuf, heap, DYNAMIC_TYPE_TMP_BUFFER); + } +#endif + +#ifndef SINGLE_THREADED + if ((ret == 0) && (!ctx->staticKELockInit)) { + ret = wc_InitMutex(&ctx->staticKELock); + if (ret == 0) { + ctx->staticKELockInit = 1; + } + } +#endif + if ((ret == 0) + #ifndef SINGLE_THREADED + && ((ret = wc_LockMutex(&ctx->staticKELock)) == 0) + #endif + ) { + switch (keyAlgo) { + #ifndef NO_DH + case WC_PK_TYPE_DH: + FreeDer(&staticKE->dhKey); + staticKE->dhKey = der; + der = NULL; + break; + #endif + #ifdef HAVE_ECC + case WC_PK_TYPE_ECDH: + FreeDer(&staticKE->ecKey); + staticKE->ecKey = der; + der = NULL; + break; + #endif + #ifdef HAVE_CURVE25519 + case WC_PK_TYPE_CURVE25519: + FreeDer(&staticKE->x25519Key); + staticKE->x25519Key = der; + der = NULL; + break; + #endif + #ifdef HAVE_CURVE448 + case WC_PK_TYPE_CURVE448: + FreeDer(&staticKE->x448Key); + staticKE->x448Key = der; + der = NULL; + break; + #endif + default: + /* Not supported. */ + ret = NOT_COMPILED_IN; + break; + } + + #ifndef SINGLE_THREADED + wc_UnLockMutex(&ctx->staticKELock); + #endif + } + + if (ret != 0) { + FreeDer(&der); + } + + (void)ctx; /* not used for single threaded */ + + WOLFSSL_LEAVE("SetStaticEphemeralKey", ret); + + return ret; +} + +/* Set the static ephemeral key on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] keyAlgo Key algorithm or WC_PK_TYPE_NONE to detect. + * @param [in] key Key data or file path. + * @param [in] keySz Length of key data in bytes, 0 to load a file. + * @param [in] format WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @return 0 on success. + * @return BAD_FUNC_ARG when ctx is NULL. + * @return Other negative value on error. + */ +int wolfSSL_CTX_set_ephemeral_key(WOLFSSL_CTX* ctx, int keyAlgo, + const char* key, unsigned int keySz, int format) +{ + int ret; + + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + else { + /* Store into the context's static ephemeral key store. */ + ret = SetStaticEphemeralKey(ctx, &ctx->staticKE, keyAlgo, key, keySz, + format, ctx->heap); + } + + return ret; +} +/* Set the static ephemeral key on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] keyAlgo Key algorithm or WC_PK_TYPE_NONE to detect. + * @param [in] key Key data or file path. + * @param [in] keySz Length of key data in bytes, 0 to load a file. + * @param [in] format WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @return 0 on success. + * @return BAD_FUNC_ARG when ssl or its context is NULL. + * @return Other negative value on error. + */ +int wolfSSL_set_ephemeral_key(WOLFSSL* ssl, int keyAlgo, const char* key, + unsigned int keySz, int format) +{ + int ret; + + if ((ssl == NULL) || (ssl->ctx == NULL)) { + ret = BAD_FUNC_ARG; + } + else { + /* Store into the object's own static ephemeral key store. */ + ret = SetStaticEphemeralKey(ssl->ctx, &ssl->staticKE, keyAlgo, key, + keySz, format, ssl->heap); + } + + return ret; +} + +/* Get the loaded static ephemeral key as ASN.1 DER data. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] ssl SSL/TLS object, may be NULL to use only the context. + * @param [in] keyAlgo Key algorithm to retrieve. + * @param [out] key Pointer to the key's DER data. May be NULL. + * @param [out] keySz Length of the key's DER data. May be NULL. + * @return 0 on success. + * @return NOT_COMPILED_IN when the key algorithm is not supported. + * @return Other negative value on error. + */ +static int GetStaticEphemeralKey(WOLFSSL_CTX* ctx, WOLFSSL* ssl, int keyAlgo, + const unsigned char** key, unsigned int* keySz) +{ + int ret = 0; + DerBuffer* der = NULL; + + if (key != NULL) { + *key = NULL; + } + if (keySz != NULL) { + *keySz = 0; + } + +#ifndef SINGLE_THREADED + if (ctx->staticKELockInit) { + ret = wc_LockMutex(&ctx->staticKELock); + } +#endif + + if (ret == 0) { + switch (keyAlgo) { + #ifndef NO_DH + case WC_PK_TYPE_DH: + if (ssl != NULL) { + der = ssl->staticKE.dhKey; + } + if (der == NULL) { + der = ctx->staticKE.dhKey; + } + break; + #endif + #ifdef HAVE_ECC + case WC_PK_TYPE_ECDH: + if (ssl != NULL) { + der = ssl->staticKE.ecKey; + } + if (der == NULL) { + der = ctx->staticKE.ecKey; + } + break; + #endif + #ifdef HAVE_CURVE25519 + case WC_PK_TYPE_CURVE25519: + if (ssl != NULL) { + der = ssl->staticKE.x25519Key; + } + if (der == NULL) { + der = ctx->staticKE.x25519Key; + } + break; + #endif + #ifdef HAVE_CURVE448 + case WC_PK_TYPE_CURVE448: + if (ssl != NULL) { + der = ssl->staticKE.x448Key; + } + if (der == NULL) { + der = ctx->staticKE.x448Key; + } + break; + #endif + default: + /* Not supported. */ + ret = NOT_COMPILED_IN; + break; + } + + if (der != NULL) { + if (key != NULL) { + *key = der->buffer; + } + if (keySz != NULL) { + *keySz = der->length; + } + } + + #ifndef SINGLE_THREADED + wc_UnLockMutex(&ctx->staticKELock); + #endif + } + + return ret; +} + +/* Get the static ephemeral key set on the context as ASN.1 DER data. + * + * The returned data can be converted to PEM using wc_DerToPem(). + * + * @param [in] ctx SSL/TLS context object. + * @param [in] keyAlgo Key algorithm to retrieve. + * @param [out] key Pointer to the key's DER data. May be NULL. + * @param [out] keySz Length of the key's DER data. May be NULL. + * @return 0 on success. + * @return BAD_FUNC_ARG when ctx is NULL. + * @return Other negative value on error. + */ +int wolfSSL_CTX_get_ephemeral_key(WOLFSSL_CTX* ctx, int keyAlgo, + const unsigned char** key, unsigned int* keySz) +{ + int ret; + + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + else { + /* No object given, so look the key up on the context only. */ + ret = GetStaticEphemeralKey(ctx, NULL, keyAlgo, key, keySz); + } + + return ret; +} +/* Get the static ephemeral key in use by the object as ASN.1 DER data. + * + * @param [in] ssl SSL/TLS object. + * @param [in] keyAlgo Key algorithm to retrieve. + * @param [out] key Pointer to the key's DER data. May be NULL. + * @param [out] keySz Length of the key's DER data. May be NULL. + * @return 0 on success. + * @return BAD_FUNC_ARG when ssl or its context is NULL. + * @return Other negative value on error. + */ +int wolfSSL_get_ephemeral_key(WOLFSSL* ssl, int keyAlgo, + const unsigned char** key, unsigned int* keySz) +{ + int ret; + + if ((ssl == NULL) || (ssl->ctx == NULL)) { + ret = BAD_FUNC_ARG; + } + else { + /* Prefer the object's key, falling back to the context's. */ + ret = GetStaticEphemeralKey(ssl->ctx, ssl, keyAlgo, key, keySz); + } + + return ret; +} + +#endif /* WOLFSSL_STATIC_EPHEMERAL */ + + +#ifdef OPENSSL_EXTRA +/* Enable or disable automatic ECDH curve selection on the object. + * + * Provided for compatibility with SSL_set_ecdh_auto(). Automatic selection is + * always enabled in wolfSSL so this is a stub. + * + * @param [in] ssl SSL/TLS object. + * @param [in] onoff Ignored. + * @return WOLFSSL_SUCCESS always. + */ +int wolfSSL_set_ecdh_auto(WOLFSSL* ssl, int onoff) +{ + (void)ssl; + (void)onoff; + return WOLFSSL_SUCCESS; +} +/* Enable or disable automatic ECDH curve selection on the context. + * + * Provided for compatibility with SSL_CTX_set_ecdh_auto(). Automatic selection + * is always enabled in wolfSSL so this is a stub. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] onoff Ignored. + * @return WOLFSSL_SUCCESS always. + */ +int wolfSSL_CTX_set_ecdh_auto(WOLFSSL_CTX* ctx, int onoff) +{ + (void)ctx; + (void)onoff; + return WOLFSSL_SUCCESS; +} + +/* Enable or disable automatic DH parameter selection on the context. + * + * Provided for compatibility with SSL_CTX_set_dh_auto(). Automatic selection + * is always enabled in wolfSSL so this is a stub. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] onoff Ignored. + * @return WOLFSSL_SUCCESS always. + */ +int wolfSSL_CTX_set_dh_auto(WOLFSSL_CTX* ctx, int onoff) +{ + (void)ctx; + (void)onoff; + return WOLFSSL_SUCCESS; +} + +#endif /* OPENSSL_EXTRA */ + +#endif /* !WOLFCRYPT_ONLY */ + #endif /* !WOLFSSL_SSL_API_PK_INCLUDED */ diff --git a/tests/api.c b/tests/api.c index a2873fd747..9072297b9e 100644 --- a/tests/api.c +++ b/tests/api.c @@ -235,6 +235,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -34559,6 +34562,9 @@ TEST_CASE testCases[] = { TEST_DECL(test_revoked_loaded_int_cert), TEST_DTLS_DECLS, TEST_DTLS13_DECLS, + TEST_SSL_CERT_DECLS, + TEST_SSL_PK_DECLS, + TEST_SSL_EXT_DECLS, TEST_DECL(test_tls_multi_handshakes_one_record), TEST_DECL(test_write_dup), TEST_DECL(test_write_dup_want_write), diff --git a/tests/api/include.am b/tests/api/include.am index 7ad64d3e63..3d204763c6 100644 --- a/tests/api/include.am +++ b/tests/api/include.am @@ -55,6 +55,9 @@ tests_unit_test_SOURCES += tests/api/test_lms_xmss.c # TLS Protocol tests_unit_test_SOURCES += tests/api/test_dtls.c tests_unit_test_SOURCES += tests/api/test_dtls13.c +tests_unit_test_SOURCES += tests/api/test_ssl_cert.c +tests_unit_test_SOURCES += tests/api/test_ssl_pk.c +tests_unit_test_SOURCES += tests/api/test_ssl_ext.c # TLS Feature tests_unit_test_SOURCES += tests/api/test_ocsp.c tests_unit_test_SOURCES += tests/api/test_evp.c @@ -163,6 +166,9 @@ EXTRA_DIST += tests/api/test_signature.h EXTRA_DIST += tests/api/test_lms_xmss.h EXTRA_DIST += tests/api/test_dtls.h EXTRA_DIST += tests/api/test_dtls13.h +EXTRA_DIST += tests/api/test_ssl_cert.h +EXTRA_DIST += tests/api/test_ssl_pk.h +EXTRA_DIST += tests/api/test_ssl_ext.h EXTRA_DIST += tests/api/test_ocsp.h EXTRA_DIST += tests/api/test_ocsp_test_blobs.h EXTRA_DIST += tests/api/create_ocsp_test_blobs.py diff --git a/tests/api/test_dtls.c b/tests/api/test_dtls.c index ac90f5b7ec..5cf6adc3a6 100644 --- a/tests/api/test_dtls.c +++ b/tests/api/test_dtls.c @@ -515,11 +515,52 @@ int test_wolfSSL_dtls_set_pending_peer(void) wolfSSL_CTX_free(ctx_s); wolfSSL_CTX_free(ctx_c); #endif - return EXPECT_RESULT(); -} - +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS_CID) && \ + !defined(WOLFSSL_NO_SOCK) && defined(XINET_PTON) && \ + defined(HAVE_SOCKADDR) && !defined(WOLFSSL_NO_TLS12) && \ + !defined(NO_WOLFSSL_CLIENT) + { + /* Exercise the "already the current peer" branch, which needs real + * AF_INET addresses (sockAddrEqual() validates the sockaddr). */ + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + void* cur = NULL; + void* other = NULL; + unsigned int addrSz = (unsigned int)sizeof(SOCKADDR_IN); + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectNotNull(cur = + wolfSSL_dtls_create_peer(11111, (char*)"127.0.0.1")); + ExpectNotNull(other = + wolfSSL_dtls_create_peer(22222, (char*)"127.0.0.1")); + + /* NULL object fails. */ + ExpectIntEQ(wolfSSL_dtls_set_pending_peer(NULL, cur, addrSz), + WOLFSSL_FAILURE); + + /* Make 'cur' the current peer. */ + ExpectIntEQ(wolfSSL_dtls_set_peer(ssl, cur, addrSz), WOLFSSL_SUCCESS); + + /* A different address goes to the pending slot (SockAddrSet path). */ + ExpectIntEQ(wolfSSL_dtls_set_pending_peer(ssl, other, addrSz), + WOLFSSL_SUCCESS); + /* The current address matches: the staged pending peer is cleared. */ + ExpectIntEQ(wolfSSL_dtls_set_pending_peer(ssl, cur, addrSz), + WOLFSSL_SUCCESS); + /* Matches again with no pending peer left to clear. */ + ExpectIntEQ(wolfSSL_dtls_set_pending_peer(ssl, cur, addrSz), + WOLFSSL_SUCCESS); + + wolfSSL_dtls_free_peer(cur); + wolfSSL_dtls_free_peer(other); + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); + } +#endif + return EXPECT_RESULT(); +} int test_dtls_version_checking(void) @@ -5340,3 +5381,796 @@ int test_dtls12_missing_finished(void) #endif return EXPECT_RESULT(); } + +/* ---------------------------------------------------------------------------- + * Coverage tests for DTLS APIs in src/ssl_api_dtls.c + * ------------------------------------------------------------------------- */ + +int test_wolfSSL_dtls_create_free_peer(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && defined(XINET_PTON) && \ + !defined(WOLFSSL_NO_SOCK) && defined(HAVE_SOCKADDR) + void* peer = NULL; + + /* Valid IPv4 address and port. */ + ExpectNotNull(peer = wolfSSL_dtls_create_peer(11111, (char*)"127.0.0.1")); + ExpectIntEQ(wolfSSL_dtls_free_peer(peer), WOLFSSL_SUCCESS); + + /* Invalid address string returns NULL. */ + ExpectNull(wolfSSL_dtls_create_peer(11111, (char*)"not-an-ip-address")); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_dtls_get0_peer(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && !defined(NO_WOLFSSL_CLIENT) && \ + !defined(WOLFSSL_NO_TLS12) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + const void* peer = NULL; + unsigned int peerSz = 0; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + ExpectIntEQ(wolfSSL_dtls_set_peer(ssl, (void*)"1234", 5), WOLFSSL_SUCCESS); +#ifndef WOLFSSL_RW_THREADED + /* NULL arguments fail. */ + ExpectIntEQ(wolfSSL_dtls_get0_peer(NULL, &peer, &peerSz), WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_dtls_get0_peer(ssl, NULL, &peerSz), WOLFSSL_FAILURE); + /* Returns a pointer to the stored peer address and its size. */ + ExpectIntEQ(wolfSSL_dtls_get0_peer(ssl, &peer, &peerSz), WOLFSSL_SUCCESS); + ExpectIntEQ(peerSz, 5); + ExpectNotNull(peer); +#else + ExpectIntEQ(wolfSSL_dtls_get0_peer(ssl, &peer, &peerSz), + WOLFSSL_NOT_IMPLEMENTED); +#endif + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_dtls_set_timeout_init(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_LEANPSK) && \ + !defined(NO_WOLFSSL_CLIENT) && !defined(WOLFSSL_NO_TLS12) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + ExpectIntEQ(wolfSSL_dtls_set_timeout_init(NULL, 1), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_dtls_set_timeout_init(ssl, -1), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_dtls_set_timeout_max(ssl, 5), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_dtls_set_timeout_init(ssl, 3), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_dtls_get_current_timeout(ssl), 3); + /* Initial timeout greater than maximum fails. */ + ExpectIntEQ(wolfSSL_dtls_set_timeout_init(ssl, 10), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_dtls_retransmit(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) && \ + !defined(WOLFSSL_NO_TLS12) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0); + + /* NULL fails. */ + ExpectIntEQ(wolfSSL_dtls_retransmit(NULL), WOLFSSL_FATAL_ERROR); + /* Send the ClientHello flight, then retransmit it (DTLS 1.2 path). */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(wolfSSL_dtls_retransmit(ssl_c), WOLFSSL_SUCCESS); + + /* Resending fails when the transport reports want-write, exercising the + * error path (sets ssl->error and returns WOLFSSL_FATAL_ERROR). */ + test_memio_simulate_want_write(&test_ctx, 1, 1); + ExpectIntEQ(wolfSSL_dtls_retransmit(ssl_c), WOLFSSL_FATAL_ERROR); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_WRITE); + test_memio_simulate_want_write(&test_ctx, 1, 0); + + /* After the handshake completes, retransmit is a no-op success. */ + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_dtls_retransmit(ssl_c), WOLFSSL_SUCCESS); + + wolfSSL_free(ssl_s); + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_s); + wolfSSL_CTX_free(ctx_c); +#endif +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \ + defined(WOLFSSL_DTLS13) && defined(WOLFSSL_TLS13) + { + /* DTLS 1.3 exercises the Dtls13DoScheduledWork() branch. */ + WOLFSSL_CTX *ctx_c13 = NULL, *ctx_s13 = NULL; + WOLFSSL *ssl_c13 = NULL, *ssl_s13 = NULL; + struct test_memio_ctx test_ctx13; + + XMEMSET(&test_ctx13, 0, sizeof(test_ctx13)); + ExpectIntEQ(test_memio_setup(&test_ctx13, &ctx_c13, &ctx_s13, &ssl_c13, + &ssl_s13, wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), + 0); + ExpectIntEQ(wolfSSL_negotiate(ssl_c13), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c13, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(wolfSSL_dtls_retransmit(ssl_c13), WOLFSSL_SUCCESS); + + wolfSSL_free(ssl_s13); + wolfSSL_free(ssl_c13); + wolfSSL_CTX_free(ctx_s13); + wolfSSL_CTX_free(ctx_c13); + } +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_DTLSv1_compat_timeouts(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && !defined(NO_WOLFSSL_CLIENT) && \ + !defined(WOLFSSL_NO_TLS12) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + WOLFSSL_TIMEVAL tv; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + XMEMSET(&tv, 0, sizeof(tv)); + ExpectIntEQ(wolfSSL_DTLSv1_get_timeout(ssl, &tv), 0); + /* NULL arguments are tolerated. */ + ExpectIntEQ(wolfSSL_DTLSv1_get_timeout(NULL, NULL), 0); +#ifndef NO_WOLFSSL_STUB + ExpectIntEQ(wolfSSL_DTLSv1_handle_timeout(ssl), 0); + wolfSSL_DTLSv1_set_initial_timeout_duration(ssl, 1000); +#endif + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_dtls13_set_send_more_acks(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_TLS13) && \ + !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_3_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* Toggle the send-more-acks option (void return). */ + wolfSSL_dtls13_set_send_more_acks(ssl, 1); + wolfSSL_dtls13_set_send_more_acks(ssl, 0); + /* NULL is tolerated. */ + wolfSSL_dtls13_set_send_more_acks(NULL, 1); + /* Quick-timeout flag defaults to off. */ + ExpectIntEQ(wolfSSL_dtls13_use_quick_timeout(ssl), 0); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_dtls_srtp_keying_material(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) && \ + defined(WOLFSSL_SRTP) && defined(HAVE_KEYING_MATERIAL) && \ + !defined(WOLFSSL_NO_TLS12) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + const WOLFSSL_SRTP_PROTECTION_PROFILE* profile = NULL; + unsigned char keyMaterial[64]; + size_t olen = 0; + const char* profileStr = "SRTP_AES128_CM_SHA1_80"; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0); + + /* No profile selected before the handshake. */ + ExpectNull(wolfSSL_get_selected_srtp_profile(NULL)); + + /* NULL arguments fail. */ + olen = sizeof(keyMaterial); + ExpectIntEQ(wolfSSL_export_dtls_srtp_keying_material(NULL, keyMaterial, + &olen), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + /* Exporting before SRTP is negotiated reports a missing extension. */ + ExpectIntEQ(wolfSSL_export_dtls_srtp_keying_material(ssl_c, keyMaterial, + &olen), WC_NO_ERR_TRACE(EXT_MISSING)); + + /* Request SRTP on both ends (0 == success, OpenSSL convention). */ + ExpectIntEQ(wolfSSL_set_tlsext_use_srtp(ssl_c, profileStr), 0); + ExpectIntEQ(wolfSSL_set_tlsext_use_srtp(ssl_s, profileStr), 0); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + /* A profile is now selected. */ + ExpectNotNull(profile = wolfSSL_get_selected_srtp_profile(ssl_c)); + + /* Length-only query (out == NULL). */ + olen = 0; + ExpectIntEQ(wolfSSL_export_dtls_srtp_keying_material(ssl_c, NULL, &olen), + WC_NO_ERR_TRACE(LENGTH_ONLY_E)); + ExpectIntGT((int)olen, 0); + ExpectIntLE((int)olen, (int)sizeof(keyMaterial)); + /* A buffer smaller than the keying material reports BUFFER_E. */ + olen = 1; + ExpectIntEQ(wolfSSL_export_dtls_srtp_keying_material(ssl_c, keyMaterial, + &olen), WC_NO_ERR_TRACE(BUFFER_E)); + /* Export the keying material into a large enough buffer. */ + olen = sizeof(keyMaterial); +#ifdef WOLFSSL_OPENVPN + ExpectIntEQ(wolfSSL_export_dtls_srtp_keying_material(ssl_c, keyMaterial, + &olen), WOLFSSL_SUCCESS); +#else + /* Arrays aren't saved without WOLFSSL_OPENVPN. */ + ExpectIntEQ(wolfSSL_export_dtls_srtp_keying_material(ssl_c, keyMaterial, + &olen), WOLFSSL_FAILURE); +#endif + +#ifndef NO_WOLFSSL_STUB + /* Stub returns NULL. */ + ExpectNull(wolfSSL_get_srtp_profiles(ssl_c)); +#endif + + wolfSSL_free(ssl_s); + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_s); + wolfSSL_CTX_free(ctx_c); +#endif + return EXPECT_RESULT(); +} + +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_MULTICAST) && \ + (defined(WOLFSSL_TLS13) || defined(WOLFSSL_SNIFFER)) && \ + !defined(NO_WOLFSSL_CLIENT) +static int test_dtls_mcast_highwater_cb(unsigned short peerId, + unsigned int maxSeq, unsigned int curSeq, void* ctx) +{ + (void)peerId; + (void)maxSeq; + (void)curSeq; + (void)ctx; + return 0; +} +#endif + +int test_wolfSSL_mcast_peers(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_MULTICAST) && \ + (defined(WOLFSSL_TLS13) || defined(WOLFSSL_SNIFFER)) && \ + !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + int hwCtx = 0; + + ExpectIntGT(wolfSSL_mcast_get_max_peers(), 0); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())); + ExpectIntEQ(wolfSSL_CTX_mcast_set_member_id(ctx, 0), WOLFSSL_SUCCESS); + + /* Highwater callback argument validation. */ + ExpectIntEQ(wolfSSL_CTX_mcast_set_highwater_cb(NULL, 320, 100, 200, + test_dtls_mcast_highwater_cb), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_CTX_mcast_set_highwater_cb(ctx, 320, 100, 200, NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_CTX_mcast_set_highwater_cb(ctx, 320, 100, 200, + test_dtls_mcast_highwater_cb), WOLFSSL_SUCCESS); + + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + ExpectIntEQ(wolfSSL_mcast_set_highwater_ctx(NULL, &hwCtx), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_mcast_set_highwater_ctx(ssl, &hwCtx), WOLFSSL_SUCCESS); + + /* Add, query and remove a multicast peer. */ + ExpectIntEQ(wolfSSL_mcast_peer_add(NULL, 1, 0), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_mcast_peer_add(ssl, 1, 0), WOLFSSL_SUCCESS); + /* Known peer that has not sent data yet -> 0. */ + ExpectIntEQ(wolfSSL_mcast_peer_known(ssl, 1), 0); + /* Unknown peer -> 0. */ + ExpectIntEQ(wolfSSL_mcast_peer_known(ssl, 2), 0); + ExpectIntEQ(wolfSSL_mcast_peer_known(NULL, 1), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + /* Once the peer has received data (non-zero sequence number) it is + * reported as known. */ + if (ssl != NULL) { + int j; + for (j = 0; j < WOLFSSL_DTLS_PEERSEQ_SZ; j++) { + if (ssl->keys.peerSeq[j].peerId == 1) { + ssl->keys.peerSeq[j].nextSeq_lo = 1; + break; + } + } + } + ExpectIntEQ(wolfSSL_mcast_peer_known(ssl, 1), 1); + /* Remove the peer (sub = 1). */ + ExpectIntEQ(wolfSSL_mcast_peer_add(ssl, 1, 1), WOLFSSL_SUCCESS); + + /* Re-adding a peer that is already present reports an error. */ + ExpectIntEQ(wolfSSL_mcast_peer_add(ssl, 5, 0), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_mcast_peer_add(ssl, 5, 0), WOLFSSL_FATAL_ERROR); + ExpectIntEQ(wolfSSL_mcast_peer_add(ssl, 5, 1), WOLFSSL_SUCCESS); + + /* Filling every peer slot then adding another peer overflows the list. */ +#if WOLFSSL_DTLS_PEERSEQ_SZ <= 255 + { + int idx; + for (idx = 0; idx < WOLFSSL_DTLS_PEERSEQ_SZ && !EXPECT_FAIL(); idx++) { + ExpectIntEQ(wolfSSL_mcast_peer_add(ssl, (word16)idx, 0), + WOLFSSL_SUCCESS); + } + ExpectIntEQ(wolfSSL_mcast_peer_add(ssl, + (word16)WOLFSSL_DTLS_PEERSEQ_SZ, 0), WOLFSSL_FATAL_ERROR); + } +#endif + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_set_dtls_fd_connected(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && !defined(NO_WOLFSSL_CLIENT) && \ + !defined(WOLFSSL_NO_TLS12) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectIntEQ(wolfSSL_set_dtls_fd_connected(NULL, 0), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntEQ(wolfSSL_set_dtls_fd_connected(ssl, 1), WOLFSSL_SUCCESS); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_dtls_get_peer(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && !defined(NO_WOLFSSL_CLIENT) && \ + !defined(WOLFSSL_NO_TLS12) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + unsigned char peer[16]; + unsigned int peerSz = (unsigned int)sizeof(peer); + + ExpectIntEQ(wolfSSL_dtls_get_peer(NULL, peer, &peerSz), WOLFSSL_FAILURE); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* No peer set yet. */ + peerSz = (unsigned int)sizeof(peer); + ExpectIntEQ(wolfSSL_dtls_get_peer(ssl, peer, &peerSz), WOLFSSL_FAILURE); + + /* Set then retrieve the peer. */ + ExpectIntEQ(wolfSSL_dtls_set_peer(ssl, (void*)"1234", 5), WOLFSSL_SUCCESS); + peerSz = (unsigned int)sizeof(peer); + ExpectIntEQ(wolfSSL_dtls_get_peer(ssl, peer, &peerSz), WOLFSSL_SUCCESS); + ExpectIntEQ(peerSz, 5); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_dtls_set_peer(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && !defined(NO_WOLFSSL_CLIENT) && \ + !defined(WOLFSSL_NO_TLS12) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + unsigned char peer[16]; + unsigned int peerSz = (unsigned int)sizeof(peer); + + ExpectIntEQ(wolfSSL_dtls_set_peer(NULL, (void*)"1234", 5), WOLFSSL_FAILURE); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* Set a peer then read it back. */ + ExpectIntEQ(wolfSSL_dtls_set_peer(ssl, (void*)"1234", 5), WOLFSSL_SUCCESS); + peerSz = (unsigned int)sizeof(peer); + ExpectIntEQ(wolfSSL_dtls_get_peer(ssl, peer, &peerSz), WOLFSSL_SUCCESS); + ExpectIntEQ(peerSz, 5); + + /* A larger peer grows the buffer, freeing the previous one. */ + ExpectIntEQ(wolfSSL_dtls_set_peer(ssl, (void*)"123456789012", 12), + WOLFSSL_SUCCESS); + peerSz = (unsigned int)sizeof(peer); + ExpectIntEQ(wolfSSL_dtls_get_peer(ssl, peer, &peerSz), WOLFSSL_SUCCESS); + ExpectIntEQ(peerSz, 12); + + /* Clearing the peer with NULL/0 frees the stored address. */ + ExpectIntEQ(wolfSSL_dtls_set_peer(ssl, NULL, 0), WOLFSSL_SUCCESS); + peerSz = (unsigned int)sizeof(peer); + ExpectIntEQ(wolfSSL_dtls_get_peer(ssl, peer, &peerSz), WOLFSSL_FAILURE); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_GetDtlsMacSecret(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_AEAD_ONLY) + /* NULL ssl returns NULL. */ + ExpectNull(wolfSSL_GetDtlsMacSecret(NULL, 0, 0)); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_dtls_get_using_nonblock(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && !defined(NO_WOLFSSL_CLIENT) && \ + !defined(WOLFSSL_NO_TLS12) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectIntEQ(wolfSSL_dtls_get_using_nonblock(NULL), WOLFSSL_FAILURE); + + /* DTLS object: default is off. */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntEQ(wolfSSL_dtls_get_using_nonblock(ssl), 0); + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); + ssl = NULL; + ctx = NULL; + +#ifndef WOLFSSL_NO_TLS12 + /* Non-DTLS object takes the deprecated-use branch and returns 0. */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntEQ(wolfSSL_dtls_get_using_nonblock(ssl), 0); + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_dtls_set_using_nonblock(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_LEANPSK) && \ + !defined(NO_WOLFSSL_CLIENT) && !defined(WOLFSSL_NO_TLS12) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + /* NULL is a no-op (must not crash). */ + wolfSSL_dtls_set_using_nonblock(NULL, 1); + + /* DTLS object: value is stored and read back. */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + wolfSSL_dtls_set_using_nonblock(ssl, 1); + ExpectIntEQ(wolfSSL_dtls_get_using_nonblock(ssl), 1); + wolfSSL_dtls_set_using_nonblock(ssl, 0); + ExpectIntEQ(wolfSSL_dtls_get_using_nonblock(ssl), 0); + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); + ssl = NULL; + ctx = NULL; + +#ifndef WOLFSSL_NO_TLS12 + /* Non-DTLS object takes the deprecated-use branch. */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + wolfSSL_dtls_set_using_nonblock(ssl, 1); + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_set_mtu_compat(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && defined(OPENSSL_EXTRA) && \ + (defined(WOLFSSL_SCTP) || defined(WOLFSSL_DTLS_MTU)) && \ + !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* A reasonable MTU succeeds. */ + ExpectIntEQ(wolfSSL_set_mtu_compat(ssl, 1500), WOLFSSL_SUCCESS); + /* An MTU larger than a record fails. */ + ExpectIntEQ(wolfSSL_set_mtu_compat(ssl, 0xFFFF), WOLFSSL_FAILURE); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_dtls_set_timeout_max(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_LEANPSK) && \ + !defined(NO_WOLFSSL_CLIENT) && !defined(WOLFSSL_NO_TLS12) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectIntEQ(wolfSSL_dtls_set_timeout_max(NULL, 5), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* Negative timeout fails. */ + ExpectIntEQ(wolfSSL_dtls_set_timeout_max(ssl, -1), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + /* Valid maximum succeeds. */ + ExpectIntEQ(wolfSSL_dtls_set_timeout_max(ssl, 5), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_dtls_set_timeout_init(ssl, 3), WOLFSSL_SUCCESS); + /* Maximum less than the initial timeout fails. */ + ExpectIntEQ(wolfSSL_dtls_set_timeout_max(ssl, 2), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_CTX_mcast_set_member_id(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_MULTICAST) && \ + (defined(WOLFSSL_TLS13) || defined(WOLFSSL_SNIFFER)) && \ + !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + + ExpectIntEQ(wolfSSL_CTX_mcast_set_member_id(NULL, 0), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())); + /* Member id out of range (> 8-bit) fails. */ + ExpectIntEQ(wolfSSL_CTX_mcast_set_member_id(ctx, 256), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + /* Valid member id succeeds. */ + ExpectIntEQ(wolfSSL_CTX_mcast_set_member_id(ctx, 0), WOLFSSL_SUCCESS); + + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_mcast_read(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_MULTICAST) && \ + (defined(WOLFSSL_TLS13) || defined(WOLFSSL_SNIFFER)) && \ + !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + word16 id = 0; + byte buf[16]; + + ExpectIntEQ(wolfSSL_mcast_read(NULL, &id, buf, (int)sizeof(buf)), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())); + ExpectIntEQ(wolfSSL_CTX_mcast_set_member_id(ctx, 0), WOLFSSL_SUCCESS); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* Negative size fails. */ + ExpectIntEQ(wolfSSL_mcast_read(ssl, &id, buf, -1), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_dtls_got_timeout(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_LEANPSK) && \ + !defined(NO_WOLFSSL_CLIENT) + /* NULL object fails. */ + ExpectIntEQ(wolfSSL_dtls_got_timeout(NULL), WOLFSSL_FATAL_ERROR); +#ifndef WOLFSSL_NO_TLS12 + { + /* A non-DTLS object also fails. */ + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl), WOLFSSL_FATAL_ERROR); + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); + } +#endif +#endif + +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) && \ + !defined(WOLFSSL_LEANPSK) && !defined(WOLFSSL_NO_TLS12) + { + /* With a DTLS 1.2 flight buffered, a transport that reports want-write + * makes the timeout handler take the pool-send error path. */ + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0); + + /* Buffer the ClientHello flight. */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + + /* Resending the flight fails -> error path, returns FATAL_ERROR. */ + test_memio_simulate_want_write(&test_ctx, 1, 1); + ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), WOLFSSL_FATAL_ERROR); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_WRITE); + + /* With the transport unblocked the resend succeeds. */ + test_memio_simulate_want_write(&test_ctx, 1, 0); + ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), WOLFSSL_SUCCESS); + + wolfSSL_free(ssl_s); + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_s); + wolfSSL_CTX_free(ctx_c); + } +#endif + +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \ + defined(WOLFSSL_DTLS13) && defined(WOLFSSL_TLS13) + { + /* DTLS 1.3: a want-write while retransmitting takes the + * Dtls13RtxTimeout() error branch. */ + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); + + /* Buffer the ClientHello flight. */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + + /* Retransmit under want-write fails. */ + test_memio_simulate_want_write(&test_ctx, 1, 1); + ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), WOLFSSL_FATAL_ERROR); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_WRITE); + test_memio_simulate_want_write(&test_ctx, 1, 0); + + wolfSSL_free(ssl_s); + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_s); + wolfSSL_CTX_free(ctx_c); + } +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_DTLS_SetCookieSecret(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && !defined(NO_WOLFSSL_SERVER) && \ + (defined(NO_CERTS) || !defined(NO_RSA)) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + byte secret1[32]; + byte secret2[16]; + + XMEMSET(secret1, 0xA5, sizeof(secret1)); + XMEMSET(secret2, 0x5A, sizeof(secret2)); + + /* NULL object fails. */ + ExpectIntEQ(wolfSSL_DTLS_SetCookieSecret(NULL, secret1, sizeof(secret1)), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_server_method())); +#ifndef NO_CERTS + /* A server WOLFSSL needs a key and certificate set on the context. */ + ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, CERT_FILETYPE), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile, + CERT_FILETYPE), WOLFSSL_SUCCESS); +#endif + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* A non-NULL secret with zero size fails. */ + ExpectIntEQ(wolfSSL_DTLS_SetCookieSecret(ssl, secret1, 0), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* Set an explicit secret (copy path). */ + ExpectIntEQ(wolfSSL_DTLS_SetCookieSecret(ssl, secret1, sizeof(secret1)), 0); + /* A different size frees the old buffer and reallocates. */ + ExpectIntEQ(wolfSSL_DTLS_SetCookieSecret(ssl, secret2, sizeof(secret2)), 0); + /* The same size keeps the existing buffer (no reallocation). */ + ExpectIntEQ(wolfSSL_DTLS_SetCookieSecret(ssl, secret2, sizeof(secret2)), 0); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_set_secret(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_MULTICAST) && \ + (defined(WOLFSSL_TLS13) || defined(WOLFSSL_SNIFFER)) && \ + !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + byte preMasterSecret[16]; + byte clientRandom[32]; + byte serverRandom[32]; + byte suite[2] = { 0, 0xfe }; /* WDM_WITH_NULL_SHA256 */ + + XMEMSET(preMasterSecret, 0x23, sizeof(preMasterSecret)); + XMEMSET(clientRandom, 0xA5, sizeof(clientRandom)); + XMEMSET(serverRandom, 0x5A, sizeof(serverRandom)); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())); + ExpectIntEQ(wolfSSL_CTX_mcast_set_member_id(ctx, 0), WOLFSSL_SUCCESS); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* Invalid arguments take the error path and return WOLFSSL_FATAL_ERROR. */ + ExpectIntEQ(wolfSSL_set_secret(ssl, 23, NULL, sizeof(preMasterSecret), + clientRandom, serverRandom, suite), WOLFSSL_FATAL_ERROR); + ExpectIntEQ(wolfSSL_set_secret(ssl, 23, preMasterSecret, 0, + clientRandom, serverRandom, suite), WOLFSSL_FATAL_ERROR); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} diff --git a/tests/api/test_dtls.h b/tests/api/test_dtls.h index cb5eb17555..5495c5164b 100644 --- a/tests/api/test_dtls.h +++ b/tests/api/test_dtls.h @@ -44,6 +44,27 @@ int test_dtls_memio_wolfio_stateless(void); int test_dtls_mtu_fragment_headroom(void); int test_dtls_mtu_split_messages(void); int test_dtls_set_session_min_downgrade(void); +int test_wolfSSL_dtls_create_free_peer(void); +int test_wolfSSL_dtls_get0_peer(void); +int test_wolfSSL_dtls_set_timeout_init(void); +int test_wolfSSL_dtls_retransmit(void); +int test_wolfSSL_DTLSv1_compat_timeouts(void); +int test_wolfSSL_dtls13_set_send_more_acks(void); +int test_wolfSSL_dtls_srtp_keying_material(void); +int test_wolfSSL_mcast_peers(void); +int test_wolfSSL_set_dtls_fd_connected(void); +int test_wolfSSL_dtls_get_peer(void); +int test_wolfSSL_dtls_set_peer(void); +int test_wolfSSL_GetDtlsMacSecret(void); +int test_wolfSSL_dtls_get_using_nonblock(void); +int test_wolfSSL_dtls_set_using_nonblock(void); +int test_wolfSSL_set_mtu_compat(void); +int test_wolfSSL_dtls_set_timeout_max(void); +int test_wolfSSL_CTX_mcast_set_member_id(void); +int test_wolfSSL_mcast_read(void); +int test_wolfSSL_dtls_got_timeout(void); +int test_wolfSSL_DTLS_SetCookieSecret(void); +int test_wolfSSL_set_secret(void); /* DTLS tests moved out of tests/api.c. */ int test_dtls_msg_from_other_peer(void); @@ -104,7 +125,8 @@ int test_WOLFSSL_dtls_version_alert(void); TEST_DECL_GROUP("dtls", test_dtls_set_session_min_downgrade), \ TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_export), \ TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_export_peers), \ - TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_import_state_extra_window_words), \ + TEST_DECL_GROUP("dtls", \ + test_wolfSSL_dtls_import_state_extra_window_words), \ TEST_DECL_GROUP("dtls", test_wolfSSL_DTLS_either_side), \ TEST_DECL_GROUP("dtls", test_generate_cookie), \ TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_set_mtu), \ @@ -133,5 +155,30 @@ int test_WOLFSSL_dtls_version_alert(void); TEST_DECL_GROUP("dtls", test_dtls_dropped_ccs), \ TEST_DECL_GROUP("dtls", test_dtls_seq_num_downgrade), \ TEST_DECL_GROUP("dtls", test_dtls_old_seq_number), \ - TEST_DECL_GROUP("dtls", test_dtls12_missing_finished) + TEST_DECL_GROUP("dtls", test_dtls12_missing_finished), \ + TEST_DECL_GROUP("dtls", test_dtls13_min_rtx_interval), \ + TEST_DECL_GROUP("dtls", test_dtls13_no_session_id_echo), \ + TEST_DECL_GROUP("dtls", test_dtls13_oversized_cert_chain), \ + TEST_DECL_GROUP("dtls", test_dtls_set_session_min_downgrade), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_create_free_peer), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_get0_peer), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_set_timeout_init), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_retransmit), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_DTLSv1_compat_timeouts), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls13_set_send_more_acks), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_srtp_keying_material), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_mcast_peers), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_set_dtls_fd_connected), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_get_peer), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_set_peer), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_GetDtlsMacSecret), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_get_using_nonblock), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_set_using_nonblock), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_set_mtu_compat), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_set_timeout_max), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_CTX_mcast_set_member_id), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_mcast_read), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_got_timeout), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_DTLS_SetCookieSecret), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_set_secret) #endif /* TESTS_API_DTLS_H */ diff --git a/tests/api/test_ssl_cert.c b/tests/api/test_ssl_cert.c new file mode 100644 index 0000000000..3a3ef77f3c --- /dev/null +++ b/tests/api/test_ssl_cert.c @@ -0,0 +1,406 @@ +/* test_ssl_cert.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 + +#ifdef NO_INLINE + #include +#else + #define WOLFSSL_MISC_INCLUDED + #include +#endif + +#include +#include + +#include +#include + +/* Tests for the certificate APIs in src/ssl_api_cert.c (moved from ssl.c). */ + +int test_wolfSSL_get_verify_mode(void) +{ + EXPECT_DECLS; +#if (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) || defined(HAVE_STUNNEL) || \ + defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(WOLFSSL_NGINX)) && \ + !defined(NO_CERTS) && !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + int mode; + + ExpectIntEQ(wolfSSL_get_verify_mode(NULL), WOLFSSL_FAILURE); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + wolfSSL_set_verify(ssl, WOLFSSL_VERIFY_NONE, NULL); + ExpectIntEQ(wolfSSL_get_verify_mode(ssl), WOLFSSL_VERIFY_NONE); + + wolfSSL_set_verify(ssl, WOLFSSL_VERIFY_PEER, NULL); + ExpectIntEQ(wolfSSL_get_verify_mode(ssl), WOLFSSL_VERIFY_PEER); + + wolfSSL_set_verify(ssl, WOLFSSL_VERIFY_PEER | + WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); + ExpectIntEQ(wolfSSL_get_verify_mode(ssl), + WOLFSSL_VERIFY_PEER | WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT); + + /* Exercise the fail-except-PSK option. */ + wolfSSL_set_verify(ssl, WOLFSSL_VERIFY_FAIL_EXCEPT_PSK, NULL); + mode = wolfSSL_get_verify_mode(ssl); + ExpectIntEQ(mode & WOLFSSL_VERIFY_FAIL_EXCEPT_PSK, + WOLFSSL_VERIFY_FAIL_EXCEPT_PSK); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_CTX_get_verify_mode(void) +{ + EXPECT_DECLS; +#if (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) || defined(HAVE_STUNNEL) || \ + defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(WOLFSSL_NGINX)) && \ + !defined(NO_CERTS) && !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + int mode; + + ExpectIntEQ(wolfSSL_CTX_get_verify_mode(NULL), WOLFSSL_FAILURE); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + + wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_NONE, NULL); + ExpectIntEQ(wolfSSL_CTX_get_verify_mode(ctx), WOLFSSL_VERIFY_NONE); + + wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER | + WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); + ExpectIntEQ(wolfSSL_CTX_get_verify_mode(ctx), + WOLFSSL_VERIFY_PEER | WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT); + + wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_FAIL_EXCEPT_PSK, NULL); + mode = wolfSSL_CTX_get_verify_mode(ctx); + ExpectIntEQ(mode & WOLFSSL_VERIFY_FAIL_EXCEPT_PSK, + WOLFSSL_VERIFY_FAIL_EXCEPT_PSK); + +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) + /* Exercise the post-handshake auth option. */ + wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER | + WOLFSSL_VERIFY_POST_HANDSHAKE, NULL); + mode = wolfSSL_CTX_get_verify_mode(ctx); + ExpectIntEQ(mode & WOLFSSL_VERIFY_POST_HANDSHAKE, + WOLFSSL_VERIFY_POST_HANDSHAKE); +#endif + + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +#if defined(OPENSSL_ALL) && !defined(NO_CERTS) && !defined(NO_WOLFSSL_CLIENT) +static int test_cert_verify_cb(int preverify, WOLFSSL_X509_STORE_CTX* store) +{ + (void)store; + return preverify; +} +#endif + +int test_wolfSSL_get_verify_callback(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_ALL) && !defined(NO_CERTS) && !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + /* CTX verify callback getter. */ + ExpectNull(wolfSSL_CTX_get_verify_callback(NULL)); + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNull(wolfSSL_CTX_get_verify_callback(ctx)); + wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER, test_cert_verify_cb); + ExpectTrue(wolfSSL_CTX_get_verify_callback(ctx) == test_cert_verify_cb); + + /* SSL verify callback getter. */ + ExpectNull(wolfSSL_get_verify_callback(NULL)); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + wolfSSL_set_verify(ssl, WOLFSSL_VERIFY_PEER, test_cert_verify_cb); + ExpectTrue(wolfSSL_get_verify_callback(ssl) == test_cert_verify_cb); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_CTX_get_extra_chain_certs(void) +{ + EXPECT_DECLS; +#if (defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || \ + defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL)) && \ + !defined(NO_CERTS) && !defined(NO_FILESYSTEM) && !defined(NO_RSA) && \ + !defined(NO_WOLFSSL_SERVER) + WOLFSSL_CTX* ctx = NULL; + WOLF_STACK_OF(WOLFSSL_X509)* sk = NULL; + + /* NULL arguments fail. */ + ExpectIntEQ(wolfSSL_CTX_get_extra_chain_certs(NULL, &sk), WOLFSSL_FAILURE); + + /* No certificate chain loaded: succeeds with an empty (NULL) stack. */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); + sk = NULL; + ExpectIntEQ(wolfSSL_CTX_get_extra_chain_certs(ctx, &sk), WOLFSSL_SUCCESS); + ExpectNull(sk); + wolfSSL_CTX_free(ctx); + ctx = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); + /* server-cert.pem holds a 2-cert chain, so the CA goes into certChain. */ + ExpectIntEQ(wolfSSL_CTX_use_certificate_chain_file(ctx, svrCertFile), + WOLFSSL_SUCCESS); + + /* Builds a stack of X509 from the stored chain. */ + sk = NULL; + ExpectIntEQ(wolfSSL_CTX_get_extra_chain_certs(ctx, &sk), WOLFSSL_SUCCESS); + ExpectNotNull(sk); + + /* get0 returns the same (cached) chain. */ + sk = NULL; + ExpectIntEQ(wolfSSL_CTX_get0_chain_certs(ctx, &sk), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_get0_chain_certs(NULL, &sk), WOLFSSL_FAILURE); + + wolfSSL_CTX_free(ctx); + ctx = NULL; + + /* A longer chain (leaf + 2 certs) exercises appending past the first + * node, building a multi-element stack. */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); + ExpectIntEQ(wolfSSL_CTX_use_certificate_chain_file(ctx, + "certs/intermediate/server-chain.pem"), WOLFSSL_SUCCESS); + sk = NULL; + ExpectIntEQ(wolfSSL_CTX_get_extra_chain_certs(ctx, &sk), WOLFSSL_SUCCESS); + ExpectNotNull(sk); + ExpectIntGE(wolfSSL_sk_X509_num(sk), 2); + +#if (defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || \ + defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_NGINX) || \ + defined(WOLFSSL_QT)) && !defined(NO_WOLFSSL_STUB) + /* Stub: returns via the control command. */ + wolfSSL_CTX_clear_extra_chain_certs(ctx); +#endif + + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_get_peer_chain(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(SESSION_CERTS) && \ + !defined(WOLFSSL_NO_TLS12) && !defined(NO_RSA) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + WOLFSSL_X509_CHAIN* chain = NULL; + + /* NULL / not-yet-populated cases. */ + ExpectNull(wolfSSL_get_peer_chain(NULL)); + ExpectIntEQ(wolfSSL_get_chain_count(NULL), 0); + ExpectIntEQ(wolfSSL_get_chain_length(NULL, 0), 0); + ExpectNull(wolfSSL_get_chain_cert(NULL, 0)); + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + /* The client now holds the server's certificate chain. */ + ExpectNotNull(chain = wolfSSL_get_peer_chain(ssl_c)); + ExpectIntGT(wolfSSL_get_chain_count(chain), 0); + ExpectIntGT(wolfSSL_get_chain_length(chain, 0), 0); + ExpectNotNull(wolfSSL_get_chain_cert(chain, 0)); + +#ifdef WOLFSSL_ALT_CERT_CHAINS + ExpectNull(wolfSSL_get_peer_alt_chain(NULL)); + ExpectNotNull(wolfSSL_get_peer_alt_chain(ssl_c)); +#endif + +#if (defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || \ + defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL)) && defined(KEEP_OUR_CERT) + { + WOLF_STACK_OF(WOLFSSL_X509)* osk = NULL; + ExpectIntEQ(wolfSSL_get0_chain_certs(NULL, &osk), WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_get0_chain_certs(ssl_c, &osk), WOLFSSL_SUCCESS); + } +#endif + + wolfSSL_free(ssl_s); + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_s); + wolfSSL_CTX_free(ctx_c); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_get_chain_X509(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(SESSION_CERTS) && \ + !defined(WOLFSSL_NO_TLS12) && !defined(NO_RSA) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + WOLFSSL_X509_CHAIN* chain = NULL; + WOLFSSL_X509* x509 = NULL; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + ExpectNotNull(chain = wolfSSL_get_peer_chain(ssl_c)); + + /* A valid index returns a parseable certificate. */ + ExpectNotNull(x509 = wolfSSL_get_chain_X509(chain, 0)); + wolfSSL_X509_free(x509); + x509 = NULL; + /* NULL chain and an index past MAX_CHAIN_DEPTH return NULL up front. */ + ExpectNull(wolfSSL_get_chain_X509(NULL, 0)); + ExpectNull(wolfSSL_get_chain_X509(chain, MAX_CHAIN_DEPTH)); + /* An index past the populated certs exercises the parse-failure path. */ + ExpectNull(wolfSSL_get_chain_X509(chain, wolfSSL_get_chain_count(chain))); + + wolfSSL_free(ssl_s); + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_s); + wolfSSL_CTX_free(ctx_c); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_get_chain_cert_pem(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(SESSION_CERTS) && \ + !defined(WOLFSSL_NO_TLS12) && !defined(NO_RSA) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + WOLFSSL_X509_CHAIN* chain = NULL; + byte pem[4096]; + int pemSz = 0; + int needed = 0; + int chainLen = 0; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + ExpectNotNull(chain = wolfSSL_get_peer_chain(ssl_c)); + + /* Successful PEM conversion. */ + pemSz = (int)sizeof(pem); + ExpectIntEQ(wolfSSL_get_chain_cert_pem(chain, 0, pem, (int)sizeof(pem), + &pemSz), WOLFSSL_SUCCESS); + ExpectIntGT(pemSz, 0); + + /* Argument validation. */ + pemSz = (int)sizeof(pem); + ExpectIntEQ(wolfSSL_get_chain_cert_pem(NULL, 0, pem, (int)sizeof(pem), + &pemSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_get_chain_cert_pem(chain, -1, pem, (int)sizeof(pem), + &pemSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_get_chain_cert_pem(chain, 99, pem, (int)sizeof(pem), + &pemSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_get_chain_cert_pem(chain, 0, pem, (int)sizeof(pem), + NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* NULL buffer returns the size needed (length-only query). */ + needed = 0; + ExpectIntEQ(wolfSSL_get_chain_cert_pem(chain, 0, NULL, 0, &needed), + WC_NO_ERR_TRACE(LENGTH_ONLY_E)); + ExpectIntGT(needed, 0); + ExpectIntLE(needed, (int)sizeof(pem)); + + /* A buffer shorter than the DER certificate fails up front. */ + pemSz = (int)sizeof(pem); + ExpectIntEQ(wolfSSL_get_chain_cert_pem(chain, 0, pem, 1, &pemSz), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* One byte short of the full size leaves no room for the footer. */ + pemSz = (int)sizeof(pem); + ExpectIntEQ(wolfSSL_get_chain_cert_pem(chain, 0, pem, needed - 1, &pemSz), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* Room for the DER length but not the base64-expanded body: the encoder + * reports an error (negative return). */ + chainLen = wolfSSL_get_chain_length(chain, 0); + pemSz = (int)sizeof(pem); + ExpectIntLT(wolfSSL_get_chain_cert_pem(chain, 0, pem, chainLen + 100, + &pemSz), 0); + + wolfSSL_free(ssl_s); + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_s); + wolfSSL_CTX_free(ctx_c); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_cmp_peer_cert_to_file(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(OPENSSL_EXTRA) && \ + defined(KEEP_PEER_CERT) && defined(HAVE_EX_DATA) && \ + !defined(NO_FILESYSTEM) && !defined(WOLFSSL_NO_TLS12) && !defined(NO_RSA) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + /* NULL arguments report failure. */ + ExpectIntEQ(wolfSSL_cmp_peer_cert_to_file(NULL, svrCertFile), + WOLFSSL_FATAL_ERROR); + ExpectIntEQ(wolfSSL_cmp_peer_cert_to_file(ssl_c, NULL), + WOLFSSL_FATAL_ERROR); + + /* The peer (server) certificate matches the file it was loaded from. */ + ExpectIntEQ(wolfSSL_cmp_peer_cert_to_file(ssl_c, svrCertFile), 0); + /* A different certificate does not match. */ + ExpectIntEQ(wolfSSL_cmp_peer_cert_to_file(ssl_c, caCertFile), + WOLFSSL_FATAL_ERROR); + /* A missing file reports a file error. */ + ExpectIntEQ(wolfSSL_cmp_peer_cert_to_file(ssl_c, + "certs/does-not-exist.pem"), WC_NO_ERR_TRACE(WOLFSSL_BAD_FILE)); + /* A readable file that is not PEM-encoded fails conversion. */ + ExpectIntEQ(wolfSSL_cmp_peer_cert_to_file(ssl_c, cliCertDerFile), + WOLFSSL_FATAL_ERROR); + + wolfSSL_free(ssl_s); + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_s); + wolfSSL_CTX_free(ctx_c); +#endif + return EXPECT_RESULT(); +} diff --git a/tests/api/test_ssl_cert.h b/tests/api/test_ssl_cert.h new file mode 100644 index 0000000000..ed459891e2 --- /dev/null +++ b/tests/api/test_ssl_cert.h @@ -0,0 +1,44 @@ +/* test_ssl_cert.h + * + * 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 + */ + +#ifndef TESTS_API_SSL_CERT_H +#define TESTS_API_SSL_CERT_H + +int test_wolfSSL_get_verify_mode(void); +int test_wolfSSL_CTX_get_verify_mode(void); +int test_wolfSSL_get_verify_callback(void); +int test_wolfSSL_CTX_get_extra_chain_certs(void); +int test_wolfSSL_get_peer_chain(void); +int test_wolfSSL_get_chain_X509(void); +int test_wolfSSL_get_chain_cert_pem(void); +int test_wolfSSL_cmp_peer_cert_to_file(void); + +#define TEST_SSL_CERT_DECLS \ + TEST_DECL_GROUP("ssl_cert", test_wolfSSL_get_verify_mode), \ + TEST_DECL_GROUP("ssl_cert", test_wolfSSL_CTX_get_verify_mode), \ + TEST_DECL_GROUP("ssl_cert", test_wolfSSL_get_verify_callback), \ + TEST_DECL_GROUP("ssl_cert", test_wolfSSL_CTX_get_extra_chain_certs), \ + TEST_DECL_GROUP("ssl_cert", test_wolfSSL_get_peer_chain), \ + TEST_DECL_GROUP("ssl_cert", test_wolfSSL_get_chain_X509), \ + TEST_DECL_GROUP("ssl_cert", test_wolfSSL_get_chain_cert_pem), \ + TEST_DECL_GROUP("ssl_cert", test_wolfSSL_cmp_peer_cert_to_file) + +#endif /* TESTS_API_SSL_CERT_H */ diff --git a/tests/api/test_ssl_ext.c b/tests/api/test_ssl_ext.c new file mode 100644 index 0000000000..9d0eda9868 --- /dev/null +++ b/tests/api/test_ssl_ext.c @@ -0,0 +1,688 @@ +/* test_ssl_ext.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 + +#ifdef NO_INLINE + #include +#else + #define WOLFSSL_MISC_INCLUDED + #include +#endif + +#include +#include + +#include +#include + +/* Tests for the TLS extension APIs in src/ssl_api_ext.c (moved from ssl.c). + * These cover functions not already exercised elsewhere in api.c. */ + +int test_wolfSSL_NoTicketTLSv12_ext(void) +{ + EXPECT_DECLS; +#if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_SERVER) && \ + (defined(NO_CERTS) || !defined(NO_RSA)) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + /* NULL arguments are rejected. */ + ExpectIntEQ(wolfSSL_CTX_NoTicketTLSv12(NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_NoTicketTLSv12(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); + ExpectIntEQ(wolfSSL_CTX_NoTicketTLSv12(ctx), WOLFSSL_SUCCESS); +#ifndef NO_CERTS + /* A server WOLFSSL needs a key and certificate set on the context. */ + ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, CERT_FILETYPE), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile, + CERT_FILETYPE), WOLFSSL_SUCCESS); +#endif + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntEQ(wolfSSL_NoTicketTLSv12(ssl), WOLFSSL_SUCCESS); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_CTX_UseMaxFragment_ext(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MAX_FRAGMENT) && !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + + /* NULL context is rejected. */ + ExpectIntEQ(wolfSSL_CTX_UseMaxFragment(NULL, WOLFSSL_MFL_2_9), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectIntEQ(wolfSSL_CTX_UseMaxFragment(ctx, WOLFSSL_MFL_2_9), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_UseMaxFragment(ctx, WOLFSSL_MFL_2_12), + WOLFSSL_SUCCESS); + + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_CTX_num_tickets_ext(void) +{ + EXPECT_DECLS; +#if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TLS13) && \ + !defined(NO_WOLFSSL_SERVER) + WOLFSSL_CTX* ctx = NULL; + + /* NULL context: set fails, get returns zero. */ + ExpectIntEQ(wolfSSL_CTX_set_num_tickets(NULL, 5), WOLFSSL_FAILURE); + ExpectIntEQ((int)wolfSSL_CTX_get_num_tickets(NULL), 0); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); + ExpectIntEQ(wolfSSL_CTX_set_num_tickets(ctx, 3), WOLFSSL_SUCCESS); + ExpectIntEQ((int)wolfSSL_CTX_get_num_tickets(ctx), 3); + + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_set1_groups_ext(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && defined(HAVE_SUPPORTED_CURVES) && \ + !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + int dummy[1]; +#ifdef HAVE_ECC + int groups[1]; +#endif + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* A zero or too-large group count is rejected. */ + ExpectIntEQ(wolfSSL_CTX_set1_groups(ctx, dummy, 0), WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_CTX_set1_groups(ctx, dummy, + WOLFSSL_MAX_GROUP_COUNT + 1), WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_set1_groups(ssl, dummy, 0), WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_set1_groups(ssl, dummy, + WOLFSSL_MAX_GROUP_COUNT + 1), WOLFSSL_FAILURE); + +#ifdef HAVE_ECC + /* A valid named group succeeds. */ + groups[0] = WOLFSSL_ECC_SECP256R1; + ExpectIntEQ(wolfSSL_CTX_set1_groups(ctx, groups, 1), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set1_groups(ssl, groups, 1), WOLFSSL_SUCCESS); +#endif + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_set1_groups_list_ext(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && defined(HAVE_ECC) && defined(WOLFSSL_TLS13) && \ + defined(HAVE_SUPPORTED_CURVES) && !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + /* NULL arguments are rejected. */ + ExpectIntEQ(wolfSSL_CTX_set1_groups_list(NULL, "P-256"), WOLFSSL_FAILURE); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + ExpectIntEQ(wolfSSL_CTX_set1_groups_list(ctx, NULL), WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_set1_groups_list(ssl, NULL), WOLFSSL_FAILURE); + + /* A known group name succeeds. */ + ExpectIntEQ(wolfSSL_CTX_set1_groups_list(ctx, "P-256"), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set1_groups_list(ssl, "P-256"), WOLFSSL_SUCCESS); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_CTX_set_TicketHint_ext(void) +{ + EXPECT_DECLS; +#if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_SERVER) + WOLFSSL_CTX* ctx = NULL; + + ExpectIntEQ(wolfSSL_CTX_set_TicketHint(NULL, 100), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); + /* RFC 8446 caps the hint at 604800 seconds (7 days). */ + ExpectIntEQ(wolfSSL_CTX_set_TicketHint(ctx, -1), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_CTX_set_TicketHint(ctx, 604801), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_CTX_set_TicketHint(ctx, 0), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_set_TicketHint(ctx, 604800), WOLFSSL_SUCCESS); + + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_tlsext_max_fragment_length_ext(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && defined(HAVE_MAX_FRAGMENT) && \ + !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectIntEQ(wolfSSL_CTX_set_tlsext_max_fragment_length(NULL, + WOLFSSL_MFL_2_9), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* Modes outside the WOLFSSL_MFL_2_9..WOLFSSL_MFL_2_12 range are rejected. */ + ExpectIntEQ(wolfSSL_CTX_set_tlsext_max_fragment_length(ctx, + WOLFSSL_MFL_2_9 - 1), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_CTX_set_tlsext_max_fragment_length(ctx, + WOLFSSL_MFL_2_12 + 1), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_CTX_set_tlsext_max_fragment_length(ctx, + WOLFSSL_MFL_2_9), WOLFSSL_SUCCESS); + + ExpectIntEQ(wolfSSL_set_tlsext_max_fragment_length(NULL, WOLFSSL_MFL_2_9), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_set_tlsext_max_fragment_length(ssl, WOLFSSL_MFL_2_12), + WOLFSSL_SUCCESS); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_DisableExtendedMasterSecret_ext(void) +{ + EXPECT_DECLS; +#if defined(HAVE_EXTENDED_MASTER) && !defined(NO_WOLFSSL_CLIENT) && \ + !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectIntEQ(wolfSSL_CTX_DisableExtendedMasterSecret(NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_DisableExtendedMasterSecret(NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectIntEQ(wolfSSL_CTX_DisableExtendedMasterSecret(ctx), WOLFSSL_SUCCESS); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntEQ(wolfSSL_DisableExtendedMasterSecret(ssl), WOLFSSL_SUCCESS); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_set_tlsext_host_name_ext(void) +{ + EXPECT_DECLS; +#if (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) && defined(HAVE_SNI) && \ + !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + ExpectIntEQ(wolfSSL_set_tlsext_host_name(ssl, "localhost"), + WOLFSSL_SUCCESS); +#ifndef NO_WOLFSSL_SERVER + /* On the client the host name just set is returned. */ + ExpectStrEQ(wolfSSL_get_servername(ssl, WOLFSSL_SNI_HOST_NAME), + "localhost"); + ExpectNull(wolfSSL_get_servername(NULL, WOLFSSL_SNI_HOST_NAME)); +#endif + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_CTX_set_tlsext_servername_callback_ext(void) +{ + EXPECT_DECLS; +#if (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) && defined(HAVE_SNI) && \ + !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + + ExpectIntEQ(wolfSSL_CTX_set_tlsext_servername_callback(NULL, NULL), + WOLFSSL_FAILURE); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectIntEQ(wolfSSL_CTX_set_tlsext_servername_callback(ctx, NULL), + WOLFSSL_SUCCESS); + + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_set_tlsext_debug_arg_ext(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && defined(HAVE_PK_CALLBACKS) && \ + !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + int arg = 0; + + ExpectIntEQ(wolfSSL_set_tlsext_debug_arg(NULL, &arg), WOLFSSL_FAILURE); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntEQ(wolfSSL_set_tlsext_debug_arg(ssl, &arg), WOLFSSL_SUCCESS); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_set_SessionTicket_cb_ext(void) +{ + EXPECT_DECLS; +#if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectIntEQ(wolfSSL_set_SessionTicket_cb(NULL, NULL, NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntEQ(wolfSSL_set_SessionTicket_cb(ssl, NULL, NULL), + WOLFSSL_SUCCESS); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_set1_curves_list_ext(void) +{ + EXPECT_DECLS; +#if (defined(OPENSSL_EXTRA) || defined(HAVE_CURL)) && \ + (defined(HAVE_ECC) || defined(HAVE_CURVE25519) || defined(HAVE_CURVE448)) \ + && !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* NULL object or list is rejected. */ + ExpectIntEQ(wolfSSL_set1_curves_list(NULL, "P-256"), WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_set1_curves_list(ssl, NULL), WOLFSSL_FAILURE); +#ifdef HAVE_ECC + ExpectIntEQ(wolfSSL_set1_curves_list(ssl, "P-256"), WOLFSSL_SUCCESS); +#endif + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_SecureResume_ext(void) +{ + EXPECT_DECLS; +#if defined(HAVE_SECURE_RENEGOTIATION) && !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectIntEQ(wolfSSL_SecureResume(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + /* Secure renegotiation has not been forced on, so resume is refused. */ + ExpectIntEQ(wolfSSL_SecureResume(ssl), + WC_NO_ERR_TRACE(SECURE_RENEGOTIATION_E)); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_CTX_UseSecureRenegotiation_ext(void) +{ + EXPECT_DECLS; +#if defined(HAVE_SERVER_RENEGOTIATION_INFO) && !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + + /* NULL context is rejected. */ + ExpectIntEQ(wolfSSL_CTX_UseSecureRenegotiation(NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectIntEQ(wolfSSL_CTX_UseSecureRenegotiation(ctx), WOLFSSL_SUCCESS); + + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_next_proto_cb_ext(void) +{ + EXPECT_DECLS; +#if (defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || \ + defined(WOLFSSL_HAPROXY) || defined(HAVE_LIGHTY) || \ + defined(WOLFSSL_QUIC)) && defined(HAVE_ALPN) && \ + !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + const unsigned char* data = NULL; + unsigned int len = 0; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* These NPN APIs are no-op stubs for OpenSSL compatibility. Exercise + * them to confirm they accept NULL callbacks without crashing. */ + wolfSSL_CTX_set_next_protos_advertised_cb(ctx, NULL, NULL); + wolfSSL_CTX_set_next_proto_select_cb(ctx, NULL, NULL); + wolfSSL_get0_next_proto_negotiated(ssl, &data, &len); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_tlsext_status_exts_ids_ext(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_WOLFSSL_STUB) && \ + !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* These status_request extension/id APIs are unimplemented stubs that + * always report failure. */ + ExpectIntEQ(wolfSSL_get_tlsext_status_exts(ssl, NULL), WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_set_tlsext_status_exts(ssl, NULL), WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_get_tlsext_status_ids(ssl, NULL), WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_set_tlsext_status_ids(ssl, NULL), WOLFSSL_FAILURE); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_SNI_GetFromBuffer_inval_ext(void) +{ + EXPECT_DECLS; +#if defined(HAVE_SNI) && !defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS) + byte sni[32]; + word32 sniSz = (word32)sizeof(sni); + byte hello[8] = { 0 }; + + /* A NULL ClientHello buffer is rejected. */ + ExpectIntEQ(wolfSSL_SNI_GetFromBuffer(NULL, (word32)sizeof(hello), 0, sni, + &sniSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_UseTrustedCA_inval_ext(void) +{ + EXPECT_DECLS; +#if defined(HAVE_TRUSTED_CA) && !defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + const byte id[1] = { 0 }; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* The pre-agreed type must not carry an identifier. */ + ExpectIntEQ(wolfSSL_UseTrustedCA(ssl, WOLFSSL_TRUSTED_CA_PRE_AGREED, id, 1), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_UseMaxFragment_inval_ext(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MAX_FRAGMENT) && !defined(NO_WOLFSSL_CLIENT) && \ + !defined(NO_TLS) + /* A NULL object is rejected. */ + ExpectIntEQ(wolfSSL_UseMaxFragment(NULL, WOLFSSL_MFL_2_9), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_set1_groups_inval_ext(void) +{ + EXPECT_DECLS; +#if defined(HAVE_SUPPORTED_CURVES) && defined(OPENSSL_EXTRA) && \ + defined(HAVE_ECC) && !defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + int badGroups[1]; + + badGroups[0] = 0xFFFE; /* neither a named group nor a valid curve NID */ + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* An unrecognized group identifier is rejected. */ + ExpectIntEQ(wolfSSL_set1_groups(ssl, badGroups, 1), WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_CTX_set1_groups(ctx, badGroups, 1), WOLFSSL_FAILURE); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_UseALPN_inval_ext(void) +{ + EXPECT_DECLS; +#if defined(HAVE_ALPN) && !defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + char proto[] = "h2"; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* A protocol-list length beyond the maximum is rejected. */ + ExpectIntEQ(wolfSSL_UseALPN(ssl, proto, + (word32)(WOLFSSL_MAX_ALPN_NUMBER * WOLFSSL_MAX_ALPN_PROTO_NAME_LEN + + WOLFSSL_MAX_ALPN_NUMBER + 1), + WOLFSSL_ALPN_CONTINUE_ON_MISMATCH), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + /* No mismatch option set is rejected. */ + ExpectIntEQ(wolfSSL_UseALPN(ssl, proto, (word32)XSTRLEN(proto), 0), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_ALPN_GetPeerProtocol_inval_ext(void) +{ + EXPECT_DECLS; +#if defined(HAVE_ALPN) && !defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + char* list = NULL; + word16 listSz = 0; + + /* NULL arguments are rejected. */ + ExpectIntEQ(wolfSSL_ALPN_GetPeerProtocol(NULL, &list, &listSz), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_ALPN_FreePeerProtocol(NULL, &list), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* The peer has not offered any protocols yet. */ + ExpectIntEQ(wolfSSL_ALPN_GetPeerProtocol(ssl, &list, &listSz), + WC_NO_ERR_TRACE(BUFFER_ERROR)); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_CTX_set_TicketEncCb_inval_ext(void) +{ + EXPECT_DECLS; +#if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_SERVER) && \ + !defined(NO_TLS) + /* A NULL context is rejected. */ + ExpectIntEQ(wolfSSL_CTX_set_TicketEncCb(NULL, NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_SessionTicket_inval_ext(void) +{ + EXPECT_DECLS; +#if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_CLIENT) && \ + !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + byte tick[8] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + byte out[8]; + word32 outSz; + byte big[4096]; + + XMEMSET(big, 0x5a, sizeof(big)); + + /* NULL object checks. */ + ExpectIntEQ(wolfSSL_UseSessionTicket(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_CTX_UseSessionTicket(NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_set_SessionTicket(NULL, tick, (word32)sizeof(tick)), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* set: a non-zero size with a NULL buffer is rejected. */ + ExpectIntEQ(wolfSSL_set_SessionTicket(ssl, NULL, 4), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + /* get: NULL object and NULL buffer with non-zero size are rejected. */ + outSz = (word32)sizeof(out); + ExpectIntEQ(wolfSSL_get_SessionTicket(NULL, out, &outSz), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + outSz = (word32)sizeof(out); + ExpectIntEQ(wolfSSL_get_SessionTicket(ssl, NULL, &outSz), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* Store a short ticket (static-buffer path). */ + ExpectIntEQ(wolfSSL_set_SessionTicket(ssl, tick, (word32)sizeof(tick)), + WOLFSSL_SUCCESS); + /* Retrieving into a buffer that is too small reports zero length. */ + outSz = 2; + ExpectIntEQ(wolfSSL_get_SessionTicket(ssl, out, &outSz), WOLFSSL_SUCCESS); + ExpectIntEQ(outSz, 0); + + /* A ticket larger than the static buffer (SESSION_TICKET_LEN) uses + * dynamic storage; growing it again frees the previous allocation, and a + * later short ticket returns to the static buffer. */ + ExpectIntEQ(wolfSSL_set_SessionTicket(ssl, big, 3000), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_SessionTicket(ssl, big, 4000), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_SessionTicket(ssl, tick, (word32)sizeof(tick)), + WOLFSSL_SUCCESS); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_CTX_set_servername_arg_inval_ext(void) +{ + EXPECT_DECLS; +#if defined(HAVE_SNI) + /* A NULL context is rejected. */ + ExpectIntEQ(wolfSSL_CTX_set_servername_arg(NULL, NULL), WOLFSSL_FAILURE); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_CTX_set_alpn_protos_inval_ext(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + const unsigned char protos[] = { 2, 'h', '2' }; +#if defined(WOLFSSL_ERROR_CODE_OPENSSL) + const int good = 0; +#else + const int good = WOLFSSL_SUCCESS; +#endif + + /* A NULL context is rejected. */ + ExpectIntEQ(wolfSSL_CTX_set_alpn_protos(NULL, protos, (unsigned int) + sizeof(protos)), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + /* Setting twice exercises the free-previous-list path. */ + ExpectIntEQ(wolfSSL_CTX_set_alpn_protos(ctx, protos, + (unsigned int)sizeof(protos)), good); + ExpectIntEQ(wolfSSL_CTX_set_alpn_protos(ctx, protos, + (unsigned int)sizeof(protos)), good); + + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} diff --git a/tests/api/test_ssl_ext.h b/tests/api/test_ssl_ext.h new file mode 100644 index 0000000000..ffb42f5fc8 --- /dev/null +++ b/tests/api/test_ssl_ext.h @@ -0,0 +1,92 @@ +/* test_ssl_ext.h + * + * 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 + */ + +#ifndef TESTS_API_SSL_EXT_H +#define TESTS_API_SSL_EXT_H + +int test_wolfSSL_NoTicketTLSv12_ext(void); +int test_wolfSSL_CTX_UseMaxFragment_ext(void); +int test_wolfSSL_CTX_num_tickets_ext(void); +int test_wolfSSL_set1_groups_ext(void); +int test_wolfSSL_set1_groups_list_ext(void); +int test_wolfSSL_CTX_set_TicketHint_ext(void); +int test_wolfSSL_tlsext_max_fragment_length_ext(void); +int test_wolfSSL_DisableExtendedMasterSecret_ext(void); +int test_wolfSSL_set_tlsext_host_name_ext(void); +int test_wolfSSL_CTX_set_tlsext_servername_callback_ext(void); +int test_wolfSSL_set_tlsext_debug_arg_ext(void); +int test_wolfSSL_set_SessionTicket_cb_ext(void); +int test_wolfSSL_set1_curves_list_ext(void); +int test_wolfSSL_SecureResume_ext(void); +int test_wolfSSL_CTX_UseSecureRenegotiation_ext(void); +int test_wolfSSL_next_proto_cb_ext(void); +int test_wolfSSL_tlsext_status_exts_ids_ext(void); +int test_wolfSSL_SNI_GetFromBuffer_inval_ext(void); +int test_wolfSSL_UseTrustedCA_inval_ext(void); +int test_wolfSSL_UseMaxFragment_inval_ext(void); +int test_wolfSSL_set1_groups_inval_ext(void); +int test_wolfSSL_UseALPN_inval_ext(void); +int test_wolfSSL_ALPN_GetPeerProtocol_inval_ext(void); +int test_wolfSSL_CTX_set_TicketEncCb_inval_ext(void); +int test_wolfSSL_SessionTicket_inval_ext(void); +int test_wolfSSL_CTX_set_servername_arg_inval_ext(void); +int test_wolfSSL_CTX_set_alpn_protos_inval_ext(void); + +#define TEST_SSL_EXT_DECLS \ + TEST_DECL_GROUP("ssl_ext", test_wolfSSL_NoTicketTLSv12_ext), \ + TEST_DECL_GROUP("ssl_ext", test_wolfSSL_CTX_UseMaxFragment_ext), \ + TEST_DECL_GROUP("ssl_ext", test_wolfSSL_CTX_num_tickets_ext), \ + TEST_DECL_GROUP("ssl_ext", test_wolfSSL_set1_groups_ext), \ + TEST_DECL_GROUP("ssl_ext", test_wolfSSL_set1_groups_list_ext), \ + TEST_DECL_GROUP("ssl_ext", test_wolfSSL_CTX_set_TicketHint_ext), \ + TEST_DECL_GROUP("ssl_ext", \ + test_wolfSSL_tlsext_max_fragment_length_ext), \ + TEST_DECL_GROUP("ssl_ext", \ + test_wolfSSL_DisableExtendedMasterSecret_ext), \ + TEST_DECL_GROUP("ssl_ext", test_wolfSSL_set_tlsext_host_name_ext), \ + TEST_DECL_GROUP("ssl_ext", \ + test_wolfSSL_CTX_set_tlsext_servername_callback_ext), \ + TEST_DECL_GROUP("ssl_ext", test_wolfSSL_set_tlsext_debug_arg_ext), \ + TEST_DECL_GROUP("ssl_ext", test_wolfSSL_set_SessionTicket_cb_ext), \ + TEST_DECL_GROUP("ssl_ext", test_wolfSSL_set1_curves_list_ext), \ + TEST_DECL_GROUP("ssl_ext", test_wolfSSL_SecureResume_ext), \ + TEST_DECL_GROUP("ssl_ext", \ + test_wolfSSL_CTX_UseSecureRenegotiation_ext), \ + TEST_DECL_GROUP("ssl_ext", test_wolfSSL_next_proto_cb_ext), \ + TEST_DECL_GROUP("ssl_ext", \ + test_wolfSSL_tlsext_status_exts_ids_ext), \ + TEST_DECL_GROUP("ssl_ext", \ + test_wolfSSL_SNI_GetFromBuffer_inval_ext), \ + TEST_DECL_GROUP("ssl_ext", test_wolfSSL_UseTrustedCA_inval_ext), \ + TEST_DECL_GROUP("ssl_ext", test_wolfSSL_UseMaxFragment_inval_ext), \ + TEST_DECL_GROUP("ssl_ext", test_wolfSSL_set1_groups_inval_ext), \ + TEST_DECL_GROUP("ssl_ext", test_wolfSSL_UseALPN_inval_ext), \ + TEST_DECL_GROUP("ssl_ext", \ + test_wolfSSL_ALPN_GetPeerProtocol_inval_ext), \ + TEST_DECL_GROUP("ssl_ext", \ + test_wolfSSL_CTX_set_TicketEncCb_inval_ext), \ + TEST_DECL_GROUP("ssl_ext", test_wolfSSL_SessionTicket_inval_ext), \ + TEST_DECL_GROUP("ssl_ext", \ + test_wolfSSL_CTX_set_servername_arg_inval_ext), \ + TEST_DECL_GROUP("ssl_ext", \ + test_wolfSSL_CTX_set_alpn_protos_inval_ext) + +#endif /* TESTS_API_SSL_EXT_H */ diff --git a/tests/api/test_ssl_pk.c b/tests/api/test_ssl_pk.c new file mode 100644 index 0000000000..a05f0cdbbe --- /dev/null +++ b/tests/api/test_ssl_pk.c @@ -0,0 +1,567 @@ +/* test_ssl_pk.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 + +#ifdef NO_INLINE + #include +#else + #define WOLFSSL_MISC_INCLUDED + #include +#endif + +#include +#include +#include + +#include +#include + +/* Tests for the public-key APIs in src/ssl_api_pk.c (moved from ssl.c). */ + +int test_wolfSSL_CTX_SetMinEccKey_Sz(void) +{ + EXPECT_DECLS; +#if defined(HAVE_ECC) && !defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); + + /* NULL context and negative size are rejected. */ + ExpectIntEQ(wolfSSL_CTX_SetMinEccKey_Sz(NULL, 256), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_CTX_SetMinEccKey_Sz(ctx, -1), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* Multiple-of-8 and non-multiple-of-8 bit sizes both succeed. */ + ExpectIntEQ(wolfSSL_CTX_SetMinEccKey_Sz(ctx, 256), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_SetMinEccKey_Sz(ctx, 255), WOLFSSL_SUCCESS); + + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_SetMinEccKey_Sz(void) +{ + EXPECT_DECLS; +#if defined(HAVE_ECC) && !defined(NO_WOLFSSL_SERVER) && \ + (defined(NO_CERTS) || !defined(NO_RSA)) && !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); +#ifndef NO_CERTS + /* A server WOLFSSL needs a key and certificate set on the context. */ + ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, CERT_FILETYPE), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile, + CERT_FILETYPE), WOLFSSL_SUCCESS); +#endif + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* NULL object and negative size are rejected. */ + ExpectIntEQ(wolfSSL_SetMinEccKey_Sz(NULL, 256), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_SetMinEccKey_Sz(ssl, -1), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* Multiple-of-8 and non-multiple-of-8 bit sizes both succeed. */ + ExpectIntEQ(wolfSSL_SetMinEccKey_Sz(ssl, 256), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_SetMinEccKey_Sz(ssl, 255), WOLFSSL_SUCCESS); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_CTX_SetMinRsaKey_Sz(void) +{ + EXPECT_DECLS; +#if !defined(NO_RSA) && !defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); + + /* NULL context, negative size and non-multiple-of-8 size are rejected. */ + ExpectIntEQ(wolfSSL_CTX_SetMinRsaKey_Sz(NULL, 2048), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_CTX_SetMinRsaKey_Sz(ctx, -8), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_CTX_SetMinRsaKey_Sz(ctx, 1001), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectIntEQ(wolfSSL_CTX_SetMinRsaKey_Sz(ctx, 2048), WOLFSSL_SUCCESS); + + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_SetMinRsaKey_Sz(void) +{ + EXPECT_DECLS; +#if !defined(NO_RSA) && !defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); +#ifndef NO_CERTS + /* A server WOLFSSL needs a key and certificate set on the context. */ + ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, CERT_FILETYPE), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile, + CERT_FILETYPE), WOLFSSL_SUCCESS); +#endif + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* NULL object, negative size and non-multiple-of-8 size are rejected. */ + ExpectIntEQ(wolfSSL_SetMinRsaKey_Sz(NULL, 2048), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_SetMinRsaKey_Sz(ssl, -8), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_SetMinRsaKey_Sz(ssl, 1001), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectIntEQ(wolfSSL_SetMinRsaKey_Sz(ssl, 2048), WOLFSSL_SUCCESS); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_SetEnableDhKeyTest(void) +{ + EXPECT_DECLS; +#if !defined(NO_DH) && !defined(WOLFSSL_OLD_PRIME_CHECK) && \ + !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ + !defined(NO_WOLFSSL_SERVER) && (defined(NO_CERTS) || !defined(NO_RSA)) && \ + !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); +#ifndef NO_CERTS + /* A server WOLFSSL needs a key and certificate set on the context. */ + ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, CERT_FILETYPE), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile, + CERT_FILETYPE), WOLFSSL_SUCCESS); +#endif + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* NULL object is rejected. */ + ExpectIntEQ(wolfSSL_SetEnableDhKeyTest(NULL, 1), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* Disable then enable the prime test. */ + ExpectIntEQ(wolfSSL_SetEnableDhKeyTest(ssl, 0), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_SetEnableDhKeyTest(ssl, 1), WOLFSSL_SUCCESS); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_CTX_SetMinDhKey_Sz(void) +{ + EXPECT_DECLS; +#if !defined(NO_DH) && !defined(NO_WOLFSSL_SERVER) && \ + (defined(NO_CERTS) || !defined(NO_RSA)) && !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); + + /* NULL context, oversized and non-multiple-of-8 sizes are rejected. */ + ExpectIntEQ(wolfSSL_CTX_SetMinDhKey_Sz(NULL, 1024), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_CTX_SetMinDhKey_Sz(ctx, 16008), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_CTX_SetMinDhKey_Sz(ctx, 1001), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectIntEQ(wolfSSL_CTX_SetMinDhKey_Sz(ctx, 1024), WOLFSSL_SUCCESS); + + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_SetMinDhKey_Sz(void) +{ + EXPECT_DECLS; +#if !defined(NO_DH) && !defined(NO_WOLFSSL_SERVER) && \ + (defined(NO_CERTS) || !defined(NO_RSA)) && !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); +#ifndef NO_CERTS + /* A server WOLFSSL needs a key and certificate set on the context. */ + ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, CERT_FILETYPE), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile, + CERT_FILETYPE), WOLFSSL_SUCCESS); +#endif + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* NULL object, oversized and non-multiple-of-8 sizes are rejected. */ + ExpectIntEQ(wolfSSL_SetMinDhKey_Sz(NULL, 1024), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_SetMinDhKey_Sz(ssl, 16008), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_SetMinDhKey_Sz(ssl, 1001), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectIntEQ(wolfSSL_SetMinDhKey_Sz(ssl, 1024), WOLFSSL_SUCCESS); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_CTX_SetMaxDhKey_Sz(void) +{ + EXPECT_DECLS; +#if !defined(NO_DH) && !defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); + + /* NULL context, oversized and non-multiple-of-8 sizes are rejected. */ + ExpectIntEQ(wolfSSL_CTX_SetMaxDhKey_Sz(NULL, 4096), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_CTX_SetMaxDhKey_Sz(ctx, 16008), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_CTX_SetMaxDhKey_Sz(ctx, 1001), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectIntEQ(wolfSSL_CTX_SetMaxDhKey_Sz(ctx, 4096), WOLFSSL_SUCCESS); + + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_SetMaxDhKey_Sz(void) +{ + EXPECT_DECLS; +#if !defined(NO_DH) && !defined(NO_WOLFSSL_SERVER) && \ + (defined(NO_CERTS) || !defined(NO_RSA)) && !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); +#ifndef NO_CERTS + /* A server WOLFSSL needs a key and certificate set on the context. */ + ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, CERT_FILETYPE), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile, + CERT_FILETYPE), WOLFSSL_SUCCESS); +#endif + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* NULL object, oversized and non-multiple-of-8 sizes are rejected. */ + ExpectIntEQ(wolfSSL_SetMaxDhKey_Sz(NULL, 4096), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_SetMaxDhKey_Sz(ssl, 16008), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_SetMaxDhKey_Sz(ssl, 1001), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectIntEQ(wolfSSL_SetMaxDhKey_Sz(ssl, 4096), WOLFSSL_SUCCESS); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_GetDhKey_Sz(void) +{ + EXPECT_DECLS; +#if !defined(NO_DH) && !defined(NO_WOLFSSL_SERVER) && \ + (defined(NO_CERTS) || !defined(NO_RSA)) && !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); +#ifndef NO_CERTS + /* A server WOLFSSL needs a key and certificate set on the context. */ + ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, CERT_FILETYPE), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile, + CERT_FILETYPE), WOLFSSL_SUCCESS); +#endif + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* NULL object is rejected. */ + ExpectIntEQ(wolfSSL_GetDhKey_Sz(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* Valid object returns the negotiated size (0 before a handshake). */ + ExpectIntGE(wolfSSL_GetDhKey_Sz(ssl), 0); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_get_privatekey(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_WOLFSSL_STUB) + /* Stub for OpenSSL compatibility - always returns NULL. */ + ExpectNull(wolfSSL_get_privatekey(NULL)); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_get_signature_nid(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_WOLFSSL_SERVER) && \ + (defined(NO_CERTS) || !defined(NO_RSA)) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + int nid = 0; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); +#ifndef NO_CERTS + /* A server WOLFSSL needs a key and certificate set on the context. */ + ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, CERT_FILETYPE), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile, + CERT_FILETYPE), WOLFSSL_SUCCESS); +#endif + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* NULL object or output pointer is rejected. */ + ExpectIntEQ(wolfSSL_get_signature_nid(NULL, &nid), WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_get_signature_nid(ssl, NULL), WOLFSSL_FAILURE); + + /* Valid object maps the hash algorithm to a NID. */ + ExpectIntEQ(wolfSSL_get_signature_nid(ssl, &nid), WOLFSSL_SUCCESS); + + /* Drive every hash-algorithm case (HashToNid). */ + if (EXPECT_SUCCESS()) { + static const byte hashAlgos[] = { + no_mac, md5_mac, sha_mac, sha224_mac, sha256_mac, sha384_mac, + sha512_mac, rmd_mac, blake2b_mac, sm3_mac + }; + size_t i; + + for (i = 0; i < sizeof(hashAlgos) / sizeof(hashAlgos[0]); i++) { + ssl->options.hashAlgo = hashAlgos[i]; + ExpectIntEQ(wolfSSL_get_signature_nid(ssl, &nid), WOLFSSL_SUCCESS); + } + /* An unknown hash algorithm is rejected. */ + ssl->options.hashAlgo = 0xFF; + ExpectIntEQ(wolfSSL_get_signature_nid(ssl, &nid), WOLFSSL_FAILURE); + } + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_get_signature_type_nid(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_WOLFSSL_SERVER) && \ + (defined(NO_CERTS) || !defined(NO_RSA)) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + int nid = 0; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); +#ifndef NO_CERTS + /* A server WOLFSSL needs a key and certificate set on the context. */ + ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, CERT_FILETYPE), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile, + CERT_FILETYPE), WOLFSSL_SUCCESS); +#endif + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* NULL object or output pointer is rejected. */ + ExpectIntEQ(wolfSSL_get_signature_type_nid(NULL, &nid), WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_get_signature_type_nid(ssl, NULL), WOLFSSL_FAILURE); + + /* Valid object maps the signature algorithm to a NID. */ + ExpectIntEQ(wolfSSL_get_signature_type_nid(ssl, &nid), WOLFSSL_SUCCESS); + + /* Drive every signature-algorithm case (SaToNid). */ + if (EXPECT_SUCCESS()) { + static const byte okAlgos[] = { + anonymous_sa_algo, rsa_sa_algo, dsa_sa_algo, ecc_dsa_sa_algo, + ecc_brainpool_sa_algo, rsa_pss_sa_algo, rsa_pss_pss_algo, + falcon_level1_sa_algo, falcon_level5_sa_algo, mldsa_44_sa_algo, + mldsa_65_sa_algo, mldsa_87_sa_algo, sm2_sa_algo + }; + static const byte failAlgos[] = { invalid_sa_algo, any_sa_algo }; + size_t i; + + for (i = 0; i < sizeof(okAlgos) / sizeof(okAlgos[0]); i++) { + ssl->options.sigAlgo = okAlgos[i]; + ExpectIntEQ(wolfSSL_get_signature_type_nid(ssl, &nid), + WOLFSSL_SUCCESS); + } + /* Ed25519/Ed448 mappings depend on build configuration. */ + ssl->options.sigAlgo = ed25519_sa_algo; + #ifdef HAVE_ED25519 + ExpectIntEQ(wolfSSL_get_signature_type_nid(ssl, &nid), WOLFSSL_SUCCESS); + #else + ExpectIntEQ(wolfSSL_get_signature_type_nid(ssl, &nid), WOLFSSL_FAILURE); + #endif + ssl->options.sigAlgo = ed448_sa_algo; + #ifdef HAVE_ED448 + ExpectIntEQ(wolfSSL_get_signature_type_nid(ssl, &nid), WOLFSSL_SUCCESS); + #else + ExpectIntEQ(wolfSSL_get_signature_type_nid(ssl, &nid), WOLFSSL_FAILURE); + #endif + /* Unknown/placeholder algorithms are rejected. */ + for (i = 0; i < sizeof(failAlgos) / sizeof(failAlgos[0]); i++) { + ssl->options.sigAlgo = failAlgos[i]; + ExpectIntEQ(wolfSSL_get_signature_type_nid(ssl, &nid), + WOLFSSL_FAILURE); + } + } + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_get_peer_signature_nid(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_WOLFSSL_SERVER) && \ + (defined(NO_CERTS) || !defined(NO_RSA)) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + int nid = 0; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); +#ifndef NO_CERTS + /* A server WOLFSSL needs a key and certificate set on the context. */ + ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, CERT_FILETYPE), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile, + CERT_FILETYPE), WOLFSSL_SUCCESS); +#endif + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* NULL object or output pointer is rejected. */ + ExpectIntEQ(wolfSSL_get_peer_signature_nid(NULL, &nid), WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_get_peer_signature_nid(ssl, NULL), WOLFSSL_FAILURE); + + /* Valid object maps the peer's hash algorithm to a NID. */ + ExpectIntEQ(wolfSSL_get_peer_signature_nid(ssl, &nid), WOLFSSL_SUCCESS); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_get_peer_signature_type_nid(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_WOLFSSL_SERVER) && \ + (defined(NO_CERTS) || !defined(NO_RSA)) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + int nid = 0; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); +#ifndef NO_CERTS + /* A server WOLFSSL needs a key and certificate set on the context. */ + ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, CERT_FILETYPE), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile, + CERT_FILETYPE), WOLFSSL_SUCCESS); +#endif + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* NULL object or output pointer is rejected. */ + ExpectIntEQ(wolfSSL_get_peer_signature_type_nid(NULL, &nid), + WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_get_peer_signature_type_nid(ssl, NULL), + WOLFSSL_FAILURE); + + /* Valid object maps the peer's signature algorithm to a NID. */ + ExpectIntEQ(wolfSSL_get_peer_signature_type_nid(ssl, &nid), + WOLFSSL_SUCCESS); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_SSL_CTX_set_tmp_ecdh(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && defined(HAVE_ECC) && !defined(NO_WOLFSSL_SERVER) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL_EC_KEY* ecdh = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); + ExpectNotNull(ecdh = wolfSSL_EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)); + + /* NULL context or key is rejected. */ + ExpectIntEQ(wolfSSL_SSL_CTX_set_tmp_ecdh(NULL, ecdh), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_SSL_CTX_set_tmp_ecdh(ctx, NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* Valid key sets the curve. */ + ExpectIntEQ(wolfSSL_SSL_CTX_set_tmp_ecdh(ctx, ecdh), WOLFSSL_SUCCESS); + + wolfSSL_EC_KEY_free(ecdh); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_CTX_set_dh_auto(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_WOLFSSL_SERVER) + WOLFSSL_CTX* ctx = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); + + /* Compatibility stub - always succeeds. */ + ExpectIntEQ(wolfSSL_CTX_set_dh_auto(ctx, 0), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_set_dh_auto(ctx, 1), WOLFSSL_SUCCESS); + + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} diff --git a/tests/api/test_ssl_pk.h b/tests/api/test_ssl_pk.h new file mode 100644 index 0000000000..1a413bc926 --- /dev/null +++ b/tests/api/test_ssl_pk.h @@ -0,0 +1,62 @@ +/* test_ssl_pk.h + * + * 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 + */ + +#ifndef TESTS_API_SSL_PK_H +#define TESTS_API_SSL_PK_H + +int test_wolfSSL_CTX_SetMinEccKey_Sz(void); +int test_wolfSSL_SetMinEccKey_Sz(void); +int test_wolfSSL_CTX_SetMinRsaKey_Sz(void); +int test_wolfSSL_SetMinRsaKey_Sz(void); +int test_wolfSSL_SetEnableDhKeyTest(void); +int test_wolfSSL_CTX_SetMinDhKey_Sz(void); +int test_wolfSSL_SetMinDhKey_Sz(void); +int test_wolfSSL_CTX_SetMaxDhKey_Sz(void); +int test_wolfSSL_SetMaxDhKey_Sz(void); +int test_wolfSSL_GetDhKey_Sz(void); +int test_wolfSSL_get_privatekey(void); +int test_wolfSSL_get_signature_nid(void); +int test_wolfSSL_get_signature_type_nid(void); +int test_wolfSSL_get_peer_signature_nid(void); +int test_wolfSSL_get_peer_signature_type_nid(void); +int test_wolfSSL_SSL_CTX_set_tmp_ecdh(void); +int test_wolfSSL_CTX_set_dh_auto(void); + +#define TEST_SSL_PK_DECLS \ + TEST_DECL_GROUP("ssl_pk", test_wolfSSL_CTX_SetMinEccKey_Sz), \ + TEST_DECL_GROUP("ssl_pk", test_wolfSSL_SetMinEccKey_Sz), \ + TEST_DECL_GROUP("ssl_pk", test_wolfSSL_CTX_SetMinRsaKey_Sz), \ + TEST_DECL_GROUP("ssl_pk", test_wolfSSL_SetMinRsaKey_Sz), \ + TEST_DECL_GROUP("ssl_pk", test_wolfSSL_SetEnableDhKeyTest), \ + TEST_DECL_GROUP("ssl_pk", test_wolfSSL_CTX_SetMinDhKey_Sz), \ + TEST_DECL_GROUP("ssl_pk", test_wolfSSL_SetMinDhKey_Sz), \ + TEST_DECL_GROUP("ssl_pk", test_wolfSSL_CTX_SetMaxDhKey_Sz), \ + TEST_DECL_GROUP("ssl_pk", test_wolfSSL_SetMaxDhKey_Sz), \ + TEST_DECL_GROUP("ssl_pk", test_wolfSSL_GetDhKey_Sz), \ + TEST_DECL_GROUP("ssl_pk", test_wolfSSL_get_privatekey), \ + TEST_DECL_GROUP("ssl_pk", test_wolfSSL_get_signature_nid), \ + TEST_DECL_GROUP("ssl_pk", test_wolfSSL_get_signature_type_nid), \ + TEST_DECL_GROUP("ssl_pk", test_wolfSSL_get_peer_signature_nid), \ + TEST_DECL_GROUP("ssl_pk", test_wolfSSL_get_peer_signature_type_nid), \ + TEST_DECL_GROUP("ssl_pk", test_wolfSSL_SSL_CTX_set_tmp_ecdh), \ + TEST_DECL_GROUP("ssl_pk", test_wolfSSL_CTX_set_dh_auto) + +#endif /* TESTS_API_SSL_PK_H */