From 2871fc670f448e5f7cab7101479cb5b88e4d21f4 Mon Sep 17 00:00:00 2001 From: Jacob Barthelmeh Date: Fri, 21 May 2021 00:19:34 +0700 Subject: [PATCH] initial serialization of TLS session --- configure.ac | 4 - src/internal.c | 728 +++++++++++++++++++++++++++++---------------- src/ssl.c | 49 ++- tests/api.c | 14 +- wolfssl/internal.h | 30 +- wolfssl/ssl.h | 3 + 6 files changed, 552 insertions(+), 276 deletions(-) diff --git a/configure.ac b/configure.ac index b417a3b43..54549f2fa 100644 --- a/configure.ac +++ b/configure.ac @@ -6013,10 +6013,6 @@ AC_ARG_ENABLE([sessionexport], if test "$ENABLED_SESSIONEXPORT" = "yes" || test "$ENABLED_SESSIONEXPORT" = "nopeer" then - if test "$ENABLED_DTLS" = "no" - then - AC_MSG_ERROR([Only DTLS supported with session export]) - fi AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SESSION_EXPORT" if test "$ENABLED_SESSIONEXPORT" = "nopeer" diff --git a/src/internal.c b/src/internal.c index 45e47c103..4c5af8058 100644 --- a/src/internal.c +++ b/src/internal.c @@ -585,9 +585,12 @@ static WC_INLINE int IsDtlsNotSctpMode(WOLFSSL* ssl) #ifdef WOLFSSL_SESSION_EXPORT -#ifdef WOLFSSL_DTLS -/* serializes the cipher specs struct for exporting */ -static int ExportCipherSpecState(WOLFSSL* ssl, byte* exp, word32 len, byte ver) +/** + * serializes the cipher specs struct for exporting + * @return the amount written to 'exp' buffer + */ +static int ExportCipherSpecState(WOLFSSL* ssl, byte* exp, word32 len, byte ver, + int isTLS) { word32 idx = 0; CipherSpecs* specs; @@ -600,11 +603,11 @@ static int ExportCipherSpecState(WOLFSSL* ssl, byte* exp, word32 len, byte ver) specs= &(ssl->specs); - if (DTLS_EXPORT_SPC_SZ > len) { + if (WOLFSSL_EXPORT_SPC_SZ > len) { return BUFFER_E; } - XMEMSET(exp, 0, DTLS_EXPORT_SPC_SZ); + XMEMSET(exp, 0, WOLFSSL_EXPORT_SPC_SZ); c16toa(specs->key_size, exp + idx); idx += OPAQUE16_LEN; c16toa(specs->iv_size, exp + idx); idx += OPAQUE16_LEN; @@ -619,11 +622,27 @@ static int ExportCipherSpecState(WOLFSSL* ssl, byte* exp, word32 len, byte ver) exp[idx++] = specs->pad_size; exp[idx++] = specs->static_ecdh; - if (idx != DTLS_EXPORT_SPC_SZ) { - WOLFSSL_MSG("DTLS_EXPORT_SPC_SZ needs updated and export version"); + if (idx != WOLFSSL_EXPORT_SPC_SZ) { + WOLFSSL_MSG("WOLFSSL_EXPORT_SPC_SZ needs updated and export version"); return DTLS_EXPORT_VER_E; } + /* send over state of AES too */ + if (isTLS && ssl->specs.bulk_cipher_algorithm == wolfssl_aes) { + byte *pt = (byte*)ssl->encrypt.aes->reg; + + if ((idx + 2*AES_BLOCK_SIZE) > len) { + WOLFSSL_MSG("Can not fit AES state into buffer\n"); + return BUFFER_E; + } + XMEMCPY(exp + idx, pt, AES_BLOCK_SIZE); + idx += AES_BLOCK_SIZE; + + pt = (byte*)ssl->decrypt.aes->reg; + XMEMCPY(exp + idx, pt, AES_BLOCK_SIZE); + idx += AES_BLOCK_SIZE; + } + WOLFSSL_LEAVE("ExportCipherSpecState", idx); (void)ver; return idx; @@ -632,7 +651,7 @@ static int ExportCipherSpecState(WOLFSSL* ssl, byte* exp, word32 len, byte ver) /* serializes the key struct for exporting */ static int ExportKeyState(WOLFSSL* ssl, byte* exp, word32 len, byte ver, - byte small) + byte small, int isTLS) { word32 idx = 0; byte sz; @@ -658,6 +677,8 @@ static int ExportKeyState(WOLFSSL* ssl, byte* exp, word32 len, byte ver, c32toa(keys->sequence_number_hi, exp + idx); idx += OPAQUE32_LEN; c32toa(keys->sequence_number_lo, exp + idx); idx += OPAQUE32_LEN; + #if defined(WOLFSSL_DTLS) + if (!isTLS) { c16toa(keys->peerSeq[0].nextEpoch, exp + idx); idx += OPAQUE16_LEN; c16toa(keys->peerSeq[0].nextSeq_hi, exp + idx); idx += OPAQUE16_LEN; c32toa(keys->peerSeq[0].nextSeq_lo, exp + idx); idx += OPAQUE32_LEN; @@ -677,6 +698,8 @@ static int ExportKeyState(WOLFSSL* ssl, byte* exp, word32 len, byte ver, c32toa(keys->dtls_prev_sequence_number_lo, exp + idx); idx += OPAQUE32_LEN; c16toa(keys->dtls_epoch, exp + idx); idx += OPAQUE16_LEN; c16toa(keys->dtls_handshake_number, exp + idx); idx += OPAQUE16_LEN; + } + #endif c32toa(keys->encryptSz, exp + idx); idx += OPAQUE32_LEN; c32toa(keys->padSz, exp + idx); idx += OPAQUE32_LEN; exp[idx++] = keys->encryptionOn; @@ -684,7 +707,8 @@ static int ExportKeyState(WOLFSSL* ssl, byte* exp, word32 len, byte ver, /* from here on the buffer needs checked because is variable length that * can be larger than DTLS_EXPORT_MIN_KEY_SZ */ - { +#ifdef WOLFSSL_DTLS + if (!isTLS) { word32 i; if ((OPAQUE16_LEN * 2) + idx + (2 * (WOLFSSL_DTLS_WINDOW_WORDS * OPAQUE32_LEN)) > len) { @@ -703,6 +727,7 @@ static int ExportKeyState(WOLFSSL* ssl, byte* exp, word32 len, byte ver, idx += OPAQUE32_LEN; } } +#endif if (idx >= len) { WOLFSSL_MSG("Buffer not large enough for truncated hmac flag"); @@ -779,13 +804,30 @@ static int ExportKeyState(WOLFSSL* ssl, byte* exp, word32 len, byte ver, WOLFSSL_LEAVE("ExportKeyState", idx); (void)ver; + (void)isTLS; return idx; } -static int ImportCipherSpecState(WOLFSSL* ssl, const byte* exp, word32 len, byte ver) + +/** + * Imports the buffer 'exp' into the 'ssl' CipherSpec structure. + * @param ssl WOLFSSL structure to import into + * @param exp input buffer to read from + * @param len length of exp buffer + * @param ver version of import buffer found + * @param isTLS flag for importing a TLS session or DTLS + * + * @return size of exp buffer consumed on success and negative value on fail + */ +static int ImportCipherSpecState(WOLFSSL* ssl, const byte* exp, word32 len, + byte ver, int isTLS) { word32 idx = 0; CipherSpecs* specs; + word32 tmp_seq_peer_lo; + word32 tmp_seq_peer_hi; + word32 tmp_seq_lo; + word32 tmp_seq_hi; WOLFSSL_ENTER("ImportCipherSpecState"); @@ -795,7 +837,7 @@ static int ImportCipherSpecState(WOLFSSL* ssl, const byte* exp, word32 len, byte specs= &(ssl->specs); - if (DTLS_EXPORT_SPC_SZ > len) { + if (WOLFSSL_EXPORT_SPC_SZ > len) { WOLFSSL_MSG("Buffer not large enough for max spec struct size"); return BUFFER_E; } @@ -813,17 +855,53 @@ static int ImportCipherSpecState(WOLFSSL* ssl, const byte* exp, word32 len, byte specs->pad_size = exp[idx++]; specs->static_ecdh = exp[idx++]; + /* temporarly save the sequence numbers */ + tmp_seq_peer_lo = ssl->keys.peer_sequence_number_lo; + tmp_seq_peer_hi = ssl->keys.peer_sequence_number_hi; + tmp_seq_lo = ssl->keys.sequence_number_lo; + tmp_seq_hi = ssl->keys.sequence_number_hi; + + SetKeysSide(ssl, ENCRYPT_AND_DECRYPT_SIDE); + + /* reset sequence numbers after setting keys */ + ssl->keys.peer_sequence_number_lo = tmp_seq_peer_lo; + ssl->keys.peer_sequence_number_hi = tmp_seq_peer_hi; + ssl->keys.sequence_number_lo = tmp_seq_lo; + ssl->keys.sequence_number_hi = tmp_seq_hi; + + if (isTLS && ssl->specs.bulk_cipher_algorithm == wolfssl_aes) { + byte *pt = (byte*)ssl->encrypt.aes->reg; + XMEMCPY(pt, exp + idx, AES_BLOCK_SIZE); + idx += AES_BLOCK_SIZE; + + pt = (byte*)ssl->decrypt.aes->reg; + XMEMCPY(pt, exp + idx, AES_BLOCK_SIZE); + idx += AES_BLOCK_SIZE; + } + WOLFSSL_LEAVE("ImportCipherSpecState", idx); (void)ver; return idx; } -static int ImportKeyState(WOLFSSL* ssl, const byte* exp, word32 len, byte ver) +/** + * Import the Key structure + * + * @param ssl WOLFSSL structure to import into + * @param exp buffer to read Key values from + * @param len max length of buffer 'exp' + * @param ver version of import buffer found + * @param isTLS flag for TLS vs DTLS + * + * @return amount of data read from exp on success or negative on fail + */ +static int ImportKeyState(WOLFSSL* ssl, const byte* exp, word32 len, byte ver, + int isTLS) { word32 idx = 0; - byte sz; - Keys* keys; + byte sz; + Keys *keys; WOLFSSL_ENTER("ImportKeyState"); @@ -843,31 +921,39 @@ static int ImportKeyState(WOLFSSL* ssl, const byte* exp, word32 len, byte ver) ato32(exp + idx, &keys->sequence_number_hi); idx += OPAQUE32_LEN; ato32(exp + idx, &keys->sequence_number_lo); idx += OPAQUE32_LEN; - ato16(exp + idx, &keys->peerSeq[0].nextEpoch); idx += OPAQUE16_LEN; - ato16(exp + idx, &keys->peerSeq[0].nextSeq_hi); idx += OPAQUE16_LEN; - ato32(exp + idx, &keys->peerSeq[0].nextSeq_lo); idx += OPAQUE32_LEN; - ato16(exp + idx, &keys->curEpoch); idx += OPAQUE16_LEN; - ato16(exp + idx, &keys->curSeq_hi); idx += OPAQUE16_LEN; - ato32(exp + idx, &keys->curSeq_lo); idx += OPAQUE32_LEN; - ato16(exp + idx, &keys->peerSeq[0].prevSeq_hi); idx += OPAQUE16_LEN; - ato32(exp + idx, &keys->peerSeq[0].prevSeq_lo); idx += OPAQUE32_LEN; + #if defined(WOLFSSL_DTLS) + if (!isTLS) { + ato16(exp + idx, &keys->peerSeq[0].nextEpoch); idx += OPAQUE16_LEN; + ato16(exp + idx, &keys->peerSeq[0].nextSeq_hi); idx += OPAQUE16_LEN; + ato32(exp + idx, &keys->peerSeq[0].nextSeq_lo); idx += OPAQUE32_LEN; + ato16(exp + idx, &keys->curEpoch); idx += OPAQUE16_LEN; + ato16(exp + idx, &keys->curSeq_hi); idx += OPAQUE16_LEN; + ato32(exp + idx, &keys->curSeq_lo); idx += OPAQUE32_LEN; + ato16(exp + idx, &keys->peerSeq[0].prevSeq_hi); idx += OPAQUE16_LEN; + ato32(exp + idx, &keys->peerSeq[0].prevSeq_lo); idx += OPAQUE32_LEN; - ato16(exp + idx, &keys->dtls_peer_handshake_number); idx += OPAQUE16_LEN; - ato16(exp + idx, &keys->dtls_expected_peer_handshake_number); - idx += OPAQUE16_LEN; + ato16(exp + idx, &keys->dtls_peer_handshake_number); + idx += OPAQUE16_LEN; + ato16(exp + idx, &keys->dtls_expected_peer_handshake_number); + idx += OPAQUE16_LEN; - ato16(exp + idx, &keys->dtls_sequence_number_hi); idx += OPAQUE16_LEN; - ato32(exp + idx, &keys->dtls_sequence_number_lo); idx += OPAQUE32_LEN; - ato16(exp + idx, &keys->dtls_prev_sequence_number_hi); idx += OPAQUE16_LEN; - ato32(exp + idx, &keys->dtls_prev_sequence_number_lo); idx += OPAQUE32_LEN; - ato16(exp + idx, &keys->dtls_epoch); idx += OPAQUE16_LEN; - ato16(exp + idx, &keys->dtls_handshake_number); idx += OPAQUE16_LEN; - ato32(exp + idx, &keys->encryptSz); idx += OPAQUE32_LEN; - ato32(exp + idx, &keys->padSz); idx += OPAQUE32_LEN; + ato16(exp + idx, &keys->dtls_sequence_number_hi); idx += OPAQUE16_LEN; + ato32(exp + idx, &keys->dtls_sequence_number_lo); idx += OPAQUE32_LEN; + ato16(exp + idx, &keys->dtls_prev_sequence_number_hi); + idx += OPAQUE16_LEN; + ato32(exp + idx, &keys->dtls_prev_sequence_number_lo); + idx += OPAQUE32_LEN; + ato16(exp + idx, &keys->dtls_epoch); idx += OPAQUE16_LEN; + ato16(exp + idx, &keys->dtls_handshake_number); idx += OPAQUE16_LEN; + } + #endif + ato32(exp + idx, &keys->encryptSz); idx += OPAQUE32_LEN; + ato32(exp + idx, &keys->padSz); idx += OPAQUE32_LEN; keys->encryptionOn = exp[idx++]; keys->decryptedCur = exp[idx++]; - { + #if defined(WOLFSSL_DTLS) + if (!isTLS) { word16 i, wordCount, wordAdj = 0; /* do window */ @@ -903,6 +989,7 @@ static int ImportKeyState(WOLFSSL* ssl, const byte* exp, word32 len, byte ver) idx += wordAdj; } + #endif #ifdef HAVE_TRUNCATED_HMAC ssl->truncated_hmac = exp[idx++]; @@ -960,21 +1047,28 @@ static int ImportKeyState(WOLFSSL* ssl, const byte* exp, word32 len, byte ver) WOLFSSL_LEAVE("ImportKeyState", idx); (void)ver; + (void)isTLS; return idx; } /* copy over necessary information from Options struct to buffer * On success returns size of buffer used on failure returns a negative value */ -static int dtls_export_new(WOLFSSL* ssl, byte* exp, word32 len, byte ver) +static int ExportOptions(WOLFSSL* ssl, byte* exp, word32 len, byte ver, + int isTLS) { - int idx = 0; - word16 zero = 0; - Options* options = &ssl->options; + int idx = 0; + word16 zero = 0; + Options *options; - WOLFSSL_ENTER("dtls_export_new"); + WOLFSSL_ENTER("ExportOptions"); - if (exp == NULL || options == NULL || len < DTLS_EXPORT_OPT_SZ) { + if (ssl == NULL || exp == NULL || len < DTLS_EXPORT_OPT_SZ) { + return BAD_FUNC_ARG; + } + + options = &ssl->options; + if (options == NULL) { return BAD_FUNC_ARG; } @@ -1054,11 +1148,11 @@ static int dtls_export_new(WOLFSSL* ssl, byte* exp, word32 len, byte ver) exp[idx++] = options->useTicket; exp[idx++] = options->noTicketTls12; #ifdef WOLFSSL_TLS13 - if (ver > DTLS_EXPORT_VERSION_3) { + if (ver > WOLFSSL_EXPORT_VERSION_3) { exp[idx++] = options->noTicketTls13; } #else - if (ver > DTLS_EXPORT_VERSION_3) { + if (ver > WOLFSSL_EXPORT_VERSION_3) { exp[idx++] = 0; } #endif @@ -1066,7 +1160,7 @@ static int dtls_export_new(WOLFSSL* ssl, byte* exp, word32 len, byte ver) exp[idx++] = 0; exp[idx++] = 0; exp[idx++] = 0; - if (ver > DTLS_EXPORT_VERSION_3) { + if (ver > WOLFSSL_EXPORT_VERSION_3) { exp[idx++] = 0; } #endif @@ -1082,6 +1176,13 @@ static int dtls_export_new(WOLFSSL* ssl, byte* exp, word32 len, byte ver) exp[idx++] = options->acceptState; exp[idx++] = options->asyncState; + if (isTLS) { + exp[idx++] = ssl->options.disallowEncThenMac; + exp[idx++] = ssl->options.encThenMac; + exp[idx++] = ssl->options.startedETMRead; + exp[idx++] = ssl->options.startedETMWrite; + } + /* version of connection */ exp[idx++] = ssl->version.major; exp[idx++] = ssl->version.minor; @@ -1090,15 +1191,15 @@ static int dtls_export_new(WOLFSSL* ssl, byte* exp, word32 len, byte ver) /* check if changes were made and notify of need to update export version */ switch (ver) { - case DTLS_EXPORT_VERSION_3: + case WOLFSSL_EXPORT_VERSION_3: if (idx != DTLS_EXPORT_OPT_SZ_3) { WOLFSSL_MSG("Update DTLS_EXPORT_OPT_SZ and version of export"); return DTLS_EXPORT_VER_E; } break; - case DTLS_EXPORT_VERSION: - if (idx != DTLS_EXPORT_OPT_SZ) { + case WOLFSSL_EXPORT_VERSION: + if (idx != DTLS_EXPORT_OPT_SZ && !isTLS) { WOLFSSL_MSG("Update DTLS_EXPORT_OPT_SZ and version of export"); return DTLS_EXPORT_VER_E; } @@ -1109,28 +1210,30 @@ static int dtls_export_new(WOLFSSL* ssl, byte* exp, word32 len, byte ver) return DTLS_EXPORT_VER_E; } - WOLFSSL_LEAVE("dtls_export_new", idx); + WOLFSSL_LEAVE("ExportOptions", idx); + (void)isTLS; return idx; } /* copy items from Export struct to Options struct * On success returns size of buffer used on failure returns a negative value */ -static int dtls_export_load(WOLFSSL* ssl, const byte* exp, word32 len, byte ver) +static int ImportOptions(WOLFSSL* ssl, const byte* exp, word32 len, byte ver, + int isTLS) { int idx = 0; Options* options = &ssl->options; switch (ver) { - case DTLS_EXPORT_VERSION: + case WOLFSSL_EXPORT_VERSION: if (len < DTLS_EXPORT_OPT_SZ) { WOLFSSL_MSG("Sanity check on buffer size failed"); return BAD_FUNC_ARG; } break; - case DTLS_EXPORT_VERSION_3: + case WOLFSSL_EXPORT_VERSION_3: if (len < DTLS_EXPORT_OPT_SZ_3) { WOLFSSL_MSG("Sanity check on buffer size failed"); return BAD_FUNC_ARG; @@ -1221,11 +1324,11 @@ static int dtls_export_load(WOLFSSL* ssl, const byte* exp, word32 len, byte ver) options->useTicket = exp[idx++]; /* Use Ticket not session cache */ options->noTicketTls12 = exp[idx++]; /* Server won't create new Ticket */ #ifdef WOLFSSL_TLS13 - if (ver > DTLS_EXPORT_VERSION_3) { + if (ver > WOLFSSL_EXPORT_VERSION_3) { options->noTicketTls13 = exp[idx++];/* Server won't create new Ticket */ } #else - if (ver > DTLS_EXPORT_VERSION_3) { + if (ver > WOLFSSL_EXPORT_VERSION_3) { idx++; } #endif @@ -1233,7 +1336,7 @@ static int dtls_export_load(WOLFSSL* ssl, const byte* exp, word32 len, byte ver) idx++; idx++; idx++; - if (ver > DTLS_EXPORT_VERSION_3) { + if (ver > WOLFSSL_EXPORT_VERSION_3) { idx++; } #endif @@ -1249,15 +1352,25 @@ static int dtls_export_load(WOLFSSL* ssl, const byte* exp, word32 len, byte ver) options->acceptState = exp[idx++]; options->asyncState = exp[idx++]; + if (isTLS) { + ssl->options.disallowEncThenMac = exp[idx++]; + ssl->options.encThenMac = exp[idx++]; + ssl->options.startedETMRead = exp[idx++]; + ssl->options.startedETMWrite = exp[idx++]; + } + /* version of connection */ if (ssl->version.major != exp[idx++] || ssl->version.minor != exp[idx++]) { WOLFSSL_MSG("Version mismatch ie DTLS v1 vs v1.2"); return VERSION_ERROR; } + (void)isTLS; return idx; } + +#ifdef WOLFSSL_DTLS #ifndef WOLFSSL_SESSION_EXPORT_NOPEER static int ExportPeerInfo(WOLFSSL* ssl, byte* exp, word32 len, byte ver) { @@ -1267,12 +1380,12 @@ static int ExportPeerInfo(WOLFSSL* ssl, byte* exp, word32 len, byte ver) word16 port = 0; char ip[DTLS_EXPORT_IP]; - if (ver != DTLS_EXPORT_VERSION) { + if (ver != WOLFSSL_EXPORT_VERSION) { WOLFSSL_MSG("Export version not supported"); return BAD_FUNC_ARG; } - if (ssl == NULL || exp == NULL || len < sizeof(ip) + 3 * DTLS_EXPORT_LEN) { + if (ssl == NULL || exp == NULL || len < sizeof(ip) + 3 * WOLFSSL_EXPORT_LEN) { return BAD_FUNC_ARG; } @@ -1291,10 +1404,10 @@ static int ExportPeerInfo(WOLFSSL* ssl, byte* exp, word32 len, byte ver) return SOCKET_ERROR_E; } - c16toa((word16)fam, exp + idx); idx += DTLS_EXPORT_LEN; - c16toa((word16)ipSz, exp + idx); idx += DTLS_EXPORT_LEN; + c16toa((word16)fam, exp + idx); idx += WOLFSSL_EXPORT_LEN; + c16toa((word16)ipSz, exp + idx); idx += WOLFSSL_EXPORT_LEN; XMEMCPY(exp + idx, ip, ipSz); idx += ipSz; - c16toa(port, exp + idx); idx += DTLS_EXPORT_LEN; + c16toa(port, exp + idx); idx += WOLFSSL_EXPORT_LEN; return idx; } @@ -1309,7 +1422,7 @@ static int ImportPeerInfo(WOLFSSL* ssl, const byte* buf, word32 len, byte ver) word16 port; char ip[DTLS_EXPORT_IP]; - if (ver != DTLS_EXPORT_VERSION && ver != DTLS_EXPORT_VERSION_3) { + if (ver != WOLFSSL_EXPORT_VERSION && ver != WOLFSSL_EXPORT_VERSION_3) { WOLFSSL_MSG("Export version not supported"); return BAD_FUNC_ARG; } @@ -1319,22 +1432,22 @@ static int ImportPeerInfo(WOLFSSL* ssl, const byte* buf, word32 len, byte ver) return 0; } - if (ssl == NULL || buf == NULL || len < 3 * DTLS_EXPORT_LEN) { + if (ssl == NULL || buf == NULL || len < 3 * WOLFSSL_EXPORT_LEN) { return BAD_FUNC_ARG; } /* import sin family */ - ato16(buf + idx, &fam); idx += DTLS_EXPORT_LEN; + ato16(buf + idx, &fam); idx += WOLFSSL_EXPORT_LEN; /* import ip address idx, and ipSz are unsigned but cast for enum */ - ato16(buf + idx, &ipSz); idx += DTLS_EXPORT_LEN; - if (ipSz >= sizeof(ip) || (word16)(idx + ipSz + DTLS_EXPORT_LEN) > len) { + ato16(buf + idx, &ipSz); idx += WOLFSSL_EXPORT_LEN; + if (ipSz >= sizeof(ip) || (word16)(idx + ipSz + WOLFSSL_EXPORT_LEN) > len) { return BUFFER_E; } XMEMSET(ip, 0, sizeof(ip)); XMEMCPY(ip, buf + idx, ipSz); idx += ipSz; ip[ipSz] = '\0'; /* with check that ipSz less than ip this is valid */ - ato16(buf + idx, &port); idx += DTLS_EXPORT_LEN; + ato16(buf + idx, &port); idx += WOLFSSL_EXPORT_LEN; /* sanity check for a function to call, then use it to import peer info */ if (ssl->ctx->CBSetPeer == NULL) { @@ -1367,9 +1480,9 @@ int wolfSSL_dtls_export_state_internal(WOLFSSL* ssl, byte* buf, word32 sz) return BAD_FUNC_ARG; } - totalLen += DTLS_EXPORT_LEN * 2; /* 2 protocol bytes and 2 length bytes */ + totalLen += WOLFSSL_EXPORT_LEN * 2; /* 2 protocol bytes and 2 length bytes */ /* each of the following have a 2 byte length before data */ - totalLen += DTLS_EXPORT_LEN + DTLS_EXPORT_MIN_KEY_SZ; + totalLen += WOLFSSL_EXPORT_LEN + DTLS_EXPORT_MIN_KEY_SZ; if (totalLen > sz) { WOLFSSL_LEAVE("wolfSSL_dtls_export_state_internal", BUFFER_E); return BUFFER_E; @@ -1377,20 +1490,20 @@ int wolfSSL_dtls_export_state_internal(WOLFSSL* ssl, byte* buf, word32 sz) buf[idx++] = (byte)DTLS_EXPORT_STATE_PRO; buf[idx++] = ((byte)DTLS_EXPORT_STATE_PRO & 0xF0) | - ((byte)DTLS_EXPORT_VERSION & 0X0F); - idx += DTLS_EXPORT_LEN; /* leave room for total length */ + ((byte)WOLFSSL_EXPORT_VERSION & 0X0F); + idx += WOLFSSL_EXPORT_LEN; /* leave room for total length */ /* export keys struct and dtls state -- variable length stored in ret */ - idx += DTLS_EXPORT_LEN; /* leave room for length */ + idx += WOLFSSL_EXPORT_LEN; /* leave room for length */ if ((ret = ExportKeyState(ssl, buf + idx, sz - idx, - DTLS_EXPORT_VERSION, 1)) < 0) { + WOLFSSL_EXPORT_VERSION, 1, WOLFSSL_EXPORT_DTLS)) < 0) { WOLFSSL_LEAVE("wolfSSL_dtls_export_state_internal", ret); return ret; } - c16toa((word16)ret, buf + idx - DTLS_EXPORT_LEN); idx += ret; + c16toa((word16)ret, buf + idx - WOLFSSL_EXPORT_LEN); idx += ret; /* place total length of exported buffer minus 2 bytes protocol/version */ - c16toa((word16)(idx - DTLS_EXPORT_LEN), buf + DTLS_EXPORT_LEN); + c16toa((word16)(idx - WOLFSSL_EXPORT_LEN), buf + WOLFSSL_EXPORT_LEN); #ifdef WOLFSSL_SESSION_EXPORT_DEBUG /* if compiled with debug options then print the version, protocol, size */ @@ -1408,100 +1521,6 @@ int wolfSSL_dtls_export_state_internal(WOLFSSL* ssl, byte* buf, word32 sz) } -/* WOLFSSL_LOCAL function that serializes the current WOLFSSL session - * buf is used to hold the serialized WOLFSSL struct and sz is the size of buf - * passed in. - * On success returns the size of serialized session.*/ -int wolfSSL_dtls_export_internal(WOLFSSL* ssl, byte* buf, word32 sz) -{ - int ret; - word32 idx = 0; - word32 totalLen = 0; - - WOLFSSL_ENTER("wolfSSL_dtls_export_internal"); - - if (buf == NULL || ssl == NULL) { - WOLFSSL_LEAVE("wolfSSL_dtls_export_internal", BAD_FUNC_ARG); - return BAD_FUNC_ARG; - } - - totalLen += DTLS_EXPORT_LEN * 2; /* 2 protocol bytes and 2 length bytes */ - /* each of the following have a 2 byte length before data */ - totalLen += DTLS_EXPORT_LEN + DTLS_EXPORT_OPT_SZ; - totalLen += DTLS_EXPORT_LEN + DTLS_EXPORT_KEY_SZ; - totalLen += DTLS_EXPORT_LEN + DTLS_EXPORT_SPC_SZ; - totalLen += DTLS_EXPORT_LEN + ssl->buffers.dtlsCtx.peer.sz; - - if (totalLen > sz) { - WOLFSSL_LEAVE("wolfSSL_dtls_export_internal", BUFFER_E); - return BUFFER_E; - } - - buf[idx++] = (byte)DTLS_EXPORT_PRO; - buf[idx++] = ((byte)DTLS_EXPORT_PRO & 0xF0) | - ((byte)DTLS_EXPORT_VERSION & 0X0F); - - idx += DTLS_EXPORT_LEN; /* leave spot for length */ - - c16toa((word16)DTLS_EXPORT_OPT_SZ, buf + idx); idx += DTLS_EXPORT_LEN; - if ((ret = dtls_export_new(ssl, buf + idx, sz - idx, - DTLS_EXPORT_VERSION)) < 0) { - WOLFSSL_LEAVE("wolfSSL_dtls_export_internal", ret); - return ret; - } - idx += ret; - - /* export keys struct and dtls state -- variable length stored in ret */ - idx += DTLS_EXPORT_LEN; /* leave room for length */ - if ((ret = ExportKeyState(ssl, buf + idx, sz - idx, - DTLS_EXPORT_VERSION, 0)) < 0) { - WOLFSSL_LEAVE("wolfSSL_dtls_export_internal", ret); - return ret; - } - c16toa((word16)ret, buf + idx - DTLS_EXPORT_LEN); idx += ret; - - /* export of cipher specs struct */ - c16toa((word16)DTLS_EXPORT_SPC_SZ, buf + idx); idx += DTLS_EXPORT_LEN; - if ((ret = ExportCipherSpecState(ssl, buf + idx, sz - idx, - DTLS_EXPORT_VERSION)) < 0) { - WOLFSSL_LEAVE("wolfSSL_dtls_export_internal", ret); - return ret; - } - idx += ret; - - /* export of dtls peer information */ - idx += DTLS_EXPORT_LEN; -#ifdef WOLFSSL_SESSION_EXPORT_NOPEER - ret = 0; /* not saving peer port/ip information */ -#else - if ((ret = ExportPeerInfo(ssl, buf + idx, sz - idx, - DTLS_EXPORT_VERSION)) < 0) { - WOLFSSL_LEAVE("wolfSSL_dtls_export_internal", ret); - return ret; - } -#endif - c16toa(ret, buf + idx - DTLS_EXPORT_LEN); - idx += ret; - - /* place total length of exported buffer minus 2 bytes protocol/version */ - c16toa((word16)(idx - DTLS_EXPORT_LEN), buf + DTLS_EXPORT_LEN); - - /* if compiled with debug options then print the version, protocol, size */ -#ifdef WOLFSSL_SESSION_EXPORT_DEBUG - { - char debug[256]; - XSNPRINTF(debug, sizeof(debug), "Exporting DTLS session\n" - "\tVersion : %d\n\tProtocol : %02X%01X\n\tLength of: %d\n\n" - , (int)DTLS_EXPORT_VERSION, buf[0], (buf[1] >> 4), idx - 2); - WOLFSSL_MSG(debug); - } -#endif /* WOLFSSL_SESSION_EXPORT_DEBUG */ - - WOLFSSL_LEAVE("wolfSSL_dtls_export_internal", idx); - return idx; -} - - /* On success return amount of buffer consumed */ int wolfSSL_dtls_import_state_internal(WOLFSSL* ssl, const byte* buf, word32 sz) { @@ -1512,7 +1531,7 @@ int wolfSSL_dtls_import_state_internal(WOLFSSL* ssl, const byte* buf, word32 sz) WOLFSSL_ENTER("wolfSSL_dtls_import_state_internal"); /* check at least enough room for protocol and length */ - if (sz < DTLS_EXPORT_LEN * 2 || ssl == NULL) { + if (sz < WOLFSSL_EXPORT_LEN * 2 || ssl == NULL) { WOLFSSL_LEAVE("wolfSSL_dtls_import_state_internal", BAD_FUNC_ARG); return BAD_FUNC_ARG; } @@ -1524,8 +1543,8 @@ int wolfSSL_dtls_import_state_internal(WOLFSSL* ssl, const byte* buf, word32 sz) } version = buf[idx++] & 0x0F; - ato16(buf + idx, &length); idx += DTLS_EXPORT_LEN; - if (length > sz - DTLS_EXPORT_LEN) { /* subtract 2 for protocol */ + ato16(buf + idx, &length); idx += WOLFSSL_EXPORT_LEN; + if (length > sz - WOLFSSL_EXPORT_LEN) { /* subtract 2 for protocol */ WOLFSSL_MSG("Buffer size sanity check failed"); return BUFFER_E; } @@ -1543,7 +1562,7 @@ int wolfSSL_dtls_import_state_internal(WOLFSSL* ssl, const byte* buf, word32 sz) /* perform sanity checks and extract Options information used */ switch (version) { - case DTLS_EXPORT_VERSION: + case WOLFSSL_EXPORT_VERSION: break; default: @@ -1553,16 +1572,17 @@ int wolfSSL_dtls_import_state_internal(WOLFSSL* ssl, const byte* buf, word32 sz) } /* perform sanity checks and extract Keys struct */ - if (DTLS_EXPORT_LEN + idx > sz) { + if (WOLFSSL_EXPORT_LEN + idx > sz) { WOLFSSL_MSG("Import Key struct error"); return BUFFER_E; } - ato16(buf + idx, &length); idx += DTLS_EXPORT_LEN; + ato16(buf + idx, &length); idx += WOLFSSL_EXPORT_LEN; if (length > DTLS_EXPORT_KEY_SZ || length + idx > sz) { WOLFSSL_MSG("Import Key struct error"); return BUFFER_E; } - if ((ret = ImportKeyState(ssl, buf + idx, length, version)) < 0) { + if ((ret = ImportKeyState(ssl, buf + idx, length, version, + WOLFSSL_EXPORT_DTLS)) < 0) { WOLFSSL_MSG("Import Key struct error"); WOLFSSL_LEAVE("wolfSSL_dtls_import_state_internal", ret); return ret; @@ -1572,36 +1592,66 @@ int wolfSSL_dtls_import_state_internal(WOLFSSL* ssl, const byte* buf, word32 sz) WOLFSSL_LEAVE("wolfSSL_dtls_import_state_internal", ret); return idx; } +#endif /* WOLFSSL_DTLS */ -/* On success return amount of buffer consumed */ -int wolfSSL_dtls_import_internal(WOLFSSL* ssl, const byte* buf, word32 sz) +/** + * Imports a serialized buffer (both TLS and DTLS) + * + * @param ssl WOLFSSL structure to import into + * @param buf buffer containing serialized session + * @param sz size of buffer 'buf' + * @param isTLS flag for TLS or DTLS + * + * @return the size of serialized buffer on success + */ +int wolfSSL_session_import_internal(WOLFSSL* ssl, const unsigned char* buf, + unsigned int sz, int isTLS) { word32 idx = 0; word16 length = 0; int version; - int ret; + int ret = 0; int optSz; + int rc; + byte validProto = 0; /* did we find a valid protocol */ - WOLFSSL_ENTER("wolfSSL_dtls_import_internal"); + WOLFSSL_ENTER("wolfSSL_session_import_internal"); /* check at least enough room for protocol and length */ - if (sz < DTLS_EXPORT_LEN * 2 || ssl == NULL) { - return BAD_FUNC_ARG; + if (sz < WOLFSSL_EXPORT_LEN * 2 || ssl == NULL) { + ret = BAD_FUNC_ARG; } - /* sanity check on protocol ID and size of buffer */ - if (buf[idx++] != (byte)DTLS_EXPORT_PRO || - (buf[idx] & 0xF0) != ((byte)DTLS_EXPORT_PRO & 0xF0)) { - /* don't increment on second idx to next get version */ + /* Check if is TLS export protocol */ + if (ret == 0) { + if (buf[idx] == (byte)TLS_EXPORT_PRO && + (buf[idx + 1] & 0xF0) == ((byte)TLS_EXPORT_PRO & 0xF0)) { + validProto = 1; + } - /* check if importing state only */ - return wolfSSL_dtls_import_state_internal(ssl, buf, sz); + /* Check if is DTLS export protocol */ + if (buf[idx] == (byte)DTLS_EXPORT_PRO && + (buf[idx + 1] & 0xF0) == ((byte)DTLS_EXPORT_PRO & 0xF0)) { + validProto = 1; + } + + if (validProto == 0) { + #ifdef WOLFSSL_DTLS + /* check if importing state only */ + return wolfSSL_dtls_import_state_internal(ssl, buf, sz); + #else + ret = BAD_FUNC_ARG; + #endif + } + idx += 1; } - version = buf[idx++] & 0x0F; - ato16(buf + idx, &length); idx += DTLS_EXPORT_LEN; - if (length > sz - DTLS_EXPORT_LEN) { /* subtract 2 for protocol */ - return BUFFER_E; + if (ret == 0) { + version = buf[idx++] & 0x0F; + ato16(buf + idx, &length); idx += WOLFSSL_EXPORT_LEN; + if (length > sz - WOLFSSL_EXPORT_LEN) { /* subtract 2 for protocol */ + ret = BUFFER_E; + } } /* if compiled with debug options then print the version, protocol, size */ @@ -1616,90 +1666,130 @@ int wolfSSL_dtls_import_internal(WOLFSSL* ssl, const byte* buf, word32 sz) #endif /* WOLFSSL_SESSION_EXPORT_DEBUG */ /* perform sanity checks and extract Options information used */ - switch (version) { - case DTLS_EXPORT_VERSION: - optSz = DTLS_EXPORT_OPT_SZ; - break; + if (ret == 0) { + switch (version) { + case WOLFSSL_EXPORT_VERSION: + optSz = DTLS_EXPORT_OPT_SZ; + break; - case DTLS_EXPORT_VERSION_3: - WOLFSSL_MSG("Importing older version 3"); - optSz = DTLS_EXPORT_OPT_SZ_3; - break; - - default: - WOLFSSL_MSG("Bad export version"); - return BAD_FUNC_ARG; + case WOLFSSL_EXPORT_VERSION_3: + WOLFSSL_MSG("Importing older version 3"); + optSz = DTLS_EXPORT_OPT_SZ_3; + break; + default: + WOLFSSL_MSG("Bad export version"); + ret = BAD_FUNC_ARG; + } } - if (DTLS_EXPORT_LEN + optSz + idx > sz) { + if (ret == 0 && (WOLFSSL_EXPORT_LEN + optSz + idx > sz)) { WOLFSSL_MSG("Import Options struct error"); - return BUFFER_E; + ret = BUFFER_E; } - ato16(buf + idx, &length); idx += DTLS_EXPORT_LEN; - if (length != optSz) { - WOLFSSL_MSG("Import Options struct error"); - return BUFFER_E; + + if (ret == 0) { + ato16(buf + idx, &length); idx += WOLFSSL_EXPORT_LEN; + if (length != optSz) { + WOLFSSL_MSG("Import Options struct error"); + ret = BUFFER_E; + } } - if ((ret = dtls_export_load(ssl, buf + idx, length, version)) < 0) { - WOLFSSL_MSG("Import Options struct error"); - return ret; + + if (ret == 0) { + rc = ImportOptions(ssl, buf + idx, length, version, isTLS); + if (rc < 0) { + WOLFSSL_MSG("Import Options struct error"); + ret = rc; + } + else { + idx += length; + } } - idx += length; /* perform sanity checks and extract Keys struct */ - if (DTLS_EXPORT_LEN + idx > sz) { + if (ret == 0 && (WOLFSSL_EXPORT_LEN + idx > sz)) { WOLFSSL_MSG("Import Key struct error"); - return BUFFER_E; + ret = BUFFER_E; } - ato16(buf + idx, &length); idx += DTLS_EXPORT_LEN; - if (length > DTLS_EXPORT_KEY_SZ || length + idx > sz) { - WOLFSSL_MSG("Import Key struct error"); - return BUFFER_E; + + if (ret == 0) { + ato16(buf + idx, &length); idx += WOLFSSL_EXPORT_LEN; + if (length > DTLS_EXPORT_KEY_SZ || length + idx > sz) { + WOLFSSL_MSG("Import Key struct error"); + ret = BUFFER_E; + } } - if ((ret = ImportKeyState(ssl, buf + idx, length, version)) < 0) { - WOLFSSL_MSG("Import Key struct error"); - return ret; + + if (ret == 0) { + rc = ImportKeyState(ssl, buf + idx, length, version, isTLS); + if (rc < 0) { + WOLFSSL_MSG("Import Key struct error"); + ret = rc; + } + else { + idx += rc; + } } - idx += ret; /* perform sanity checks and extract CipherSpecs struct */ - if (DTLS_EXPORT_LEN + DTLS_EXPORT_SPC_SZ + idx > sz) { + if (ret == 0 && (WOLFSSL_EXPORT_LEN + WOLFSSL_EXPORT_SPC_SZ + idx > sz)) { WOLFSSL_MSG("Import CipherSpecs struct error"); - return BUFFER_E; + ret = BUFFER_E; } - ato16(buf + idx, &length); idx += DTLS_EXPORT_LEN; - if ( length != DTLS_EXPORT_SPC_SZ) { - WOLFSSL_MSG("Import CipherSpecs struct error"); - return BUFFER_E; + + if (ret == 0) { + ato16(buf + idx, &length); idx += WOLFSSL_EXPORT_LEN; + if (length != WOLFSSL_EXPORT_SPC_SZ) { + WOLFSSL_MSG("Import CipherSpecs struct error"); + ret = BUFFER_E; + } } - if ((ret = ImportCipherSpecState(ssl, buf + idx, length, version)) < 0) { - WOLFSSL_MSG("Import CipherSpecs struct error"); - return ret; + + if (ret == 0) { + rc = ImportCipherSpecState(ssl, buf + idx, length, version, isTLS); + if (rc < 0) { + WOLFSSL_MSG("Import CipherSpecs struct error"); + ret = rc; + } + else { + idx += rc; + } } - idx += ret; /* perform sanity checks and extract DTLS peer info */ - if (DTLS_EXPORT_LEN + idx > sz) { - WOLFSSL_MSG("Import DTLS peer info error"); - return BUFFER_E; - } - ato16(buf + idx, &length); idx += DTLS_EXPORT_LEN; - if (idx + length > sz) { - WOLFSSL_MSG("Import DTLS peer info error"); - return BUFFER_E; - } - if ((ret = ImportPeerInfo(ssl, buf + idx, length, version)) < 0) { - WOLFSSL_MSG("Import Peer Addr error"); - return ret; - } - idx += ret; + if (!isTLS) { + if (ret == 0 && (WOLFSSL_EXPORT_LEN + idx > sz)) { + WOLFSSL_MSG("Import DTLS peer info error"); + ret = BUFFER_E; + } + + if (ret == 0) { + ato16(buf + idx, &length); idx += WOLFSSL_EXPORT_LEN; + if (idx + length > sz) { + WOLFSSL_MSG("Import DTLS peer info error"); + ret = BUFFER_E; + } + } + + #ifdef WOLFSSL_DTLS + if (ret == 0) { + rc = ImportPeerInfo(ssl, buf + idx, length, version); + if (rc < 0) { + WOLFSSL_MSG("Import Peer Addr error"); + ret = rc; + } + else { + idx += rc; + } + } + #endif + } - SetKeysSide(ssl, ENCRYPT_AND_DECRYPT_SIDE); /* make sure is a valid suite used */ - if (wolfSSL_get_cipher(ssl) == NULL) { + if (ret == 0 && wolfSSL_get_cipher(ssl) == NULL) { WOLFSSL_MSG("Can not match cipher suite imported"); - return MATCH_SUITE_ERROR; + ret = MATCH_SUITE_ERROR; } #ifndef WOLFSSL_AEAD_ONLY @@ -1710,16 +1800,151 @@ int wolfSSL_dtls_import_internal(WOLFSSL* ssl, const byte* buf, word32 sz) } /* do not allow stream ciphers with DTLS, except for NULL cipher */ - if (ssl->specs.cipher_type == stream && + if (ret == 0 && ssl->specs.cipher_type == stream && ssl->specs.bulk_cipher_algorithm != wolfssl_cipher_null) { WOLFSSL_MSG("Can not import stream ciphers for DTLS"); - return SANITY_CIPHER_E; + ret = SANITY_CIPHER_E; } #endif /* !WOLFSSL_AEAD_ONLY */ + if (ret != 0) { + idx = ret; + } + WOLFSSL_LEAVE("wolfSSL_session_import_internal", idx); return idx; } -#endif /* WOLFSSL_DTLS */ + + +/** + * Handles serializing the session information. + * + * @param ssl WOLFSSL structure to serialize session from + * @param buf output buffer to hold serialized session + * @param sz the size of buffer 'buf', if too small then gets updated + * @param isTLS if the input WOLFSSL structure is expected to be TLS or DTLS + * 1 for yes is TLS and 0 for no is DTLS + * + * @return the size of serialized buffer on success and negative values on fail + */ +int wolfSSL_session_export_internal(WOLFSSL* ssl, byte* buf, word32* sz, + int isTLS) +{ + int ret = 0; + word32 idx = 0; + word32 totalLen = 0; + + WOLFSSL_ENTER("wolfSSL_session_export_internal"); + + if (buf == NULL || ssl == NULL) { + WOLFSSL_MSG("unexpected null argument"); + ret = BAD_FUNC_ARG; + } + + if (ret == 0) { + totalLen += WOLFSSL_EXPORT_LEN * 2; /* 2 protocol bytes and 2 length bytes */ + /* each of the following have a 2 byte length before data */ + totalLen += WOLFSSL_EXPORT_LEN + DTLS_EXPORT_OPT_SZ; + totalLen += WOLFSSL_EXPORT_LEN + DTLS_EXPORT_KEY_SZ; + totalLen += WOLFSSL_EXPORT_LEN + WOLFSSL_EXPORT_SPC_SZ; + #ifdef WOLFSSL_DTLS + if (!isTLS) { + totalLen += WOLFSSL_EXPORT_LEN + ssl->buffers.dtlsCtx.peer.sz; + } + #endif + } + + /* check is at least the minimum size needed, TLS cipher states add more */ + if (ret == 0 && totalLen > *sz) { + WOLFSSL_MSG("export buffer was too small"); + *sz = totalLen; + + /* possible AES state needed */ + if (isTLS) { + *sz += AES_BLOCK_SIZE*2; + } + ret = LENGTH_ONLY_E; + } + + if (ret == 0) { + buf[idx++] = (byte)(isTLS)? TLS_EXPORT_PRO : DTLS_EXPORT_PRO; + buf[idx++] = ((byte)((isTLS)? TLS_EXPORT_PRO : DTLS_EXPORT_PRO) & 0xF0) + | ((byte)WOLFSSL_EXPORT_VERSION & 0X0F); + + idx += WOLFSSL_EXPORT_LEN; /* leave spot for length */ + c16toa((word16)DTLS_EXPORT_OPT_SZ, buf + idx); + idx += WOLFSSL_EXPORT_LEN; + ret = ExportOptions(ssl, buf + idx, *sz - idx, WOLFSSL_EXPORT_VERSION, + isTLS); + if (ret >= 0) { + idx += ret; + ret = 0; + } + } + + /* export keys struct and dtls state -- variable length stored in ret */ + if (ret == 0) { + idx += WOLFSSL_EXPORT_LEN; /* leave room for length */ + ret = ExportKeyState(ssl, buf + idx, *sz - idx, WOLFSSL_EXPORT_VERSION, + 0, isTLS); + if (ret >= 0) { + c16toa((word16)ret, buf + idx - WOLFSSL_EXPORT_LEN); idx += ret; + ret = 0; + } + } + + /* export of cipher specs struct */ + if (ret == 0) { + c16toa((word16)WOLFSSL_EXPORT_SPC_SZ, buf + idx); + idx += WOLFSSL_EXPORT_LEN; + ret = ExportCipherSpecState(ssl, buf + idx, *sz - idx, + WOLFSSL_EXPORT_VERSION, isTLS); + if (ret >= 0) { + idx += ret; + ret = 0; + } + } + + /* export of dtls peer information */ +#ifdef WOLFSSL_DTLS + if (ret == 0 && !isTLS) { + idx += WOLFSSL_EXPORT_LEN; + #ifdef WOLFSSL_SESSION_EXPORT_NOPEER + ret = 0; /* not saving peer port/ip information */ + #else + ret = ExportPeerInfo(ssl, buf + idx, *sz - idx, WOLFSSL_EXPORT_VERSION); + #endif + if (ret >= 0) { + c16toa(ret, buf + idx - WOLFSSL_EXPORT_LEN); + idx += ret; + ret = 0; + } + } +#endif + + if (ret != 0) { + /*in a fail case clear the buffer which could contain partial key info*/ + XMEMSET(buf, 0, *sz); + } + + /* place total length of exported buffer minus 2 bytes protocol/version */ + if (ret == 0) { + c16toa((word16)(idx - WOLFSSL_EXPORT_LEN), buf + WOLFSSL_EXPORT_LEN); + ret = idx; + + #ifdef WOLFSSL_SESSION_EXPORT_DEBUG + { + char debug[256]; + XSNPRINTF(debug, sizeof(debug), "Exporting TLS session\n" + "\tVersion : %d\n\tProtocol : %02X%01X\n\tLength of: %d\n\n" + ,(int)WOLFSSL_EXPORT_VERSION, buf[0], (buf[1] >> 4), idx - 2); + WOLFSSL_MSG(debug); + } + #endif /* WOLFSSL_SESSION_EXPORT_DEBUG */ + } + + WOLFSSL_LEAVE("wolfSSL_session_export_internal", ret); + return ret; +} #endif /* WOLFSSL_SESSION_EXPORT */ @@ -17671,6 +17896,7 @@ int BuildMessage(WOLFSSL* ssl, byte* output, int outSz, const byte* input, if (ret != 0) goto exit_buildmsg; + XMEMSET(args->iv, 0, args->ivSz); } #if !defined(NO_PUBLIC_GCM_SET_IV) && \ ((defined(HAVE_FIPS) || defined(HAVE_SELFTEST)) && \ diff --git a/src/ssl.c b/src/ssl.c index cdbd8bb8b..9391974f8 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -239,6 +239,45 @@ byte tsip_rootCAverified( ); #endif #ifdef WOLFSSL_SESSION_EXPORT +/** + * Used to import a serialized TLS session. In most cases wolfSSL_get_session + * should be used instead, this function is for exporting the state of the + * connection and when imported a resumption is not needed. + * WARNING: buf contains sensitive information about the state and is best to be + * encrypted before storing if stored. + * + * @param ssl WOLFSSL structure to import the session into + * @param buf serialized session + * @param sz size of buffer 'buf' + * @return the number of bytes read from buffer 'buf' + */ +int wolfSSL_tls_import(WOLFSSL* ssl, const unsigned char* buf, unsigned int sz) +{ + if (ssl == NULL || buf == NULL) { + return BAD_FUNC_ARG; + } + return wolfSSL_session_import_internal(ssl, buf, sz, WOLFSSL_EXPORT_TLS); +} + + +/** + * Used to export a serialized TLS session. In most cases wolfSSL_set_session + * should be used instead, this function is for importing a serialized state of + * the connection. + * + * @param ssl WOLFSSL structure to export the session from + * @param buf output of serialized session + * @param sz size in bytes set in 'buf' + * @return the number of bytes written into buffer 'buf' + */ +int wolfSSL_tls_export(WOLFSSL* ssl, unsigned char* buf, unsigned int* sz) +{ + if (ssl == NULL || sz == NULL) { + return BAD_FUNC_ARG; + } + return wolfSSL_session_export_internal(ssl, buf, sz, WOLFSSL_EXPORT_TLS); +} + #ifdef WOLFSSL_DTLS int wolfSSL_dtls_import(WOLFSSL* ssl, const unsigned char* buf, unsigned int sz) { @@ -249,7 +288,7 @@ int wolfSSL_dtls_import(WOLFSSL* ssl, const unsigned char* buf, unsigned int sz) } /* sanity checks on buffer and protocol are done in internal function */ - return wolfSSL_dtls_import_internal(ssl, buf, sz); + return wolfSSL_session_import_internal(ssl, buf, sz, WOLFSSL_EXPORT_DTLS); } @@ -319,7 +358,7 @@ int wolfSSL_dtls_export(WOLFSSL* ssl, unsigned char* buf, unsigned int* sz) } /* copy over keys, options, and dtls state struct */ - return wolfSSL_dtls_export_internal(ssl, buf, *sz); + return wolfSSL_session_export_internal(ssl, buf, sz, WOLFSSL_EXPORT_DTLS); } @@ -363,7 +402,7 @@ int wolfSSL_send_session(WOLFSSL* ssl) { int ret; byte* buf; - word16 bufSz = MAX_EXPORT_BUFFER; + word32 bufSz = MAX_EXPORT_BUFFER; WOLFSSL_ENTER("wolfSSL_send_session"); @@ -384,7 +423,7 @@ int wolfSSL_send_session(WOLFSSL* ssl) } /* copy over keys, options, and dtls state struct */ - ret = wolfSSL_dtls_export_internal(ssl, buf, bufSz); + ret = wolfSSL_session_export_internal(ssl, buf, &bufSz, WOLFSSL_EXPORT_DTLS); if (ret < 0) { XFREE(buf, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); return ret; @@ -14247,7 +14286,7 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, } #endif /* WOLFSSL_ASYNC_CRYPT && HAVE_SECURE_RENEGOTIATION */ -#ifdef WOLFSSL_SESSION_EXPORT +#if defined(WOLFSSL_SESSION_EXPORT) && defined(WOLFSSL_DTLS) if (ssl->dtls_export) { if ((ssl->error = wolfSSL_send_session(ssl)) != 0) { WOLFSSL_MSG("Export DTLS session error"); diff --git a/tests/api.c b/tests/api.c index a77bb55f6..616ae4090 100644 --- a/tests/api.c +++ b/tests/api.c @@ -3642,11 +3642,12 @@ static void test_wolfSSL_EVP_CIPHER_CTX(void) #ifdef HAVE_IO_TESTS_DEPENDENCIES #ifdef WOLFSSL_SESSION_EXPORT +#ifdef WOLFSSL_DTLS /* set up function for sending session information */ static int test_export(WOLFSSL* inSsl, byte* buf, word32 sz, void* userCtx) { - WOLFSSL_CTX* ctx; - WOLFSSL* ssl; + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; AssertNotNull(inSsl); AssertNotNull(buf); @@ -3666,6 +3667,7 @@ static int test_export(WOLFSSL* inSsl, byte* buf, word32 sz, void* userCtx) (void)userCtx; return WOLFSSL_SUCCESS; } +#endif /* returns negative value on fail and positive (including 0) on success */ static int nonblocking_accept_read(void* args, WOLFSSL* ssl, SOCKET_T* sockfd) @@ -4814,7 +4816,8 @@ done: /* SNI / ALPN / session export helper functions */ -#if defined(HAVE_SNI) || defined(HAVE_ALPN) || defined(WOLFSSL_SESSION_EXPORT) +#if defined(HAVE_SNI) || defined(HAVE_ALPN) ||\ + (defined(WOLFSSL_SESSION_EXPORT) && defined(WOLFSSL_DTLS)) static THREAD_RETURN WOLFSSL_THREAD run_wolfssl_server(void* args) { @@ -4854,7 +4857,7 @@ static THREAD_RETURN WOLFSSL_THREAD run_wolfssl_server(void* args) #ifdef WOLFSSL_ENCRYPTED_KEYS wolfSSL_CTX_set_default_passwd_cb(ctx, PasswordCallBack); #endif -#ifdef WOLFSSL_SESSION_EXPORT +#if defined(WOLFSSL_SESSION_EXPORT) && defined(WOLFSSL_DTLS) AssertIntEQ(WOLFSSL_SUCCESS, wolfSSL_CTX_dtls_set_export(ctx, test_export)); #endif @@ -4929,7 +4932,8 @@ static THREAD_RETURN WOLFSSL_THREAD run_wolfssl_server(void* args) } AssertIntEQ(len, wolfSSL_write(ssl, msg, len)); -#if defined(WOLFSSL_SESSION_EXPORT) && !defined(HAVE_IO_POOL) +#if defined(WOLFSSL_SESSION_EXPORT) && !defined(HAVE_IO_POOL) && \ + defined(WOLFSSL_DTLS) if (wolfSSL_dtls(ssl)) { byte* import; word32 sz; diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 858c5c368..8d0d73739 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1323,23 +1323,29 @@ enum Misc { DTLS_POOL_SZ = 255,/* allowed number of list items in TX pool */ DTLS_EXPORT_PRO = 165,/* wolfSSL protocol for serialized session */ DTLS_EXPORT_STATE_PRO = 166,/* wolfSSL protocol for serialized state */ - DTLS_EXPORT_VERSION = 4, /* wolfSSL version for serialized session */ + TLS_EXPORT_PRO = 167,/* wolfSSL protocol for serialized TLS */ DTLS_EXPORT_OPT_SZ = 61, /* amount of bytes used from Options */ - DTLS_EXPORT_VERSION_3 = 3, /* wolfSSL version before TLS 1.3 addition */ DTLS_EXPORT_OPT_SZ_3 = 60, /* amount of bytes used from Options */ DTLS_EXPORT_KEY_SZ = 325 + (DTLS_SEQ_SZ * 2), /* max amount of bytes used from Keys */ DTLS_EXPORT_MIN_KEY_SZ = 85 + (DTLS_SEQ_SZ * 2), /* min amount of bytes used from Keys */ - DTLS_EXPORT_SPC_SZ = 16, /* amount of bytes used from CipherSpecs */ - DTLS_EXPORT_LEN = 2, /* 2 bytes for length and protocol */ + WOLFSSL_EXPORT_TLS = 1, + WOLFSSL_EXPORT_DTLS = 0, + WOLFSSL_EXPORT_SPC_SZ = 16, /* amount of bytes used from CipherSpecs */ + WOLFSSL_EXPORT_LEN = 2, /* 2 bytes for length and protocol */ + WOLFSSL_EXPORT_VERSION = 4, /* wolfSSL version for serialized session */ + + /* older export versions supported */ + WOLFSSL_EXPORT_VERSION_3 = 3, /* wolfSSL version before TLS 1.3 addition */ + DTLS_EXPORT_IP = 46, /* max ip size IPv4 mapped IPv6 */ DTLS_MTU_ADDITIONAL_READ_BUFFER = WOLFSSL_DTLS_MTU_ADDITIONAL_READ_BUFFER, /* Additional bytes to read so that * we can work with a peer that has * a slightly different MTU than us. */ MAX_EXPORT_BUFFER = 514, /* max size of buffer for exporting */ - MAX_EXPORT_STATE_BUFFER = (DTLS_EXPORT_MIN_KEY_SZ) + (3 * DTLS_EXPORT_LEN), + MAX_EXPORT_STATE_BUFFER = (DTLS_EXPORT_MIN_KEY_SZ) + (3 * WOLFSSL_EXPORT_LEN), /* max size of buffer for exporting state */ FINISHED_LABEL_SZ = 15, /* TLS finished label size */ TLS_FINISHED_SZ = 12, /* TLS has a shorter size */ @@ -1654,17 +1660,19 @@ WOLFSSL_LOCAL ProtocolVersion MakeTLSv1_3(void); WOLFSSL_LOCAL ProtocolVersion MakeDTLSv1(void); WOLFSSL_LOCAL ProtocolVersion MakeDTLSv1_2(void); - #ifdef WOLFSSL_SESSION_EXPORT - WOLFSSL_LOCAL int wolfSSL_dtls_import_internal(WOLFSSL* ssl, const byte* buf, - word32 sz); - WOLFSSL_LOCAL int wolfSSL_dtls_export_internal(WOLFSSL* ssl, byte* buf, - word32 sz); +#endif +#ifdef WOLFSSL_SESSION_EXPORT +WOLFSSL_LOCAL int wolfSSL_session_export_internal(WOLFSSL* ssl, byte* buf, + word32* sz, int isTLS); +WOLFSSL_LOCAL int wolfSSL_session_import_internal(WOLFSSL* ssl, const byte* buf, + word32 sz, int isTLS); +#ifdef WOLFSSL_DTLS WOLFSSL_LOCAL int wolfSSL_dtls_export_state_internal(WOLFSSL* ssl, byte* buf, word32 sz); WOLFSSL_LOCAL int wolfSSL_dtls_import_state_internal(WOLFSSL* ssl, const byte* buf, word32 sz); WOLFSSL_LOCAL int wolfSSL_send_session(WOLFSSL* ssl); - #endif +#endif #endif struct WOLFSSL_BY_DIR_HASH { diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 44572de4c..83c99d875 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -878,6 +878,9 @@ WOLFSSL_ABI WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_2_client_method(void); #endif #ifdef WOLFSSL_SESSION_EXPORT +int wolfSSL_tls_import(WOLFSSL* ssl, const unsigned char* buf, unsigned int sz); +int wolfSSL_tls_export(WOLFSSL* ssl, unsigned char* buf, unsigned int* sz); + #ifdef WOLFSSL_DTLS #ifndef WOLFSSL_DTLS_EXPORT_TYPES