Merge pull request #995 from SparkiDev/tls13_cookie

Add TLS v1.3 Cookie extension support
This commit is contained in:
toddouska
2017-06-28 10:12:49 -07:00
committed by GitHub
9 changed files with 784 additions and 147 deletions

View File

@@ -297,6 +297,22 @@ then
fi 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], AC_ARG_ENABLE([rng],
[AS_HELP_STRING([--enable-rng],[Enable compiling and using RNG (default: enabled)])], [AS_HELP_STRING([--enable-rng],[Enable compiling and using RNG (default: enabled)])],
[ ENABLED_RNG=$enableval ], [ ENABLED_RNG=$enableval ],
@@ -3798,6 +3814,7 @@ echo " * TLS v1.3: $ENABLED_TLS13"
echo " * TLS v1.3 Draft 18: $ENABLED_TLS13_DRAFT18" echo " * TLS v1.3 Draft 18: $ENABLED_TLS13_DRAFT18"
echo " * Post-handshake Auth: $ENABLED_TLS13_POST_AUTH" echo " * Post-handshake Auth: $ENABLED_TLS13_POST_AUTH"
echo " * Early Data: $ENABLED_TLS13_EARLY_DATA" echo " * Early Data: $ENABLED_TLS13_EARLY_DATA"
echo " * Send State in HRR Cookie: $ENABLED_SEND_HRR_COOKIE"
echo " * OCSP: $ENABLED_OCSP" echo " * OCSP: $ENABLED_OCSP"
echo " * OCSP Stapling: $ENABLED_CERTIFICATE_STATUS_REQUEST" echo " * OCSP Stapling: $ENABLED_CERTIFICATE_STATUS_REQUEST"
echo " * OCSP Stapling v2: $ENABLED_CERTIFICATE_STATUS_REQUEST_V2" echo " * OCSP Stapling v2: $ENABLED_CERTIFICATE_STATUS_REQUEST_V2"

View File

@@ -379,6 +379,9 @@ static void Usage(void)
#ifdef WOLFSSL_POST_HANDSHAKE_AUTH #ifdef WOLFSSL_POST_HANDSHAKE_AUTH
printf("-Q Request certificate from client post-handshake\n"); printf("-Q Request certificate from client post-handshake\n");
#endif #endif
#ifdef WOLFSSL_SEND_HRR_COOKIE
printf("-J Server sends Cookie Extension containing state\n");
#endif
#endif #endif
#ifdef WOLFSSL_EARLY_DATA #ifdef WOLFSSL_EARLY_DATA
printf("-0 Early data read from client (0-RTT handshake)\n"); 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 #ifdef WOLFSSL_EARLY_DATA
int earlyData = 0; int earlyData = 0;
#endif #endif
#ifdef WOLFSSL_SEND_HRR_COOKIE
int hrrCookie = 0;
#endif
#ifdef WOLFSSL_STATIC_MEMORY #ifdef WOLFSSL_STATIC_MEMORY
#if (defined(HAVE_ECC) && !defined(ALT_ECC_SIZE)) \ #if (defined(HAVE_ECC) && !defined(ALT_ECC_SIZE)) \
@@ -518,10 +524,11 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args)
#ifdef WOLFSSL_VXWORKS #ifdef WOLFSSL_VXWORKS
useAnyAddr = 1; useAnyAddr = 1;
#else #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, "?" while ((ch = mygetopt(argc, argv, "?"
"abc:defgijk:l:nop:q:rsuv:wx" "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) { switch (ch) {
case '?' : case '?' :
Usage(); Usage();
@@ -746,6 +753,12 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args)
#endif #endif
break; break;
case 'J' :
#ifdef WOLFSSL_SEND_HRR_COOKIE
hrrCookie = 1;
#endif
break;
case '0' : case '0' :
#ifdef WOLFSSL_EARLY_DATA #ifdef WOLFSSL_EARLY_DATA
earlyData = 1; earlyData = 1;
@@ -1083,6 +1096,12 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args)
wolfSSL_KeepArrays(ssl); wolfSSL_KeepArrays(ssl);
#endif #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) #if defined(WOLFSSL_STATIC_MEMORY) && defined(DEBUG_WOLFSSL)
{ {
WOLFSSL_MEM_STATS mem_stats; WOLFSSL_MEM_STATS mem_stats;

View File

@@ -95,6 +95,22 @@ if [ $RESULT -ne 0 ]; then
fi fi
echo "" 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. # Use HelloRetryRequest with TLS v1.3 server / TLS v1.3 client - SHA384.
echo -e "\n\nTLS v1.3 HelloRetryRequest - SHA384" echo -e "\n\nTLS v1.3 HelloRetryRequest - SHA384"
port=0 port=0

View File

@@ -4550,6 +4550,10 @@ void SSL_ResourceFree(WOLFSSL* ssl)
ShrinkInputBuffer(ssl, FORCED_FREE); ShrinkInputBuffer(ssl, FORCED_FREE);
if (ssl->buffers.outputBuffer.dynamicFlag) if (ssl->buffers.outputBuffer.dynamicFlag)
ShrinkOutputBuffer(ssl); 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 #ifdef WOLFSSL_DTLS
DtlsMsgPoolReset(ssl); DtlsMsgPoolReset(ssl);
if (ssl->dtls_rx_msg_list != NULL) { 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: case POST_HAND_AUTH_ERROR:
return "Client will not do post handshake authentication"; return "Client will not do post handshake authentication";
case HRR_COOKIE_ERROR:
return "Cookie does not match one sent in HelloRetryRequest";
default : default :
return "unknown error number"; return "unknown error number";
} }
@@ -15742,7 +15749,7 @@ void PickHashSigAlgo(WOLFSSL* ssl, const byte* hashSigAlgo,
if (QSH_Init(ssl) != 0) if (QSH_Init(ssl) != 0)
return MEMORY_E; return MEMORY_E;
#endif #endif
extSz = TLSX_GetRequestSize(ssl); extSz = TLSX_GetRequestSize(ssl, client_hello);
if (extSz != 0) if (extSz != 0)
length += extSz; length += extSz;
#else #else
@@ -15835,7 +15842,7 @@ void PickHashSigAlgo(WOLFSSL* ssl, const byte* hashSigAlgo,
output[idx++] = NO_COMPRESSION; output[idx++] = NO_COMPRESSION;
#ifdef HAVE_TLS_EXTENSIONS #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 */ (void)idx; /* suppress analyzer warning, keep idx current */
#else #else

404
src/tls.c
View File

@@ -4452,6 +4452,170 @@ static int TLSX_SetSupportedVersions(TLSX** extensions, const void* data,
#endif /* WOLFSSL_TLS13 */ #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 */ /* Sugnature Algorithms */
/******************************************************************************/ /******************************************************************************/
@@ -6376,7 +6540,8 @@ int TLSX_PskKeModes_Use(WOLFSSL* ssl, byte modes)
* Only in ClientHello. * Only in ClientHello.
* *
* msgType The type of the message this extension is being written into. * 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) static word16 TLSX_PostHandAuth_GetSize(byte msgType)
{ {
@@ -6478,7 +6643,7 @@ static int TLSX_PostHandAuth_Use(WOLFSSL* ssl)
* In messages: ClientHello, EncryptedExtensions and NewSessionTicket. * In messages: ClientHello, EncryptedExtensions and NewSessionTicket.
* *
* msgType The type of the message this extension is being written into. * 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) static word16 TLSX_EarlyData_GetSize(byte msgType)
{ {
@@ -6561,10 +6726,10 @@ int TLSX_EarlyData_Use(WOLFSSL* ssl, word32 max)
int ret = 0; int ret = 0;
TLSX* extension; 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); extension = TLSX_Find(ssl->extensions, TLSX_EARLY_DATA);
if (extension == NULL) { if (extension == NULL) {
/* Push new early extension. */ /* Push new early data extension. */
ret = TLSX_Push(&ssl->extensions, TLSX_EARLY_DATA, NULL, ssl->heap); ret = TLSX_Push(&ssl->extensions, TLSX_EARLY_DATA, NULL, ssl->heap);
if (ret != 0) if (ret != 0)
return ret; return ret;
@@ -6665,6 +6830,10 @@ void TLSX_FreeAll(TLSX* list, void* heap)
case TLSX_SUPPORTED_VERSIONS: case TLSX_SUPPORTED_VERSIONS:
break; break;
case TLSX_COOKIE:
CKE_FREE_ALL((Cookie*)extension->data, heap);
break;
case TLSX_KEY_SHARE: case TLSX_KEY_SHARE:
KS_FREE_ALL((KeyShareEntry*)extension->data, heap); KS_FREE_ALL((KeyShareEntry*)extension->data, heap);
break; break;
@@ -6782,6 +6951,10 @@ static word16 TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType)
length += SV_GET_SIZE(extension->data); length += SV_GET_SIZE(extension->data);
break; break;
case TLSX_COOKIE:
length += CKE_GET_SIZE((Cookie*)extension->data, msgType);
break;
case TLSX_KEY_SHARE: case TLSX_KEY_SHARE:
length += KS_GET_SIZE((KeyShareEntry*)extension->data, msgType); length += KS_GET_SIZE((KeyShareEntry*)extension->data, msgType);
break; break;
@@ -6919,6 +7092,12 @@ static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore,
offset += SV_WRITE(extension->data, output + offset); offset += SV_WRITE(extension->data, output + offset);
break; break;
case TLSX_COOKIE:
WOLFSSL_MSG("Cookie extension to write");
offset += CKE_WRITE((Cookie*)extension->data, output + offset,
msgType);
break;
case TLSX_KEY_SHARE: case TLSX_KEY_SHARE:
WOLFSSL_MSG("Key Share extension to write"); WOLFSSL_MSG("Key Share extension to write");
offset += KS_WRITE((KeyShareEntry*)extension->data, offset += KS_WRITE((KeyShareEntry*)extension->data,
@@ -7531,13 +7710,14 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer)
#ifndef NO_WOLFSSL_CLIENT #ifndef NO_WOLFSSL_CLIENT
/** Tells the buffered size of extensions to be sent into the client hello. */ /** 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; word16 length = 0;
byte semaphore[SEMAPHORE_SIZE] = {0};
if (TLSX_SupportExtensions(ssl)) { if (!TLSX_SupportExtensions(ssl))
byte semaphore[SEMAPHORE_SIZE] = {0}; return 0;
if (msgType == client_hello) {
EC_VALIDATE_REQUEST(ssl, semaphore); EC_VALIDATE_REQUEST(ssl, semaphore);
QSH_VALIDATE_REQUEST(ssl, semaphore); QSH_VALIDATE_REQUEST(ssl, semaphore);
WOLF_STK_VALIDATE_REQUEST(ssl); WOLF_STK_VALIDATE_REQUEST(ssl);
@@ -7547,28 +7727,43 @@ word16 TLSX_GetRequestSize(WOLFSSL* ssl)
if (!IsAtLeastTLSv1_2(ssl)) if (!IsAtLeastTLSv1_2(ssl))
TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS)); TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
if (!IsAtLeastTLSv1_3(ssl->version)) { if (!IsAtLeastTLSv1_3(ssl->version)) {
TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY)); TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PSK_KEY_EXCHANGE_MODES)); 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
} }
#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) if (length)
length += OPAQUE16_LEN; /* for total length storage. */ 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. */ /** 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; word16 offset = 0;
byte semaphore[SEMAPHORE_SIZE] = {0};
if (TLSX_SupportExtensions(ssl) && output) { if (!TLSX_SupportExtensions(ssl) || output == NULL)
byte semaphore[SEMAPHORE_SIZE] = {0}; return 0;
offset += OPAQUE16_LEN; /* extensions length */ offset += OPAQUE16_LEN; /* extensions length */
if (msgType == client_hello) {
EC_VALIDATE_REQUEST(ssl, semaphore); EC_VALIDATE_REQUEST(ssl, semaphore);
WOLF_STK_VALIDATE_REQUEST(ssl); WOLF_STK_VALIDATE_REQUEST(ssl);
QSH_VALIDATE_REQUEST(ssl, semaphore); QSH_VALIDATE_REQUEST(ssl, semaphore);
if (ssl->suites->hashSigAlgoSz == 0) if (ssl->suites->hashSigAlgoSz == 0)
TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS)); TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS));
#if defined(WOLFSSL_TLS13) #ifdef WOLFSSL_TLS13
if (!IsAtLeastTLSv1_2(ssl)) if (!IsAtLeastTLSv1_2(ssl))
TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS)); TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
if (!IsAtLeastTLSv1_3(ssl->version)) { if (!IsAtLeastTLSv1_3(ssl->version)) {
TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PSK_KEY_EXCHANGE_MODES)); 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 defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) #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)); TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
#endif #endif
#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) if (ssl->extensions) {
offset += TLSX_Write(ssl->extensions, output + offset, semaphore, offset += TLSX_Write(ssl->extensions, output + offset, semaphore,
client_hello); msgType);
}
if (ssl->ctx && ssl->ctx->extensions) if (ssl->ctx && ssl->ctx->extensions) {
offset += TLSX_Write(ssl->ctx->extensions, output + offset, offset += TLSX_Write(ssl->ctx->extensions, output + offset, semaphore,
semaphore, client_hello); msgType);
}
#ifdef HAVE_EXTENDED_MASTER #ifdef HAVE_EXTENDED_MASTER
if (ssl->options.haveEMS) { if (msgType == client_hello && ssl->options.haveEMS) {
c16toa(HELLO_EXT_EXTMS, output + offset); c16toa(HELLO_EXT_EXTMS, output + offset);
offset += HELLO_EXT_TYPE_SZ; offset += HELLO_EXT_TYPE_SZ;
c16toa(0, output + offset); c16toa(0, output + offset);
offset += HELLO_EXT_SZ_SZ; offset += HELLO_EXT_SZ_SZ;
} }
#endif #endif
#ifdef WOLFSSL_TLS13 #ifdef WOLFSSL_TLS13
if (IsAtLeastTLSv1_3(ssl->version)) {
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) #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 #endif
offset += TLSX_Write(ssl->extensions, output + offset, semaphore,
client_hello);
}
#endif #endif
if (offset > OPAQUE16_LEN) if (offset > OPAQUE16_LEN || msgType != client_hello)
c16toa(offset - OPAQUE16_LEN, output); /* extensions length */ c16toa(offset - OPAQUE16_LEN, output); /* extensions length */
}
return offset; return offset;
} }
@@ -7653,14 +7874,20 @@ word16 TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType)
switch (msgType) { switch (msgType) {
case server_hello: case server_hello:
#ifdef WOLFSSL_TLS13 #ifdef WOLFSSL_TLS13
case hello_retry_request: if (ssl->options.tls1_3) {
if (ssl->options.tls1_3) { XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE); TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) #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
} }
#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 #endif
break; break;
#ifdef WOLFSSL_TLS13 #ifdef WOLFSSL_TLS13
@@ -7671,19 +7898,22 @@ word16 TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType)
TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY)); TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
#endif #endif
break; break;
#ifndef NO_CERTS #ifdef WOLFSSL_EARLY_DATA
case certificate_request: case session_ticket:
XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE); if (ssl->options.tls1_3) {
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS)); XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_EARLY_DATA));
}
break; break;
#endif #endif
#ifdef WOLFSSL_EARLY_DATA #ifndef NO_CERT
case session_ticket: case certificate:
if (ssl->options.tls1_3) { XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE); TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_EARLY_DATA)); /* TODO: TLSX_SIGNED_CERTIFICATE_TIMESTAMP,
} * TLSX_SERVER_CERTIFICATE_TYPE
break; */
break;
#endif #endif
#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. */ /* 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. */ length += OPAQUE16_LEN; /* for total length storage. */
return length; return length;
@@ -7724,7 +7954,6 @@ word16 TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType)
switch (msgType) { switch (msgType) {
case server_hello: case server_hello:
#ifdef WOLFSSL_TLS13 #ifdef WOLFSSL_TLS13
case hello_retry_request:
if (ssl->options.tls1_3) { if (ssl->options.tls1_3) {
XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE); XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
@@ -7734,6 +7963,12 @@ word16 TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType)
} }
#endif #endif
break; 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 #ifdef WOLFSSL_TLS13
case encrypted_extensions: case encrypted_extensions:
TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SESSION_TICKET)); TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SESSION_TICKET));
@@ -7743,10 +7978,12 @@ word16 TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType)
#endif #endif
break; break;
#ifndef NO_CERTS #ifndef NO_CERTS
case certificate_request: case certificate:
XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE); XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
TURN_OFF(semaphore, TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS)); /* TODO: TLSX_SIGNED_CERTIFICATE_TIMESTAMP,
* TLSX_SERVER_CERTIFICATE_TYPE
*/
break; break;
#endif #endif
#ifdef WOLFSSL_EARLY_DATA #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, offset += TLSX_Write(ssl->extensions, output + offset, semaphore,
msgType); 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 #ifdef HAVE_EXTENDED_MASTER
if (ssl->options.haveEMS && msgType == server_hello) { if (ssl->options.haveEMS && msgType == server_hello) {
c16toa(HELLO_EXT_EXTMS, output + offset); c16toa(HELLO_EXT_EXTMS, output + offset);
@@ -7774,7 +8020,7 @@ word16 TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType)
} }
#endif #endif
if (offset > OPAQUE16_LEN || msgType == encrypted_extensions) if (offset > OPAQUE16_LEN || msgType != server_hello)
c16toa(offset - OPAQUE16_LEN, output); /* extensions length */ 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); ret = SV_PARSE(ssl, input + offset, size);
break; 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: case TLSX_KEY_SHARE:
WOLFSSL_MSG("Key Share extension received"); WOLFSSL_MSG("Key Share extension received");

View File

@@ -1366,60 +1366,6 @@ static int HashInputRaw(WOLFSSL* ssl, const byte* input, int sz)
} }
#endif #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. /* Extract the handshake header information.
* *
* ssl The SSL/TLS object. * ssl The SSL/TLS object.
@@ -2348,7 +2294,7 @@ int SendTls13ClientHello(WOLFSSL* ssl)
return MEMORY_E; return MEMORY_E;
#endif #endif
/* Include length of TLS extensions. */ /* Include length of TLS extensions. */
length += TLSX_GetRequestSize(ssl); length += TLSX_GetRequestSize(ssl, client_hello);
/* Total message size. */ /* Total message size. */
sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
@@ -2396,7 +2342,7 @@ int SendTls13ClientHello(WOLFSSL* ssl)
output[idx++] = NO_COMPRESSION; output[idx++] = NO_COMPRESSION;
/* Write out extensions for a request. */ /* 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) #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
/* Resumption has a specific set of extensions and binder is calculated /* Resumption has a specific set of extensions and binder is calculated
@@ -2429,6 +2375,117 @@ int SendTls13ClientHello(WOLFSSL* ssl)
return ret; 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. /* Parse and handle a HelloRetryRequest message.
* Only a client will receive this message. * Only a client will receive this message.
* *
@@ -3059,6 +3116,154 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz,
} }
#endif #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. /* Handle a ClientHello handshake message.
* If the protocol version in the message is not TLS v1.3 or higher, use * If the protocol version in the message is not TLS v1.3 or higher, use
* DoClientHello() * DoClientHello()
@@ -3182,6 +3387,23 @@ static int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
if (TLSX_Find(ssl->extensions, TLSX_SUPPORTED_VERSIONS) == NULL) if (TLSX_Find(ssl->extensions, TLSX_SUPPORTED_VERSIONS) == NULL)
ssl->version.minor = pv.minor; 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; ssl->options.sendVerify = SEND_CERT;
@@ -3244,6 +3466,11 @@ int SendTls13HelloRetryRequest(WOLFSSL* ssl)
WOLFSSL_ENTER("SendTls13HelloRetryRequest"); 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. */ /* Get the length of the extensions that will be written. */
len = TLSX_GetResponseSize(ssl, hello_retry_request); len = TLSX_GetResponseSize(ssl, hello_retry_request);
/* There must be extensions sent to indicate what client needs to do. */ /* There must be extensions sent to indicate what client needs to do. */
@@ -3294,11 +3521,6 @@ int SendTls13HelloRetryRequest(WOLFSSL* ssl)
} }
#endif #endif
#ifndef WOLFSSL_TLS13_DRAFT_18
if ((ret = RestartHandshakeHash(ssl)) < 0)
return ret;
#endif
if ((ret = HashOutput(ssl, output, idx, 0)) != 0) if ((ret = HashOutput(ssl, output, idx, 0)) != 0)
return ret; return ret;
@@ -3504,6 +3726,9 @@ static int SendTls13CertificateRequest(WOLFSSL* ssl, byte* reqCtx,
int sendSz; int sendSz;
word32 i; word32 i;
int reqSz; int reqSz;
#ifndef WOLFSSL_TLS13_DRAFT_18
TLSX* ext;
#endif
WOLFSSL_ENTER("SendTls13CertificateRequest"); WOLFSSL_ENTER("SendTls13CertificateRequest");
@@ -3549,9 +3774,12 @@ static int SendTls13CertificateRequest(WOLFSSL* ssl, byte* reqCtx,
c16toa(0, &output[i]); /* auth's */ c16toa(0, &output[i]); /* auth's */
i += REQ_HEADER_SZ; i += REQ_HEADER_SZ;
#else #else
ext = TLSX_Find(ssl->extensions, TLSX_SIGNATURE_ALGORITHMS);
ext->resp = 0;
i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
reqSz = OPAQUE8_LEN + reqCtxLen + reqSz = OPAQUE8_LEN + reqCtxLen +
TLSX_GetResponseSize(ssl, certificate_request); TLSX_GetRequestSize(ssl, certificate_request);
sendSz = i + reqSz; sendSz = i + reqSz;
/* Always encrypted and make room for padding. */ /* Always encrypted and make room for padding. */
@@ -3576,7 +3804,7 @@ static int SendTls13CertificateRequest(WOLFSSL* ssl, byte* reqCtx,
} }
/* Certificate extensions. */ /* Certificate extensions. */
i += TLSX_WriteResponse(ssl, output + i, certificate_request); i += TLSX_WriteRequest(ssl, output + i, certificate_request);
#endif #endif
/* Always encrypted. */ /* Always encrypted. */
@@ -6060,7 +6288,7 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx,
if (ret == 0 && type != client_hello && type != session_ticket && 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); 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. /* Create a key share entry from group.
* Generates a key pair. * Generates a key pair.
* *

View File

@@ -168,7 +168,8 @@ enum wolfSSL_ErrorCodes {
MATCH_SUITE_ERROR = -501, /* can't match cipher suite */ MATCH_SUITE_ERROR = -501, /* can't match cipher suite */
COMPRESSION_ERROR = -502, /* compression mismatch */ COMPRESSION_ERROR = -502, /* compression mismatch */
KEY_SHARE_ERROR = -503, /* key share 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 */ /* end negotiation parameter errors only 10 for now */
/* add strings to wolfSSL_ERR_reason_error_string in internal.c !!!!! */ /* add strings to wolfSSL_ERR_reason_error_string in internal.c !!!!! */

View File

@@ -1789,6 +1789,7 @@ typedef enum {
TLSX_EARLY_DATA = 0x002a, TLSX_EARLY_DATA = 0x002a,
#endif #endif
TLSX_SUPPORTED_VERSIONS = 0x002b, TLSX_SUPPORTED_VERSIONS = 0x002b,
TLSX_COOKIE = 0x002c,
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
TLSX_PSK_KEY_EXCHANGE_MODES = 0x002d, TLSX_PSK_KEY_EXCHANGE_MODES = 0x002d,
#endif #endif
@@ -1813,8 +1814,9 @@ WOLFSSL_LOCAL int TLSX_SupportExtensions(WOLFSSL* ssl);
WOLFSSL_LOCAL int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isRequest); WOLFSSL_LOCAL int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isRequest);
#ifndef NO_WOLFSSL_CLIENT #ifndef NO_WOLFSSL_CLIENT
WOLFSSL_LOCAL word16 TLSX_GetRequestSize(WOLFSSL* ssl); WOLFSSL_LOCAL word16 TLSX_GetRequestSize(WOLFSSL* ssl, byte msgType);
WOLFSSL_LOCAL word16 TLSX_WriteRequest(WOLFSSL* ssl, byte* output); WOLFSSL_LOCAL word16 TLSX_WriteRequest(WOLFSSL* ssl, byte* output,
byte msgType);
#endif #endif
#ifndef NO_WOLFSSL_SERVER #ifndef NO_WOLFSSL_SERVER
@@ -2063,6 +2065,16 @@ WOLFSSL_LOCAL int TLSX_ValidateQSHScheme(TLSX** extensions, word16 name);
#endif /* HAVE_QSH */ #endif /* HAVE_QSH */
#ifdef WOLFSSL_TLS13 #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 */ /* Key Share - TLS v1.3 Specification */
/* The KeyShare extension information - entry in a linked list. */ /* 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_Empty(WOLFSSL* ssl);
WOLFSSL_LOCAL int TLSX_KeyShare_Establish(WOLFSSL* ssl); WOLFSSL_LOCAL int TLSX_KeyShare_Establish(WOLFSSL* ssl);
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
/* The PreSharedKey extension information - entry in a linked list. */ /* The PreSharedKey extension information - entry in a linked list. */
typedef struct PreSharedKey { typedef struct PreSharedKey {
@@ -2106,6 +2119,7 @@ WOLFSSL_LOCAL int TLSX_PreSharedKey_Use(WOLFSSL* ssl, byte* identity,
byte resumption, byte resumption,
PreSharedKey **preSharedKey); PreSharedKey **preSharedKey);
/* The possible Pre-Shared Key key exchange modes. */
enum PskKeyExchangeMode { enum PskKeyExchangeMode {
PSK_KE, PSK_KE,
PSK_DHE_KE PSK_DHE_KE
@@ -2123,6 +2137,7 @@ WOLFSSL_LOCAL int TLSX_EarlyData_Use(WOLFSSL* ssl, word32 max);
#endif #endif
#endif /* HAVE_SESSION_TICKET || !NO_PSK */ #endif /* HAVE_SESSION_TICKET || !NO_PSK */
/* The types of keys to derive for. */ /* The types of keys to derive for. */
enum DeriveKeyType { enum DeriveKeyType {
no_key, no_key,
@@ -2196,13 +2211,13 @@ struct WOLFSSL_CTX {
byte groupMessages; /* group handshake messages before sending */ byte groupMessages; /* group handshake messages before sending */
byte minDowngrade; /* minimum downgrade version */ byte minDowngrade; /* minimum downgrade version */
byte haveEMS; /* have extended master secret extension */ 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 #ifdef WOLFSSL_TLS13
byte noTicketTls13; /* Server won't create new Ticket */ byte noTicketTls13:1; /* Server won't create new Ticket */
byte noPskDheKe; /* Don't use (EC)DHE with PSK */ byte noPskDheKe:1; /* Don't use (EC)DHE with PSK */
#endif #endif
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH)
byte postHandshakeAuth;/* Post-handshake authentication supported. */ byte postHandshakeAuth:1; /* Post-handshake auth supported. */
#endif #endif
#if defined(WOLFSSL_SCTP) && defined(WOLFSSL_DTLS) #if defined(WOLFSSL_SCTP) && defined(WOLFSSL_DTLS)
byte dtlsSctp; /* DTLS-over-SCTP mode */ byte dtlsSctp; /* DTLS-over-SCTP mode */
@@ -2676,6 +2691,9 @@ typedef struct Buffers {
int certChainCnt; int certChainCnt;
#endif #endif
#endif #endif
#ifdef WOLFSSL_SEND_HRR_COOKIE
buffer tls13CookieSecret; /* HRR cookie secret */
#endif
#ifdef WOLFSSL_DTLS #ifdef WOLFSSL_DTLS
WOLFSSL_DTLS_CTX dtlsCtx; /* DTLS connection context */ WOLFSSL_DTLS_CTX dtlsCtx; /* DTLS connection context */
#ifndef NO_WOLFSSL_SERVER #ifndef NO_WOLFSSL_SERVER
@@ -2808,6 +2826,9 @@ typedef struct Options {
word16 postHandshakeAuth:1;/* Client send post_handshake_auth word16 postHandshakeAuth:1;/* Client send post_handshake_auth
* extendion. */ * extendion. */
#endif #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 */ /* need full byte values for this section */
byte processReply; /* nonblocking resume */ byte processReply; /* nonblocking resume */

View File

@@ -404,6 +404,8 @@ WOLFSSL_API int wolfSSL_read(WOLFSSL*, void*, int);
WOLFSSL_API int wolfSSL_peek(WOLFSSL*, void*, int); WOLFSSL_API int wolfSSL_peek(WOLFSSL*, void*, int);
WOLFSSL_API int wolfSSL_accept(WOLFSSL*); WOLFSSL_API int wolfSSL_accept(WOLFSSL*);
#ifdef WOLFSSL_TLS13 #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_CTX_no_ticket_TLSv13(WOLFSSL_CTX* ctx);
WOLFSSL_API int wolfSSL_no_ticket_TLSv13(WOLFSSL* ssl); WOLFSSL_API int wolfSSL_no_ticket_TLSv13(WOLFSSL* ssl);
WOLFSSL_API int wolfSSL_CTX_no_dhe_psk(WOLFSSL_CTX* ctx); WOLFSSL_API int wolfSSL_CTX_no_dhe_psk(WOLFSSL_CTX* ctx);