forked from wolfSSL/wolfssl
Merge pull request #995 from SparkiDev/tls13_cookie
Add TLS v1.3 Cookie extension support
This commit is contained in:
17
configure.ac
17
configure.ac
@ -297,6 +297,22 @@ then
|
||||
fi
|
||||
|
||||
|
||||
# Post-handshake Authentication
|
||||
AC_ARG_ENABLE([hrrcookie],
|
||||
[AS_HELP_STRING([--enable-hrrcookie],[Enable the server to send Cookie Extension in HRR with state (default: disabled)])],
|
||||
[ ENABLED_SEND_HRR_COOKIE=$enableval ],
|
||||
[ ENABLED_SEND_HRR_COOKIE=no ]
|
||||
)
|
||||
if test "$ENABLED_SEND_HRR_COOKIE" = "yes"
|
||||
then
|
||||
if test "x$ENABLED_TLS13" = "xno"
|
||||
then
|
||||
AC_MSG_ERROR([cannot enable hrrcookie without enabling tls13.])
|
||||
fi
|
||||
AM_CFLAGS="-DWOLFSSL_SEND_HRR_COOKIE $AM_CFLAGS"
|
||||
fi
|
||||
|
||||
|
||||
AC_ARG_ENABLE([rng],
|
||||
[AS_HELP_STRING([--enable-rng],[Enable compiling and using RNG (default: enabled)])],
|
||||
[ ENABLED_RNG=$enableval ],
|
||||
@ -3798,6 +3814,7 @@ echo " * TLS v1.3: $ENABLED_TLS13"
|
||||
echo " * TLS v1.3 Draft 18: $ENABLED_TLS13_DRAFT18"
|
||||
echo " * Post-handshake Auth: $ENABLED_TLS13_POST_AUTH"
|
||||
echo " * Early Data: $ENABLED_TLS13_EARLY_DATA"
|
||||
echo " * Send State in HRR Cookie: $ENABLED_SEND_HRR_COOKIE"
|
||||
echo " * OCSP: $ENABLED_OCSP"
|
||||
echo " * OCSP Stapling: $ENABLED_CERTIFICATE_STATUS_REQUEST"
|
||||
echo " * OCSP Stapling v2: $ENABLED_CERTIFICATE_STATUS_REQUEST_V2"
|
||||
|
@ -379,6 +379,9 @@ static void Usage(void)
|
||||
#ifdef WOLFSSL_POST_HANDSHAKE_AUTH
|
||||
printf("-Q Request certificate from client post-handshake\n");
|
||||
#endif
|
||||
#ifdef WOLFSSL_SEND_HRR_COOKIE
|
||||
printf("-J Server sends Cookie Extension containing state\n");
|
||||
#endif
|
||||
#endif
|
||||
#ifdef WOLFSSL_EARLY_DATA
|
||||
printf("-0 Early data read from client (0-RTT handshake)\n");
|
||||
@ -474,6 +477,9 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args)
|
||||
#ifdef WOLFSSL_EARLY_DATA
|
||||
int earlyData = 0;
|
||||
#endif
|
||||
#ifdef WOLFSSL_SEND_HRR_COOKIE
|
||||
int hrrCookie = 0;
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSL_STATIC_MEMORY
|
||||
#if (defined(HAVE_ECC) && !defined(ALT_ECC_SIZE)) \
|
||||
@ -518,10 +524,11 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args)
|
||||
#ifdef WOLFSSL_VXWORKS
|
||||
useAnyAddr = 1;
|
||||
#else
|
||||
/* Not Used: h, m, t, y, z, F, J, M, T, V, W, X, Y */
|
||||
/* Not Used: h, m, t, y, z, F, M, T, V, W, X, Y */
|
||||
while ((ch = mygetopt(argc, argv, "?"
|
||||
"abc:defgijk:l:nop:q:rsuv:wx"
|
||||
"A:B:C:D:E:GHIKL:NO:PQR:S:UYZ:""0")) != -1) {
|
||||
"A:B:C:D:E:GHIJKL:NO:PQR:S:UYZ:"
|
||||
"0")) != -1) {
|
||||
switch (ch) {
|
||||
case '?' :
|
||||
Usage();
|
||||
@ -746,6 +753,12 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args)
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 'J' :
|
||||
#ifdef WOLFSSL_SEND_HRR_COOKIE
|
||||
hrrCookie = 1;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case '0' :
|
||||
#ifdef WOLFSSL_EARLY_DATA
|
||||
earlyData = 1;
|
||||
@ -1083,6 +1096,12 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args)
|
||||
wolfSSL_KeepArrays(ssl);
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSL_SEND_HRR_COOKIE
|
||||
if (hrrCookie && wolfSSL_send_hrr_cookie(ssl, NULL, 0) != SSL_SUCCESS) {
|
||||
err_sys("unable to set use of cookie with HRR msg");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WOLFSSL_STATIC_MEMORY) && defined(DEBUG_WOLFSSL)
|
||||
{
|
||||
WOLFSSL_MEM_STATS mem_stats;
|
||||
|
@ -95,6 +95,22 @@ if [ $RESULT -ne 0 ]; then
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Use HelloRetryRequest with TLS v1.3 server / TLS v1.3 client using cookie
|
||||
echo -e "\n\nTLS v1.3 HelloRetryRequest with cookie"
|
||||
port=0
|
||||
./examples/server/server -v 4 -J -R $ready_file -p $port &
|
||||
server_pid=$!
|
||||
create_port
|
||||
./examples/client/client -v 4 -J -p $port
|
||||
RESULT=$?
|
||||
remove_ready_file
|
||||
if [ $RESULT -ne 0 ]; then
|
||||
echo -e "\n\nTLS v1.3 HelloRetryRequest with cookie not working"
|
||||
do_cleanup
|
||||
exit 1
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Use HelloRetryRequest with TLS v1.3 server / TLS v1.3 client - SHA384.
|
||||
echo -e "\n\nTLS v1.3 HelloRetryRequest - SHA384"
|
||||
port=0
|
||||
|
@ -4550,6 +4550,10 @@ void SSL_ResourceFree(WOLFSSL* ssl)
|
||||
ShrinkInputBuffer(ssl, FORCED_FREE);
|
||||
if (ssl->buffers.outputBuffer.dynamicFlag)
|
||||
ShrinkOutputBuffer(ssl);
|
||||
#if defined(WOLFSSL_SEND_HRR_COOKIE) && !defined(NO_WOLFSSL_SERVER)
|
||||
XFREE(ssl->buffers.tls13CookieSecret.buffer, ssl->heap,
|
||||
DYNAMIC_TYPE_COOKIE_PWD);
|
||||
#endif
|
||||
#ifdef WOLFSSL_DTLS
|
||||
DtlsMsgPoolReset(ssl);
|
||||
if (ssl->dtls_rx_msg_list != NULL) {
|
||||
@ -13934,6 +13938,9 @@ const char* wolfSSL_ERR_reason_error_string(unsigned long e)
|
||||
case POST_HAND_AUTH_ERROR:
|
||||
return "Client will not do post handshake authentication";
|
||||
|
||||
case HRR_COOKIE_ERROR:
|
||||
return "Cookie does not match one sent in HelloRetryRequest";
|
||||
|
||||
default :
|
||||
return "unknown error number";
|
||||
}
|
||||
@ -15742,7 +15749,7 @@ void PickHashSigAlgo(WOLFSSL* ssl, const byte* hashSigAlgo,
|
||||
if (QSH_Init(ssl) != 0)
|
||||
return MEMORY_E;
|
||||
#endif
|
||||
extSz = TLSX_GetRequestSize(ssl);
|
||||
extSz = TLSX_GetRequestSize(ssl, client_hello);
|
||||
if (extSz != 0)
|
||||
length += extSz;
|
||||
#else
|
||||
@ -15835,7 +15842,7 @@ void PickHashSigAlgo(WOLFSSL* ssl, const byte* hashSigAlgo,
|
||||
output[idx++] = NO_COMPRESSION;
|
||||
|
||||
#ifdef HAVE_TLS_EXTENSIONS
|
||||
idx += TLSX_WriteRequest(ssl, output + idx);
|
||||
idx += TLSX_WriteRequest(ssl, output + idx, client_hello);
|
||||
|
||||
(void)idx; /* suppress analyzer warning, keep idx current */
|
||||
#else
|
||||
|
404
src/tls.c
404
src/tls.c
@ -4452,6 +4452,170 @@ static int TLSX_SetSupportedVersions(TLSX** extensions, const void* data,
|
||||
|
||||
#endif /* WOLFSSL_TLS13 */
|
||||
|
||||
#if defined(WOLFSSL_TLS13)
|
||||
|
||||
/******************************************************************************/
|
||||
/* Cookie */
|
||||
/******************************************************************************/
|
||||
|
||||
/* Free the cookie data.
|
||||
*
|
||||
* cookie Cookie data.
|
||||
* heap The heap used for allocation.
|
||||
*/
|
||||
static void TLSX_Cookie_FreeAll(Cookie* cookie, void* heap)
|
||||
{
|
||||
(void)heap;
|
||||
|
||||
if (cookie != NULL)
|
||||
XFREE(cookie, heap, DYNAMIC_TYPE_TLSX);
|
||||
}
|
||||
|
||||
/* Get the size of the encoded Cookie extension.
|
||||
* In messages: ClientHello and HelloRetryRequest.
|
||||
*
|
||||
* cookie The cookie to write.
|
||||
* msgType The type of the message this extension is being written into.
|
||||
* returns the number of bytes of the encoded Cookie extension.
|
||||
*/
|
||||
static word16 TLSX_Cookie_GetSize(Cookie* cookie, byte msgType)
|
||||
{
|
||||
if (msgType == client_hello || msgType == hello_retry_request)
|
||||
return OPAQUE16_LEN + cookie->len;
|
||||
|
||||
return SANITY_MSG_E;
|
||||
}
|
||||
|
||||
/* Writes the Cookie extension into the output buffer.
|
||||
* Assumes that the the output buffer is big enough to hold data.
|
||||
* In messages: ClientHello and HelloRetryRequest.
|
||||
*
|
||||
* cookie The cookie to write.
|
||||
* output The buffer to write into.
|
||||
* msgType The type of the message this extension is being written into.
|
||||
* returns the number of bytes written into the buffer.
|
||||
*/
|
||||
static word16 TLSX_Cookie_Write(Cookie* cookie, byte* output, byte msgType)
|
||||
{
|
||||
if (msgType == client_hello || msgType == hello_retry_request) {
|
||||
c16toa(cookie->len, output);
|
||||
output += OPAQUE16_LEN;
|
||||
XMEMCPY(output, &cookie->data, cookie->len);
|
||||
return OPAQUE16_LEN + cookie->len;
|
||||
}
|
||||
|
||||
return SANITY_MSG_E;
|
||||
}
|
||||
|
||||
/* Parse the Cookie extension.
|
||||
* In messages: ClientHello and HelloRetryRequest.
|
||||
*
|
||||
* ssl The SSL/TLS object.
|
||||
* input The extension data.
|
||||
* length The length of the extension data.
|
||||
* msgType The type of the message this extension is being parsed from.
|
||||
* returns 0 on success and other values indicate failure.
|
||||
*/
|
||||
static int TLSX_Cookie_Parse(WOLFSSL* ssl, byte* input, word16 length,
|
||||
byte msgType)
|
||||
{
|
||||
word16 len;
|
||||
word16 idx = 0;
|
||||
TLSX* extension;
|
||||
Cookie* cookie;
|
||||
|
||||
if (msgType != client_hello && msgType != hello_retry_request)
|
||||
return SANITY_MSG_E;
|
||||
|
||||
/* Message contains length and Cookie which must be at least one byte
|
||||
* in length.
|
||||
*/
|
||||
if (length < OPAQUE16_LEN + 1)
|
||||
return BUFFER_E;
|
||||
ato16(input + idx, &len);
|
||||
idx += OPAQUE16_LEN;
|
||||
if (length - idx != len)
|
||||
return BUFFER_E;
|
||||
|
||||
if (msgType == hello_retry_request)
|
||||
return TLSX_Cookie_Use(ssl, input + idx, len, NULL, 0, 0);
|
||||
|
||||
/* client_hello */
|
||||
extension = TLSX_Find(ssl->extensions, TLSX_COOKIE);
|
||||
if (extension == NULL)
|
||||
return HRR_COOKIE_ERROR;
|
||||
|
||||
cookie = (Cookie*)extension->data;
|
||||
if (cookie->len != len || XMEMCMP(&cookie->data, input + idx, len) != 0)
|
||||
return HRR_COOKIE_ERROR;
|
||||
|
||||
/* Request seen. */
|
||||
extension->resp = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Use the data to create a new Cookie object in the extensions.
|
||||
*
|
||||
* ssl SSL/TLS object.
|
||||
* data Cookie data.
|
||||
* len Length of cookie data in bytes.
|
||||
* mac MAC data.
|
||||
* macSz Length of MAC data in bytes.
|
||||
* resp Indicates the extension will go into a response (HelloRetryRequest).
|
||||
* returns 0 on success and other values indicate failure.
|
||||
*/
|
||||
int TLSX_Cookie_Use(WOLFSSL* ssl, byte* data, word16 len, byte* mac,
|
||||
byte macSz, int resp)
|
||||
{
|
||||
int ret = 0;
|
||||
TLSX* extension;
|
||||
Cookie* cookie;
|
||||
|
||||
/* Find the cookie extension if it exists. */
|
||||
extension = TLSX_Find(ssl->extensions, TLSX_COOKIE);
|
||||
if (extension == NULL) {
|
||||
/* Push new cookie extension. */
|
||||
ret = TLSX_Push(&ssl->extensions, TLSX_COOKIE, NULL, ssl->heap);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
extension = TLSX_Find(ssl->extensions, TLSX_COOKIE);
|
||||
if (extension == NULL)
|
||||
return MEMORY_E;
|
||||
}
|
||||
|
||||
/* The Cookie structure has one byte for cookie data already. */
|
||||
cookie = (Cookie*)XMALLOC(sizeof(Cookie) + len + macSz - 1, ssl->heap,
|
||||
DYNAMIC_TYPE_TLSX);
|
||||
if (cookie == NULL)
|
||||
return MEMORY_E;
|
||||
|
||||
cookie->len = len + macSz;
|
||||
XMEMCPY(&cookie->data, data, len);
|
||||
if (mac != NULL)
|
||||
XMEMCPY(&cookie->data + len, mac, macSz);
|
||||
|
||||
extension->data = (void*)cookie;
|
||||
extension->resp = resp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define CKE_FREE_ALL TLSX_Cookie_FreeAll
|
||||
#define CKE_GET_SIZE TLSX_Cookie_GetSize
|
||||
#define CKE_WRITE TLSX_Cookie_Write
|
||||
#define CKE_PARSE TLSX_Cookie_Parse
|
||||
|
||||
#else
|
||||
|
||||
#define CKE_FREE_ALL(a, b) 0
|
||||
#define CKE_GET_SIZE(a, b) 0
|
||||
#define CKE_WRITE(a, b, c) 0
|
||||
#define CKE_PARSE(a, b, c, d) 0
|
||||
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
/* Sugnature Algorithms */
|
||||
/******************************************************************************/
|
||||
@ -6376,7 +6540,8 @@ int TLSX_PskKeModes_Use(WOLFSSL* ssl, byte modes)
|
||||
* Only in ClientHello.
|
||||
*
|
||||
* msgType The type of the message this extension is being written into.
|
||||
* returns the number of bytes of the encoded key share extension.
|
||||
* returns the number of bytes of the encoded Post-Hanshake Authentication
|
||||
* extension.
|
||||
*/
|
||||
static word16 TLSX_PostHandAuth_GetSize(byte msgType)
|
||||
{
|
||||
@ -6478,7 +6643,7 @@ static int TLSX_PostHandAuth_Use(WOLFSSL* ssl)
|
||||
* In messages: ClientHello, EncryptedExtensions and NewSessionTicket.
|
||||
*
|
||||
* msgType The type of the message this extension is being written into.
|
||||
* returns the number of bytes of the encoded key share extension.
|
||||
* returns the number of bytes of the encoded Early Data Indication extension.
|
||||
*/
|
||||
static word16 TLSX_EarlyData_GetSize(byte msgType)
|
||||
{
|
||||
@ -6561,10 +6726,10 @@ int TLSX_EarlyData_Use(WOLFSSL* ssl, word32 max)
|
||||
int ret = 0;
|
||||
TLSX* extension;
|
||||
|
||||
/* Find the early extension if it exists. */
|
||||
/* Find the early data extension if it exists. */
|
||||
extension = TLSX_Find(ssl->extensions, TLSX_EARLY_DATA);
|
||||
if (extension == NULL) {
|
||||
/* Push new early extension. */
|
||||
/* Push new early data extension. */
|
||||
ret = TLSX_Push(&ssl->extensions, TLSX_EARLY_DATA, NULL, ssl->heap);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
@ -6665,6 +6830,10 @@ void TLSX_FreeAll(TLSX* list, void* heap)
|
||||
case TLSX_SUPPORTED_VERSIONS:
|
||||
break;
|
||||
|
||||
case TLSX_COOKIE:
|
||||
CKE_FREE_ALL((Cookie*)extension->data, heap);
|
||||
break;
|
||||
|
||||
case TLSX_KEY_SHARE:
|
||||
KS_FREE_ALL((KeyShareEntry*)extension->data, heap);
|
||||
break;
|
||||
@ -6782,6 +6951,10 @@ static word16 TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType)
|
||||
length += SV_GET_SIZE(extension->data);
|
||||
break;
|
||||
|
||||
case TLSX_COOKIE:
|
||||
length += CKE_GET_SIZE((Cookie*)extension->data, msgType);
|
||||
break;
|
||||
|
||||
case TLSX_KEY_SHARE:
|
||||
length += KS_GET_SIZE((KeyShareEntry*)extension->data, msgType);
|
||||
break;
|
||||
@ -6919,6 +7092,12 @@ static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore,
|
||||
offset += SV_WRITE(extension->data, output + offset);
|
||||
break;
|
||||
|
||||
case TLSX_COOKIE:
|
||||
WOLFSSL_MSG("Cookie extension to write");
|
||||
offset += CKE_WRITE((Cookie*)extension->data, output + offset,
|
||||
msgType);
|
||||
break;
|
||||
|
||||
case TLSX_KEY_SHARE:
|
||||
WOLFSSL_MSG("Key Share extension to write");
|
||||
offset += KS_WRITE((KeyShareEntry*)extension->data,
|
||||
@ -7531,13 +7710,14 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer)
|
||||
#ifndef NO_WOLFSSL_CLIENT
|
||||
|
||||
/** Tells the buffered size of extensions to be sent into the client hello. */
|
||||
word16 TLSX_GetRequestSize(WOLFSSL* ssl)
|
||||
word16 TLSX_GetRequestSize(WOLFSSL* ssl, byte msgType)
|
||||
{
|
||||
word16 length = 0;
|
||||
byte semaphore[SEMAPHORE_SIZE] = {0};
|
||||
|
||||
if (TLSX_SupportExtensions(ssl)) {
|
||||
byte semaphore[SEMAPHORE_SIZE] = {0};
|
||||
|
||||
if (!TLSX_SupportExtensions(ssl))
|
||||
return 0;
|
||||
if (msgType == client_hello) {
|
||||
EC_VALIDATE_REQUEST(ssl, semaphore);
|
||||
QSH_VALIDATE_REQUEST(ssl, semaphore);
|
||||
WOLF_STK_VALIDATE_REQUEST(ssl);
|
||||
@ -7547,28 +7727,43 @@ word16 TLSX_GetRequestSize(WOLFSSL* ssl)
|
||||
if (!IsAtLeastTLSv1_2(ssl))
|
||||
TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
|
||||
if (!IsAtLeastTLSv1_3(ssl->version)) {
|
||||
TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
|
||||
TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
|
||||
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
|
||||
TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
|
||||
TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PSK_KEY_EXCHANGE_MODES));
|
||||
#endif
|
||||
#ifdef WOLFSSL_EARLY_DATA
|
||||
TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EARLY_DATA));
|
||||
#endif
|
||||
TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_COOKIE));
|
||||
#ifdef WOLFSSL_POST_HANDSHAKE_AUTH
|
||||
TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_POST_HANDSHAKE_AUTH));
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ssl->extensions)
|
||||
length += TLSX_GetSize(ssl->extensions, semaphore, client_hello);
|
||||
|
||||
if (ssl->ctx && ssl->ctx->extensions) {
|
||||
length += TLSX_GetSize(ssl->ctx->extensions, semaphore,
|
||||
client_hello);
|
||||
}
|
||||
|
||||
#ifdef HAVE_EXTENDED_MASTER
|
||||
if (ssl->options.haveEMS)
|
||||
length += HELLO_EXT_SZ;
|
||||
#endif
|
||||
}
|
||||
#ifdef WOLFSSL_TLS13
|
||||
#ifndef NO_CERTS
|
||||
else if (msgType == certificate_request) {
|
||||
XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
|
||||
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS));
|
||||
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
|
||||
/* TODO: TLSX_SIGNED_CERTIFICATE_TIMESTAMP,
|
||||
* TLSX_CERTIFICATE_AUTHORITIES, OID_FILTERS
|
||||
*/
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (ssl->extensions)
|
||||
length += TLSX_GetSize(ssl->extensions, semaphore, msgType);
|
||||
if (ssl->ctx && ssl->ctx->extensions)
|
||||
length += TLSX_GetSize(ssl->ctx->extensions, semaphore, msgType);
|
||||
|
||||
#ifdef HAVE_EXTENDED_MASTER
|
||||
if (msgType == client_hello && ssl->options.haveEMS)
|
||||
length += HELLO_EXT_SZ;
|
||||
#endif
|
||||
|
||||
if (length)
|
||||
length += OPAQUE16_LEN; /* for total length storage. */
|
||||
@ -7577,65 +7772,91 @@ word16 TLSX_GetRequestSize(WOLFSSL* ssl)
|
||||
}
|
||||
|
||||
/** Writes the extensions to be sent into the client hello. */
|
||||
word16 TLSX_WriteRequest(WOLFSSL* ssl, byte* output)
|
||||
word16 TLSX_WriteRequest(WOLFSSL* ssl, byte* output, byte msgType)
|
||||
{
|
||||
word16 offset = 0;
|
||||
byte semaphore[SEMAPHORE_SIZE] = {0};
|
||||
|
||||
if (TLSX_SupportExtensions(ssl) && output) {
|
||||
byte semaphore[SEMAPHORE_SIZE] = {0};
|
||||
if (!TLSX_SupportExtensions(ssl) || output == NULL)
|
||||
return 0;
|
||||
|
||||
offset += OPAQUE16_LEN; /* extensions length */
|
||||
offset += OPAQUE16_LEN; /* extensions length */
|
||||
|
||||
if (msgType == client_hello) {
|
||||
EC_VALIDATE_REQUEST(ssl, semaphore);
|
||||
WOLF_STK_VALIDATE_REQUEST(ssl);
|
||||
QSH_VALIDATE_REQUEST(ssl, semaphore);
|
||||
if (ssl->suites->hashSigAlgoSz == 0)
|
||||
TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS));
|
||||
#if defined(WOLFSSL_TLS13)
|
||||
#ifdef WOLFSSL_TLS13
|
||||
if (!IsAtLeastTLSv1_2(ssl))
|
||||
TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
|
||||
if (!IsAtLeastTLSv1_3(ssl->version)) {
|
||||
TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
|
||||
TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
|
||||
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
|
||||
TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PSK_KEY_EXCHANGE_MODES));
|
||||
#endif
|
||||
#ifdef WOLFSSL_EARLY_DATA
|
||||
TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EARLY_DATA));
|
||||
#endif
|
||||
TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_COOKIE));
|
||||
#ifdef WOLFSSL_POST_HANDSHAKE_AUTH
|
||||
TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_POST_HANDSHAKE_AUTH));
|
||||
#endif
|
||||
}
|
||||
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
|
||||
/* Must write Pre-shared Key extension at the end in TLS v1.3.
|
||||
* Must not write out Pre-shared Key extension in earlier versions of
|
||||
* protocol.
|
||||
*/
|
||||
TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#ifdef WOLFSSL_TLS13
|
||||
#ifndef NO_CERT
|
||||
else if (msgType == certificate_request) {
|
||||
XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
|
||||
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS));
|
||||
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
|
||||
/* TODO: TLSX_SIGNED_CERTIFICATE_TIMESTAMP,
|
||||
* TLSX_CERTIFICATE_AUTHORITIES, TLSX_OID_FILTERS
|
||||
*/
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (ssl->extensions)
|
||||
offset += TLSX_Write(ssl->extensions, output + offset, semaphore,
|
||||
client_hello);
|
||||
|
||||
if (ssl->ctx && ssl->ctx->extensions)
|
||||
offset += TLSX_Write(ssl->ctx->extensions, output + offset,
|
||||
semaphore, client_hello);
|
||||
if (ssl->extensions) {
|
||||
offset += TLSX_Write(ssl->extensions, output + offset, semaphore,
|
||||
msgType);
|
||||
}
|
||||
if (ssl->ctx && ssl->ctx->extensions) {
|
||||
offset += TLSX_Write(ssl->ctx->extensions, output + offset, semaphore,
|
||||
msgType);
|
||||
}
|
||||
|
||||
#ifdef HAVE_EXTENDED_MASTER
|
||||
if (ssl->options.haveEMS) {
|
||||
c16toa(HELLO_EXT_EXTMS, output + offset);
|
||||
offset += HELLO_EXT_TYPE_SZ;
|
||||
c16toa(0, output + offset);
|
||||
offset += HELLO_EXT_SZ_SZ;
|
||||
}
|
||||
if (msgType == client_hello && ssl->options.haveEMS) {
|
||||
c16toa(HELLO_EXT_EXTMS, output + offset);
|
||||
offset += HELLO_EXT_TYPE_SZ;
|
||||
c16toa(0, output + offset);
|
||||
offset += HELLO_EXT_SZ_SZ;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSL_TLS13
|
||||
if (IsAtLeastTLSv1_3(ssl->version)) {
|
||||
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
|
||||
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
|
||||
if (msgType == client_hello && IsAtLeastTLSv1_3(ssl->version)) {
|
||||
/* Write out what we can of Pre-shared key extension. */
|
||||
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
|
||||
offset += TLSX_Write(ssl->extensions, output + offset, semaphore,
|
||||
client_hello);
|
||||
}
|
||||
#endif
|
||||
offset += TLSX_Write(ssl->extensions, output + offset, semaphore,
|
||||
client_hello);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (offset > OPAQUE16_LEN)
|
||||
c16toa(offset - OPAQUE16_LEN, output); /* extensions length */
|
||||
}
|
||||
if (offset > OPAQUE16_LEN || msgType != client_hello)
|
||||
c16toa(offset - OPAQUE16_LEN, output); /* extensions length */
|
||||
|
||||
return offset;
|
||||
}
|
||||
@ -7653,14 +7874,20 @@ word16 TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType)
|
||||
switch (msgType) {
|
||||
case server_hello:
|
||||
#ifdef WOLFSSL_TLS13
|
||||
case hello_retry_request:
|
||||
if (ssl->options.tls1_3) {
|
||||
XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
|
||||
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
|
||||
if (ssl->options.tls1_3) {
|
||||
XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
|
||||
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
|
||||
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
|
||||
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
|
||||
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
#ifdef WOLFSSL_TLS13
|
||||
case hello_retry_request:
|
||||
XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
|
||||
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
|
||||
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_COOKIE));
|
||||
#endif
|
||||
break;
|
||||
#ifdef WOLFSSL_TLS13
|
||||
@ -7671,19 +7898,22 @@ word16 TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType)
|
||||
TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
|
||||
#endif
|
||||
break;
|
||||
#ifndef NO_CERTS
|
||||
case certificate_request:
|
||||
XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
|
||||
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS));
|
||||
#ifdef WOLFSSL_EARLY_DATA
|
||||
case session_ticket:
|
||||
if (ssl->options.tls1_3) {
|
||||
XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
|
||||
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_EARLY_DATA));
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef WOLFSSL_EARLY_DATA
|
||||
case session_ticket:
|
||||
if (ssl->options.tls1_3) {
|
||||
XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
|
||||
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_EARLY_DATA));
|
||||
}
|
||||
break;
|
||||
#ifndef NO_CERT
|
||||
case certificate:
|
||||
XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
|
||||
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
|
||||
/* TODO: TLSX_SIGNED_CERTIFICATE_TIMESTAMP,
|
||||
* TLSX_SERVER_CERTIFICATE_TYPE
|
||||
*/
|
||||
break;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
@ -7707,7 +7937,7 @@ word16 TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType)
|
||||
|
||||
/* All the response data is set at the ssl object only, so no ctx here. */
|
||||
|
||||
if (length || (msgType != server_hello))
|
||||
if (length || msgType != server_hello)
|
||||
length += OPAQUE16_LEN; /* for total length storage. */
|
||||
|
||||
return length;
|
||||
@ -7724,7 +7954,6 @@ word16 TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType)
|
||||
switch (msgType) {
|
||||
case server_hello:
|
||||
#ifdef WOLFSSL_TLS13
|
||||
case hello_retry_request:
|
||||
if (ssl->options.tls1_3) {
|
||||
XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
|
||||
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
|
||||
@ -7734,6 +7963,12 @@ word16 TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType)
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
#ifdef WOLFSSL_TLS13
|
||||
case hello_retry_request:
|
||||
XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
|
||||
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
|
||||
#endif
|
||||
break;
|
||||
#ifdef WOLFSSL_TLS13
|
||||
case encrypted_extensions:
|
||||
TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SESSION_TICKET));
|
||||
@ -7743,10 +7978,12 @@ word16 TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType)
|
||||
#endif
|
||||
break;
|
||||
#ifndef NO_CERTS
|
||||
case certificate_request:
|
||||
case certificate:
|
||||
XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
|
||||
TURN_OFF(semaphore,
|
||||
TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS));
|
||||
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
|
||||
/* TODO: TLSX_SIGNED_CERTIFICATE_TIMESTAMP,
|
||||
* TLSX_SERVER_CERTIFICATE_TYPE
|
||||
*/
|
||||
break;
|
||||
#endif
|
||||
#ifdef WOLFSSL_EARLY_DATA
|
||||
@ -7765,6 +8002,15 @@ word16 TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType)
|
||||
offset += TLSX_Write(ssl->extensions, output + offset, semaphore,
|
||||
msgType);
|
||||
|
||||
#ifdef WOLFSSL_TLS13
|
||||
if (msgType == hello_retry_request) {
|
||||
XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
|
||||
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_COOKIE));
|
||||
offset += TLSX_Write(ssl->extensions, output + offset, semaphore,
|
||||
msgType);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_EXTENDED_MASTER
|
||||
if (ssl->options.haveEMS && msgType == server_hello) {
|
||||
c16toa(HELLO_EXT_EXTMS, output + offset);
|
||||
@ -7774,7 +8020,7 @@ word16 TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (offset > OPAQUE16_LEN || msgType == encrypted_extensions)
|
||||
if (offset > OPAQUE16_LEN || msgType != server_hello)
|
||||
c16toa(offset - OPAQUE16_LEN, output); /* extensions length */
|
||||
}
|
||||
|
||||
@ -7977,6 +8223,20 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte msgType,
|
||||
ret = SV_PARSE(ssl, input + offset, size);
|
||||
break;
|
||||
|
||||
case TLSX_COOKIE:
|
||||
WOLFSSL_MSG("Cookie extension received");
|
||||
|
||||
if (!IsAtLeastTLSv1_3(ssl->version))
|
||||
break;
|
||||
|
||||
if (IsAtLeastTLSv1_3(ssl->version) &&
|
||||
msgType != client_hello &&
|
||||
msgType != hello_retry_request) {
|
||||
return EXT_NOT_ALLOWED;
|
||||
}
|
||||
ret = CKE_PARSE(ssl, input + offset, size, msgType);
|
||||
break;
|
||||
|
||||
case TLSX_KEY_SHARE:
|
||||
WOLFSSL_MSG("Key Share extension received");
|
||||
|
||||
|
422
src/tls13.c
422
src/tls13.c
@ -1366,60 +1366,6 @@ static int HashInputRaw(WOLFSSL* ssl, const byte* input, int sz)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef WOLFSSL_TLS13_DRAFT_18
|
||||
/* The offset into MessageHash of the low byte of the length field. */
|
||||
#define MSG_HASH_LEN_OFFSET 3
|
||||
|
||||
/* Restart the Hanshake hash with a hash of the previous messages.
|
||||
*
|
||||
* ssl The SSL/TLS object.
|
||||
* returns 0 on success, otherwise failure.
|
||||
*/
|
||||
static int RestartHandshakeHash(WOLFSSL* ssl)
|
||||
{
|
||||
int ret;
|
||||
Hashes hashes;
|
||||
byte header[] = { message_hash, 0, 0, 0 };
|
||||
byte* hash = NULL;
|
||||
|
||||
ret = BuildCertHashes(ssl, &hashes);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
ret = InitHandshakeHashes(ssl);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
switch (ssl->specs.mac_algorithm) {
|
||||
#ifndef NO_SHA256
|
||||
case sha256_mac:
|
||||
header[MSG_HASH_LEN_OFFSET] = SHA256_DIGEST_SIZE;
|
||||
hash = hashes.sha256;
|
||||
break;
|
||||
#endif
|
||||
#ifdef WOLFSSL_SHA384
|
||||
case sha384_mac:
|
||||
header[MSG_HASH_LEN_OFFSET] = SHA384_DIGEST_SIZE;
|
||||
hash = hashes.sha384;
|
||||
break;
|
||||
#endif
|
||||
#ifdef WOLFSSL_SHA512
|
||||
case sha512_mac:
|
||||
header[MSG_HASH_LEN_OFFSET] = SHA512_DIGEST_SIZE;
|
||||
hash = hashes.sha512;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
WOLFSSL_MSG("Restart Hash");
|
||||
WOLFSSL_BUFFER(hash, header[3]);
|
||||
|
||||
ret = HashOutputRaw(ssl, header, sizeof(header));
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
return HashOutputRaw(ssl, hash, header[MSG_HASH_LEN_OFFSET]);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Extract the handshake header information.
|
||||
*
|
||||
* ssl The SSL/TLS object.
|
||||
@ -2348,7 +2294,7 @@ int SendTls13ClientHello(WOLFSSL* ssl)
|
||||
return MEMORY_E;
|
||||
#endif
|
||||
/* Include length of TLS extensions. */
|
||||
length += TLSX_GetRequestSize(ssl);
|
||||
length += TLSX_GetRequestSize(ssl, client_hello);
|
||||
|
||||
/* Total message size. */
|
||||
sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
|
||||
@ -2396,7 +2342,7 @@ int SendTls13ClientHello(WOLFSSL* ssl)
|
||||
output[idx++] = NO_COMPRESSION;
|
||||
|
||||
/* Write out extensions for a request. */
|
||||
idx += TLSX_WriteRequest(ssl, output + idx);
|
||||
idx += TLSX_WriteRequest(ssl, output + idx, client_hello);
|
||||
|
||||
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
|
||||
/* Resumption has a specific set of extensions and binder is calculated
|
||||
@ -2429,6 +2375,117 @@ int SendTls13ClientHello(WOLFSSL* ssl)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifndef WOLFSSL_TLS13_DRAFT_18
|
||||
#ifdef WOLFSSL_SEND_HRR_COOKIE
|
||||
/* Create Cookie extension using the hash of the first ClientHello.
|
||||
*
|
||||
* ssl SSL/TLS object.
|
||||
* hash The hash data.
|
||||
* hashSz The size of the hash data in bytes.
|
||||
* returns 0 on success, otherwise failure.
|
||||
*/
|
||||
static int CreateCookie(WOLFSSL* ssl, byte* hash, byte hashSz)
|
||||
{
|
||||
int ret;
|
||||
byte mac[MAX_DIGEST_SIZE];
|
||||
Hmac cookieHmac;
|
||||
byte cookieType;
|
||||
byte macSz;
|
||||
|
||||
#if !defined(NO_SHA) && defined(NO_SHA256)
|
||||
cookieType = SHA;
|
||||
macSz = SHA_DIGEST_SIZE;
|
||||
#endif /* NO_SHA */
|
||||
#ifndef NO_SHA256
|
||||
cookieType = SHA256;
|
||||
macSz = SHA256_DIGEST_SIZE;
|
||||
#endif /* NO_SHA256 */
|
||||
|
||||
ret = wc_HmacSetKey(&cookieHmac, cookieType,
|
||||
ssl->buffers.tls13CookieSecret.buffer,
|
||||
ssl->buffers.tls13CookieSecret.length);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
if ((ret = wc_HmacUpdate(&cookieHmac, hash, hashSz)) != 0)
|
||||
return ret;
|
||||
if ((ret = wc_HmacFinal(&cookieHmac, mac)) != 0)
|
||||
return ret;
|
||||
|
||||
/* The cookie data is the hash and the integrity check. */
|
||||
return TLSX_Cookie_Use(ssl, hash, hashSz, mac, macSz, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Restart the Hanshake hash with a hash of the previous messages.
|
||||
*
|
||||
* ssl The SSL/TLS object.
|
||||
* returns 0 on success, otherwise failure.
|
||||
*/
|
||||
static int RestartHandshakeHash(WOLFSSL* ssl)
|
||||
{
|
||||
int ret;
|
||||
Hashes hashes;
|
||||
byte header[HANDSHAKE_HEADER_SZ];
|
||||
byte* hash = NULL;
|
||||
byte hashSz = 0;
|
||||
|
||||
ret = BuildCertHashes(ssl, &hashes);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
switch (ssl->specs.mac_algorithm) {
|
||||
#ifndef NO_SHA256
|
||||
case sha256_mac:
|
||||
hash = hashes.sha256;
|
||||
break;
|
||||
#endif
|
||||
#ifdef WOLFSSL_SHA384
|
||||
case sha384_mac:
|
||||
hash = hashes.sha384;
|
||||
break;
|
||||
#endif
|
||||
#ifdef WOLFSSL_SHA512
|
||||
case sha512_mac:
|
||||
hash = hashes.sha512;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
hashSz = ssl->specs.hash_size;
|
||||
AddTls13HandShakeHeader(header, hashSz, 0, 0, message_hash, ssl);
|
||||
|
||||
WOLFSSL_MSG("Restart Hash");
|
||||
WOLFSSL_BUFFER(hash, hashSz);
|
||||
|
||||
#ifdef WOLFSSL_SEND_HRR_COOKIE
|
||||
if (ssl->options.sendCookie) {
|
||||
byte cookie[OPAQUE8_LEN + MAX_DIGEST_SIZE + OPAQUE16_LEN * 2];
|
||||
TLSX* ext;
|
||||
word32 idx = 0;
|
||||
|
||||
/* Cookie Data = Hash Len | Hash | CS | KeyShare Group */
|
||||
cookie[idx++] = hashSz;
|
||||
XMEMCPY(cookie + idx, hash, hashSz);
|
||||
idx += hashSz;
|
||||
cookie[idx++] = ssl->options.cipherSuite0;
|
||||
cookie[idx++] = ssl->options.cipherSuite;
|
||||
if ((ext = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE)) != NULL) {
|
||||
KeyShareEntry* kse = (KeyShareEntry*)ext->data;
|
||||
c16toa(kse->group, cookie + idx);
|
||||
idx += OPAQUE16_LEN;
|
||||
}
|
||||
return CreateCookie(ssl, cookie, idx);
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = InitHandshakeHashes(ssl);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
ret = HashOutputRaw(ssl, header, sizeof(header));
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
return HashOutputRaw(ssl, hash, hashSz);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Parse and handle a HelloRetryRequest message.
|
||||
* Only a client will receive this message.
|
||||
*
|
||||
@ -3059,6 +3116,154 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz,
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(WOLFSSL_TLS13_DRAFT_18) && defined(WOLFSSL_SEND_HRR_COOKIE)
|
||||
/* Check that the Cookie data's integrity.
|
||||
*
|
||||
* ssl SSL/TLS object.
|
||||
* cookie The cookie data - hash and MAC.
|
||||
* cookieSz The length of the cookie data in bytes.
|
||||
* returns Length of the hash on success, otherwise failure.
|
||||
*/
|
||||
static int CheckCookie(WOLFSSL* ssl, byte* cookie, byte cookieSz)
|
||||
{
|
||||
int ret;
|
||||
byte mac[MAX_DIGEST_SIZE];
|
||||
Hmac cookieHmac;
|
||||
byte cookieType;
|
||||
byte macSz;
|
||||
|
||||
#if !defined(NO_SHA) && defined(NO_SHA256)
|
||||
cookieType = SHA;
|
||||
macSz = SHA_DIGEST_SIZE;
|
||||
#endif /* NO_SHA */
|
||||
#ifndef NO_SHA256
|
||||
cookieType = SHA256;
|
||||
macSz = SHA256_DIGEST_SIZE;
|
||||
#endif /* NO_SHA256 */
|
||||
|
||||
if (cookieSz < ssl->specs.hash_size + macSz)
|
||||
return HRR_COOKIE_ERROR;
|
||||
cookieSz -= macSz;
|
||||
|
||||
ret = wc_HmacSetKey(&cookieHmac, cookieType,
|
||||
ssl->buffers.tls13CookieSecret.buffer,
|
||||
ssl->buffers.tls13CookieSecret.length);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
if ((ret = wc_HmacUpdate(&cookieHmac, cookie, cookieSz)) != 0)
|
||||
return ret;
|
||||
if ((ret = wc_HmacFinal(&cookieHmac, mac)) != 0)
|
||||
return ret;
|
||||
|
||||
if (ConstantCompare(cookie + cookieSz, mac, macSz) != 0)
|
||||
return HRR_COOKIE_ERROR;
|
||||
return cookieSz;
|
||||
}
|
||||
|
||||
/* Length of the KeyShare Extension */
|
||||
#define HRR_KEY_SHARE_SZ (OPAQUE16_LEN + OPAQUE16_LEN + OPAQUE16_LEN)
|
||||
/* Length of the Cookie Extension excluding cookie data */
|
||||
#define HRR_COOKIE_HDR_SZ (OPAQUE16_LEN + OPAQUE16_LEN + OPAQUE16_LEN)
|
||||
/* PV | CipherSuite | Ext Len */
|
||||
#define HRR_BODY_SZ (OPAQUE16_LEN + OPAQUE16_LEN + OPAQUE16_LEN)
|
||||
/* HH | PV | CipherSuite | Ext Len | Key Share | Cookie */
|
||||
#define MAX_HRR_SZ (HANDSHAKE_HEADER_SZ + \
|
||||
HRR_BODY_SZ + \
|
||||
HRR_KEY_SHARE_SZ + \
|
||||
HRR_COOKIE_HDR_SZ)
|
||||
/* Restart the Hanshake hash from the cookie value.
|
||||
*
|
||||
* ssl SSL/TLS object.
|
||||
* cookie Cookie data from client.
|
||||
* returns 0 on success, otherwise failure.
|
||||
*/
|
||||
static int RestartHandshakeHashWithCookie(WOLFSSL* ssl, Cookie* cookie)
|
||||
{
|
||||
byte header[HANDSHAKE_HEADER_SZ];
|
||||
byte hrr[MAX_HRR_SZ];
|
||||
int hrrIdx;
|
||||
word32 idx;
|
||||
byte hashSz;
|
||||
byte* cookieData;
|
||||
byte cookieDataSz;
|
||||
word16 length;
|
||||
int keyShareExt = 0;
|
||||
int ret;
|
||||
|
||||
cookieDataSz = ret = CheckCookie(ssl, &cookie->data, cookie->len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
hashSz = cookie->data;
|
||||
cookieData = &cookie->data;
|
||||
idx = OPAQUE8_LEN;
|
||||
|
||||
/* Restart handshake hash with synthetic message hash. */
|
||||
AddTls13HandShakeHeader(header, hashSz, 0, 0, message_hash, ssl);
|
||||
if ((ret = InitHandshakeHashes(ssl)) != 0)
|
||||
return ret;
|
||||
if ((ret = HashOutputRaw(ssl, header, sizeof(header))) != 0)
|
||||
return ret;
|
||||
if ((ret = HashOutputRaw(ssl, cookieData + idx, hashSz)) != 0)
|
||||
return ret;
|
||||
|
||||
/* Reconstruct the HelloRetryMessage for handshake hash. */
|
||||
length = HRR_BODY_SZ + HRR_COOKIE_HDR_SZ + cookie->len;
|
||||
if (cookieDataSz > hashSz + OPAQUE16_LEN) {
|
||||
keyShareExt = 1;
|
||||
length += HRR_KEY_SHARE_SZ;
|
||||
}
|
||||
AddTls13HandShakeHeader(hrr, length, 0, 0, hello_retry_request, ssl);
|
||||
|
||||
idx += hashSz;
|
||||
hrrIdx = HANDSHAKE_HEADER_SZ;
|
||||
/* TODO: [TLS13] Replace existing code with code in comment.
|
||||
* Use the TLS v1.3 draft version for now.
|
||||
*
|
||||
* Change to:
|
||||
* hrr[hrrIdx++] = ssl->version.major;
|
||||
* hrr[hrrIdx++] = ssl->version.minor;
|
||||
*/
|
||||
/* The negotiated protocol version. */
|
||||
hrr[hrrIdx++] = TLS_DRAFT_MAJOR;
|
||||
hrr[hrrIdx++] = TLS_DRAFT_MINOR;
|
||||
/* Cipher Suite */
|
||||
hrr[hrrIdx++] = cookieData[idx++];
|
||||
hrr[hrrIdx++] = cookieData[idx++];
|
||||
|
||||
/* Extensions' length */
|
||||
length -= HRR_BODY_SZ;
|
||||
c16toa(length, hrr + hrrIdx);
|
||||
hrrIdx += 2;
|
||||
/* Optional KeyShare Extension */
|
||||
if (keyShareExt) {
|
||||
c16toa(TLSX_KEY_SHARE, hrr + hrrIdx);
|
||||
hrrIdx += 2;
|
||||
c16toa(OPAQUE16_LEN, hrr + hrrIdx);
|
||||
hrrIdx += 2;
|
||||
hrr[hrrIdx++] = cookieData[idx++];
|
||||
hrr[hrrIdx++] = cookieData[idx++];
|
||||
}
|
||||
/* Mandatory Cookie Extension */
|
||||
c16toa(TLSX_COOKIE, hrr + hrrIdx);
|
||||
hrrIdx += 2;
|
||||
c16toa(cookie->len + OPAQUE16_LEN, hrr + hrrIdx);
|
||||
hrrIdx += 2;
|
||||
c16toa(cookie->len, hrr + hrrIdx);
|
||||
hrrIdx += 2;
|
||||
|
||||
#ifdef WOLFSSL_DEBUG_TLS
|
||||
WOLFSSL_MSG("Reconstucted HelloRetryRequest");
|
||||
WOLFSSL_BUFFER(hrr, hrrIdx);
|
||||
WOLFSSL_MSG("Cookie");
|
||||
WOLFSSL_BUFFER(cookieData, cookie->len);
|
||||
#endif
|
||||
|
||||
if ((ret = HashOutputRaw(ssl, hrr, hrrIdx)) != 0)
|
||||
return ret;
|
||||
return HashOutputRaw(ssl, cookieData, cookie->len);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Handle a ClientHello handshake message.
|
||||
* If the protocol version in the message is not TLS v1.3 or higher, use
|
||||
* DoClientHello()
|
||||
@ -3182,6 +3387,23 @@ static int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
|
||||
if (TLSX_Find(ssl->extensions, TLSX_SUPPORTED_VERSIONS) == NULL)
|
||||
ssl->version.minor = pv.minor;
|
||||
#ifdef WOLFSSL_SEND_HRR_COOKIE
|
||||
if (ssl->options.sendCookie &&
|
||||
ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST) {
|
||||
TLSX* ext;
|
||||
|
||||
if ((ext = TLSX_Find(ssl->extensions, TLSX_COOKIE)) == NULL)
|
||||
return HRR_COOKIE_ERROR;
|
||||
/* Ensure the cookie came from client and isn't the one in the response
|
||||
* - HelloRetryRequest.
|
||||
*/
|
||||
if (ext->resp == 1)
|
||||
return HRR_COOKIE_ERROR;
|
||||
ret = RestartHandshakeHashWithCookie(ssl, (Cookie*)ext->data);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
ssl->options.sendVerify = SEND_CERT;
|
||||
|
||||
@ -3244,6 +3466,11 @@ int SendTls13HelloRetryRequest(WOLFSSL* ssl)
|
||||
|
||||
WOLFSSL_ENTER("SendTls13HelloRetryRequest");
|
||||
|
||||
#ifndef WOLFSSL_TLS13_DRAFT_18
|
||||
if ((ret = RestartHandshakeHash(ssl)) < 0)
|
||||
return ret;
|
||||
#endif
|
||||
|
||||
/* Get the length of the extensions that will be written. */
|
||||
len = TLSX_GetResponseSize(ssl, hello_retry_request);
|
||||
/* There must be extensions sent to indicate what client needs to do. */
|
||||
@ -3294,11 +3521,6 @@ int SendTls13HelloRetryRequest(WOLFSSL* ssl)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef WOLFSSL_TLS13_DRAFT_18
|
||||
if ((ret = RestartHandshakeHash(ssl)) < 0)
|
||||
return ret;
|
||||
#endif
|
||||
|
||||
if ((ret = HashOutput(ssl, output, idx, 0)) != 0)
|
||||
return ret;
|
||||
|
||||
@ -3504,6 +3726,9 @@ static int SendTls13CertificateRequest(WOLFSSL* ssl, byte* reqCtx,
|
||||
int sendSz;
|
||||
word32 i;
|
||||
int reqSz;
|
||||
#ifndef WOLFSSL_TLS13_DRAFT_18
|
||||
TLSX* ext;
|
||||
#endif
|
||||
|
||||
WOLFSSL_ENTER("SendTls13CertificateRequest");
|
||||
|
||||
@ -3549,9 +3774,12 @@ static int SendTls13CertificateRequest(WOLFSSL* ssl, byte* reqCtx,
|
||||
c16toa(0, &output[i]); /* auth's */
|
||||
i += REQ_HEADER_SZ;
|
||||
#else
|
||||
ext = TLSX_Find(ssl->extensions, TLSX_SIGNATURE_ALGORITHMS);
|
||||
ext->resp = 0;
|
||||
|
||||
i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
|
||||
reqSz = OPAQUE8_LEN + reqCtxLen +
|
||||
TLSX_GetResponseSize(ssl, certificate_request);
|
||||
TLSX_GetRequestSize(ssl, certificate_request);
|
||||
|
||||
sendSz = i + reqSz;
|
||||
/* Always encrypted and make room for padding. */
|
||||
@ -3576,7 +3804,7 @@ static int SendTls13CertificateRequest(WOLFSSL* ssl, byte* reqCtx,
|
||||
}
|
||||
|
||||
/* Certificate extensions. */
|
||||
i += TLSX_WriteResponse(ssl, output + i, certificate_request);
|
||||
i += TLSX_WriteRequest(ssl, output + i, certificate_request);
|
||||
#endif
|
||||
|
||||
/* Always encrypted. */
|
||||
@ -6060,7 +6288,7 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||
|
||||
|
||||
if (ret == 0 && type != client_hello && type != session_ticket &&
|
||||
type != key_update && ssl->error != WC_PENDING_E) {
|
||||
type != key_update && ssl->error != WC_PENDING_E) {
|
||||
ret = HashInput(ssl, input + inIdx, size);
|
||||
}
|
||||
|
||||
@ -6446,6 +6674,72 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl)
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(WOLFSSL_SEND_HRR_COOKIE) && !defined(NO_WOLFSSL_SERVER)
|
||||
/* Send a cookie with the HelloRetryRequest to avoid storing state.
|
||||
*
|
||||
* ssl SSL/TLS object.
|
||||
* secret Secret to use when generating integrity check for cookie.
|
||||
* A value of NULL indicates to generate a new random secret.
|
||||
* secretSz Size of secret data in bytes.
|
||||
* Use a value of 0 to indicate use of default size.
|
||||
* returns BAD_FUNC_ARG when ssl is NULL, not using TLS v1.3, or called on a
|
||||
* client; SSL_SUCCESS on success and otherwise failure.
|
||||
*/
|
||||
int wolfSSL_send_hrr_cookie(WOLFSSL* ssl, const unsigned char* secret,
|
||||
unsigned int secretSz)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (ssl == NULL || !IsAtLeastTLSv1_3(ssl->version) ||
|
||||
ssl->options.side == WOLFSSL_CLIENT_END)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
if (secretSz == 0) {
|
||||
#if !defined(NO_SHA) && defined(NO_SHA256)
|
||||
secretSz = SHA_DIGEST_SIZE;
|
||||
#endif /* NO_SHA */
|
||||
#ifndef NO_SHA256
|
||||
secretSz = SHA256_DIGEST_SIZE;
|
||||
#endif /* NO_SHA256 */
|
||||
}
|
||||
|
||||
if (secretSz != ssl->buffers.tls13CookieSecret.length) {
|
||||
byte* newSecret;
|
||||
|
||||
if (ssl->buffers.tls13CookieSecret.buffer != NULL) {
|
||||
ForceZero(ssl->buffers.tls13CookieSecret.buffer,
|
||||
ssl->buffers.tls13CookieSecret.length);
|
||||
XFREE(ssl->buffers.tls13CookieSecret.buffer,
|
||||
ssl->heap, DYNAMIC_TYPE_COOKIE_PWD);
|
||||
}
|
||||
|
||||
newSecret = (byte*)XMALLOC(secretSz, ssl->heap,DYNAMIC_TYPE_COOKIE_PWD);
|
||||
if (newSecret == NULL) {
|
||||
ssl->buffers.tls13CookieSecret.buffer = NULL;
|
||||
ssl->buffers.tls13CookieSecret.length = 0;
|
||||
WOLFSSL_MSG("couldn't allocate new cookie secret");
|
||||
return MEMORY_ERROR;
|
||||
}
|
||||
ssl->buffers.tls13CookieSecret.buffer = newSecret;
|
||||
ssl->buffers.tls13CookieSecret.length = secretSz;
|
||||
}
|
||||
|
||||
/* If the supplied secret is NULL, randomly generate a new secret. */
|
||||
if (secret == NULL) {
|
||||
ret = wc_RNG_GenerateBlock(ssl->rng,
|
||||
ssl->buffers.tls13CookieSecret.buffer, secretSz);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
XMEMCPY(ssl->buffers.tls13CookieSecret.buffer, secret, secretSz);
|
||||
|
||||
ssl->options.sendCookie = 1;
|
||||
|
||||
return SSL_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Create a key share entry from group.
|
||||
* Generates a key pair.
|
||||
*
|
||||
|
@ -168,7 +168,8 @@ enum wolfSSL_ErrorCodes {
|
||||
MATCH_SUITE_ERROR = -501, /* can't match cipher suite */
|
||||
COMPRESSION_ERROR = -502, /* compression mismatch */
|
||||
KEY_SHARE_ERROR = -503, /* key share mismatch */
|
||||
POST_HAND_AUTH_ERROR = -504 /* client won't do post-hand auth */
|
||||
POST_HAND_AUTH_ERROR = -504, /* client won't do post-hand auth */
|
||||
HRR_COOKIE_ERROR = -505 /* HRR msg cookie mismatch */
|
||||
/* end negotiation parameter errors only 10 for now */
|
||||
/* add strings to wolfSSL_ERR_reason_error_string in internal.c !!!!! */
|
||||
|
||||
|
@ -1789,6 +1789,7 @@ typedef enum {
|
||||
TLSX_EARLY_DATA = 0x002a,
|
||||
#endif
|
||||
TLSX_SUPPORTED_VERSIONS = 0x002b,
|
||||
TLSX_COOKIE = 0x002c,
|
||||
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
|
||||
TLSX_PSK_KEY_EXCHANGE_MODES = 0x002d,
|
||||
#endif
|
||||
@ -1813,8 +1814,9 @@ WOLFSSL_LOCAL int TLSX_SupportExtensions(WOLFSSL* ssl);
|
||||
WOLFSSL_LOCAL int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isRequest);
|
||||
|
||||
#ifndef NO_WOLFSSL_CLIENT
|
||||
WOLFSSL_LOCAL word16 TLSX_GetRequestSize(WOLFSSL* ssl);
|
||||
WOLFSSL_LOCAL word16 TLSX_WriteRequest(WOLFSSL* ssl, byte* output);
|
||||
WOLFSSL_LOCAL word16 TLSX_GetRequestSize(WOLFSSL* ssl, byte msgType);
|
||||
WOLFSSL_LOCAL word16 TLSX_WriteRequest(WOLFSSL* ssl, byte* output,
|
||||
byte msgType);
|
||||
#endif
|
||||
|
||||
#ifndef NO_WOLFSSL_SERVER
|
||||
@ -2063,6 +2065,16 @@ WOLFSSL_LOCAL int TLSX_ValidateQSHScheme(TLSX** extensions, word16 name);
|
||||
#endif /* HAVE_QSH */
|
||||
|
||||
#ifdef WOLFSSL_TLS13
|
||||
/* Cookie extension information - cookie data. */
|
||||
typedef struct Cookie {
|
||||
word16 len;
|
||||
byte data;
|
||||
} Cookie;
|
||||
|
||||
WOLFSSL_LOCAL int TLSX_Cookie_Use(WOLFSSL* ssl, byte* data, word16 len,
|
||||
byte* mac, byte macSz, int resp);
|
||||
|
||||
|
||||
/* Key Share - TLS v1.3 Specification */
|
||||
|
||||
/* The KeyShare extension information - entry in a linked list. */
|
||||
@ -2080,6 +2092,7 @@ WOLFSSL_LOCAL int TLSX_KeyShare_Use(WOLFSSL* ssl, word16 group, word16 len,
|
||||
WOLFSSL_LOCAL int TLSX_KeyShare_Empty(WOLFSSL* ssl);
|
||||
WOLFSSL_LOCAL int TLSX_KeyShare_Establish(WOLFSSL* ssl);
|
||||
|
||||
|
||||
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
|
||||
/* The PreSharedKey extension information - entry in a linked list. */
|
||||
typedef struct PreSharedKey {
|
||||
@ -2106,6 +2119,7 @@ WOLFSSL_LOCAL int TLSX_PreSharedKey_Use(WOLFSSL* ssl, byte* identity,
|
||||
byte resumption,
|
||||
PreSharedKey **preSharedKey);
|
||||
|
||||
/* The possible Pre-Shared Key key exchange modes. */
|
||||
enum PskKeyExchangeMode {
|
||||
PSK_KE,
|
||||
PSK_DHE_KE
|
||||
@ -2123,6 +2137,7 @@ WOLFSSL_LOCAL int TLSX_EarlyData_Use(WOLFSSL* ssl, word32 max);
|
||||
#endif
|
||||
#endif /* HAVE_SESSION_TICKET || !NO_PSK */
|
||||
|
||||
|
||||
/* The types of keys to derive for. */
|
||||
enum DeriveKeyType {
|
||||
no_key,
|
||||
@ -2196,13 +2211,13 @@ struct WOLFSSL_CTX {
|
||||
byte groupMessages; /* group handshake messages before sending */
|
||||
byte minDowngrade; /* minimum downgrade version */
|
||||
byte haveEMS; /* have extended master secret extension */
|
||||
byte useClientOrder; /* Use client's cipher preference order */
|
||||
byte useClientOrder:1; /* Use client's cipher preference order */
|
||||
#ifdef WOLFSSL_TLS13
|
||||
byte noTicketTls13; /* Server won't create new Ticket */
|
||||
byte noPskDheKe; /* Don't use (EC)DHE with PSK */
|
||||
byte noTicketTls13:1; /* Server won't create new Ticket */
|
||||
byte noPskDheKe:1; /* Don't use (EC)DHE with PSK */
|
||||
#endif
|
||||
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH)
|
||||
byte postHandshakeAuth;/* Post-handshake authentication supported. */
|
||||
byte postHandshakeAuth:1; /* Post-handshake auth supported. */
|
||||
#endif
|
||||
#if defined(WOLFSSL_SCTP) && defined(WOLFSSL_DTLS)
|
||||
byte dtlsSctp; /* DTLS-over-SCTP mode */
|
||||
@ -2676,6 +2691,9 @@ typedef struct Buffers {
|
||||
int certChainCnt;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef WOLFSSL_SEND_HRR_COOKIE
|
||||
buffer tls13CookieSecret; /* HRR cookie secret */
|
||||
#endif
|
||||
#ifdef WOLFSSL_DTLS
|
||||
WOLFSSL_DTLS_CTX dtlsCtx; /* DTLS connection context */
|
||||
#ifndef NO_WOLFSSL_SERVER
|
||||
@ -2808,6 +2826,9 @@ typedef struct Options {
|
||||
word16 postHandshakeAuth:1;/* Client send post_handshake_auth
|
||||
* extendion. */
|
||||
#endif
|
||||
#if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_SERVER)
|
||||
word16 sendCookie:1; /* Server creates a Cookie in HRR */
|
||||
#endif
|
||||
|
||||
/* need full byte values for this section */
|
||||
byte processReply; /* nonblocking resume */
|
||||
|
@ -404,6 +404,8 @@ WOLFSSL_API int wolfSSL_read(WOLFSSL*, void*, int);
|
||||
WOLFSSL_API int wolfSSL_peek(WOLFSSL*, void*, int);
|
||||
WOLFSSL_API int wolfSSL_accept(WOLFSSL*);
|
||||
#ifdef WOLFSSL_TLS13
|
||||
WOLFSSL_API int wolfSSL_send_hrr_cookie(WOLFSSL* ssl,
|
||||
const unsigned char* secret, unsigned int secretSz);
|
||||
WOLFSSL_API int wolfSSL_CTX_no_ticket_TLSv13(WOLFSSL_CTX* ctx);
|
||||
WOLFSSL_API int wolfSSL_no_ticket_TLSv13(WOLFSSL* ssl);
|
||||
WOLFSSL_API int wolfSSL_CTX_no_dhe_psk(WOLFSSL_CTX* ctx);
|
||||
|
Reference in New Issue
Block a user