mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-06 07:30:50 +02:00
2423 lines
73 KiB
C
2423 lines
73 KiB
C
/* 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 <wolfssl/wolfcrypt/libwolfssl_sources.h>
|
|
|
|
#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)
|
|
{
|
|
if (ssl == NULL)
|
|
return BAD_FUNC_ARG;
|
|
|
|
return TLSX_UseSNI(&ssl->extensions, type, data, size, ssl->heap);
|
|
}
|
|
|
|
|
|
/* 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)
|
|
{
|
|
if (ctx == NULL)
|
|
return BAD_FUNC_ARG;
|
|
|
|
return TLSX_UseSNI(&ctx->extensions, type, data, size, ctx->heap);
|
|
}
|
|
|
|
#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)
|
|
{
|
|
if (data)
|
|
*data = NULL;
|
|
|
|
if (ssl && ssl->extensions)
|
|
return TLSX_SNI_GetRequest(ssl->extensions, type, data, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* 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)
|
|
{
|
|
if (clientHello && helloSz > 0 && sni && inOutSz && *inOutSz > 0)
|
|
return TLSX_SNI_GetFromBuffer(clientHello, helloSz, type, sni, inOutSz);
|
|
|
|
return BAD_FUNC_ARG;
|
|
}
|
|
|
|
#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)
|
|
{
|
|
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;
|
|
|
|
return TLSX_UseTrustedCA(&ssl->extensions,
|
|
type, certId, certIdSz, ssl->heap);
|
|
}
|
|
|
|
#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)
|
|
{
|
|
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);
|
|
}
|
|
|
|
|
|
/* 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)
|
|
{
|
|
if (ctx == NULL)
|
|
return BAD_FUNC_ARG;
|
|
|
|
return TLSX_UseMaxFragment(&ctx->extensions, mfl, ctx->heap);
|
|
}
|
|
|
|
#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)
|
|
{
|
|
if (ssl == NULL)
|
|
return BAD_FUNC_ARG;
|
|
|
|
return TLSX_UseTruncatedHMAC(&ssl->extensions, ssl->heap);
|
|
}
|
|
|
|
|
|
/* 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)
|
|
{
|
|
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)
|
|
|
|
/* 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)
|
|
{
|
|
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
|
|
return 1;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* 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)
|
|
{
|
|
if (ssl == NULL || !isValidCurveGroup(name))
|
|
return BAD_FUNC_ARG;
|
|
|
|
ssl->options.userCurves = 1;
|
|
#if defined(NO_TLS)
|
|
return WOLFSSL_FAILURE;
|
|
#else
|
|
return TLSX_UseSupportedCurve(&ssl->extensions, name, ssl->heap,
|
|
ssl->options.side);
|
|
#endif /* NO_TLS */
|
|
}
|
|
|
|
|
|
/* 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)
|
|
{
|
|
if (ctx == NULL || !isValidCurveGroup(name))
|
|
return BAD_FUNC_ARG;
|
|
|
|
ctx->userCurves = 1;
|
|
#if defined(NO_TLS)
|
|
return WOLFSSL_FAILURE;
|
|
#else
|
|
return TLSX_UseSupportedCurve(&ctx->extensions, name, ctx->heap,
|
|
ctx->method->side);
|
|
#endif /* NO_TLS */
|
|
}
|
|
|
|
#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 (groups == NULL || count <= 0) {
|
|
WOLFSSL_MSG("Groups NULL or count not positive");
|
|
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_set1_groups");
|
|
if (groups == NULL || count <= 0) {
|
|
WOLFSSL_MSG("Groups NULL or count not positive");
|
|
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)) {
|
|
return 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");
|
|
return BAD_FUNC_ARG;
|
|
}
|
|
else 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);
|
|
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;
|
|
|
|
if (ssl == NULL || list == NULL || listSz == 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;
|
|
|
|
return WOLFSSL_SUCCESS;
|
|
}
|
|
|
|
|
|
/* 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)
|
|
{
|
|
if (ssl == NULL) {
|
|
return BAD_FUNC_ARG;
|
|
}
|
|
|
|
XFREE(*list, ssl->heap, DYNAMIC_TYPE_TLSX);
|
|
*list = NULL;
|
|
|
|
return WOLFSSL_SUCCESS;
|
|
}
|
|
|
|
#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)
|
|
{
|
|
if (ctx == NULL)
|
|
return BAD_FUNC_ARG;
|
|
|
|
ctx->useSecureReneg = 1;
|
|
return WOLFSSL_SUCCESS;
|
|
}
|
|
|
|
#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)
|
|
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;
|
|
|
|
#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 */
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
/* 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)
|
|
return WOLFSSL_FAILURE;
|
|
|
|
#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)
|
|
{
|
|
WOLFSSL_ENTER("wolfSSL_SecureResume");
|
|
|
|
if (ssl == NULL)
|
|
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 */
|
|
|
|
/* 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");
|
|
|
|
if (ssl == NULL)
|
|
return BAD_FUNC_ARG;
|
|
|
|
return 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)
|
|
{
|
|
WOLFSSL_ENTER("wolfSSL_set_scr_check_enabled");
|
|
|
|
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)
|
|
/* 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)
|
|
{
|
|
if (ctx == NULL)
|
|
return BAD_FUNC_ARG;
|
|
|
|
ctx->noTicketTls12 = 1;
|
|
|
|
return WOLFSSL_SUCCESS;
|
|
}
|
|
|
|
/* 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)
|
|
{
|
|
if (ssl == NULL)
|
|
return BAD_FUNC_ARG;
|
|
|
|
ssl->options.noTicketTls12 = 1;
|
|
|
|
return WOLFSSL_SUCCESS;
|
|
}
|
|
|
|
/* 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)
|
|
{
|
|
if (ctx == NULL)
|
|
return BAD_FUNC_ARG;
|
|
|
|
ctx->ticketEncCb = cb;
|
|
|
|
return WOLFSSL_SUCCESS;
|
|
}
|
|
|
|
/* 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)
|
|
{
|
|
if (ctx == NULL)
|
|
return BAD_FUNC_ARG;
|
|
|
|
/* 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;
|
|
|
|
ctx->ticketHint = hint;
|
|
|
|
return WOLFSSL_SUCCESS;
|
|
}
|
|
|
|
/* 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)
|
|
{
|
|
if (ctx == NULL)
|
|
return BAD_FUNC_ARG;
|
|
|
|
ctx->ticketEncCtx = userCtx;
|
|
|
|
return WOLFSSL_SUCCESS;
|
|
}
|
|
|
|
/* 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)
|
|
{
|
|
if (ctx == NULL)
|
|
return NULL;
|
|
|
|
return ctx->ticketEncCtx;
|
|
}
|
|
|
|
#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)
|
|
{
|
|
if (ctx == NULL)
|
|
return WOLFSSL_FAILURE;
|
|
|
|
ctx->maxTicketTls13 = (unsigned int)mxTickets;
|
|
return WOLFSSL_SUCCESS;
|
|
}
|
|
|
|
/* 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)
|
|
{
|
|
if (ctx == NULL)
|
|
return 0;
|
|
|
|
return (size_t)ctx->maxTicketTls13;
|
|
}
|
|
#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)
|
|
{
|
|
if (ssl == NULL)
|
|
return BAD_FUNC_ARG;
|
|
|
|
return TLSX_UseSessionTicket(&ssl->extensions, NULL, ssl->heap);
|
|
}
|
|
|
|
/* 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)
|
|
{
|
|
if (ctx == NULL)
|
|
return BAD_FUNC_ARG;
|
|
|
|
return TLSX_UseSessionTicket(&ctx->extensions, NULL, ctx->heap);
|
|
}
|
|
|
|
/* 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)
|
|
{
|
|
if (ssl == NULL || bufSz == NULL)
|
|
return BAD_FUNC_ARG;
|
|
|
|
if (*bufSz == 0 && buf == NULL) {
|
|
*bufSz = ssl->session->ticketLen;
|
|
return LENGTH_ONLY_E;
|
|
}
|
|
|
|
if (buf == NULL)
|
|
return BAD_FUNC_ARG;
|
|
|
|
if (ssl->session->ticketLen <= *bufSz) {
|
|
XMEMCPY(buf, ssl->session->ticket, ssl->session->ticketLen);
|
|
*bufSz = ssl->session->ticketLen;
|
|
}
|
|
else
|
|
*bufSz = 0;
|
|
|
|
return WOLFSSL_SUCCESS;
|
|
}
|
|
|
|
/* 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)
|
|
{
|
|
if (ssl == NULL || (buf == NULL && bufSz > 0))
|
|
return BAD_FUNC_ARG;
|
|
|
|
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;
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
XMEMCPY(ssl->session->ticket, buf, bufSz);
|
|
}
|
|
ssl->session->ticketLen = (word16)bufSz;
|
|
|
|
return WOLFSSL_SUCCESS;
|
|
}
|
|
|
|
|
|
/* 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)
|
|
{
|
|
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
|
|
|
|
/* 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)
|
|
{
|
|
if (ctx == NULL)
|
|
return BAD_FUNC_ARG;
|
|
|
|
ctx->haveEMS = 0;
|
|
|
|
return WOLFSSL_SUCCESS;
|
|
}
|
|
|
|
|
|
/* 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)
|
|
{
|
|
if (ssl == NULL)
|
|
return BAD_FUNC_ARG;
|
|
|
|
ssl->options.haveEMS = 0;
|
|
|
|
return WOLFSSL_SUCCESS;
|
|
}
|
|
|
|
#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)
|
|
{
|
|
if (ssl == NULL) {
|
|
return WOLFSSL_FAILURE;
|
|
}
|
|
|
|
ssl->loggingCtx = arg;
|
|
return WOLFSSL_SUCCESS;
|
|
}
|
|
#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)
|
|
{
|
|
if (c == NULL || (mode < WOLFSSL_MFL_2_9 || mode > WOLFSSL_MFL_2_12 ))
|
|
return BAD_FUNC_ARG;
|
|
|
|
return wolfSSL_CTX_UseMaxFragment(c, mode);
|
|
}
|
|
/* 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)
|
|
{
|
|
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 */
|
|
|
|
/* Set the signature algorithms list on the context.
|
|
*
|
|
* @param [in] ctx SSL/TLS context object.
|
|
* @param [in] list Colon-separated list of <public key>+<digest> 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)
|
|
{
|
|
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);
|
|
}
|
|
|
|
/* Set the signature algorithms list on the object.
|
|
*
|
|
* @param [in] ssl SSL/TLS object.
|
|
* @param [in] list Colon-separated list of <public key>+<digest> 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)
|
|
{
|
|
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);
|
|
}
|
|
|
|
#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)
|
|
{
|
|
if (!ctx || !list) {
|
|
return WOLFSSL_FAILURE;
|
|
}
|
|
|
|
return set_curves_list(NULL, ctx, list, 0);
|
|
}
|
|
|
|
/* 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)
|
|
{
|
|
if (!ssl || !list) {
|
|
return WOLFSSL_FAILURE;
|
|
}
|
|
|
|
return set_curves_list(ssl, NULL, list, 0);
|
|
}
|
|
#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)
|
|
return NULL;
|
|
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)
|
|
{
|
|
WOLFSSL_ENTER("wolfSSL_CTX_set_tlsext_servername_callback");
|
|
if (ctx) {
|
|
ctx->sniRecvCb = cb;
|
|
return WOLFSSL_SUCCESS;
|
|
}
|
|
return WOLFSSL_FAILURE;
|
|
}
|
|
|
|
#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)
|
|
{
|
|
WOLFSSL_ENTER("wolfSSL_CTX_set_servername_arg");
|
|
if (ctx) {
|
|
ctx->sniRecvCbArg = arg;
|
|
return WOLFSSL_SUCCESS;
|
|
}
|
|
return WOLFSSL_FAILURE;
|
|
}
|
|
|
|
#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)
|
|
{
|
|
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(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)
|
|
{
|
|
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);
|
|
}
|
|
|
|
/* 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)
|
|
{
|
|
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 */
|
|
|
|
#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)
|
|
{
|
|
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
|
|
/* 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 */
|