Files
wolfssl/src/ssl_api_dtls.c
T
Sean Parkinson 359e688dc3 ssl.c: Move functions out to own files and add testing
ssl_api_pk.c: added Public-key APIs (min/max key sizes, DH key test,
signature NIDs, tmp ecdh. Reworked code of new functions.
ssl_api_cert.c: added more SSL Certificate APIs. Reworked code of new
functions.
ssl_api_ext.c: TLS extension APIs (session tickets, max fragment,
groups, etc.). Reworked code.
ssl_api_dtls.c: DTLS APIs (cookie secret, etc.)

Improved test coverage for functions moved.
2026-06-10 09:11:59 +10:00

1463 lines
42 KiB
C

/* 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 <wolfssl/wolfcrypt/libwolfssl_sources.h>
#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 */