diff --git a/configure.ac b/configure.ac index ed413c984..7efa87230 100644 --- a/configure.ac +++ b/configure.ac @@ -2526,6 +2526,23 @@ fi AM_CONDITIONAL([BUILD_ASYNCCRYPT], [test "x$ENABLED_ASYNCCRYPT" = "xyes"]) +# Session Export +AC_ARG_ENABLE([sessionexport], + [AS_HELP_STRING([--enable-sessionexport],[Enable export and import of sessions (default: disabled)])], + [ ENABLED_SESSIONEXPORT=$enableval ], + [ ENABLED_SESSIONEXPORT=no ] + ) + +if test "$ENABLED_SESSIONEXPORT" = "yes" +then + if test "$ENABLED_DTLS" = "no" + then + AC_MSG_ERROR([Only DTLS supported with session export]) + fi + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SESSION_EXPORT" +fi + + # check if PSK was enabled for conditionally running psk.test script AM_CONDITIONAL([BUILD_PSK], [test "x$ENABLED_PSK" = "xyes"]) diff --git a/examples/client/client.c b/examples/client/client.c index 46b08304f..0df275dcc 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -1403,6 +1403,17 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) strncpy(resumeMsg, "GET /index.html HTTP/1.0\r\n\r\n", resumeSz); resumeMsg[resumeSz] = '\0'; } + +/* allow some time for exporting the session */ +#ifdef WOLFSSL_SESSION_EXPORT_DEBUG + #ifdef USE_WINDOWS_API + Sleep(500); + #elif defined(WOLFSSL_TIRTOS) + Task_sleep(1); + #else + sleep(1); + #endif +#endif /* WOLFSSL_SESSION_EXPORT_DEBUG */ if (wolfSSL_write(ssl, msg, msgSz) != msgSz) err_sys("SSL_write failed"); @@ -1521,6 +1532,18 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) printf("Getting ALPN protocol name failed\n"); } #endif + + /* allow some time for exporting the session */ + #ifdef WOLFSSL_SESSION_EXPORT_DEBUG + #ifdef USE_WINDOWS_API + Sleep(500); + #elif defined(WOLFSSL_TIRTOS) + Task_sleep(1); + #else + sleep(1); + #endif + #endif /* WOLFSSL_SESSION_EXPORT_DEBUG */ + if (wolfSSL_write(sslResume, resumeMsg, resumeSz) != resumeSz) err_sys("SSL_write failed"); diff --git a/src/internal.c b/src/internal.c index 39af8da3d..683835fd2 100755 --- a/src/internal.c +++ b/src/internal.c @@ -48,7 +48,8 @@ #include "libntruencrypt/ntru_crypto.h" #endif -#if defined(DEBUG_WOLFSSL) || defined(SHOW_SECRETS) || defined(CHACHA_AEAD_TEST) +#if defined(DEBUG_WOLFSSL) || defined(SHOW_SECRETS) || \ + defined(CHACHA_AEAD_TEST) || defined(WOLFSSL_SESSION_EXPORT_DEBUG) #if defined(FREESCALE_MQX) || defined(FREESCALE_KSDK_MQX) #if MQX_USE_IO_OLD #include @@ -469,6 +470,427 @@ static INLINE void ato32(const byte* c, word32* u32) #endif /* HAVE_LIBZ */ +#ifdef WOLFSSL_SESSION_EXPORT +#ifdef WOLFSSL_DTLS +/* copy over necessary information from Options struct to buffer + * On success returns 0 on failure returns a negative value */ +static int dtls_export_new(byte* exp, word32 len, byte ver, WOLFSSL* ssl) +{ + int idx = 0; + word16 zero = 0; + Options* options = &ssl->options; + + WOLFSSL_ENTER("dtls_export_new"); + + if (exp == NULL || options == NULL || len < DTLS_EXPORT_OPT_SZ) { + return BAD_FUNC_ARG; + } + + /* these options are kept and sent to indicate verify status and strength + * of handshake */ + exp[idx++] = options->sendVerify; + exp[idx++] = options->verifyPeer; + exp[idx++] = options->verifyNone; + exp[idx++] = options->downgrade; +#ifndef NO_DH + c16toa(options->minDhKeySz, exp + idx); idx += 2; + c16toa(options->dhKeySz, exp + idx); idx += 2; +#else + c16toa(zero, exp + idx); idx += 2; + c16toa(zero, exp + idx); idx += 2; +#endif +#ifndef NO_RSA + c16toa((word16)(options->minRsaKeySz), exp + idx); idx += 2; +#else + c16toa(zero, exp + idx); idx += 2; +#endif +#ifdef HAVE_ECC + c16toa((word16)(options->minEccKeySz), exp + idx); idx += 2; +#else + c16toa(zero, exp + idx); idx += 2; +#endif + + /* these options are kept to indicate state and behavior */ +#ifndef NO_PSK + exp[idx++] = options->havePSK; +#else + exp[idx++] = 0; +#endif + exp[idx++] = options->sessionCacheOff; + exp[idx++] = options->sessionCacheFlushOff; + exp[idx++] = options->side; + exp[idx++] = options->resuming; + exp[idx++] = options->haveSessionId; + exp[idx++] = options->tls; + exp[idx++] = options->tls1_1; + exp[idx++] = options->dtls; + exp[idx++] = options->connReset; + exp[idx++] = options->isClosed; + exp[idx++] = options->closeNotify; + exp[idx++] = options->sentNotify; + exp[idx++] = options->usingCompression; + exp[idx++] = options->haveRSA; + exp[idx++] = options->haveECC; + exp[idx++] = options->haveDH; + exp[idx++] = options->haveNTRU; + exp[idx++] = options->haveQSH; + exp[idx++] = options->haveECDSAsig; + exp[idx++] = options->haveStaticECC; + exp[idx++] = options->havePeerVerify; + exp[idx++] = options->usingPSK_cipher; + exp[idx++] = options->usingAnon_cipher; + exp[idx++] = options->sendAlertState; + exp[idx++] = options->partialWrite; + exp[idx++] = options->quietShutdown; + exp[idx++] = options->groupMessages; +#ifdef HAVE_POLY1305 + exp[idx++] = options->oldPoly; +#else + exp[idx++] = 0; +#endif +#ifdef HAVE_ANON + exp[idx++] = options->haveAnon; +#else + exp[idx++] = 0; +#endif +#ifdef HAVE_SESSION_TICKET + exp[idx++] = options->createTicket; + exp[idx++] = options->useTicket; +#else + exp[idx++] = 0; + exp[idx++] = 0; +#endif + exp[idx++] = options->processReply; + exp[idx++] = options->cipherSuite0; + exp[idx++] = options->cipherSuite; + exp[idx++] = options->serverState; + exp[idx++] = options->clientState; + exp[idx++] = options->handShakeState; + exp[idx++] = options->handShakeDone; + exp[idx++] = options->minDowngrade; + exp[idx++] = options->connectState; + exp[idx++] = options->acceptState; + exp[idx++] = options->keyShareState; + + + /* version of connection */ + exp[idx++] = ssl->version.major; + exp[idx++] = ssl->version.minor; + + (void)zero; + (void)ver; + + /* check if changes were made and notify of need to update export version */ + if (idx != DTLS_EXPORT_OPT_SZ) { + WOLFSSL_MSG("Update DTLS_EXPORT_OPT_SZ and version of wolfSSL export"); + return BUFFER_E; + } + + WOLFSSL_LEAVE("dtls_export_new", 0); + + return 0; +} + + +/* copy items from Export struct to Options struct + * On success returns 0 on failure returns a negative value */ +static int dtls_export_load(byte* exp, word32 len, byte ver, WOLFSSL* ssl) +{ + int idx = 0; + Options* options = &ssl->options; + + if (ver != 1) { + WOLFSSL_MSG("Export version not supported"); + return BAD_FUNC_ARG; + } + + if (exp == NULL || options == NULL || len < DTLS_EXPORT_OPT_SZ) { + return BAD_FUNC_ARG; + } + + /* these options are kept and sent to indicate verify status and strength + * of handshake */ + options->sendVerify = exp[idx++]; + options->verifyPeer = exp[idx++]; + options->verifyNone = exp[idx++]; + options->downgrade = exp[idx++]; +#ifndef NO_DH + ato16(exp + idx, &(options->minDhKeySz)); idx += 2; + ato16(exp + idx, &(options->dhKeySz)); idx += 2; +#else + idx += 2; + idx += 2; +#endif +#ifndef NO_RSA + ato16(exp + idx, (word16*)&(options->minRsaKeySz)); idx += 2; +#else + idx += 2; +#endif +#ifdef HAVE_ECC + ato16(exp + idx, (word16*)&(options->minEccKeySz)); idx += 2; +#else + idx += 2; +#endif + + /* these options are kept to indicate state and behavior */ +#ifndef NO_PSK + options->havePSK = exp[idx++]; +#else + idx++; +#endif + options->sessionCacheOff = exp[idx++]; + options->sessionCacheFlushOff = exp[idx++]; + options->side = exp[idx++]; + options->resuming = exp[idx++]; + options->haveSessionId = exp[idx++]; + options->tls = exp[idx++]; + options->tls1_1 = exp[idx++]; + options->dtls = exp[idx++]; + options->connReset = exp[idx++]; + options->isClosed = exp[idx++]; + options->closeNotify = exp[idx++]; + options->sentNotify = exp[idx++]; + options->usingCompression = exp[idx++]; + options->haveRSA = exp[idx++]; + options->haveECC = exp[idx++]; + options->haveDH = exp[idx++]; + options->haveNTRU = exp[idx++]; + options->haveQSH = exp[idx++]; + options->haveECDSAsig = exp[idx++]; + options->haveStaticECC = exp[idx++]; + options->havePeerVerify = exp[idx++]; + options->usingPSK_cipher = exp[idx++]; + options->usingAnon_cipher = exp[idx++]; + options->sendAlertState = exp[idx++]; + options->partialWrite = exp[idx++]; + options->quietShutdown = exp[idx++]; + options->groupMessages = exp[idx++]; +#ifdef HAVE_POLY1305 + options->oldPoly = exp[idx++]; /* set when to use old rfc way of poly*/ +#else + idx++; +#endif +#ifdef HAVE_ANON + options->haveAnon = exp[idx++]; /* User wants to allow Anon suites */ +#else + idx++; +#endif +#ifdef HAVE_SESSION_TICKET + options->createTicket = exp[idx++]; /* Server to create new Ticket */ + options->useTicket = exp[idx++]; /* Use Ticket not session cache */ +#else + idx++; + idx++; +#endif + options->processReply = exp[idx++]; + options->cipherSuite0 = exp[idx++]; + options->cipherSuite = exp[idx++]; + options->serverState = exp[idx++]; + options->clientState = exp[idx++]; + options->handShakeState = exp[idx++]; + options->handShakeDone = exp[idx++]; + options->minDowngrade = exp[idx++]; + options->connectState = exp[idx++]; + options->acceptState = exp[idx++]; + options->keyShareState = 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; + } + + return 0; +} + + +/* 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(byte* buf, word32 sz, WOLFSSL* ssl) +{ + int ret; + word32 idx = 0; + word32 totalLen = 0; + + WOLFSSL_ENTER("wolfSSL_dtls_export"); + + if (buf == NULL || ssl == NULL) { + WOLFSSL_LEAVE("wolfSSL_dtls_export", 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 + sizeof(Keys); + totalLen += DTLS_EXPORT_LEN + sizeof(CipherSpecs); + totalLen += DTLS_EXPORT_LEN + ssl->buffers.dtlsCtx.peer.sz; + + if (totalLen > sz) { + WOLFSSL_LEAVE("wolfSSL_dtls_export", BUFFER_E); + return BUFFER_E; + } + + buf[idx++] = (byte)DTLS_EXPORT_PRO; + buf[idx++] = ((byte)DTLS_EXPORT_PRO & 0xF0) | + ((byte)DTLS_EXPORT_VERSION & 0X0F); + + c16toa((word16)(totalLen - DTLS_EXPORT_LEN), buf + idx); + idx += DTLS_EXPORT_LEN; + + /* if compiled with debug options then print the version, protocol, size */ +#ifdef WOLFSSL_SESSION_EXPORT_DEBUG + { + char debug[256]; + snprintf(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), totalLen - 2); + WOLFSSL_MSG(debug); + } +#endif /* WOLFSSL_SESSION_EXPORT_DEBUG */ + + c16toa((word16)DTLS_EXPORT_OPT_SZ, buf + idx); idx += DTLS_EXPORT_LEN; + if ((ret = dtls_export_new(buf + idx, sz - idx, DTLS_EXPORT_VERSION, + ssl)) != 0) { + WOLFSSL_LEAVE("wolfSSL_dtls_export", ret); + return ret; + } + idx += DTLS_EXPORT_OPT_SZ; + + /* export keys struct and dtls state */ + c16toa((word16)sizeof(Keys), buf + idx); + idx += DTLS_EXPORT_LEN; + XMEMCPY(buf + idx, (byte*)&ssl->keys, sizeof(Keys)); + idx += sizeof(Keys); + + c16toa((word16)sizeof(CipherSpecs), buf + idx); + idx += DTLS_EXPORT_LEN; + XMEMCPY(buf + idx, (byte*)&ssl->specs, sizeof(CipherSpecs)); + idx += sizeof(CipherSpecs); + + c16toa((word16)ssl->buffers.dtlsCtx.peer.sz, buf + idx); + idx += DTLS_EXPORT_LEN; + XMEMCPY(buf + idx, ssl->buffers.dtlsCtx.peer.sa, + ssl->buffers.dtlsCtx.peer.sz); + idx += ssl->buffers.dtlsCtx.peer.sz; + + WOLFSSL_LEAVE("wolfSSL_dtls_export", idx); + return idx; +} + + +/* On success return amount of buffer consumed */ +int wolfSSL_dtls_import_internal(byte* buf, word32 sz, WOLFSSL* ssl) +{ + word32 idx = 0; + word16 length = 0; + int version; + int ret; + + WOLFSSL_ENTER("wolfSSL_dtls_import_internal"); + /* check at least enough room for protocol and length */ + if (sz < DTLS_EXPORT_LEN * 2 || ssl == NULL) { + return 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 */ + WOLFSSL_MSG("Incorrect protocol"); + return BAD_FUNC_ARG; + } + 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 compiled with debug options then print the version, protocol, size */ +#ifdef WOLFSSL_SESSION_EXPORT_DEBUG + { + char debug[256]; + snprintf(debug, sizeof(debug), "Importing DTLS session\n" + "\tVersion : %d\n\tProtocol : %02X%01X\n\tLength of: %d\n\n" + , (int)version, buf[0], (buf[1] >> 4), length); + WOLFSSL_MSG(debug); + } +#endif /* WOLFSSL_SESSION_EXPORT_DEBUG */ + + /* perform sanity checks and extract Options information used */ + if (DTLS_EXPORT_LEN + DTLS_EXPORT_OPT_SZ + idx > sz) { + return BUFFER_E; + } + ato16(buf + idx, &length); idx += DTLS_EXPORT_LEN; + if (length != DTLS_EXPORT_OPT_SZ) { + return BUFFER_E; + } + if ((ret = dtls_export_load(buf + idx, length, version, ssl)) != 0) { + return ret; + } + idx += length; + + /* perform sanity checks and extract Keys struct */ + if (DTLS_EXPORT_LEN + sizeof(Keys) + idx > sz) { + return BUFFER_E; + } + ato16(buf + idx, &length); idx += DTLS_EXPORT_LEN; + if (length < sizeof(Keys) || length + idx > sz) { + return BUFFER_E; + } + XMEMCPY(&ssl->keys, buf + idx, sizeof(Keys)); + idx += sizeof(Keys); + + /* perform sanity checks and extract CipherSpecs struct */ + if (DTLS_EXPORT_LEN + sizeof(CipherSpecs) + idx > sz) { + return BUFFER_E; + } + ato16(buf + idx, &length); idx += DTLS_EXPORT_LEN; + if ( length != sizeof(CipherSpecs)) { + return BUFFER_E; + } + XMEMCPY(&ssl->specs, buf + idx, length); + idx += length; + + /* perform sanity checks and extract DTLS peer info */ + if (DTLS_EXPORT_LEN + idx > sz) { + return BUFFER_E; + } + ato16(buf + idx, &length); idx += DTLS_EXPORT_LEN; + ssl->buffers.dtlsCtx.peer.sz = length; + + if (idx + ssl->buffers.dtlsCtx.peer.sz > sz) { + return BUFFER_E; + } + + /* peer sa is free'd in SSL_ResourceFree */ + ssl->buffers.dtlsCtx.peer.sa = XMALLOC(ssl->buffers.dtlsCtx.peer.sz, + ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (ssl->buffers.dtlsCtx.peer.sa == NULL) { + return MEMORY_E; + } + + XMEMCPY(ssl->buffers.dtlsCtx.peer.sa, buf + idx, + ssl->buffers.dtlsCtx.peer.sz); + idx += ssl->buffers.dtlsCtx.peer.sz; + + SetKeysSide(ssl, ENCRYPT_AND_DECRYPT_SIDE); + + /* set hmac function to use when verifying */ + if (ssl->options.tls == 1 || ssl->options.tls1_1 == 1 || + ssl->options.dtls == 1) { + ssl->hmac = TLS_hmac; + } + + return idx; +} +#endif /* WOLFSSL_DTLS */ +#endif /* WOLFSSL_SESSION_EXPORT */ + + #ifdef HAVE_WOLF_EVENT int wolfSSL_EventInit(WOLFSSL* ssl, WOLF_EVENT_TYPE type) { @@ -2316,7 +2738,7 @@ int SetSSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx) ssl->options.haveECC, ssl->options.haveStaticECC, ssl->options.side); -#ifndef NO_CERTS +#if !defined(NO_CERTS) && !defined(WOLFSSL_SESSION_EXPORT) /* make sure server has cert and key unless using PSK or Anon * This should be true even if just switching ssl ctx */ if (ssl->options.side == WOLFSSL_SERVER_END && !havePSK && !haveAnon) @@ -2327,6 +2749,12 @@ int SetSSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx) } #endif +#ifdef WOLFSSL_SESSION_EXPORT + #ifdef WOLFSSL_DTLS + ssl->dtls_export = ctx->dtls_export; /* export function for session */ + #endif +#endif + return SSL_SUCCESS; } diff --git a/src/ssl.c b/src/ssl.c index 21a801259..8013858d6 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -153,6 +153,103 @@ char* mystrnstr(const char* s1, const char* s2, unsigned int n) } #endif +#ifdef WOLFSSL_SESSION_EXPORT +#ifdef WOLFSSL_DTLS +int wolfSSL_dtls_import(WOLFSSL* ssl, unsigned char* buf, unsigned int sz) +{ + WOLFSSL_ENTER("wolfSSL_session_import"); + + if (ssl == NULL || buf == NULL) { + return BAD_FUNC_ARG; + } + + /* sanity checks on buffer and protocol are done in internal function */ + return wolfSSL_dtls_import_internal(buf, sz, ssl); +} + + +int wolfSSL_CTX_dtls_set_export(WOLFSSL_CTX* ctx, wc_dtls_export func) +{ + + WOLFSSL_ENTER("wolfSSL_CTX_dtls_set_export"); + + /* purposefully allow func to be NULL */ + if (ctx == NULL) { + return BAD_FUNC_ARG; + } + + ctx->dtls_export = func; + + return SSL_SUCCESS; +} + + +int wolfSSL_dtls_set_export(WOLFSSL* ssl, wc_dtls_export func) +{ + + WOLFSSL_ENTER("wolfSSL_dtls_set_export"); + + /* purposefully allow func to be NULL */ + if (ssl == NULL) { + return BAD_FUNC_ARG; + } + + ssl->dtls_export = func; + + return SSL_SUCCESS; +} + + +int wolfSSL_send_session(WOLFSSL* ssl) +{ + int ret; + byte* buf; + word16 bufSz = MAX_EXPORT_BUFFER; + + WOLFSSL_ENTER("wolfSSL_send_session"); + + if (ssl == NULL) { + return BAD_FUNC_ARG; + } + + buf = (byte*)XMALLOC(bufSz, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (buf == NULL) { + return MEMORY_E; + } + + /* if not DTLS do nothing */ + if (!ssl->options.dtls) { + XFREE(buf, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + WOLFSSL_MSG("Currently only DTLS export is supported"); + return SSL_SUCCESS; + } + + if (ssl->dtls_export) { + /* copy over keys, options, and dtls state struct */ + ret = wolfSSL_dtls_export(buf, bufSz, ssl); + if (ret < 0) { + XFREE(buf, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + return ret; + } + + /* if no error ret has size of buffer */ + ret = ssl->dtls_export(ssl, buf, ret, NULL); + if (ret != SSL_SUCCESS) { + XFREE(buf, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + return ret; + } + + XFREE(buf, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + return SSL_SUCCESS; + } + else { + XFREE(buf, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + return SSL_FAILURE; + } +} +#endif /* WOLFSSL_DTLS */ +#endif /* WOLFSSL_SESSION_EXPORT */ + /* prevent multiple mutex initializations */ static volatile int initRefCount = 0; @@ -6544,6 +6641,7 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, #ifdef WOLFSSL_DTLS else { ssl->options.dtlsHsRetain = 1; + } #endif /* WOLFSSL_DTLS */ @@ -6832,6 +6930,11 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, } #endif /* WOLFSSL_DTLS */ +#ifdef WOLFSSL_SESSION_EXPORT + WOLFSSL_MSG("sending session"); + wolfSSL_send_session(ssl); +#endif + WOLFSSL_LEAVE("SSL_accept()", SSL_SUCCESS); return SSL_SUCCESS; diff --git a/tests/api.c b/tests/api.c index 9e6932941..22ef72213 100644 --- a/tests/api.c +++ b/tests/api.c @@ -369,7 +369,9 @@ static void test_server_wolfSSL_new(void) /* invalid context */ AssertNull(ssl = wolfSSL_new(NULL)); +#ifndef WOLFSSL_SESSION_EXPORT AssertNull(ssl = wolfSSL_new(ctx_nocert)); +#endif /* success */ AssertNotNull(ssl = wolfSSL_new(ctx)); diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 7047b4567..c0c0ca01e 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -949,7 +949,11 @@ enum Misc { DTLS_HANDSHAKE_SEQ_SZ = 2, /* handshake header sequence number */ DTLS_HANDSHAKE_FRAG_SZ = 3, /* fragment offset and length are 24 bit */ DTLS_POOL_SZ = 5, /* buffers to hold in the retry pool */ - + DTLS_EXPORT_PRO = 165,/* wolfSSL protocol for serialized session */ + DTLS_EXPORT_VERSION = 1, /* wolfSSL version for serialized session */ + DTLS_EXPORT_OPT_SZ = 57, /* amount of bytes used from Options */ + DTLS_EXPORT_LEN = 2, /* 2 bytes for length and protocol */ + MAX_EXPORT_BUFFER = 500, /* max size of buffer for exporting */ FINISHED_LABEL_SZ = 15, /* TLS finished label size */ TLS_FINISHED_SZ = 12, /* TLS has a shorter size */ MASTER_LABEL_SZ = 13, /* TLS master secret label sz */ @@ -1195,6 +1199,8 @@ typedef struct ProtocolVersion { } WOLFSSL_PACK ProtocolVersion; +WOLFSSL_LOCAL int wolfSSL_dtls_import_internal(byte* buf, word32 sz, WOLFSSL* ssl); +WOLFSSL_LOCAL int wolfSSL_dtls_export(byte* buf, word32 sz, WOLFSSL* ssl); WOLFSSL_LOCAL ProtocolVersion MakeSSLv3(void); WOLFSSL_LOCAL ProtocolVersion MakeTLSv1(void); WOLFSSL_LOCAL ProtocolVersion MakeTLSv1_1(void); @@ -1369,7 +1375,10 @@ int SetCipherList(Suites*, const char* list); typedef unsigned int (*wc_psk_server_callback)(WOLFSSL*, const char*, unsigned char*, unsigned int); #endif /* PSK_TYPES_DEFINED */ - +#ifdef WOLFSSL_DTLS + typedef int (*wc_dtls_export)(WOLFSSL* ssl, + unsigned char* exportBuffer, unsigned int sz, void* userCtx); +#endif #ifdef HAVE_NETX WOLFSSL_LOCAL int NetX_Receive(WOLFSSL *ssl, char *buf, int sz, void *ctx); @@ -1575,7 +1584,8 @@ typedef struct WOLFSSL_DTLS_CTX { #define MAX_WRITE_IV_SZ 16 /* max size of client/server write_IV */ -/* keys and secrets */ +/* keys and secrets + * keep as a constant size (no additional ifdefs) for session export */ typedef struct Keys { byte client_write_MAC_secret[MAX_DIGEST_SIZE]; /* max sizes */ byte server_write_MAC_secret[MAX_DIGEST_SIZE]; @@ -1583,7 +1593,7 @@ typedef struct Keys { byte server_write_key[AES_256_KEY_SIZE]; byte client_write_IV[MAX_WRITE_IV_SZ]; /* max sizes */ byte server_write_IV[MAX_WRITE_IV_SZ]; -#ifdef HAVE_AEAD +#if defined(HAVE_AEAD) || defined(WOLFSSL_SESSION_EXPORT) byte aead_exp_IV[AEAD_MAX_EXP_SZ]; byte aead_enc_imp_IV[AEAD_MAX_IMP_SZ]; byte aead_dec_imp_IV[AEAD_MAX_IMP_SZ]; @@ -1938,6 +1948,7 @@ struct WOLFSSL_CTX { CallbackIOSend CBIOSend; #ifdef WOLFSSL_DTLS CallbackGenCookie CBIOCookie; /* gen cookie callback */ + wc_dtls_export dtls_export; /* export function for DTLS session */ #endif VerifyCallback verifyCallback; /* cert verification callback */ word32 timeout; /* session timeout */ @@ -2033,7 +2044,8 @@ int ProcessOldClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #endif #endif -/* All cipher suite related info */ +/* All cipher suite related info + * Keep as a constant size (no ifdefs) for session export */ typedef struct CipherSpecs { word16 key_size; word16 iv_size; @@ -2712,6 +2724,7 @@ struct WOLFSSL { DtlsMsg* dtls_msg_list; void* IOCB_CookieCtx; /* gen cookie ctx */ word32 dtls_expected_rx; + wc_dtls_export dtls_export; /* export function for session */ #endif #ifdef WOLFSSL_CALLBACKS HandShakeInfo handShakeInfo; /* info saved during handshake */ diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 92d783976..0d08c1291 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -225,6 +225,17 @@ WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_2_client_method(void); WOLFSSL_API int wolfSSL_use_old_poly(WOLFSSL*, int); #endif +#ifdef WOLFSSL_SESSION_EXPORT +#ifdef WOLFSSL_DTLS +typedef int (*wc_dtls_export)(WOLFSSL* ssl, + unsigned char* exportBuffer, unsigned int sz, void* userCtx); +WOLFSSL_API int wolfSSL_dtls_import(WOLFSSL* ssl, unsigned char* buf, unsigned int sz); +WOLFSSL_API int wolfSSL_CTX_dtls_set_export(WOLFSSL_CTX* ctx, wc_dtls_export func); +WOLFSSL_API int wolfSSL_dtls_set_export(WOLFSSL* ssl, wc_dtls_export func); +WOLFSSL_LOCAL int wolfSSL_send_session(WOLFSSL* ssl); +#endif /* WOLFSSL_DTLS */ +#endif /* WOLFSSL_SESSION_EXPORT */ + #if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) WOLFSSL_API int wolfSSL_CTX_use_certificate_file(WOLFSSL_CTX*, const char*, int);