From 8c45cb1938c98d50129370292f92fd3bac64b33c Mon Sep 17 00:00:00 2001 From: Jacob Barthelmeh Date: Tue, 10 May 2016 13:27:45 -0600 Subject: [PATCH 1/7] add DTLS session export option --- configure.ac | 17 ++ examples/client/client.c | 23 +++ src/internal.c | 432 ++++++++++++++++++++++++++++++++++++++- src/ssl.c | 103 ++++++++++ tests/api.c | 2 + wolfssl/internal.h | 23 ++- wolfssl/ssl.h | 11 + 7 files changed, 604 insertions(+), 7 deletions(-) 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); From f9ce2f26773d63f41bbad8db3c4f450fbdef3a73 Mon Sep 17 00:00:00 2001 From: Jacob Barthelmeh Date: Wed, 11 May 2016 11:18:08 -0600 Subject: [PATCH 2/7] verify cipher suite is valid on import --- src/internal.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/internal.c b/src/internal.c index 683835fd2..56e6a3e66 100755 --- a/src/internal.c +++ b/src/internal.c @@ -787,7 +787,7 @@ int wolfSSL_dtls_import_internal(byte* buf, word32 sz, WOLFSSL* ssl) word32 idx = 0; word16 length = 0; int version; - int ret; + int ret, i; WOLFSSL_ENTER("wolfSSL_dtls_import_internal"); /* check at least enough room for protocol and length */ @@ -885,6 +885,19 @@ int wolfSSL_dtls_import_internal(byte* buf, word32 sz, WOLFSSL* ssl) ssl->hmac = TLS_hmac; } + /* make sure is a valid suite used */ + ret = SUITES_ERROR; + for (i = 0; i < ssl->suites->suiteSz; i += 2) { + if (ssl->suites->suites[i] == ssl->options.cipherSuite0 && + ssl->suites->suites[i+1] == ssl->options.cipherSuite) { + ret = 0; + break; + } + } + if (ret != 0) { + return ret; + } + return idx; } #endif /* WOLFSSL_DTLS */ From fbf39a761a1833de72efd698c02d16ae369382e8 Mon Sep 17 00:00:00 2001 From: Jacob Barthelmeh Date: Wed, 11 May 2016 13:58:23 -0600 Subject: [PATCH 3/7] refactor export/import of key struct --- src/internal.c | 229 +++++++++++++++++++++++++++++++++++++++------ wolfssl/internal.h | 4 +- 2 files changed, 205 insertions(+), 28 deletions(-) diff --git a/src/internal.c b/src/internal.c index 56e6a3e66..395bb4d89 100755 --- a/src/internal.c +++ b/src/internal.c @@ -347,7 +347,7 @@ static INLINE void c16toa(word16 u16, byte* c) #if !defined(NO_OLD_TLS) || defined(HAVE_CHACHA) || defined(HAVE_AESCCM) \ - || defined(HAVE_AESGCM) + || defined(HAVE_AESGCM) || defined(WOLFSSL_SESSION_EXPORT) /* convert 32 bit integer to opaque */ static INLINE void c32toa(word32 u32, byte* c) { @@ -356,6 +356,18 @@ static INLINE void c32toa(word32 u32, byte* c) c[2] = (u32 >> 8) & 0xff; c[3] = u32 & 0xff; } + +static INLINE void cw64toa(word64 u64, byte* c) +{ + unsigned int i; + int idx = OPAQUE64_LEN - 1; + + XMEMSET(c, 0, OPAQUE64_LEN); + + for (i = 0; i < sizeof(word64); i++) { + c[idx--] = (u64 >> (i * WOLFSSL_BIT_SIZE)) & 0xff; + } +} #endif @@ -373,7 +385,8 @@ static INLINE void ato16(const byte* c, word16* u16) } -#if defined(WOLFSSL_DTLS) || defined(HAVE_SESSION_TICKET) +#if defined(WOLFSSL_DTLS) || defined(HAVE_SESSION_TICKET) || \ + defined(WOLFSSL_SESSION_EXPORT) /* convert opaque to 32 bit integer */ static INLINE void ato32(const byte* c, word32* u32) @@ -381,6 +394,17 @@ static INLINE void ato32(const byte* c, word32* u32) *u32 = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3]; } +/* convert opaque to word64 type */ +static INLINE void atow64(const byte* c, word64* u64) +{ + unsigned int i; + int idx = sizeof(word64); + + for (i = 0; i < sizeof(word64) && idx >= 0; i++) { + *u64 |= ((word64)c[idx--] << (i * WOLFSSL_BIT_SIZE)); + } +} + #endif /* WOLFSSL_DTLS */ @@ -472,6 +496,151 @@ static INLINE void ato32(const byte* c, word32* u32) #ifdef WOLFSSL_SESSION_EXPORT #ifdef WOLFSSL_DTLS +/* serializes the key struct for exporting */ +static int ExportKeyState(byte* exp, word32 len, byte ver, WOLFSSL* ssl) +{ + word32 idx = 0; + Keys* keys; + + if (exp == NULL || ssl == NULL) { + return BAD_FUNC_ARG; + } + + keys = &(ssl->keys); + + if (DTLS_EXPORT_KEY_SZ > len) { + return BUFFER_E; + } + + XMEMCPY(exp + idx, keys->client_write_MAC_secret, MAX_DIGEST_SIZE); + idx += MAX_DIGEST_SIZE; /* largest digest size */ + XMEMCPY(exp + idx, keys->server_write_MAC_secret, MAX_DIGEST_SIZE); + idx += MAX_DIGEST_SIZE; /* largest digest size */ + XMEMCPY(exp + idx, keys->client_write_key, AES_256_KEY_SIZE); + idx += AES_256_KEY_SIZE; + XMEMCPY(exp + idx, keys->server_write_key, AES_256_KEY_SIZE); + idx += AES_256_KEY_SIZE; + XMEMCPY(exp + idx, keys->client_write_IV, MAX_WRITE_IV_SZ); + idx += MAX_WRITE_IV_SZ; + XMEMCPY(exp + idx, keys->server_write_IV, MAX_WRITE_IV_SZ); + idx += MAX_WRITE_IV_SZ; + XMEMCPY(exp + idx, keys->aead_exp_IV, AEAD_MAX_EXP_SZ); + idx += AEAD_MAX_EXP_SZ; + XMEMCPY(exp + idx, keys->aead_enc_imp_IV, AEAD_MAX_IMP_SZ); + idx += AEAD_MAX_IMP_SZ; + XMEMCPY(exp + idx, keys->aead_dec_imp_IV, AEAD_MAX_IMP_SZ); + idx += AEAD_MAX_IMP_SZ; + + c32toa(keys->peer_sequence_number, exp + idx); idx += OPAQUE32_LEN; + c32toa(keys->peer_sequence_number, exp + idx); idx += OPAQUE32_LEN; + c32toa(keys->sequence_number, exp + idx); idx += OPAQUE32_LEN; + + c16toa(keys->dtls_state.nextEpoch, exp + idx); idx += OPAQUE16_LEN; + c32toa(keys->dtls_state.nextSeq, exp + idx); idx += OPAQUE32_LEN; + c16toa(keys->dtls_state.curEpoch, exp + idx); idx += OPAQUE16_LEN; + c32toa(keys->dtls_state.curSeq, exp + idx); idx += OPAQUE32_LEN; + c32toa(keys->dtls_state.prevSeq, exp + idx); idx += OPAQUE32_LEN; + + c16toa(keys->dtls_peer_handshake_number, exp + idx); idx += OPAQUE16_LEN; + c16toa(keys->dtls_expected_peer_handshake_number, exp + idx); + idx += OPAQUE16_LEN; + + c32toa(keys->dtls_sequence_number, exp + idx); idx += OPAQUE32_LEN; + c32toa(keys->dtls_prev_sequence_number, exp + idx); idx += OPAQUE32_LEN; + c16toa(keys->dtls_epoch, exp + idx); idx += OPAQUE16_LEN; + c16toa(keys->dtls_handshake_number, exp + idx); idx += OPAQUE16_LEN; + c32toa(keys->encryptSz, exp + idx); idx += OPAQUE32_LEN; + c32toa(keys->padSz, exp + idx); idx += OPAQUE32_LEN; + exp[idx++] = keys->encryptionOn; + exp[idx++] = keys->decryptedCur; + + #ifdef WORD64_AVAILABLE + cw64toa(keys->dtls_state.window, exp + idx); idx += OPAQUE64_LEN; + cw64toa(keys->dtls_state.prevWindow, exp + idx); idx += OPAQUE64_LEN; + #else + c32toa(keys->dtls_state.window, exp + idx); idx += OPAQUE32_LEN; + c32toa(0, exp + idx); idx += OPAQUE32_LEN; + c32toa(keys->dtls_state.prevWindow, exp + idx); idx += OPAQUE32_LEN; + c32toa(0, exp + idx); idx += OPAQUE32_LEN; + #endif + + (void)ver; + return 0; +} + + +static int ImportKeyState(byte* exp, word32 len, byte ver, WOLFSSL* ssl) +{ + word32 idx = 0; + Keys* keys; + + if (exp == NULL || ssl == NULL) { + return BAD_FUNC_ARG; + } + + keys = &(ssl->keys); + + if (DTLS_EXPORT_KEY_SZ > len) { + return BUFFER_E; + } + + XMEMCPY(keys->client_write_MAC_secret, exp + idx, MAX_DIGEST_SIZE); + idx += MAX_DIGEST_SIZE; + XMEMCPY(keys->server_write_MAC_secret, exp + idx, MAX_DIGEST_SIZE); + idx += MAX_DIGEST_SIZE; + XMEMCPY(keys->client_write_key, exp + idx, AES_256_KEY_SIZE); + idx += AES_256_KEY_SIZE; + XMEMCPY(keys->server_write_key, exp + idx, AES_256_KEY_SIZE); + idx += AES_256_KEY_SIZE; + XMEMCPY(keys->client_write_IV, exp + idx, MAX_WRITE_IV_SZ); + idx += MAX_WRITE_IV_SZ; + XMEMCPY(keys->server_write_IV, exp + idx, MAX_WRITE_IV_SZ); + idx += MAX_WRITE_IV_SZ; + XMEMCPY(keys->aead_exp_IV, exp + idx, AEAD_MAX_EXP_SZ); + idx += AEAD_MAX_EXP_SZ; + XMEMCPY(keys->aead_enc_imp_IV, exp + idx, AEAD_MAX_IMP_SZ); + idx += AEAD_MAX_IMP_SZ; + XMEMCPY(keys->aead_dec_imp_IV, exp + idx, AEAD_MAX_IMP_SZ); + idx += AEAD_MAX_IMP_SZ; + + ato32(exp + idx, &keys->peer_sequence_number); idx += OPAQUE32_LEN; + ato32(exp + idx, &keys->peer_sequence_number); idx += OPAQUE32_LEN; + ato32(exp + idx, &keys->sequence_number); idx += OPAQUE32_LEN; + + ato16(exp + idx, &keys->dtls_state.nextEpoch); idx += OPAQUE16_LEN; + ato32(exp + idx, &keys->dtls_state.nextSeq); idx += OPAQUE32_LEN; + ato16(exp + idx, &keys->dtls_state.curEpoch); idx += OPAQUE16_LEN; + ato32(exp + idx, &keys->dtls_state.curSeq); idx += OPAQUE32_LEN; + ato32(exp + idx, &keys->dtls_state.prevSeq); 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; + + ato32(exp + idx, &keys->dtls_sequence_number); idx += OPAQUE32_LEN; + ato32(exp + idx, &keys->dtls_prev_sequence_number); 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; + keys->encryptionOn = exp[idx++]; + keys->decryptedCur = exp[idx++]; + + #ifdef WORD64_AVAILABLE + atow64(exp + idx, &keys->dtls_state.window); idx += OPAQUE64_LEN; + atow64(exp + idx, &keys->dtls_state.prevWindow); idx += OPAQUE64_LEN; + #else + ato32(exp + idx, &keys->dtls_state.window); idx += OPAQUE32_LEN; + ato32(exp + idx, 0); idx += OPAQUE32_LEN; + ato32(exp + idx, &keys->dtls_state.prevWindow); idx += OPAQUE32_LEN; + ato32(exp + idx, 0); idx += OPAQUE32_LEN; + #endif + + (void)ver; + return 0; +} + + /* 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) @@ -493,21 +662,21 @@ static int dtls_export_new(byte* exp, word32 len, byte ver, WOLFSSL* ssl) 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; + c16toa(options->minDhKeySz, exp + idx); idx += OPAQUE16_LEN; + c16toa(options->dhKeySz, exp + idx); idx += OPAQUE16_LEN; #else - c16toa(zero, exp + idx); idx += 2; - c16toa(zero, exp + idx); idx += 2; + c16toa(zero, exp + idx); idx += OPAQUE16_LEN; + c16toa(zero, exp + idx); idx += OPAQUE16_LEN; #endif #ifndef NO_RSA - c16toa((word16)(options->minRsaKeySz), exp + idx); idx += 2; + c16toa((word16)(options->minRsaKeySz), exp + idx); idx += OPAQUE16_LEN; #else - c16toa(zero, exp + idx); idx += 2; + c16toa(zero, exp + idx); idx += OPAQUE16_LEN; #endif #ifdef HAVE_ECC - c16toa((word16)(options->minEccKeySz), exp + idx); idx += 2; + c16toa((word16)(options->minEccKeySz), exp + idx); idx += OPAQUE16_LEN; #else - c16toa(zero, exp + idx); idx += 2; + c16toa(zero, exp + idx); idx += OPAQUE16_LEN; #endif /* these options are kept to indicate state and behavior */ @@ -615,21 +784,21 @@ static int dtls_export_load(byte* exp, word32 len, byte ver, WOLFSSL* ssl) 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; + ato16(exp + idx, &(options->minDhKeySz)); idx += OPAQUE16_LEN; + ato16(exp + idx, &(options->dhKeySz)); idx += OPAQUE16_LEN; #else - idx += 2; - idx += 2; + idx += OPAQUE16_LEN; + idx += OPAQUE16_LEN; #endif #ifndef NO_RSA - ato16(exp + idx, (word16*)&(options->minRsaKeySz)); idx += 2; + ato16(exp + idx, (word16*)&(options->minRsaKeySz)); idx += OPAQUE16_LEN; #else - idx += 2; + idx += OPAQUE16_LEN; #endif #ifdef HAVE_ECC - ato16(exp + idx, (word16*)&(options->minEccKeySz)); idx += 2; + ato16(exp + idx, (word16*)&(options->minEccKeySz)); idx += OPAQUE16_LEN; #else - idx += 2; + idx += OPAQUE16_LEN; #endif /* these options are kept to indicate state and behavior */ @@ -724,7 +893,7 @@ int wolfSSL_dtls_export(byte* buf, word32 sz, WOLFSSL* ssl) 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 + DTLS_EXPORT_KEY_SZ; totalLen += DTLS_EXPORT_LEN + sizeof(CipherSpecs); totalLen += DTLS_EXPORT_LEN + ssl->buffers.dtlsCtx.peer.sz; @@ -760,10 +929,14 @@ int wolfSSL_dtls_export(byte* buf, word32 sz, WOLFSSL* ssl) 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)DTLS_EXPORT_KEY_SZ, buf + idx); + idx = DTLS_EXPORT_LEN; + if ((ret = ExportKeyState(buf + idx, sz - idx, + DTLS_EXPORT_VERSION, ssl)) != 0) { + WOLFSSL_LEAVE("wolfSSL_dtls_export", ret); + return ret; + } + idx += DTLS_EXPORT_KEY_SZ; c16toa((word16)sizeof(CipherSpecs), buf + idx); idx += DTLS_EXPORT_LEN; @@ -834,15 +1007,17 @@ int wolfSSL_dtls_import_internal(byte* buf, word32 sz, WOLFSSL* ssl) idx += length; /* perform sanity checks and extract Keys struct */ - if (DTLS_EXPORT_LEN + sizeof(Keys) + idx > sz) { + if (DTLS_EXPORT_LEN + DTLS_EXPORT_KEY_SZ + idx > sz) { return BUFFER_E; } ato16(buf + idx, &length); idx += DTLS_EXPORT_LEN; - if (length < sizeof(Keys) || length + idx > sz) { + if (length != DTLS_EXPORT_KEY_SZ || length + idx > sz) { return BUFFER_E; } - XMEMCPY(&ssl->keys, buf + idx, sizeof(Keys)); - idx += sizeof(Keys); + if ((ret = ImportKeyState(buf + idx, length, version, ssl)) != 0) { + return ret; + } + idx += DTLS_EXPORT_KEY_SZ; /* perform sanity checks and extract CipherSpecs struct */ if (DTLS_EXPORT_LEN + sizeof(CipherSpecs) + idx > sz) { diff --git a/wolfssl/internal.h b/wolfssl/internal.h index c0c0ca01e..80a53dc92 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -926,6 +926,7 @@ enum Misc { OPAQUE16_LEN = 2, /* 2 bytes */ OPAQUE24_LEN = 3, /* 3 bytes */ OPAQUE32_LEN = 4, /* 4 bytes */ + OPAQUE64_LEN = 8, /* 8 bytes */ COMP_LEN = 1, /* compression length */ CURVE_LEN = 2, /* ecc named curve length */ SERVER_ID_LEN = 20, /* server session id length */ @@ -951,7 +952,8 @@ enum Misc { 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_OPT_SZ = 57, /* amount of bytes used from Options */ + DTLS_EXPORT_KEY_SZ = 326, /* amount of bytes used from Keys */ 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 */ From 8d66ba29233e993eb43fd550e3d8522ba2c6db8f Mon Sep 17 00:00:00 2001 From: Jacob Barthelmeh Date: Wed, 11 May 2016 14:48:53 -0600 Subject: [PATCH 4/7] refactor export/import of cipher specs struct --- src/internal.c | 102 ++++++++++++++++++++++++++++++++++++++++----- wolfssl/internal.h | 1 + 2 files changed, 92 insertions(+), 11 deletions(-) diff --git a/src/internal.c b/src/internal.c index 395bb4d89..4078c2808 100755 --- a/src/internal.c +++ b/src/internal.c @@ -364,7 +364,7 @@ static INLINE void cw64toa(word64 u64, byte* c) XMEMSET(c, 0, OPAQUE64_LEN); - for (i = 0; i < sizeof(word64); i++) { + for (i = 0; i < sizeof(word64) && idx >= 0; i++) { c[idx--] = (u64 >> (i * WOLFSSL_BIT_SIZE)) & 0xff; } } @@ -496,6 +496,45 @@ static INLINE void atow64(const byte* c, word64* u64) #ifdef WOLFSSL_SESSION_EXPORT #ifdef WOLFSSL_DTLS +/* serializes the cipher specs struct for exporting */ +static int ExportCipherSpecState(byte* exp, word32 len, byte ver, WOLFSSL* ssl) +{ + word32 idx = 0; + CipherSpecs* specs; + + if (exp == NULL || ssl == NULL) { + return BAD_FUNC_ARG; + } + + specs= &(ssl->specs); + + if (DTLS_EXPORT_SPC_SZ > len) { + return BUFFER_E; + } + + c16toa(specs->key_size, exp + idx); idx += OPAQUE16_LEN; + c16toa(specs->iv_size, exp + idx); idx += OPAQUE16_LEN; + c16toa(specs->block_size, exp + idx); idx += OPAQUE16_LEN; + c16toa(specs->aead_mac_size, exp + idx); idx += OPAQUE16_LEN; + exp[idx++] = specs->bulk_cipher_algorithm; + exp[idx++] = specs->cipher_type; + exp[idx++] = specs->mac_algorithm; + exp[idx++] = specs->kea; + exp[idx++] = specs->sig_algo; + exp[idx++] = specs->hash_size; + 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"); + return BUFFER_E; + } + + (void)ver; + return 0; +} + + /* serializes the key struct for exporting */ static int ExportKeyState(byte* exp, word32 len, byte ver, WOLFSSL* ssl) { @@ -564,6 +603,43 @@ static int ExportKeyState(byte* exp, word32 len, byte ver, WOLFSSL* ssl) c32toa(0, exp + idx); idx += OPAQUE32_LEN; #endif + if (idx != DTLS_EXPORT_KEY_SZ) { + WOLFSSL_MSG("DTLS_EXPORT_KEY_SZ needs updated and export version"); + return BUFFER_E; + } + + (void)ver; + return 0; +} + +static int ImportCipherSpecState(byte* exp, word32 len, byte ver, WOLFSSL* ssl) +{ + word32 idx = 0; + CipherSpecs* specs; + + if (exp == NULL || ssl == NULL) { + return BAD_FUNC_ARG; + } + + specs= &(ssl->specs); + + if (DTLS_EXPORT_SPC_SZ > len) { + return BUFFER_E; + } + + ato16(exp + idx, &specs->key_size); idx += OPAQUE16_LEN; + ato16(exp + idx, &specs->iv_size); idx += OPAQUE16_LEN; + ato16(exp + idx, &specs->block_size); idx += OPAQUE16_LEN; + ato16(exp + idx, &specs->aead_mac_size); idx += OPAQUE16_LEN; + specs->bulk_cipher_algorithm = exp[idx++]; + specs->cipher_type = exp[idx++]; + specs->mac_algorithm = exp[idx++]; + specs->kea = exp[idx++]; + specs->sig_algo = exp[idx++]; + specs->hash_size = exp[idx++]; + specs->pad_size = exp[idx++]; + specs->static_ecdh = exp[idx++]; + (void)ver; return 0; } @@ -894,7 +970,7 @@ int wolfSSL_dtls_export(byte* buf, word32 sz, WOLFSSL* ssl) /* 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 + sizeof(CipherSpecs); + totalLen += DTLS_EXPORT_LEN + DTLS_EXPORT_SPC_SZ; totalLen += DTLS_EXPORT_LEN + ssl->buffers.dtlsCtx.peer.sz; if (totalLen > sz) { @@ -929,8 +1005,7 @@ int wolfSSL_dtls_export(byte* buf, word32 sz, WOLFSSL* ssl) idx += DTLS_EXPORT_OPT_SZ; /* export keys struct and dtls state */ - c16toa((word16)DTLS_EXPORT_KEY_SZ, buf + idx); - idx = DTLS_EXPORT_LEN; + c16toa((word16)DTLS_EXPORT_KEY_SZ, buf + idx); idx += DTLS_EXPORT_LEN; if ((ret = ExportKeyState(buf + idx, sz - idx, DTLS_EXPORT_VERSION, ssl)) != 0) { WOLFSSL_LEAVE("wolfSSL_dtls_export", ret); @@ -938,10 +1013,13 @@ int wolfSSL_dtls_export(byte* buf, word32 sz, WOLFSSL* ssl) } idx += DTLS_EXPORT_KEY_SZ; - c16toa((word16)sizeof(CipherSpecs), buf + idx); - idx += DTLS_EXPORT_LEN; - XMEMCPY(buf + idx, (byte*)&ssl->specs, sizeof(CipherSpecs)); - idx += sizeof(CipherSpecs); + c16toa((word16)DTLS_EXPORT_SPC_SZ, buf + idx); idx += DTLS_EXPORT_LEN; + if ((ret = ExportCipherSpecState(buf + idx, sz - idx, + DTLS_EXPORT_VERSION, ssl)) != 0) { + WOLFSSL_LEAVE("wolfSSL_dtls_export", ret); + return ret; + } + idx += DTLS_EXPORT_SPC_SZ; c16toa((word16)ssl->buffers.dtlsCtx.peer.sz, buf + idx); idx += DTLS_EXPORT_LEN; @@ -1020,14 +1098,16 @@ int wolfSSL_dtls_import_internal(byte* buf, word32 sz, WOLFSSL* ssl) idx += DTLS_EXPORT_KEY_SZ; /* perform sanity checks and extract CipherSpecs struct */ - if (DTLS_EXPORT_LEN + sizeof(CipherSpecs) + idx > sz) { + if (DTLS_EXPORT_LEN + DTLS_EXPORT_SPC_SZ + idx > sz) { return BUFFER_E; } ato16(buf + idx, &length); idx += DTLS_EXPORT_LEN; - if ( length != sizeof(CipherSpecs)) { + if ( length != DTLS_EXPORT_SPC_SZ) { return BUFFER_E; } - XMEMCPY(&ssl->specs, buf + idx, length); + if ((ret = ImportCipherSpecState(buf + idx, length, version, ssl)) != 0) { + return ret; + } idx += length; /* perform sanity checks and extract DTLS peer info */ diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 80a53dc92..3a6df3031 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -954,6 +954,7 @@ enum Misc { DTLS_EXPORT_VERSION = 1, /* wolfSSL version for serialized session */ DTLS_EXPORT_OPT_SZ = 57, /* amount of bytes used from Options */ DTLS_EXPORT_KEY_SZ = 326, /* 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 */ MAX_EXPORT_BUFFER = 500, /* max size of buffer for exporting */ FINISHED_LABEL_SZ = 15, /* TLS finished label size */ From 3897f78073de93f91c92c6a6cf6d0297529f2c98 Mon Sep 17 00:00:00 2001 From: Jacob Barthelmeh Date: Fri, 13 May 2016 09:11:38 -0600 Subject: [PATCH 5/7] truncated hmac export and sanity checks --- src/internal.c | 298 +++++++++++++++++++++++++++----------------- wolfssl/error-ssl.h | 2 + wolfssl/internal.h | 5 +- 3 files changed, 191 insertions(+), 114 deletions(-) diff --git a/src/internal.c b/src/internal.c index 4078c2808..db75da214 100755 --- a/src/internal.c +++ b/src/internal.c @@ -357,16 +357,17 @@ static INLINE void c32toa(word32 u32, byte* c) c[3] = u32 & 0xff; } -static INLINE void cw64toa(word64 u64, byte* c) +/* convert 64 bit integer to opaque */ +static INLINE void c64toa(word64 u64, byte* c) { - unsigned int i; - int idx = OPAQUE64_LEN - 1; - - XMEMSET(c, 0, OPAQUE64_LEN); - - for (i = 0; i < sizeof(word64) && idx >= 0; i++) { - c[idx--] = (u64 >> (i * WOLFSSL_BIT_SIZE)) & 0xff; - } + c[0] = (u64 >> 56) & 0xff; + c[1] = (u64 >> 48) & 0xff; + c[2] = (u64 >> 40) & 0xff; + c[3] = (u64 >> 32) & 0xff; + c[4] = (u64 >> 24) & 0xff; + c[5] = (u64 >> 16) & 0xff; + c[6] = (u64 >> 8) & 0xff; + c[7] = u64 & 0xff; } #endif @@ -395,14 +396,17 @@ static INLINE void ato32(const byte* c, word32* u32) } /* convert opaque to word64 type */ -static INLINE void atow64(const byte* c, word64* u64) +static INLINE void ato64(const byte* c, word64* u64) { - unsigned int i; - int idx = sizeof(word64); - - for (i = 0; i < sizeof(word64) && idx >= 0; i++) { - *u64 |= ((word64)c[idx--] << (i * WOLFSSL_BIT_SIZE)); - } + /* when doing cast to allow for shift, mask the values */ + *u64 = (((word64)c[0] << 56) & 0xff00000000000000) | + (((word64)c[1] << 48) & 0x00ff000000000000) | + (((word64)c[2] << 40) & 0x0000ff0000000000) | + (((word64)c[3] << 32) & 0x000000ff00000000) | + (((word64)c[4] << 24) & 0x00000000ff000000) | + (((word64)c[5] << 16) & 0x0000000000ff0000) | + (((word64)c[6] << 8) & 0x000000000000ff00) | + ((word64)c[7] & 0x00000000000000ff); } #endif /* WOLFSSL_DTLS */ @@ -502,6 +506,8 @@ static int ExportCipherSpecState(byte* exp, word32 len, byte ver, WOLFSSL* ssl) word32 idx = 0; CipherSpecs* specs; + WOLFSSL_ENTER("ExportCipherSpecState"); + if (exp == NULL || ssl == NULL) { return BAD_FUNC_ARG; } @@ -512,6 +518,8 @@ static int ExportCipherSpecState(byte* exp, word32 len, byte ver, WOLFSSL* ssl) return BUFFER_E; } + XMEMSET(exp, 0, DTLS_EXPORT_SPC_SZ); + c16toa(specs->key_size, exp + idx); idx += OPAQUE16_LEN; c16toa(specs->iv_size, exp + idx); idx += OPAQUE16_LEN; c16toa(specs->block_size, exp + idx); idx += OPAQUE16_LEN; @@ -527,11 +535,12 @@ static int ExportCipherSpecState(byte* exp, word32 len, byte ver, WOLFSSL* ssl) if (idx != DTLS_EXPORT_SPC_SZ) { WOLFSSL_MSG("DTLS_EXPORT_SPC_SZ needs updated and export version"); - return BUFFER_E; + return DTLS_EXPORT_VER_E; } + WOLFSSL_LEAVE("ExportCipherSpecState", idx); (void)ver; - return 0; + return idx; } @@ -539,8 +548,11 @@ static int ExportCipherSpecState(byte* exp, word32 len, byte ver, WOLFSSL* ssl) static int ExportKeyState(byte* exp, word32 len, byte ver, WOLFSSL* ssl) { word32 idx = 0; + byte sz; Keys* keys; + WOLFSSL_ENTER("ExportKeyState"); + if (exp == NULL || ssl == NULL) { return BAD_FUNC_ARG; } @@ -551,24 +563,7 @@ static int ExportKeyState(byte* exp, word32 len, byte ver, WOLFSSL* ssl) return BUFFER_E; } - XMEMCPY(exp + idx, keys->client_write_MAC_secret, MAX_DIGEST_SIZE); - idx += MAX_DIGEST_SIZE; /* largest digest size */ - XMEMCPY(exp + idx, keys->server_write_MAC_secret, MAX_DIGEST_SIZE); - idx += MAX_DIGEST_SIZE; /* largest digest size */ - XMEMCPY(exp + idx, keys->client_write_key, AES_256_KEY_SIZE); - idx += AES_256_KEY_SIZE; - XMEMCPY(exp + idx, keys->server_write_key, AES_256_KEY_SIZE); - idx += AES_256_KEY_SIZE; - XMEMCPY(exp + idx, keys->client_write_IV, MAX_WRITE_IV_SZ); - idx += MAX_WRITE_IV_SZ; - XMEMCPY(exp + idx, keys->server_write_IV, MAX_WRITE_IV_SZ); - idx += MAX_WRITE_IV_SZ; - XMEMCPY(exp + idx, keys->aead_exp_IV, AEAD_MAX_EXP_SZ); - idx += AEAD_MAX_EXP_SZ; - XMEMCPY(exp + idx, keys->aead_enc_imp_IV, AEAD_MAX_IMP_SZ); - idx += AEAD_MAX_IMP_SZ; - XMEMCPY(exp + idx, keys->aead_dec_imp_IV, AEAD_MAX_IMP_SZ); - idx += AEAD_MAX_IMP_SZ; + XMEMSET(exp, 0, DTLS_EXPORT_KEY_SZ); c32toa(keys->peer_sequence_number, exp + idx); idx += OPAQUE32_LEN; c32toa(keys->peer_sequence_number, exp + idx); idx += OPAQUE32_LEN; @@ -594,8 +589,8 @@ static int ExportKeyState(byte* exp, word32 len, byte ver, WOLFSSL* ssl) exp[idx++] = keys->decryptedCur; #ifdef WORD64_AVAILABLE - cw64toa(keys->dtls_state.window, exp + idx); idx += OPAQUE64_LEN; - cw64toa(keys->dtls_state.prevWindow, exp + idx); idx += OPAQUE64_LEN; + c64toa(keys->dtls_state.window, exp + idx); idx += OPAQUE64_LEN; + c64toa(keys->dtls_state.prevWindow, exp + idx); idx += OPAQUE64_LEN; #else c32toa(keys->dtls_state.window, exp + idx); idx += OPAQUE32_LEN; c32toa(0, exp + idx); idx += OPAQUE32_LEN; @@ -603,13 +598,42 @@ static int ExportKeyState(byte* exp, word32 len, byte ver, WOLFSSL* ssl) c32toa(0, exp + idx); idx += OPAQUE32_LEN; #endif - if (idx != DTLS_EXPORT_KEY_SZ) { +#ifdef HAVE_TRUNCATED_HMAC + sz = ssl->truncated_hmac ? TRUNCATED_HMAC_SZ: ssl->specs.hash_size; + exp[idx++] = ssl->truncated_hmac; +#else + sz = ssl->specs.hash_size; + exp[idx++] = 0; /* no truncated hmac */ +#endif + exp[idx++] = sz; + XMEMCPY(exp + idx, keys->client_write_MAC_secret, sz); idx += sz; + XMEMCPY(exp + idx, keys->server_write_MAC_secret, sz); idx += sz; + + sz = ssl->specs.key_size; + exp[idx++] = sz; + XMEMCPY(exp + idx, keys->client_write_key, sz); idx += sz; + XMEMCPY(exp + idx, keys->server_write_key, sz); idx += sz; + + sz = ssl->specs.iv_size; + exp[idx++] = sz; + XMEMCPY(exp + idx, keys->client_write_IV, sz); idx += sz; + XMEMCPY(exp + idx, keys->server_write_IV, sz); idx += sz; + XMEMCPY(exp + idx, keys->aead_exp_IV, AEAD_MAX_EXP_SZ); + idx += AEAD_MAX_EXP_SZ; + + sz = AEAD_MAX_IMP_SZ; + exp[idx++] = sz; + XMEMCPY(exp + idx, keys->aead_enc_imp_IV, sz); idx += sz; + XMEMCPY(exp + idx, keys->aead_dec_imp_IV, sz); idx += sz; + + if (idx > DTLS_EXPORT_KEY_SZ) { WOLFSSL_MSG("DTLS_EXPORT_KEY_SZ needs updated and export version"); - return BUFFER_E; + return DTLS_EXPORT_VER_E; } + WOLFSSL_LEAVE("ExportKeyState", idx); (void)ver; - return 0; + return idx; } static int ImportCipherSpecState(byte* exp, word32 len, byte ver, WOLFSSL* ssl) @@ -617,6 +641,8 @@ static int ImportCipherSpecState(byte* exp, word32 len, byte ver, WOLFSSL* ssl) word32 idx = 0; CipherSpecs* specs; + WOLFSSL_ENTER("ImportCipherSpecState"); + if (exp == NULL || ssl == NULL) { return BAD_FUNC_ARG; } @@ -640,45 +666,30 @@ static int ImportCipherSpecState(byte* exp, word32 len, byte ver, WOLFSSL* ssl) specs->pad_size = exp[idx++]; specs->static_ecdh = exp[idx++]; + WOLFSSL_LEAVE("ImportCipherSpecState", idx); (void)ver; - return 0; + return idx; } static int ImportKeyState(byte* exp, word32 len, byte ver, WOLFSSL* ssl) { word32 idx = 0; + byte sz; Keys* keys; + WOLFSSL_ENTER("ImportKeyState"); + if (exp == NULL || ssl == NULL) { return BAD_FUNC_ARG; } keys = &(ssl->keys); - if (DTLS_EXPORT_KEY_SZ > len) { + /* check minimum length -- includes byte used for size indicators */ + if (len < DTLS_EXPORT_MIN_KEY_SZ) { return BUFFER_E; } - - XMEMCPY(keys->client_write_MAC_secret, exp + idx, MAX_DIGEST_SIZE); - idx += MAX_DIGEST_SIZE; - XMEMCPY(keys->server_write_MAC_secret, exp + idx, MAX_DIGEST_SIZE); - idx += MAX_DIGEST_SIZE; - XMEMCPY(keys->client_write_key, exp + idx, AES_256_KEY_SIZE); - idx += AES_256_KEY_SIZE; - XMEMCPY(keys->server_write_key, exp + idx, AES_256_KEY_SIZE); - idx += AES_256_KEY_SIZE; - XMEMCPY(keys->client_write_IV, exp + idx, MAX_WRITE_IV_SZ); - idx += MAX_WRITE_IV_SZ; - XMEMCPY(keys->server_write_IV, exp + idx, MAX_WRITE_IV_SZ); - idx += MAX_WRITE_IV_SZ; - XMEMCPY(keys->aead_exp_IV, exp + idx, AEAD_MAX_EXP_SZ); - idx += AEAD_MAX_EXP_SZ; - XMEMCPY(keys->aead_enc_imp_IV, exp + idx, AEAD_MAX_IMP_SZ); - idx += AEAD_MAX_IMP_SZ; - XMEMCPY(keys->aead_dec_imp_IV, exp + idx, AEAD_MAX_IMP_SZ); - idx += AEAD_MAX_IMP_SZ; - ato32(exp + idx, &keys->peer_sequence_number); idx += OPAQUE32_LEN; ato32(exp + idx, &keys->peer_sequence_number); idx += OPAQUE32_LEN; ato32(exp + idx, &keys->sequence_number); idx += OPAQUE32_LEN; @@ -703,8 +714,8 @@ static int ImportKeyState(byte* exp, word32 len, byte ver, WOLFSSL* ssl) keys->decryptedCur = exp[idx++]; #ifdef WORD64_AVAILABLE - atow64(exp + idx, &keys->dtls_state.window); idx += OPAQUE64_LEN; - atow64(exp + idx, &keys->dtls_state.prevWindow); idx += OPAQUE64_LEN; + ato64(exp + idx, &keys->dtls_state.window); idx += OPAQUE64_LEN; + ato64(exp + idx, &keys->dtls_state.prevWindow); idx += OPAQUE64_LEN; #else ato32(exp + idx, &keys->dtls_state.window); idx += OPAQUE32_LEN; ato32(exp + idx, 0); idx += OPAQUE32_LEN; @@ -712,8 +723,44 @@ static int ImportKeyState(byte* exp, word32 len, byte ver, WOLFSSL* ssl) ato32(exp + idx, 0); idx += OPAQUE32_LEN; #endif +#ifdef HAVE_TRUNCATED_HMAC + ssl->truncated_hmac = exp[idx++]; +#else + idx++; /* no truncated hmac */ +#endif + sz = exp[idx++]; + if (sz > MAX_DIGEST_SIZE || sz + idx > len) { + return BUFFER_E; + } + XMEMCPY(keys->client_write_MAC_secret, exp + idx, sz); idx += sz; + XMEMCPY(keys->server_write_MAC_secret, exp + idx, sz); idx += sz; + + sz = exp[idx++]; + if (sz > AES_256_KEY_SIZE || sz + idx > len) { + return BUFFER_E; + } + XMEMCPY(keys->client_write_key, exp + idx, sz); idx += sz; + XMEMCPY(keys->server_write_key, exp + idx, sz); idx += sz; + + sz = exp[idx++]; + if (sz > MAX_WRITE_IV_SZ || sz + idx > len) { + return BUFFER_E; + } + XMEMCPY(keys->client_write_IV, exp + idx, sz); idx += sz; + XMEMCPY(keys->server_write_IV, exp + idx, sz); idx += sz; + XMEMCPY(keys->aead_exp_IV, exp + idx, AEAD_MAX_EXP_SZ); + idx += AEAD_MAX_EXP_SZ; + + sz = exp[idx++]; + if (sz > AEAD_MAX_IMP_SZ || sz + idx > len) { + return BUFFER_E; + } + XMEMCPY(keys->aead_enc_imp_IV, exp + idx, sz); idx += sz; + XMEMCPY(keys->aead_dec_imp_IV, exp + idx, sz); idx += sz; + + WOLFSSL_LEAVE("ImportKeyState", idx); (void)ver; - return 0; + return idx; } @@ -731,6 +778,8 @@ static int dtls_export_new(byte* exp, word32 len, byte ver, WOLFSSL* ssl) return BAD_FUNC_ARG; } + XMEMSET(exp, 0, DTLS_EXPORT_OPT_SZ); + /* these options are kept and sent to indicate verify status and strength * of handshake */ exp[idx++] = options->sendVerify; @@ -817,7 +866,6 @@ static int dtls_export_new(byte* exp, word32 len, byte ver, WOLFSSL* ssl) exp[idx++] = options->acceptState; exp[idx++] = options->keyShareState; - /* version of connection */ exp[idx++] = ssl->version.major; exp[idx++] = ssl->version.minor; @@ -828,12 +876,12 @@ static int dtls_export_new(byte* exp, word32 len, byte ver, WOLFSSL* ssl) /* 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; + return DTLS_EXPORT_VER_E; } - WOLFSSL_LEAVE("dtls_export_new", 0); + WOLFSSL_LEAVE("dtls_export_new", idx); - return 0; + return idx; } @@ -945,7 +993,7 @@ static int dtls_export_load(byte* exp, word32 len, byte ver, WOLFSSL* ssl) return VERSION_ERROR; } - return 0; + return idx; } @@ -982,8 +1030,43 @@ int wolfSSL_dtls_export(byte* buf, word32 sz, WOLFSSL* ssl) buf[idx++] = ((byte)DTLS_EXPORT_PRO & 0xF0) | ((byte)DTLS_EXPORT_VERSION & 0X0F); - c16toa((word16)(totalLen - DTLS_EXPORT_LEN), buf + idx); + 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(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 -- variable length stored in ret */ + idx += DTLS_EXPORT_LEN; /* leave room for length */ + if ((ret = ExportKeyState(buf + idx, sz - idx, + DTLS_EXPORT_VERSION, ssl)) < 0) { + WOLFSSL_LEAVE("wolfSSL_dtls_export", 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(buf + idx, sz - idx, + DTLS_EXPORT_VERSION, ssl)) < 0) { + WOLFSSL_LEAVE("wolfSSL_dtls_export", ret); + return ret; + } + idx += DTLS_EXPORT_SPC_SZ; + + /* export of dtls peer information */ + 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; + + /* 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 @@ -991,42 +1074,11 @@ int wolfSSL_dtls_export(byte* buf, word32 sz, WOLFSSL* ssl) 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); + , (int)DTLS_EXPORT_VERSION, buf[0], (buf[1] >> 4), idx - 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)DTLS_EXPORT_KEY_SZ, buf + idx); idx += DTLS_EXPORT_LEN; - if ((ret = ExportKeyState(buf + idx, sz - idx, - DTLS_EXPORT_VERSION, ssl)) != 0) { - WOLFSSL_LEAVE("wolfSSL_dtls_export", ret); - return ret; - } - idx += DTLS_EXPORT_KEY_SZ; - - c16toa((word16)DTLS_EXPORT_SPC_SZ, buf + idx); idx += DTLS_EXPORT_LEN; - if ((ret = ExportCipherSpecState(buf + idx, sz - idx, - DTLS_EXPORT_VERSION, ssl)) != 0) { - WOLFSSL_LEAVE("wolfSSL_dtls_export", ret); - return ret; - } - idx += DTLS_EXPORT_SPC_SZ; - - 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; } @@ -1073,51 +1125,62 @@ int wolfSSL_dtls_import_internal(byte* buf, word32 sz, WOLFSSL* ssl) /* perform sanity checks and extract Options information used */ if (DTLS_EXPORT_LEN + DTLS_EXPORT_OPT_SZ + idx > sz) { + WOLFSSL_MSG("Import Options struct error"); return BUFFER_E; } ato16(buf + idx, &length); idx += DTLS_EXPORT_LEN; if (length != DTLS_EXPORT_OPT_SZ) { + WOLFSSL_MSG("Import Options struct error"); return BUFFER_E; } - if ((ret = dtls_export_load(buf + idx, length, version, ssl)) != 0) { - return ret; + if ((ret = dtls_export_load(buf + idx, length, version, ssl)) < 0) { + WOLFSSL_MSG("Import Options struct error"); + return ret; } idx += length; /* perform sanity checks and extract Keys struct */ - if (DTLS_EXPORT_LEN + DTLS_EXPORT_KEY_SZ + idx > sz) { + if (DTLS_EXPORT_LEN + idx > sz) { + WOLFSSL_MSG("Import Key struct error"); return BUFFER_E; } ato16(buf + idx, &length); idx += DTLS_EXPORT_LEN; - if (length != DTLS_EXPORT_KEY_SZ || length + idx > sz) { + if (length > DTLS_EXPORT_KEY_SZ || length + idx > sz) { + WOLFSSL_MSG("Import Key struct error"); return BUFFER_E; } - if ((ret = ImportKeyState(buf + idx, length, version, ssl)) != 0) { + if ((ret = ImportKeyState(buf + idx, length, version, ssl)) < 0) { + WOLFSSL_MSG("Import Key struct error"); return ret; } - idx += DTLS_EXPORT_KEY_SZ; + idx += ret; /* perform sanity checks and extract CipherSpecs struct */ if (DTLS_EXPORT_LEN + DTLS_EXPORT_SPC_SZ + idx > sz) { + WOLFSSL_MSG("Import CipherSpecs struct error"); return 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 = ImportCipherSpecState(buf + idx, length, version, ssl)) != 0) { + if ((ret = ImportCipherSpecState(buf + idx, length, version, ssl)) < 0) { + WOLFSSL_MSG("Import CipherSpecs struct error"); return ret; } idx += length; /* 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; ssl->buffers.dtlsCtx.peer.sz = length; if (idx + ssl->buffers.dtlsCtx.peer.sz > sz) { + WOLFSSL_MSG("Import DTLS peer info error"); return BUFFER_E; } @@ -1125,6 +1188,7 @@ int wolfSSL_dtls_import_internal(byte* buf, word32 sz, WOLFSSL* ssl) ssl->buffers.dtlsCtx.peer.sa = XMALLOC(ssl->buffers.dtlsCtx.peer.sz, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); if (ssl->buffers.dtlsCtx.peer.sa == NULL) { + WOLFSSL_MSG("Import DTLS peer info error"); return MEMORY_E; } @@ -1141,7 +1205,7 @@ int wolfSSL_dtls_import_internal(byte* buf, word32 sz, WOLFSSL* ssl) } /* make sure is a valid suite used */ - ret = SUITES_ERROR; + ret = MATCH_SUITE_ERROR; for (i = 0; i < ssl->suites->suiteSz; i += 2) { if (ssl->suites->suites[i] == ssl->options.cipherSuite0 && ssl->suites->suites[i+1] == ssl->options.cipherSuite) { @@ -1150,9 +1214,16 @@ int wolfSSL_dtls_import_internal(byte* buf, word32 sz, WOLFSSL* ssl) } } if (ret != 0) { + WOLFSSL_MSG("Can not match cipher suite imported"); return ret; } + /* do not allow stream ciphers with DTLS */ + if (ssl->specs.cipher_type == stream) { + WOLFSSL_MSG("Can not import stream ciphers for DTLS"); + return SANITY_CIPHER_E; + } + return idx; } #endif /* WOLFSSL_DTLS */ @@ -10935,6 +11006,9 @@ const char* wolfSSL_ERR_reason_error_string(unsigned long e) case ECC_KEY_SIZE_E: return "ECC key too small"; + case DTLS_EXPORT_VER_E: + return "Version needs updated after code change or version mismatch"; + default : return "unknown error number"; } diff --git a/wolfssl/error-ssl.h b/wolfssl/error-ssl.h index 11aedea53..5bbcd80c0 100644 --- a/wolfssl/error-ssl.h +++ b/wolfssl/error-ssl.h @@ -146,6 +146,8 @@ enum wolfSSL_ErrorCodes { RSA_KEY_SIZE_E = -409, /* RSA key too small */ ECC_KEY_SIZE_E = -410, /* ECC key too small */ + + DTLS_EXPORT_VER_E = -411, /* export version error */ /* add strings to wolfSSL_ERR_reason_error_string in internal.c !!!!! */ /* begin negotiation parameter errors */ diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 3a6df3031..d9bcfe7ba 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -952,8 +952,9 @@ enum Misc { 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_KEY_SZ = 326, /* amount of bytes used from Keys */ + DTLS_EXPORT_OPT_SZ = 57, /* amount of bytes used from Options */ + DTLS_EXPORT_KEY_SZ = 331,/* max amount of bytes used from Keys */ + DTLS_EXPORT_MIN_KEY_SZ = 75, /* 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 */ MAX_EXPORT_BUFFER = 500, /* max size of buffer for exporting */ From c8576566ccc32b71724fb87ba6b33553f28783f8 Mon Sep 17 00:00:00 2001 From: Jacob Barthelmeh Date: Sat, 14 May 2016 12:49:09 -0600 Subject: [PATCH 6/7] add public wolfSSL_dtls_export and api tests --- src/internal.c | 44 ++++++---------- src/ssl.c | 74 +++++++++++++++++++-------- tests/api.c | 122 ++++++++++++++++++++++++++++++++++++++++++--- wolfssl/internal.h | 10 +++- wolfssl/ssl.h | 9 ++-- 5 files changed, 198 insertions(+), 61 deletions(-) diff --git a/src/internal.c b/src/internal.c index db75da214..8c897fb8e 100755 --- a/src/internal.c +++ b/src/internal.c @@ -1001,16 +1001,16 @@ static int dtls_export_load(byte* exp, word32 len, byte ver, WOLFSSL* ssl) * 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 wolfSSL_dtls_export_internal(byte* buf, word32 sz, WOLFSSL* ssl) { int ret; word32 idx = 0; word32 totalLen = 0; - WOLFSSL_ENTER("wolfSSL_dtls_export"); + WOLFSSL_ENTER("wolfSSL_dtls_export_internal"); if (buf == NULL || ssl == NULL) { - WOLFSSL_LEAVE("wolfSSL_dtls_export", BAD_FUNC_ARG); + WOLFSSL_LEAVE("wolfSSL_dtls_export_internal", BAD_FUNC_ARG); return BAD_FUNC_ARG; } @@ -1022,7 +1022,7 @@ int wolfSSL_dtls_export(byte* buf, word32 sz, WOLFSSL* ssl) totalLen += DTLS_EXPORT_LEN + ssl->buffers.dtlsCtx.peer.sz; if (totalLen > sz) { - WOLFSSL_LEAVE("wolfSSL_dtls_export", BUFFER_E); + WOLFSSL_LEAVE("wolfSSL_dtls_export_internal", BUFFER_E); return BUFFER_E; } @@ -1035,16 +1035,16 @@ int wolfSSL_dtls_export(byte* buf, word32 sz, WOLFSSL* ssl) 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); + WOLFSSL_LEAVE("wolfSSL_dtls_export_internal", ret); return ret; } - idx += DTLS_EXPORT_OPT_SZ; + idx += ret; /* export keys struct and dtls state -- variable length stored in ret */ idx += DTLS_EXPORT_LEN; /* leave room for length */ if ((ret = ExportKeyState(buf + idx, sz - idx, DTLS_EXPORT_VERSION, ssl)) < 0) { - WOLFSSL_LEAVE("wolfSSL_dtls_export", ret); + WOLFSSL_LEAVE("wolfSSL_dtls_export_internal", ret); return ret; } c16toa((word16)ret, buf + idx - DTLS_EXPORT_LEN); idx += ret; @@ -1053,10 +1053,10 @@ int wolfSSL_dtls_export(byte* buf, word32 sz, WOLFSSL* ssl) c16toa((word16)DTLS_EXPORT_SPC_SZ, buf + idx); idx += DTLS_EXPORT_LEN; if ((ret = ExportCipherSpecState(buf + idx, sz - idx, DTLS_EXPORT_VERSION, ssl)) < 0) { - WOLFSSL_LEAVE("wolfSSL_dtls_export", ret); + WOLFSSL_LEAVE("wolfSSL_dtls_export_internal", ret); return ret; } - idx += DTLS_EXPORT_SPC_SZ; + idx += ret; /* export of dtls peer information */ c16toa((word16)ssl->buffers.dtlsCtx.peer.sz, buf + idx); @@ -1079,7 +1079,7 @@ int wolfSSL_dtls_export(byte* buf, word32 sz, WOLFSSL* ssl) } #endif /* WOLFSSL_SESSION_EXPORT_DEBUG */ - WOLFSSL_LEAVE("wolfSSL_dtls_export", idx); + WOLFSSL_LEAVE("wolfSSL_dtls_export_internal", idx); return idx; } @@ -1090,7 +1090,7 @@ int wolfSSL_dtls_import_internal(byte* buf, word32 sz, WOLFSSL* ssl) word32 idx = 0; word16 length = 0; int version; - int ret, i; + int ret; WOLFSSL_ENTER("wolfSSL_dtls_import_internal"); /* check at least enough room for protocol and length */ @@ -1185,15 +1185,11 @@ int wolfSSL_dtls_import_internal(byte* buf, word32 sz, WOLFSSL* ssl) } /* 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) { + if ((ret = wolfSSL_dtls_set_peer(ssl, buf + idx, + ssl->buffers.dtlsCtx.peer.sz)) != SSL_SUCCESS) { WOLFSSL_MSG("Import DTLS peer info error"); - return MEMORY_E; + return ret; } - - 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); @@ -1205,17 +1201,9 @@ int wolfSSL_dtls_import_internal(byte* buf, word32 sz, WOLFSSL* ssl) } /* make sure is a valid suite used */ - ret = MATCH_SUITE_ERROR; - for (i = 0; i < ssl->suites->suiteSz; i += 2) { - if (ssl->suites->suites[i] == ssl->options.cipherSuite0 && - ssl->suites->suites[i+1] == ssl->options.cipherSuite) { - ret = 0; - break; - } - } - if (ret != 0) { + if (wolfSSL_get_cipher(ssl) == NULL) { WOLFSSL_MSG("Can not match cipher suite imported"); - return ret; + return MATCH_SUITE_ERROR; } /* do not allow stream ciphers with DTLS */ diff --git a/src/ssl.c b/src/ssl.c index 8013858d6..11dac0cdd 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -200,6 +200,38 @@ int wolfSSL_dtls_set_export(WOLFSSL* ssl, wc_dtls_export func) } +int wolfSSL_dtls_export(unsigned char* buf, unsigned int* sz, WOLFSSL* ssl) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_dtls_export"); + + if (ssl == NULL || sz == NULL) { + return BAD_FUNC_ARG; + } + + if (buf == NULL) { + *sz = MAX_EXPORT_BUFFER; + return 0; + } + + /* if not DTLS do nothing */ + if (!ssl->options.dtls) { + WOLFSSL_MSG("Currently only DTLS export is supported"); + return 0; + } + + /* copy over keys, options, and dtls state struct */ + ret = wolfSSL_dtls_export_internal(buf, *sz, ssl); + if (ret < 0) { + return ret; + } + + return ret; +} + + +/* returns 0 on success */ int wolfSSL_send_session(WOLFSSL* ssl) { int ret; @@ -221,31 +253,25 @@ int wolfSSL_send_session(WOLFSSL* ssl) if (!ssl->options.dtls) { XFREE(buf, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); WOLFSSL_MSG("Currently only DTLS export is supported"); - return SSL_SUCCESS; + return 0; } - 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; - } - + /* copy over keys, options, and dtls state struct */ + ret = wolfSSL_dtls_export_internal(buf, bufSz, ssl); + if (ret < 0) { XFREE(buf, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); - return SSL_SUCCESS; + return ret; } - else { + + /* 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 SSL_FAILURE; + return ret; } + + XFREE(buf, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + return 0; } #endif /* WOLFSSL_DTLS */ #endif /* WOLFSSL_SESSION_EXPORT */ @@ -6641,7 +6667,6 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, #ifdef WOLFSSL_DTLS else { ssl->options.dtlsHsRetain = 1; - } #endif /* WOLFSSL_DTLS */ @@ -6931,8 +6956,13 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, #endif /* WOLFSSL_DTLS */ #ifdef WOLFSSL_SESSION_EXPORT - WOLFSSL_MSG("sending session"); - wolfSSL_send_session(ssl); + if (ssl->dtls_export) { + if ((ssl->error = wolfSSL_send_session(ssl)) != 0) { + WOLFSSL_MSG("Export DTLS session error"); + WOLFSSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + } #endif WOLFSSL_LEAVE("SSL_accept()", SSL_SUCCESS); diff --git a/tests/api.c b/tests/api.c index 22ef72213..7e7148591 100644 --- a/tests/api.c +++ b/tests/api.c @@ -493,6 +493,34 @@ static void test_wolfSSL_SetTmpDH_buffer(void) /* helper functions */ #ifdef HAVE_IO_TESTS_DEPENDENCIES +#ifdef WOLFSSL_SESSION_EXPORT +/* set up function for sending session information */ +static int test_export(WOLFSSL* inSsl, byte* buf, word32 sz, void* userCtx) +{ + WOLFSSL_CTX* ctx; + WOLFSSL* ssl; + + AssertNotNull(inSsl); + AssertNotNull(buf); + AssertIntNE(0, sz); + + /* Set ctx to DTLS 1.2 */ + ctx = wolfSSL_CTX_new(wolfDTLSv1_2_server_method()); + AssertNotNull(ctx); + + ssl = wolfSSL_new(ctx); + AssertNotNull(ssl); + + AssertIntGE(wolfSSL_dtls_import(ssl, buf, sz), 0); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); + (void)userCtx; + return SSL_SUCCESS; +} +#endif + + static THREAD_RETURN WOLFSSL_THREAD test_server_nofail(void* args) { SOCKET_T sockfd = 0; @@ -711,8 +739,8 @@ done2: return; } -/* SNI / ALPN helper functions */ -#if defined(HAVE_SNI) || defined(HAVE_ALPN) +/* SNI / ALPN / session export helper functions */ +#if defined(HAVE_SNI) || defined(HAVE_ALPN) || defined(WOLFSSL_SESSION_EXPORT) static THREAD_RETURN WOLFSSL_THREAD run_wolfssl_server(void* args) { @@ -752,6 +780,9 @@ static THREAD_RETURN WOLFSSL_THREAD run_wolfssl_server(void* args) #ifdef OPENSSL_EXTRA wolfSSL_CTX_set_default_passwd_cb(ctx, PasswordCallBack); #endif +#ifdef WOLFSSL_SESSION_EXPORT + AssertIntEQ(SSL_SUCCESS, wolfSSL_CTX_dtls_set_export(ctx, test_export)); +#endif AssertIntEQ(SSL_SUCCESS, wolfSSL_CTX_load_verify_locations(ctx, cliCert, 0)); @@ -766,9 +797,21 @@ static THREAD_RETURN WOLFSSL_THREAD run_wolfssl_server(void* args) callbacks->ctx_ready(ctx); ssl = wolfSSL_new(ctx); + if (wolfSSL_dtls(ssl)) { + SOCKADDR_IN_T cliAddr; + socklen_t cliLen; - tcp_accept(&sfd, &cfd, (func_args*)args, port, 0, 0, 0, 1); - CloseSocket(sfd); + cliLen = sizeof(cliAddr); + tcp_accept(&sfd, &cfd, (func_args*)args, port, 0, 1, 0, 0); + idx = (int)recvfrom(sfd, input, sizeof(input), MSG_PEEK, + (struct sockaddr*)&cliAddr, &cliLen); + AssertIntGT(idx, 0); + wolfSSL_dtls_set_peer(ssl, &cliAddr, cliLen); + } + else { + tcp_accept(&sfd, &cfd, (func_args*)args, port, 0, 0, 0, 1); + CloseSocket(sfd); + } AssertIntEQ(SSL_SUCCESS, wolfSSL_set_fd(ssl, cfd)); @@ -796,6 +839,20 @@ static THREAD_RETURN WOLFSSL_THREAD run_wolfssl_server(void* args) } AssertIntEQ(len, wolfSSL_write(ssl, msg, len)); +#ifdef WOLFSSL_SESSION_EXPORT + if (wolfSSL_dtls(ssl)) { + byte* import; + word32 sz; + + wolfSSL_dtls_export(NULL, &sz, ssl); + import = (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + AssertNotNull(import); + idx = wolfSSL_dtls_export(import, &sz, ssl); + AssertIntGE(idx, 0); + AssertIntGE(wolfSSL_dtls_import(ssl, import, idx), 0); + XFREE(import, NULL, DYNAMIC_TYPE_TMP_BUFFER); + } +#endif #ifdef WOLFSSL_TIRTOS Task_yield(); #endif @@ -861,7 +918,12 @@ static void run_wolfssl_client(void* args) callbacks->ctx_ready(ctx); ssl = wolfSSL_new(ctx); - tcp_connect(&sfd, wolfSSLIP, ((func_args*)args)->signal->port, 0, ssl); + if (wolfSSL_dtls(ssl)) { + tcp_connect(&sfd, wolfSSLIP, ((func_args*)args)->signal->port, 1, ssl); + } + else { + tcp_connect(&sfd, wolfSSLIP, ((func_args*)args)->signal->port, 0, ssl); + } AssertIntEQ(SSL_SUCCESS, wolfSSL_set_fd(ssl, sfd)); if (callbacks->ssl_ready) @@ -894,7 +956,8 @@ static void run_wolfssl_client(void* args) #endif } -#endif /* defined(HAVE_SNI) || defined(HAVE_ALPN) */ +#endif /* defined(HAVE_SNI) || defined(HAVE_ALPN) || + defined(WOLFSSL_SESSION_EXPORT) */ #endif /* io tests dependencies */ @@ -952,6 +1015,52 @@ static void test_wolfSSL_read_write(void) #endif } + +static void test_wolfSSL_dtls_export(void) +{ +#if defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) && \ + defined(WOLFSSL_SESSION_EXPORT) + tcp_ready ready; + func_args client_args; + func_args server_args; + THREAD_TYPE serverThread; + callback_functions server_cbf; + callback_functions client_cbf; +#ifdef WOLFSSL_TIRTOS + fdOpenSession(Task_self()); +#endif + + InitTcpReady(&ready); + + /* set using dtls */ + XMEMSET(&server_cbf, 0, sizeof(callback_functions)); + XMEMSET(&client_cbf, 0, sizeof(callback_functions)); + server_cbf.method = wolfDTLSv1_2_server_method; + client_cbf.method = wolfDTLSv1_2_client_method; + server_args.callbacks = &server_cbf; + client_args.callbacks = &client_cbf; + + server_args.signal = &ready; + client_args.signal = &ready; + + start_thread(run_wolfssl_server, &server_args, &serverThread); + wait_tcp_ready(&server_args); + run_wolfssl_client(&client_args); + join_thread(serverThread); + + AssertTrue(client_args.return_code); + AssertTrue(server_args.return_code); + + FreeTcpReady(&ready); + +#ifdef WOLFSSL_TIRTOS + fdOpenSession(Task_self()); +#endif + printf(testingFmt, "wolfSSL_dtls_export()"); + printf(resultFmt, passed); +#endif +} + /*----------------------------------------------------------------------------* | TLS extensions tests *----------------------------------------------------------------------------*/ @@ -1738,6 +1847,7 @@ void ApiTest(void) test_wolfSSL_SetTmpDH_file(); test_wolfSSL_SetTmpDH_buffer(); test_wolfSSL_read_write(); + test_wolfSSL_dtls_export(); /* TLS extensions tests */ test_wolfSSL_UseSNI(); diff --git a/wolfssl/internal.h b/wolfssl/internal.h index d9bcfe7ba..0c9dfe388 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1203,8 +1203,6 @@ 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); @@ -1213,6 +1211,14 @@ WOLFSSL_LOCAL ProtocolVersion MakeTLSv1_2(void); #ifdef WOLFSSL_DTLS WOLFSSL_LOCAL ProtocolVersion MakeDTLSv1(void); WOLFSSL_LOCAL ProtocolVersion MakeDTLSv1_2(void); + + #ifdef WOLFSSL_SESSION_EXPORT + WOLFSSL_LOCAL int wolfSSL_dtls_import_internal(byte* buf, word32 sz, + WOLFSSL* ssl); + WOLFSSL_LOCAL int wolfSSL_dtls_export_internal(byte* buf, word32 sz, + WOLFSSL* ssl); + WOLFSSL_LOCAL int wolfSSL_send_session(WOLFSSL* ssl); + #endif #endif diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 0d08c1291..cafcd5572 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -229,10 +229,13 @@ WOLFSSL_API WOLFSSL_METHOD *wolfTLSv1_2_client_method(void); #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_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); +WOLFSSL_API int wolfSSL_dtls_export(unsigned char* buf, unsigned int* sz, + WOLFSSL* ssl); #endif /* WOLFSSL_DTLS */ #endif /* WOLFSSL_SESSION_EXPORT */ From 1b278edfd0857379f478105faf8cb5936ef6df57 Mon Sep 17 00:00:00 2001 From: Jacob Barthelmeh Date: Mon, 16 May 2016 23:48:26 -0600 Subject: [PATCH 7/7] fix unused functions, make WOLFSSL first parameter, add comments --- src/internal.c | 43 +++++++++++++++++++++++-------------------- src/ssl.c | 29 ++++++++++++++++++----------- tests/api.c | 6 +++--- wolfssl/internal.h | 8 ++++---- wolfssl/ssl.h | 4 ++-- 5 files changed, 50 insertions(+), 40 deletions(-) diff --git a/src/internal.c b/src/internal.c index 8c897fb8e..2efe5a537 100755 --- a/src/internal.c +++ b/src/internal.c @@ -357,6 +357,7 @@ static INLINE void c32toa(word32 u32, byte* c) c[3] = u32 & 0xff; } +#if defined(WOLFSSL_SESSION_EXPORT) /* convert 64 bit integer to opaque */ static INLINE void c64toa(word64 u64, byte* c) { @@ -369,6 +370,7 @@ static INLINE void c64toa(word64 u64, byte* c) c[6] = (u64 >> 8) & 0xff; c[7] = u64 & 0xff; } +#endif /* WOLFSSL_SESSION_EXPORT */ #endif @@ -395,6 +397,7 @@ static INLINE void ato32(const byte* c, word32* u32) *u32 = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3]; } +#if defined(WOLFSSL_SESSION_EXPORT) /* convert opaque to word64 type */ static INLINE void ato64(const byte* c, word64* u64) { @@ -408,7 +411,7 @@ static INLINE void ato64(const byte* c, word64* u64) (((word64)c[6] << 8) & 0x000000000000ff00) | ((word64)c[7] & 0x00000000000000ff); } - +#endif /* WOLFSSL_SESSION_EXPORT */ #endif /* WOLFSSL_DTLS */ @@ -501,7 +504,7 @@ static INLINE void ato64(const byte* c, word64* u64) #ifdef WOLFSSL_SESSION_EXPORT #ifdef WOLFSSL_DTLS /* serializes the cipher specs struct for exporting */ -static int ExportCipherSpecState(byte* exp, word32 len, byte ver, WOLFSSL* ssl) +static int ExportCipherSpecState(WOLFSSL* ssl, byte* exp, word32 len, byte ver) { word32 idx = 0; CipherSpecs* specs; @@ -545,7 +548,7 @@ static int ExportCipherSpecState(byte* exp, word32 len, byte ver, WOLFSSL* ssl) /* serializes the key struct for exporting */ -static int ExportKeyState(byte* exp, word32 len, byte ver, WOLFSSL* ssl) +static int ExportKeyState(WOLFSSL* ssl, byte* exp, word32 len, byte ver) { word32 idx = 0; byte sz; @@ -636,7 +639,7 @@ static int ExportKeyState(byte* exp, word32 len, byte ver, WOLFSSL* ssl) return idx; } -static int ImportCipherSpecState(byte* exp, word32 len, byte ver, WOLFSSL* ssl) +static int ImportCipherSpecState(WOLFSSL* ssl, byte* exp, word32 len, byte ver) { word32 idx = 0; CipherSpecs* specs; @@ -672,7 +675,7 @@ static int ImportCipherSpecState(byte* exp, word32 len, byte ver, WOLFSSL* ssl) } -static int ImportKeyState(byte* exp, word32 len, byte ver, WOLFSSL* ssl) +static int ImportKeyState(WOLFSSL* ssl, byte* exp, word32 len, byte ver) { word32 idx = 0; byte sz; @@ -765,8 +768,8 @@ static int ImportKeyState(byte* exp, word32 len, byte ver, WOLFSSL* ssl) /* 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) + * 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) { int idx = 0; word16 zero = 0; @@ -886,8 +889,8 @@ static int dtls_export_new(byte* exp, word32 len, byte ver, WOLFSSL* ssl) /* 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) + * On success returns size of buffer used on failure returns a negative value */ +static int dtls_export_load(WOLFSSL* ssl, byte* exp, word32 len, byte ver) { int idx = 0; Options* options = &ssl->options; @@ -1001,7 +1004,7 @@ static int dtls_export_load(byte* exp, word32 len, byte ver, WOLFSSL* ssl) * 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(byte* buf, word32 sz, WOLFSSL* ssl) +int wolfSSL_dtls_export_internal(WOLFSSL* ssl, byte* buf, word32 sz) { int ret; word32 idx = 0; @@ -1033,8 +1036,8 @@ int wolfSSL_dtls_export_internal(byte* buf, word32 sz, WOLFSSL* ssl) 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(buf + idx, sz - idx, DTLS_EXPORT_VERSION, - ssl)) < 0) { + if ((ret = dtls_export_new(ssl, buf + idx, sz - idx, + DTLS_EXPORT_VERSION)) < 0) { WOLFSSL_LEAVE("wolfSSL_dtls_export_internal", ret); return ret; } @@ -1042,8 +1045,8 @@ int wolfSSL_dtls_export_internal(byte* buf, word32 sz, WOLFSSL* ssl) /* export keys struct and dtls state -- variable length stored in ret */ idx += DTLS_EXPORT_LEN; /* leave room for length */ - if ((ret = ExportKeyState(buf + idx, sz - idx, - DTLS_EXPORT_VERSION, ssl)) < 0) { + if ((ret = ExportKeyState(ssl, buf + idx, sz - idx, + DTLS_EXPORT_VERSION)) < 0) { WOLFSSL_LEAVE("wolfSSL_dtls_export_internal", ret); return ret; } @@ -1051,8 +1054,8 @@ int wolfSSL_dtls_export_internal(byte* buf, word32 sz, WOLFSSL* ssl) /* export of cipher specs struct */ c16toa((word16)DTLS_EXPORT_SPC_SZ, buf + idx); idx += DTLS_EXPORT_LEN; - if ((ret = ExportCipherSpecState(buf + idx, sz - idx, - DTLS_EXPORT_VERSION, ssl)) < 0) { + if ((ret = ExportCipherSpecState(ssl, buf + idx, sz - idx, + DTLS_EXPORT_VERSION)) < 0) { WOLFSSL_LEAVE("wolfSSL_dtls_export_internal", ret); return ret; } @@ -1085,7 +1088,7 @@ int wolfSSL_dtls_export_internal(byte* buf, word32 sz, WOLFSSL* ssl) /* On success return amount of buffer consumed */ -int wolfSSL_dtls_import_internal(byte* buf, word32 sz, WOLFSSL* ssl) +int wolfSSL_dtls_import_internal(WOLFSSL* ssl, byte* buf, word32 sz) { word32 idx = 0; word16 length = 0; @@ -1133,7 +1136,7 @@ int wolfSSL_dtls_import_internal(byte* buf, word32 sz, WOLFSSL* ssl) WOLFSSL_MSG("Import Options struct error"); return BUFFER_E; } - if ((ret = dtls_export_load(buf + idx, length, version, ssl)) < 0) { + if ((ret = dtls_export_load(ssl, buf + idx, length, version)) < 0) { WOLFSSL_MSG("Import Options struct error"); return ret; } @@ -1149,7 +1152,7 @@ int wolfSSL_dtls_import_internal(byte* buf, word32 sz, WOLFSSL* ssl) WOLFSSL_MSG("Import Key struct error"); return BUFFER_E; } - if ((ret = ImportKeyState(buf + idx, length, version, ssl)) < 0) { + if ((ret = ImportKeyState(ssl, buf + idx, length, version)) < 0) { WOLFSSL_MSG("Import Key struct error"); return ret; } @@ -1165,7 +1168,7 @@ int wolfSSL_dtls_import_internal(byte* buf, word32 sz, WOLFSSL* ssl) WOLFSSL_MSG("Import CipherSpecs struct error"); return BUFFER_E; } - if ((ret = ImportCipherSpecState(buf + idx, length, version, ssl)) < 0) { + if ((ret = ImportCipherSpecState(ssl, buf + idx, length, version)) < 0) { WOLFSSL_MSG("Import CipherSpecs struct error"); return ret; } diff --git a/src/ssl.c b/src/ssl.c index 11dac0cdd..c083b9cf3 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -164,10 +164,12 @@ int wolfSSL_dtls_import(WOLFSSL* ssl, unsigned char* buf, unsigned int sz) } /* sanity checks on buffer and protocol are done in internal function */ - return wolfSSL_dtls_import_internal(buf, sz, ssl); + return wolfSSL_dtls_import_internal(ssl, buf, sz); } +/* Sets the function to call for serializing the session. This function is + * called right after the handshake is completed. */ int wolfSSL_CTX_dtls_set_export(WOLFSSL_CTX* ctx, wc_dtls_export func) { @@ -184,6 +186,8 @@ int wolfSSL_CTX_dtls_set_export(WOLFSSL_CTX* ctx, wc_dtls_export func) } +/* Sets the function in WOLFSSL struct to call for serializing the session. This + * function is called right after the handshake is completed. */ int wolfSSL_dtls_set_export(WOLFSSL* ssl, wc_dtls_export func) { @@ -200,10 +204,18 @@ int wolfSSL_dtls_set_export(WOLFSSL* ssl, wc_dtls_export func) } -int wolfSSL_dtls_export(unsigned char* buf, unsigned int* sz, WOLFSSL* ssl) +/* This function allows for directly serializing a session rather than using + * callbacks. It has less overhead by removing a temporary buffer and gives + * control over when the session gets serialized. When using callbacks the + * session is always serialized immediatly after the handshake is finished. + * + * buf is the argument to contain the serialized session + * sz is the size of the buffer passed in + * ssl is the WOLFSSL struct to serialize + * returns the size of serialized session on success, 0 on no action, and + * negative value on error */ +int wolfSSL_dtls_export(WOLFSSL* ssl, unsigned char* buf, unsigned int* sz) { - int ret; - WOLFSSL_ENTER("wolfSSL_dtls_export"); if (ssl == NULL || sz == NULL) { @@ -222,12 +234,7 @@ int wolfSSL_dtls_export(unsigned char* buf, unsigned int* sz, WOLFSSL* ssl) } /* copy over keys, options, and dtls state struct */ - ret = wolfSSL_dtls_export_internal(buf, *sz, ssl); - if (ret < 0) { - return ret; - } - - return ret; + return wolfSSL_dtls_export_internal(ssl, buf, *sz); } @@ -257,7 +264,7 @@ int wolfSSL_send_session(WOLFSSL* ssl) } /* copy over keys, options, and dtls state struct */ - ret = wolfSSL_dtls_export_internal(buf, bufSz, ssl); + ret = wolfSSL_dtls_export_internal(ssl, buf, bufSz); if (ret < 0) { XFREE(buf, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); return ret; diff --git a/tests/api.c b/tests/api.c index 7e7148591..eb5da20fb 100644 --- a/tests/api.c +++ b/tests/api.c @@ -839,15 +839,15 @@ static THREAD_RETURN WOLFSSL_THREAD run_wolfssl_server(void* args) } AssertIntEQ(len, wolfSSL_write(ssl, msg, len)); -#ifdef WOLFSSL_SESSION_EXPORT +#if defined(WOLFSSL_SESSION_EXPORT) && !defined(HAVE_IO_POOL) if (wolfSSL_dtls(ssl)) { byte* import; word32 sz; - wolfSSL_dtls_export(NULL, &sz, ssl); + wolfSSL_dtls_export(ssl, NULL, &sz); import = (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_TMP_BUFFER); AssertNotNull(import); - idx = wolfSSL_dtls_export(import, &sz, ssl); + idx = wolfSSL_dtls_export(ssl, import, &sz); AssertIntGE(idx, 0); AssertIntGE(wolfSSL_dtls_import(ssl, import, idx), 0); XFREE(import, NULL, DYNAMIC_TYPE_TMP_BUFFER); diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 0c9dfe388..0c2a96846 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1213,10 +1213,10 @@ WOLFSSL_LOCAL ProtocolVersion MakeTLSv1_2(void); WOLFSSL_LOCAL ProtocolVersion MakeDTLSv1_2(void); #ifdef WOLFSSL_SESSION_EXPORT - WOLFSSL_LOCAL int wolfSSL_dtls_import_internal(byte* buf, word32 sz, - WOLFSSL* ssl); - WOLFSSL_LOCAL int wolfSSL_dtls_export_internal(byte* buf, word32 sz, - WOLFSSL* ssl); + WOLFSSL_LOCAL int wolfSSL_dtls_import_internal(WOLFSSL* ssl, byte* buf, + word32 sz); + WOLFSSL_LOCAL int wolfSSL_dtls_export_internal(WOLFSSL* ssl, byte* buf, + word32 sz); WOLFSSL_LOCAL int wolfSSL_send_session(WOLFSSL* ssl); #endif #endif diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index cafcd5572..f2a64c706 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -234,8 +234,8 @@ WOLFSSL_API int wolfSSL_dtls_import(WOLFSSL* ssl, unsigned char* buf, 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_API int wolfSSL_dtls_export(unsigned char* buf, unsigned int* sz, - WOLFSSL* ssl); +WOLFSSL_API int wolfSSL_dtls_export(WOLFSSL* ssl, unsigned char* buf, + unsigned int* sz); #endif /* WOLFSSL_DTLS */ #endif /* WOLFSSL_SESSION_EXPORT */