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 */