TLS v1.3 0-RTT

This commit is contained in:
Sean Parkinson 2017-06-19 11:37:10 +10:00
parent 97906bfdb2
commit 350ce5fcef
12 changed files with 1271 additions and 194 deletions

View File

@ -2326,6 +2326,26 @@ then
AM_CFLAGS="$AM_CFLAGS -DHAVE_SUPPORTED_CURVES"])
fi
# Early Data handshake in TLS v1.3 and above
AC_ARG_ENABLE([earlydata],
[AS_HELP_STRING([--enable-earlydata],[Enable Early Data handshake with wolfSSL TLS v1.3 (default: disabled)])],
[ ENABLED_EARLY_DATA=$enableval ],
[ ENABLED_EARLY_DATA=no ]
)
if test "$ENABLED_EARLY_DATA" = "yes"
then
if test "x$ENABLED_TLS13" = "xno"
then
AC_MSG_ERROR([cannot enable earlydata without enabling tls13.])
fi
if test "x$ENABLED_SESSION_TICKET" = "xno" && test "x$ENABLED_PSK" = "xno"
then
AC_MSG_ERROR([cannot enable earlydata without enabling session tickets and/or PSK.])
fi
AM_CFLAGS="-DWOLFSSL_EARLY_DATA $AM_CFLAGS"
fi
# PKCS7
AC_ARG_ENABLE([pkcs7],
[AS_HELP_STRING([--enable-pkcs7],[Enable PKCS7 (default: disabled)])],
@ -3740,6 +3760,7 @@ echo " * SCTP: $ENABLED_SCTP"
echo " * Old TLS Versions: $ENABLED_OLD_TLS"
echo " * SSL version 3.0: $ENABLED_SSLV3"
echo " * TLS v1.3: $ENABLED_TLS13"
echo " * Early Data: $ENABLED_EARLY_DATA"
echo " * OCSP: $ENABLED_OCSP"
echo " * OCSP Stapling: $ENABLED_CERTIFICATE_STATUS_REQUEST"
echo " * OCSP Stapling v2: $ENABLED_CERTIFICATE_STATUS_REQUEST_V2"

View File

@ -716,6 +716,9 @@ static void Usage(void)
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH)
printf("-Q Support requesting certificate post-handshake\n");
#endif
#ifdef WOLFSSL_EARLY_DATA
printf("-0 Early data sent to server (0-RTT handshake)\n");
#endif
}
THREAD_RETURN WOLFSSL_THREAD client_test(void* args)
@ -817,6 +820,9 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args)
#endif
#endif
int updateKeysIVs = 0;
#ifdef WOLFSSL_EARLY_DATA
int earlyData = 0;
#endif
#ifdef HAVE_OCSP
int useOcsp = 0;
@ -864,7 +870,8 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args)
/* Not used: All used */
while ((ch = mygetopt(argc, argv, "?"
"ab:c:defgh:ijk:l:mnop:q:rstuv:wxyz"
"A:B:CDE:F:GHIJKL:M:NO:PQRS:TUVW:XYZ:")) != -1) {
"A:B:CDE:F:GHIJKL:M:NO:PQRS:TUVW:XYZ:"
"0")) != -1) {
switch (ch) {
case '?' :
Usage();
@ -1184,6 +1191,12 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args)
#endif
break;
case '0' :
#ifdef WOLFSSL_EARLY_DATA
earlyData = 1;
#endif
break;
default:
Usage();
exit(MY_EX_USAGE);
@ -2027,6 +2040,59 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args)
ret = NonBlockingSSL_Connect(sslResume);
}
else {
#ifdef WOLFSSL_EARLY_DATA
#ifndef HAVE_SESSION_TICKET
if (!usePsk) {
}
else
#endif
if (earlyData) {
do {
err = 0; /* reset error */
ret = wolfSSL_write_early_data(sslResume, msg, msgSz,
&msgSz);
if (ret <= 0) {
err = wolfSSL_get_error(sslResume, 0);
#ifdef WOLFSSL_ASYNC_CRYPT
if (err == WC_PENDING_E) {
ret = wolfSSL_AsyncPoll(sslResume,
WOLF_POLL_FLAG_CHECK_HW);
if (ret < 0) break;
}
#endif
}
} while (err == WC_PENDING_E);
if (ret != msgSz) {
printf("SSL_write_early_data msg error %d, %s\n", err,
wolfSSL_ERR_error_string(err, buffer));
wolfSSL_free(sslResume);
wolfSSL_CTX_free(ctx);
err_sys("SSL_write_early_data failed");
}
do {
err = 0; /* reset error */
ret = wolfSSL_write_early_data(sslResume, msg, msgSz,
&msgSz);
if (ret <= 0) {
err = wolfSSL_get_error(sslResume, 0);
#ifdef WOLFSSL_ASYNC_CRYPT
if (err == WC_PENDING_E) {
ret = wolfSSL_AsyncPoll(sslResume,
WOLF_POLL_FLAG_CHECK_HW);
if (ret < 0) break;
}
#endif
}
} while (err == WC_PENDING_E);
if (ret != msgSz) {
printf("SSL_write_early_data msg error %d, %s\n", err,
wolfSSL_ERR_error_string(err, buffer));
wolfSSL_free(sslResume);
wolfSSL_CTX_free(ctx);
err_sys("SSL_write_early_data failed");
}
}
#endif
do {
err = 0; /* reset error */
ret = wolfSSL_connect(sslResume);

View File

@ -368,6 +368,9 @@ static void Usage(void)
printf("-Q Request certificate from client post-handshake\n");
#endif
#endif
#ifdef WOLFSSL_EARLY_DATA
printf("-0 Early data read from client (0-RTT handshake)\n");
#endif
}
THREAD_RETURN CYASSL_THREAD server_test(void* args)
@ -456,6 +459,9 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args)
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH)
int postHandAuth = 0;
#endif
#ifdef WOLFSSL_EARLY_DATA
int earlyData = 0;
#endif
#ifdef WOLFSSL_STATIC_MEMORY
#if (defined(HAVE_ECC) && !defined(ALT_ECC_SIZE)) \
@ -503,7 +509,8 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args)
/* Not Used: h, m, t, x, y, z, F, J, M, T, V, W, X, Y */
while ((ch = mygetopt(argc, argv, "?"
"abc:defgijk:l:nop:q:rsuv:w"
"A:B:C:D:E:GHIKL:NO:PQR:S:UYZ:")) != -1) {
"A:B:C:D:E:GHIKL:NO:PQR:S:UYZ:"
"0")) != -1) {
switch (ch) {
case '?' :
Usage();
@ -724,6 +731,12 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args)
#endif
break;
case '0' :
#ifdef WOLFSSL_EARLY_DATA
earlyData = 1;
#endif
break;
default:
Usage();
exit(MY_EX_USAGE);
@ -1167,6 +1180,29 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args)
ret = NonBlockingSSL_Accept(ssl);
}
else {
#ifdef WOLFSSL_EARLY_DATA
if (earlyData) {
do {
int len;
err = 0; /* reset error */
ret = wolfSSL_read_early_data(ssl, input, sizeof(input)-1,
&len);
if (ret != SSL_SUCCESS) {
err = SSL_get_error(ssl, 0);
#ifdef WOLFSSL_ASYNC_CRYPT
if (err == WC_PENDING_E) {
ret = wolfSSL_AsyncPoll(ssl, WOLF_POLL_FLAG_CHECK_HW);
if (ret < 0) break;
}
#endif
}
if (ret > 0) {
input[ret] = 0; /* null terminate message */
printf("Early Data Client message: %s\n", input);
}
} while (err == WC_PENDING_E || ret > 0);
}
#endif
do {
err = 0; /* reset error */
ret = SSL_accept(ssl);

View File

@ -1433,6 +1433,10 @@ int InitSSL_Ctx(WOLFSSL_CTX* ctx, WOLFSSL_METHOD* method, void* heap)
ret = wolfEventQueue_Init(&ctx->event_queue);
#endif /* HAVE_WOLF_EVENT */
#ifdef WOLFSSL_EARLY_DATA
ctx->maxEarlyDataSz = MAX_EARLY_DATA_SZ;
#endif
ctx->heap = heap; /* wolfSSL_CTX_load_static_memory sets */
return ret;
@ -3782,6 +3786,10 @@ int SetSSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup)
ssl->options.client_psk_cb = ctx->client_psk_cb;
ssl->options.server_psk_cb = ctx->server_psk_cb;
#endif /* NO_PSK */
#ifdef WOLFSSL_EARLY_DATA
if (ssl->options.side == WOLFSSL_SERVER_END)
ssl->options.maxEarlyDataSz = ctx->maxEarlyDataSz;
#endif
#ifdef HAVE_ANON
ssl->options.haveAnon = ctx->haveAnon;
@ -10898,6 +10906,11 @@ int DoApplicationData(WOLFSSL* ssl, byte* input, word32* inOutIdx)
byte decomp[MAX_RECORD_SIZE + MAX_COMP_EXTRA];
#endif
#ifdef WOLFSSL_EARLY_DATA
if (ssl->earlyData) {
}
else
#endif
if (ssl->options.handShakeDone == 0) {
WOLFSSL_MSG("Received App data before a handshake completed");
SendAlert(ssl, alert_fatal, unexpected_message);
@ -10918,6 +10931,15 @@ int DoApplicationData(WOLFSSL* ssl, byte* input, word32* inOutIdx)
WOLFSSL_MSG("App data buffer error, malicious input?");
return BUFFER_ERROR;
}
#ifdef WOLFSSL_EARLY_DATA
if (ssl->earlyData) {
if (ssl->earlyDataSz + dataSz > ssl->options.maxEarlyDataSz) {
SendAlert(ssl, alert_fatal, unexpected_message);
return SSL_FATAL_ERROR;
}
ssl->earlyDataSz += dataSz;
}
#endif
/* read data */
if (dataSz) {
@ -11375,6 +11397,19 @@ int ProcessReply(WOLFSSL* ssl)
else {
WOLFSSL_MSG("Decrypt failed");
WOLFSSL_ERROR(ret);
#ifdef WOLFSSL_EARLY_DATA
if (ssl->options.tls1_3) {
ssl->earlyDataSz += ssl->curSize;
if (ssl->earlyDataSz <= ssl->options.maxEarlyDataSz) {
if (ssl->keys.peer_sequence_number_lo-- == 0)
ssl->keys.peer_sequence_number_hi--;
ssl->options.processReply = doProcessInit;
ssl->buffers.inputBuffer.idx =
ssl->buffers.inputBuffer.length;
return 0;
}
}
#endif
#ifdef WOLFSSL_DTLS
/* If in DTLS mode, if the decrypt fails for any
* reason, pretend the datagram never happened. */
@ -11461,6 +11496,17 @@ int ProcessReply(WOLFSSL* ssl)
ssl->buffers.inputBuffer.buffer,
&ssl->buffers.inputBuffer.idx,
ssl->buffers.inputBuffer.length);
#ifdef WOLFSSL_EARLY_DATA
if (ret != 0)
return ret;
if (ssl->options.side == WOLFSSL_SERVER_END &&
ssl->earlyData &&
ssl->options.handShakeState == HANDSHAKE_DONE) {
ssl->earlyData = 0;
ssl->options.processReply = doProcessInit;
return ZERO_RETURN;
}
#endif
#else
ret = BUFFER_ERROR;
#endif
@ -13153,6 +13199,15 @@ int SendData(WOLFSSL* ssl, const void* data, int sz)
if (ssl->error == WANT_WRITE || ssl->error == WC_PENDING_E)
ssl->error = 0;
#ifdef WOLFSSL_EARLY_DATA
if (ssl->earlyData) {
if (ssl->options.handShakeState == HANDSHAKE_DONE) {
WOLFSSL_MSG("handshake complete, trying to send early data");
return BUILD_MSG_ERROR;
}
}
else
#endif
if (ssl->options.handShakeState != HANDSHAKE_DONE) {
int err;
WOLFSSL_MSG("handshake not complete, trying to finish");
@ -13305,6 +13360,11 @@ int ReceiveData(WOLFSSL* ssl, byte* output, int sz, int peek)
return ssl->error;
}
#ifdef WOLFSSL_EARLY_DATA
if (ssl->earlyData) {
}
else
#endif
if (ssl->options.handShakeState != HANDSHAKE_DONE) {
int err;
WOLFSSL_MSG("Handshake not complete, trying to finish");
@ -22472,6 +22532,9 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
#ifdef WOLFSSL_TLS13
word32 ageAdd; /* Obfuscation of age */
byte namedGroup; /* Named group used */
#ifdef WOLFSSL_EARLY_DATA
word32 maxEarlyDataSz; /* Max size of early data */
#endif
#endif
} InternalTicket;
@ -22503,6 +22566,10 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
it.suite[0] = ssl->options.cipherSuite0;
it.suite[1] = ssl->options.cipherSuite;
#ifdef WOLFSSL_EARLY_DATA
it.maxEarlyDataSz = ssl->options.maxEarlyDataSz;
#endif
if (!ssl->options.tls1_3) {
XMEMCPY(it.msecret, ssl->arrays->masterSecret, SECRET_LEN);
c32toa(LowResTimer(), (byte*)&it.timestamp);
@ -22627,6 +22694,9 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
ssl->session.ticketAdd = it->ageAdd;
ssl->session.cipherSuite0 = it->suite[0];
ssl->session.cipherSuite = it->suite[1];
#ifdef WOLFSSL_EARLY_DATA
ssl->session.maxEarlyDataSz = it->maxEarlyDataSz;
#endif
/* Resumption master secret. */
XMEMCPY(ssl->session.masterSecret, it->msecret, SECRET_LEN);
ssl->session.namedGroup = it->namedGroup;

View File

@ -2900,14 +2900,42 @@ int SetKeysSide(WOLFSSL* ssl, enum encrypt_side side)
switch (side) {
case ENCRYPT_SIDE_ONLY:
WOLFSSL_MSG("Provisioning ENCRYPT key");
if (ssl->options.side == WOLFSSL_CLIENT_END) {
WOLFSSL_BUFFER(ssl->keys.client_write_key, AES_256_KEY_SIZE);
}
else {
WOLFSSL_BUFFER(ssl->keys.server_write_key, AES_256_KEY_SIZE);
}
wc_encrypt = &ssl->encrypt;
break;
case DECRYPT_SIDE_ONLY:
WOLFSSL_MSG("Provisioning DECRYPT key");
if (ssl->options.side == WOLFSSL_CLIENT_END) {
WOLFSSL_BUFFER(ssl->keys.server_write_key, AES_256_KEY_SIZE);
}
else {
WOLFSSL_BUFFER(ssl->keys.client_write_key, AES_256_KEY_SIZE);
}
wc_decrypt = &ssl->decrypt;
break;
case ENCRYPT_AND_DECRYPT_SIDE:
WOLFSSL_MSG("Provisioning ENCRYPT key");
if (ssl->options.side == WOLFSSL_CLIENT_END) {
WOLFSSL_BUFFER(ssl->keys.client_write_key, AES_256_KEY_SIZE);
}
else {
WOLFSSL_BUFFER(ssl->keys.server_write_key, AES_256_KEY_SIZE);
}
WOLFSSL_MSG("Provisioning DECRYPT key");
if (ssl->options.side == WOLFSSL_CLIENT_END) {
WOLFSSL_BUFFER(ssl->keys.server_write_key, AES_256_KEY_SIZE);
}
else {
WOLFSSL_BUFFER(ssl->keys.client_write_key, AES_256_KEY_SIZE);
}
wc_encrypt = &ssl->encrypt;
wc_decrypt = &ssl->decrypt;
break;
@ -2996,7 +3024,7 @@ int SetKeysSide(WOLFSSL* ssl, enum encrypt_side side)
/* TLS can call too */
int StoreKeys(WOLFSSL* ssl, const byte* keyData)
int StoreKeys(WOLFSSL* ssl, const byte* keyData, int side)
{
int sz, i = 0;
Keys* keys = &ssl->keys;
@ -3011,21 +3039,32 @@ int StoreKeys(WOLFSSL* ssl, const byte* keyData)
if (ssl->specs.cipher_type != aead) {
sz = ssl->specs.hash_size;
XMEMCPY(keys->client_write_MAC_secret,&keyData[i], sz);
i += sz;
XMEMCPY(keys->server_write_MAC_secret,&keyData[i], sz);
i += sz;
if (side & PROVISION_CLIENT) {
XMEMCPY(keys->client_write_MAC_secret,&keyData[i], sz);
i += sz;
}
if (side & PROVISION_SERVER) {
XMEMCPY(keys->server_write_MAC_secret,&keyData[i], sz);
i += sz;
}
}
sz = ssl->specs.key_size;
XMEMCPY(keys->client_write_key, &keyData[i], sz);
i += sz;
XMEMCPY(keys->server_write_key, &keyData[i], sz);
i += sz;
if (side & PROVISION_CLIENT) {
XMEMCPY(keys->client_write_key, &keyData[i], sz);
i += sz;
}
if (side & PROVISION_SERVER) {
XMEMCPY(keys->server_write_key, &keyData[i], sz);
i += sz;
}
sz = ssl->specs.iv_size;
XMEMCPY(keys->client_write_IV, &keyData[i], sz);
i += sz;
XMEMCPY(keys->server_write_IV, &keyData[i], sz);
if (side & PROVISION_CLIENT) {
XMEMCPY(keys->client_write_IV, &keyData[i], sz);
i += sz;
}
if (side & PROVISION_SERVER)
XMEMCPY(keys->server_write_IV, &keyData[i], sz);
#ifdef HAVE_AEAD
if (ssl->specs.cipher_type == aead) {
@ -3126,7 +3165,7 @@ int DeriveKeys(WOLFSSL* ssl)
}
if (ret == 0)
ret = StoreKeys(ssl, keyData);
ret = StoreKeys(ssl, keyData, PROVISION_CLIENT_SERVER);
}
#ifdef WOLFSSL_SMALL_STACK

View File

@ -1313,6 +1313,14 @@ int wolfSSL_write(WOLFSSL* ssl, const void* data, int sz)
if (ssl == NULL || data == NULL || sz < 0)
return BAD_FUNC_ARG;
#ifdef WOLFSSL_EARLY_DATA
if (ssl->earlyData && (ret = wolfSSL_negotiate(ssl)) < 0) {
ssl->error = ret;
return SSL_FATAL_ERROR;
}
ssl->earlyData = 0;
#endif
#ifdef HAVE_WRITE_DUP
{ /* local variable scope */
int dupErr = 0; /* local copy */
@ -1357,7 +1365,6 @@ int wolfSSL_write(WOLFSSL* ssl, const void* data, int sz)
return ret;
}
static int wolfSSL_read_internal(WOLFSSL* ssl, void* data, int sz, int peek)
{
int ret;
@ -8273,6 +8280,11 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl,
}
}
#ifdef WOLFSSL_TLS13
if (ssl->options.tls1_3)
return wolfSSL_connect_TLSv13(ssl);
#endif
switch (ssl->options.connectState) {
case CONNECT_BEGIN :
@ -9222,11 +9234,14 @@ static int GetDeepCopySession(WOLFSSL* ssl, WOLFSSL_SESSION* copyFrom)
return BAD_MUTEX_E;
}
copyInto->cipherSuite0 = copyFrom->cipherSuite0;
copyInto->cipherSuite = copyFrom->cipherSuite;
copyInto->namedGroup = copyFrom->namedGroup;
copyInto->ticketSeen = copyFrom->ticketSeen;
copyInto->ticketAdd = copyFrom->ticketAdd;
copyInto->cipherSuite0 = copyFrom->cipherSuite0;
copyInto->cipherSuite = copyFrom->cipherSuite;
copyInto->namedGroup = copyFrom->namedGroup;
copyInto->ticketSeen = copyFrom->ticketSeen;
copyInto->ticketAdd = copyFrom->ticketAdd;
#ifdef WOLFSSL_EARLY_DATA
copyInto->maxEarlyDataSz = copyFrom->maxEarlyDataSz;
#endif
XMEMCPY(copyInto->masterSecret, copyFrom->masterSecret, SECRET_LEN);
if (wc_UnLockMutex(&session_mutex) != 0) {
@ -9453,9 +9468,12 @@ int AddSession(WOLFSSL* ssl)
#endif /* SESSION_CERTS || (WOLFSSL_TLS13 & HAVE_SESSION_TICKET) */
#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)
if (error == 0) {
session->namedGroup = ssl->session.namedGroup;
session->ticketSeen = ssl->session.ticketSeen;
session->ticketAdd = ssl->session.ticketAdd;
session->namedGroup = ssl->session.namedGroup;
session->ticketSeen = ssl->session.ticketSeen;
session->ticketAdd = ssl->session.ticketAdd;
#ifdef WOLFSSL_EARLY_DATA
session->maxEarlyDataSz = ssl->session.maxEarlyDataSz;
#endif
}
#endif /* WOLFSSL_TLS13 && HAVE_SESSION_TICKET */
#ifdef HAVE_EXT_CACHE

232
src/tls.c
View File

@ -533,7 +533,7 @@ int DeriveTlsKeys(WOLFSSL* ssl)
IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm,
ssl->heap, ssl->devId);
if (ret == 0)
ret = StoreKeys(ssl, key_dig);
ret = StoreKeys(ssl, key_dig, PROVISION_CLIENT_SERVER);
#ifdef WOLFSSL_SMALL_STACK
XFREE(key_dig, ssl->heap, DYNAMIC_TYPE_DIGEST);
@ -5992,7 +5992,7 @@ static int TLSX_PreSharedKey_Parse(WOLFSSL* ssl, byte* input, word16 length,
idx += OPAQUE32_LEN;
ret = TLSX_PreSharedKey_Use(ssl, identity, identityLen, age, no_mac,
1, NULL);
0, 0, 1, NULL);
if (ret != 0)
return ret;
@ -6145,12 +6145,15 @@ static INLINE byte GetHmacLength(int hmac)
* len The length of the identity data.
* age The age of the identity.
* hmac The HMAC algorithm.
* ciphersuite0 The first byte of the ciphersuite to use.
* ciphersuite The second byte of the ciphersuite to use.
* resumption The PSK is for resumption of a session.
* preSharedKey The new pre-shared key object.
* returns 0 on success and other values indicate failure.
*/
int TLSX_PreSharedKey_Use(WOLFSSL* ssl, byte* identity, word16 len, word32 age,
byte hmac, byte resumption,
byte hmac, byte cipherSuite0,
byte cipherSuite, byte resumption,
PreSharedKey **preSharedKey)
{
int ret = 0;
@ -6189,10 +6192,12 @@ int TLSX_PreSharedKey_Use(WOLFSSL* ssl, byte* identity, word16 len, word32 age,
}
/* Update/set age and HMAC algorithm. */
psk->ticketAge = age;
psk->hmac = hmac;
psk->resumption = resumption;
psk->binderLen = GetHmacLength(psk->hmac);
psk->ticketAge = age;
psk->hmac = hmac;
psk->cipherSuite0 = cipherSuite0;
psk->cipherSuite = cipherSuite;
psk->resumption = resumption;
psk->binderLen = GetHmacLength(psk->hmac);
if (preSharedKey != NULL)
*preSharedKey = psk;
@ -6224,7 +6229,7 @@ int TLSX_PreSharedKey_Use(WOLFSSL* ssl, byte* identity, word16 len, word32 age,
*
* modes The PSK KE mode bit string.
* 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 PSK KE mode extension.
*/
static word16 TLSX_PskKeModes_GetSize(byte modes, byte msgType)
{
@ -6436,8 +6441,8 @@ static int TLSX_PostHandAuth_Parse(WOLFSSL* ssl, byte* input, word16 length,
*/
static int TLSX_PostHandAuth_Use(WOLFSSL* ssl)
{
int ret = 0;
TLSX* extension;
int ret = 0;
TLSX* extension;
/* Find the PSK key exchange modes extension if it exists. */
extension = TLSX_Find(ssl->extensions, TLSX_POST_HANDSHAKE_AUTH);
@ -6464,6 +6469,129 @@ static int TLSX_PostHandAuth_Use(WOLFSSL* ssl)
#endif
/******************************************************************************/
/* Early Data Indication */
/******************************************************************************/
#ifdef WOLFSSL_EARLY_DATA
/* Get the size of the encoded Early Data Indication extension.
* 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.
*/
static word16 TLSX_EarlyData_GetSize(byte msgType)
{
if (msgType == client_hello || msgType == encrypted_extensions)
return 0;
if (msgType == session_ticket)
return OPAQUE32_LEN;
return SANITY_MSG_E;
}
/* Writes the Early Data Indicator extension into the output buffer.
* Assumes that the the output buffer is big enough to hold data.
* In messages: ClientHello, EncryptedExtensions and NewSessionTicket.
*
* max The maximum early data size.
* 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_EarlyData_Write(word32 max, byte* output, byte msgType)
{
if (msgType == client_hello || msgType == encrypted_extensions) {
return 0;
}
if (msgType == session_ticket) {
c32toa(max, output);
return OPAQUE32_LEN;
}
return SANITY_MSG_E;
}
/* Parse the Early Data Indicator extension.
* In messages: ClientHello, EncryptedExtensions and NewSessionTicket.
*
* 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_EarlyData_Parse(WOLFSSL* ssl, byte* input, word16 length,
byte msgType)
{
if (msgType == client_hello) {
if (length != 0)
return BUFFER_E;
return TLSX_EarlyData_Use(ssl, 0);
}
if (msgType == encrypted_extensions) {
if (length != 0)
return BUFFER_E;
return TLSX_EarlyData_Use(ssl, 1);
}
if (msgType == session_ticket) {
word32 max;
if (length != OPAQUE32_LEN)
return BUFFER_E;
ato32(input, &max);
ssl->session.maxEarlyDataSz = max;
return 0;
}
return SANITY_MSG_E;
}
/* Use the data to create a new Early Data object in the extensions.
*
* ssl The SSL/TLS object.
* max The maximum early data size.
* returns 0 on success and other values indicate failure.
*/
int TLSX_EarlyData_Use(WOLFSSL* ssl, word32 max)
{
int ret = 0;
TLSX* extension;
/* Find the early extension if it exists. */
extension = TLSX_Find(ssl->extensions, TLSX_EARLY_DATA);
if (extension == NULL) {
/* Push new early extension. */
ret = TLSX_Push(&ssl->extensions, TLSX_EARLY_DATA, NULL, ssl->heap);
if (ret != 0)
return ret;
extension = TLSX_Find(ssl->extensions, TLSX_EARLY_DATA);
if (extension == NULL)
return MEMORY_E;
}
extension->resp = 1;
extension->val = max;
return 0;
}
#define EDI_GET_SIZE TLSX_EarlyData_GetSize
#define EDI_WRITE TLSX_EarlyData_Write
#define EDI_PARSE TLSX_EarlyData_Parse
#else
#define EDI_GET_SIZE(a) 0
#define EDI_WRITE(a, b, c) 0
#define EDI_PARSE(a, b, c, d) 0
#endif
/******************************************************************************/
/* TLS Extensions Framework */
/******************************************************************************/
@ -6550,6 +6678,11 @@ void TLSX_FreeAll(TLSX* list, void* heap)
break;
#endif
#ifdef WOLFSSL_EARLY_DATA
case TLSX_EARLY_DATA:
break;
#endif
#ifdef WOLFSSL_POST_HANDSHAKE_AUTH
case TLSX_POST_HANDSHAKE_AUTH:
break;
@ -6662,6 +6795,13 @@ static word16 TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType)
length += PKM_GET_SIZE(extension->val, msgType);
break;
#endif
#ifdef WOLFSSL_EARLY_DATA
case TLSX_EARLY_DATA:
length += EDI_GET_SIZE(msgType);
break;
#endif
#ifdef WOLFSSL_POST_HANDSHAKE_AUTH
case TLSX_POST_HANDSHAKE_AUTH:
length += PHA_GET_SIZE(msgType);
@ -6797,6 +6937,14 @@ static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore,
offset += PKM_WRITE(extension->val, output + offset, msgType);
break;
#endif
#ifdef WOLFSSL_EARLY_DATA
case TLSX_EARLY_DATA:
WOLFSSL_MSG("Early Data extension to write");
offset += EDI_WRITE(extension->val, output + offset, msgType);
break;
#endif
#ifdef WOLFSSL_POST_HANDSHAKE_AUTH
case TLSX_POST_HANDSHAKE_AUTH:
WOLFSSL_MSG("Post-Handshake Authentication extension to write");
@ -7292,12 +7440,16 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer)
/* Determine the MAC algorithm for the cipher suite used. */
ssl->options.cipherSuite0 = sess->cipherSuite0;
ssl->options.cipherSuite = sess->cipherSuite;
SetCipherSpecs(ssl);
ret = SetCipherSpecs(ssl);
if (ret != 0)
return ret;
milli = TimeNowInMilliseconds() - sess->ticketSeen +
sess->ticketAdd;
/* Pre-shared key is mandatory extension for resumption. */
ret = TLSX_PreSharedKey_Use(ssl, sess->ticket, sess->ticketLen,
milli, ssl->specs.mac_algorithm, 1,
milli, ssl->specs.mac_algorithm,
ssl->options.cipherSuite0,
ssl->options.cipherSuite, 1,
NULL);
if (ret != 0)
return ret;
@ -7307,7 +7459,9 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer)
#endif
#ifndef NO_PSK
if (ssl->options.client_psk_cb != NULL) {
byte mac = sha256_mac;
/* Default ciphersuite. */
byte cipherSuite0 = TLS13_BYTE;
byte cipherSuite = WOLFSSL_DEF_PSK_CIPHER;
ssl->arrays->psk_keySz = ssl->options.client_psk_cb(ssl,
ssl->arrays->server_hint, ssl->arrays->client_identity,
@ -7317,12 +7471,19 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer)
return PSK_KEY_ERROR;
}
ssl->arrays->client_identity[MAX_PSK_ID_LEN] = '\0';
/* Hash algorithm defaults to SHA-256 unless cb specifies. */
/* TODO: Callback should be able to change ciphersuite. */
ssl->options.cipherSuite0 = cipherSuite0;
ssl->options.cipherSuite = cipherSuite;
ret = SetCipherSpecs(ssl);
if (ret != 0)
return ret;
ret = TLSX_PreSharedKey_Use(ssl,
(byte*)ssl->arrays->client_identity,
XSTRLEN(ssl->arrays->client_identity),
0, mac, 0, NULL);
0, ssl->specs.mac_algorithm,
cipherSuite0, cipherSuite, 0,
NULL);
if (ret != 0)
return ret;
@ -7500,7 +7661,9 @@ word16 TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType)
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
#endif
}
#endif
break;
#ifdef WOLFSSL_TLS13
case encrypted_extensions:
TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SESSION_TICKET));
TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
@ -7512,9 +7675,17 @@ word16 TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType)
case certificate_request:
XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS));
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;
#endif
#endif
break;
}
#ifdef HAVE_QSH
@ -7561,7 +7732,9 @@ word16 TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType)
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
#endif
}
#endif
break;
#ifdef WOLFSSL_TLS13
case encrypted_extensions:
TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SESSION_TICKET));
TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
@ -7574,9 +7747,17 @@ word16 TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType)
XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
TURN_OFF(semaphore,
TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS));
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;
#endif
#endif
break;
}
offset += OPAQUE16_LEN; /* extensions length */
@ -7837,6 +8018,23 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte msgType,
ret = PKM_PARSE(ssl, input + offset, size, msgType);
break;
#endif
#ifdef WOLFSSL_EARLY_DATA
case TLSX_EARLY_DATA:
WOLFSSL_MSG("Early Data extension received");
if (!IsAtLeastTLSv1_3(ssl->version))
break;
if (IsAtLeastTLSv1_3(ssl->version) &&
msgType != client_hello && msgType != session_ticket &&
msgType != encrypted_extensions) {
return EXT_NOT_ALLOWED;
}
ret = EDI_PARSE(ssl, input + offset, size, msgType);
break;
#endif
#ifdef WOLFSSL_POST_HANDSHAKE_AUTH
case TLSX_POST_HANDSHAKE_AUTH:
WOLFSSL_MSG("PSK Key Exchange Modes extension received");

File diff suppressed because it is too large Load Diff

View File

@ -261,3 +261,43 @@
-v 4
-l TLS13-AES128-GCM-SHA256
# server TLSv1.3 accepting EarlyData using PSK
-v 4
-l TLS13-AES128-GCM-SHA256
-r
-s
-0
# client TLSv1.3 sending EarlyData using PSK
-v 4
-l TLS13-AES128-GCM-SHA256
-r
-s
-0
# server TLSv1.3 not accepting EarlyData using PSK
-v 4
-l TLS13-AES128-GCM-SHA256
-r
-s
# client TLSv1.3 sending EarlyData using PSK
-v 4
-l TLS13-AES128-GCM-SHA256
-r
-s
-0
# server TLSv1.3 accepting EarlyData using PSK
-v 4
-l TLS13-AES128-GCM-SHA256
-r
-s
-0
# client TLSv1.3 not sending EarlyData using PSK
-v 4
-l TLS13-AES128-GCM-SHA256
-r
-s

View File

@ -105,3 +105,37 @@
-A ./certs/server-ecc.pem
-t
# server TLSv1.3 accepting EarlyData
-v 4
-l TLS13-AES128-GCM-SHA256
-r
-0
# client TLSv1.3 sending EarlyData
-v 4
-l TLS13-AES128-GCM-SHA256
-r
-0
# server TLSv1.3 not accepting EarlyData
-v 4
-l TLS13-AES128-GCM-SHA256
-r
# client TLSv1.3 sending EarlyData
-v 4
-l TLS13-AES128-GCM-SHA256
-r
-0
# server TLSv1.3 accepting EarlyData
-v 4
-l TLS13-AES128-GCM-SHA256
-r
-0
# client TLSv1.3 not sending EarlyData
-v 4
-l TLS13-AES128-GCM-SHA256
-r

View File

@ -978,6 +978,7 @@ enum Misc {
SESSION_HINT_SZ = 4, /* session timeout hint */
SESSION_ADD_SZ = 4, /* session age add */
MAX_LIFETIME = 604800, /* maximum ticket lifetime */
MAX_EARLY_DATA_SZ = 4096, /* maximum early data size */
RAN_LEN = 32, /* random length */
SEED_LEN = RAN_LEN * 2, /* tls prf seed length */
@ -1784,6 +1785,9 @@ typedef enum {
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
TLSX_PRE_SHARED_KEY = 0x0029,
#endif
#ifdef WOLFSSL_EARLY_DATA
TLSX_EARLY_DATA = 0x002a,
#endif
TLSX_SUPPORTED_VERSIONS = 0x002b,
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
TLSX_PSK_KEY_EXCHANGE_MODES = 0x002d,
@ -2082,6 +2086,8 @@ typedef struct PreSharedKey {
word16 identityLen; /* Length of identity */
byte* identity; /* PSK identity */
word32 ticketAge; /* Age of the ticket */
byte cipherSuite0; /* Cipher Suite */
byte cipherSuite; /* Cipher Suite */
word32 binderLen; /* Length of HMAC */
byte binder[MAX_DIGEST_SIZE]; /* HMAC of hanshake */
byte hmac; /* HMAC algorithm */
@ -2096,6 +2102,7 @@ WOLFSSL_LOCAL word16 TLSX_PreSharedKey_GetSizeBinders(PreSharedKey* list,
byte msgType);
WOLFSSL_LOCAL int TLSX_PreSharedKey_Use(WOLFSSL* ssl, byte* identity,
word16 len, word32 age, byte hmac,
byte cipherSuite0, byte cipherSuite,
byte resumption,
PreSharedKey **preSharedKey);
@ -2104,11 +2111,22 @@ enum PskKeyExchangeMode {
PSK_DHE_KE
};
/* User can define this. */
#ifndef WOLFSSL_DEF_PSK_CIPHER
#define WOLFSSL_DEF_PSK_CIPHER TLS_AES_128_GCM_SHA256
#endif
WOLFSSL_LOCAL int TLSX_PskKeModes_Use(WOLFSSL* ssl, byte modes);
#ifdef WOLFSSL_EARLY_DATA
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,
early_data_key,
handshake_key,
traffic_key,
update_traffic_key
@ -2225,6 +2243,9 @@ struct WOLFSSL_CTX {
wc_psk_server_callback server_psk_cb; /* server callback */
char server_hint[MAX_PSK_ID_LEN + NULL_TERM_LEN];
#endif /* HAVE_SESSION_TICKET || !NO_PSK */
#ifdef WOLFSSL_EARLY_DATA
word32 maxEarlyDataSz;
#endif
#ifdef HAVE_ANON
byte haveAnon; /* User wants to allow Anon suites */
#endif /* HAVE_ANON */
@ -2556,6 +2577,9 @@ struct WOLFSSL_SESSION {
word32 ticketSeen; /* Time ticket seen (ms) */
word32 ticketAdd; /* Added by client */
#endif
#ifdef WOLFSSL_EARLY_DATA
word32 maxEarlyDataSz;
#endif
byte* ticket;
word16 ticketLen;
byte staticTicket[SESSION_TICKET_LEN];
@ -2806,6 +2830,9 @@ typedef struct Options {
#ifdef HAVE_ECC
short minEccKeySz; /* minimum ECC key size */
#endif
#ifdef WOLFSSL_EARLY_DATA
word32 maxEarlyDataSz;
#endif
} Options;
@ -3017,6 +3044,7 @@ typedef struct MsgsReceived {
word16 got_server_hello:1;
word16 got_hello_verify_request:1;
word16 got_session_ticket:1;
word16 got_end_of_early_data:1;
word16 got_hello_retry_request:1;
word16 got_encrypted_extensions:1;
word16 got_certificate:1;
@ -3326,6 +3354,10 @@ struct WOLFSSL {
#ifdef WOLFSSL_JNI
void* jObjectRef; /* reference to WolfSSLSession in JNI wrapper */
#endif /* WOLFSSL_JNI */
#ifdef WOLFSSL_EARLY_DATA
int earlyData;
word32 earlyDataSz;
#endif
};
@ -3426,27 +3458,34 @@ typedef struct DtlsHandShakeHeader {
enum HandShakeType {
hello_request = 0,
client_hello = 1,
server_hello = 2,
hello_verify_request = 3, /* DTLS addition */
session_ticket = 4,
hello_retry_request = 6,
encrypted_extensions = 8,
certificate = 11,
server_key_exchange = 12,
certificate_request = 13,
server_hello_done = 14,
certificate_verify = 15,
client_key_exchange = 16,
finished = 20,
certificate_status = 22,
key_update = 24,
change_cipher_hs = 55, /* simulate unique handshake type for sanity
checks. record layer change_cipher
conflicts with handshake finished */
message_hash = 254, /* synthetic message type for TLS v1.3 */
no_shake = 255 /* used to initialize the DtlsMsg record */
hello_request = 0,
client_hello = 1,
server_hello = 2,
hello_verify_request = 3, /* DTLS addition */
session_ticket = 4,
end_of_early_data = 5,
hello_retry_request = 6,
encrypted_extensions = 8,
certificate = 11,
server_key_exchange = 12,
certificate_request = 13,
server_hello_done = 14,
certificate_verify = 15,
client_key_exchange = 16,
finished = 20,
certificate_status = 22,
key_update = 24,
change_cipher_hs = 55, /* simulate unique handshake type for sanity
checks. record layer change_cipher
conflicts with handshake finished */
message_hash = 254, /* synthetic message type for TLS v1.3 */
no_shake = 255 /* used to initialize the DtlsMsg record */
};
enum ProvisionSide {
PROVISION_CLIENT = 1,
PROVISION_SERVER = 2,
PROVISION_CLIENT_SERVER = 3
};
@ -3492,7 +3531,7 @@ WOLFSSL_LOCAL int MakeMasterSecret(WOLFSSL*);
WOLFSSL_LOCAL int AddSession(WOLFSSL*);
WOLFSSL_LOCAL int DeriveKeys(WOLFSSL* ssl);
WOLFSSL_LOCAL int StoreKeys(WOLFSSL* ssl, const byte* keyData);
WOLFSSL_LOCAL int StoreKeys(WOLFSSL* ssl, const byte* keyData, int side);
WOLFSSL_LOCAL int IsTLS(const WOLFSSL* ssl);
WOLFSSL_LOCAL int IsAtLeastTLSv1_2(const WOLFSSL* ssl);

View File

@ -399,9 +399,6 @@ WOLFSSL_API void wolfSSL_set_using_nonblock(WOLFSSL*, int);
WOLFSSL_API int wolfSSL_get_using_nonblock(WOLFSSL*);
/* please see note at top of README if you get an error from connect */
WOLFSSL_API int wolfSSL_connect(WOLFSSL*);
#ifdef WOLFSSL_TLS13
WOLFSSL_API int wolfSSL_connect_TLSv13(WOLFSSL*);
#endif
WOLFSSL_API int wolfSSL_write(WOLFSSL*, const void*, int);
WOLFSSL_API int wolfSSL_read(WOLFSSL*, void*, int);
WOLFSSL_API int wolfSSL_peek(WOLFSSL*, void*, int);
@ -415,7 +412,17 @@ WOLFSSL_API int wolfSSL_update_keys(WOLFSSL* ssl);
WOLFSSL_API int wolfSSL_CTX_allow_post_handshake_auth(WOLFSSL_CTX* ctx);
WOLFSSL_API int wolfSSL_allow_post_handshake_auth(WOLFSSL* ssl);
WOLFSSL_API int wolfSSL_request_certificate(WOLFSSL* ssl);
WOLFSSL_API int wolfSSL_connect_TLSv13(WOLFSSL*);
WOLFSSL_API int wolfSSL_accept_TLSv13(WOLFSSL*);
#ifdef WOLFSSL_EARLY_DATA
WOLFSSL_API int wolfSSL_CTX_set_max_early_data(WOLFSSL_CTX* ctx,
unsigned int sz);
WOLFSSL_API int wolfSSL_set_max_early_data(WOLFSSL* ssl, unsigned int sz);
WOLFSSL_API int wolfSSL_write_early_data(WOLFSSL*, const void*, int, int*);
WOLFSSL_API int wolfSSL_read_early_data(WOLFSSL*, void*, int, int*);
#endif
#endif
WOLFSSL_API void wolfSSL_CTX_free(WOLFSSL_CTX*);
WOLFSSL_API void wolfSSL_free(WOLFSSL*);