diff --git a/configure.ac b/configure.ac index 919acb249..b96ee01e8 100644 --- a/configure.ac +++ b/configure.ac @@ -900,6 +900,11 @@ AS_IF([test "x$ENABLED_SCTP" = "xyes"], : , : )]) +# DTLS-SRTP +AC_ARG_ENABLE([srtp], + [AS_HELP_STRING([--enable-srtp],[Enable wolfSSL DTLS-SRTP support (default: disabled)])], + [ENABLED_SRTP=$enableval], + [ENABLED_SRTP=no]) # DTLS-MULTICAST AC_ARG_ENABLE([mcast], @@ -7150,6 +7155,9 @@ AS_IF([test "x$ENABLED_MAXSTRENGTH" = "xyes" && \ AS_IF([test "x$ENABLED_SCTP" = "xyes"], [AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SCTP"]) +AS_IF([test "x$ENABLED_SRTP" = "xyes"], + [AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SRTP"]) + AS_IF([test "x$ENABLED_MCAST" = "xyes"], [AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_MULTICAST"]) @@ -7163,7 +7171,7 @@ AS_IF([(test "x$ENABLED_DEVCRYPTO" = "xyes") && (test "x$ENABLED_SHA224" = "xyes # SCTP and Multicast require DTLS AS_IF([(test "x$ENABLED_DTLS" = "xno") && \ - (test "x$ENABLED_SCTP" = "xyes" || test "x$ENABLED_MCAST" = "xyes")], + (test "x$ENABLED_SCTP" = "xyes" || test "x$ENABLED_MCAST" = "xyes" || test "x$ENABLED_SRTP" = "xyes")], [AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DTLS" ENABLED_DTLS=yes]) @@ -7366,6 +7374,7 @@ AM_CONDITIONAL([BUILD_ALL],[test "x$ENABLED_ALL" = "xyes"]) AM_CONDITIONAL([BUILD_TLS13],[test "x$ENABLED_TLS13" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_RNG],[test "x$ENABLED_RNG" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_SCTP],[test "x$ENABLED_SCTP" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) +AM_CONDITIONAL([BUILD_SRTP],[test "x$ENABLED_SRTP" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_MCAST],[test "x$ENABLED_MCAST" = "xyes"]) AM_CONDITIONAL([BUILD_IPV6],[test "x$ENABLED_IPV6" = "xyes"]) AM_CONDITIONAL([BUILD_LEANPSK],[test "x$ENABLED_LEANPSK" = "xyes"]) @@ -7810,6 +7819,7 @@ echo " * chrony: $ENABLED_CHRONY" echo " * ERROR_STRINGS: $ENABLED_ERROR_STRINGS" echo " * DTLS: $ENABLED_DTLS" echo " * SCTP: $ENABLED_SCTP" +echo " * SRTP: $ENABLED_SRTP" echo " * Indefinite Length: $ENABLED_BER_INDEF" echo " * Multicast: $ENABLED_MCAST" echo " * SSL v3.0 (Old): $ENABLED_SSLV3" diff --git a/examples/client/client.c b/examples/client/client.c index b42ba231e..7278b3d4c 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -1311,10 +1311,14 @@ static const char* client_usage_msg[][70] = { " P384_NTRU_HPS_LEVEL3, P521_NTRU_HPS_LEVEL5, P384_NTRU_HRSS_LEVEL3,\n" " P256_SABER_LEVEL1, P384_SABER_LEVEL3, P521_SABER_LEVEL5, P256_KYBER_LEVEL1,\n" " P384_KYBER_LEVEL3, P521_KYBER_LEVEL5, P256_KYBER_90S_LEVEL1, P384_KYBER_90S_LEVEL3,\n" - " P521_KYBER_90S_LEVEL5]\n\n", /* 70 */ + " P521_KYBER_90S_LEVEL5]\n", /* 70 */ #endif +#ifdef WOLFSSL_SRTP + "--srtp (default is SRTP_AES128_CM_SHA1_80)\n", /* 71 */ +#endif + "\n" "For simpler wolfSSL TLS client examples, visit\n" - "https://github.com/wolfSSL/wolfssl-examples/tree/master/tls\n", /* 71 */ + "https://github.com/wolfSSL/wolfssl-examples/tree/master/tls\n", /* 72 */ NULL, }, #ifndef NO_MULTIBYTE_PRINT @@ -1514,17 +1518,21 @@ static const char* client_usage_msg[][70] = { " SSLv3(0) - TLS1.3(4)\n", /* 69 */ #endif #ifdef HAVE_PQC - "--pqc post-quantum 名前付きグループとの鍵共有のみ\n", - "[KYBER_LEVEL1, KYBER_LEVEL3, KYBER_LEVEL5, KYBER_90S_LEVEL1, KYBER_90S_LEVEL3, KYBER_90S_LEVEL5,\n", - " NTRU_HPS_LEVEL1, NTRU_HPS_LEVEL3, NTRU_HPS_LEVEL5, NTRU_HRSS_LEVEL3,\n", - " LIGHTSABER, SABER, FIRESABER, P256_NTRU_HPS_LEVEL1,\n" - " P384_NTRU_HPS_LEVEL3, P521_NTRU_HPS_LEVEL5, P384_NTRU_HRSS_LEVEL3,\n" - " P256_SABER_LEVEL1, P384_SABER_LEVEL3, P521_SABER_LEVEL5, P256_KYBER_LEVEL1,\n" - " P384_KYBER_LEVEL3, P521_KYBER_LEVEL5, P256_KYBER_90S_LEVEL1, P384_KYBER_90S_LEVEL3,\n" - " P521_KYBER_90S_LEVEL5]\n\n", /* 70 */ + "--pqc post-quantum 名前付きグループとの鍵共有のみ [KYBER_LEVEL1, KYBER_LEVEL3,\n", + " KYBER_LEVEL5, KYBER_90S_LEVEL1, KYBER_90S_LEVEL3, KYBER_90S_LEVEL5,\n", + " NTRU_HPS_LEVEL1, NTRU_HPS_LEVEL3, NTRU_HPS_LEVEL5, NTRU_HRSS_LEVEL3,\n", + " SABER_LEVEL1, SABER_LEVEL3, SABER_LEVEL5, P256_NTRU_HPS_LEVEL1,\n" + " P384_NTRU_HPS_LEVEL3, P521_NTRU_HPS_LEVEL5, P384_NTRU_HRSS_LEVEL3,\n" + " P256_SABER_LEVEL1, P384_SABER_LEVEL3, P521_SABER_LEVEL5, P256_KYBER_LEVEL1,\n" + " P384_KYBER_LEVEL3, P521_KYBER_LEVEL5, P256_KYBER_90S_LEVEL1, P384_KYBER_90S_LEVEL3,\n" + " P521_KYBER_90S_LEVEL5]\n", /* 70 */ #endif +#ifdef WOLFSSL_SRTP + "--srtp (default is SRTP_AES128_CM_SHA1_80)\n", /* 71 */ +#endif + "\n" "For simpler wolfSSL TLS client examples, visit\n" - "https://github.com/wolfSSL/wolfssl-examples/tree/master/tls\n", /* 71 */ + "https://github.com/wolfSSL/wolfssl-examples/tree/master/tls\n", /* 72 */ NULL, }, #endif @@ -1746,8 +1754,85 @@ static void Usage(void) printf("%s", msg[++msgid]); /* more --pqc options */ printf("%s", msg[++msgid]); /* more --pqc options */ #endif +#ifdef WOLFSSL_SRTP + printf("%s", msg[++msgid]); /* dtls-srtp */ +#endif } +#ifdef WOLFSSL_SRTP +/** + * client_srtp_test() - test that the computed ekm matches with the server one + * @ssl: ssl context + * @srtp_helper: srtp_test_helper struct shared with the server + * + * if @srtp_helper is NULL no check is made, but the ekm is printed. + * + * calls srtp_helper_get_ekm() to wait and then get the ekm computed by the + * server, then check if it matches the one computed by itself. + */ +static int client_srtp_test(WOLFSSL *ssl, func_args *args) +{ + size_t srtp_secret_length; + byte *srtp_secret, *p; + int ret; +#if !defined(SINGLE_THREADED) && defined(_POSIX_THREADS) + srtp_test_helper *srtp_helper = args->srtp_helper; + byte *other_secret = NULL; + size_t other_size = 0; +#else + (void)args; +#endif + + ret = wolfSSL_export_dtls_srtp_keying_material(ssl, NULL, + &srtp_secret_length); + if (ret != LENGTH_ONLY_E) { + printf("DTLS SRTP: Error getting keying material length\n"); + return ret; + } + + srtp_secret = (byte*)XMALLOC(srtp_secret_length, + NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (srtp_secret == NULL) { + err_sys("DTLS SRTP: Low memory"); + } + + ret = wolfSSL_export_dtls_srtp_keying_material(ssl, srtp_secret, + &srtp_secret_length); + if (ret != WOLFSSL_SUCCESS) { + XFREE(srtp_secret, NULL, DYNAMIC_TYPE_TMP_BUFFER); + printf("DTLS SRTP: Error getting keying material\n"); + return ret; + } + + printf("DTLS SRTP: Exported key material: "); + for (p = srtp_secret; p < srtp_secret + srtp_secret_length; p++) + printf("%02X", *p); + printf("\n"); + +#if !defined(SINGLE_THREADED) && defined(_POSIX_THREADS) + if (srtp_helper != NULL) { + srtp_helper_get_ekm(srtp_helper, &other_secret, &other_size); + + if (other_size != srtp_secret_length || + (XMEMCMP(other_secret, srtp_secret, srtp_secret_length) != 0)) { + + /* we are delegated from server to free this buffer */ + XFREE(other_secret, NULL, DYNAMIC_TYPE_TMP_BUFFER); + printf("DTLS SRTP: Exported Keying Material mismatch\n"); + return WOLFSSL_UNKNOWN; + } + + /* we are delegated from server to free this buffer */ + XFREE(other_secret, NULL, DYNAMIC_TYPE_TMP_BUFFER); + } +#endif + + XFREE(srtp_secret, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + return 0; +} +#endif /* WOLFSSL_SRTP */ + THREAD_RETURN WOLFSSL_THREAD client_test(void* args) { SOCKET_T sockfd = WOLFSSL_SOCKET_INVALID; @@ -1789,6 +1874,9 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) { "ヘルプ", 0, 258 }, #if defined(HAVE_PQC) { "pqc", 1, 259 }, +#endif +#ifdef WOLFSSL_SRTP + { "srtp", 2, 260 }, /* optional argument */ #endif { 0, 0, 0 } }; @@ -1911,6 +1999,10 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) !defined(NO_FILESYSTEM) && !defined(NO_WOLFSSL_DIR) int useCertFolder = 0; #endif +#ifdef WOLFSSL_SRTP + const char* dtlsSrtpProfiles = NULL; +#endif + char buffer[WOLFSSL_MAX_ERROR_SZ]; int argc = ((func_args*)args)->argc; @@ -2048,9 +2140,20 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) #endif break; + #ifdef WOLFSSL_SRTP + case 260: + doDTLS = 1; + dtlsUDP = 1; + dtlsSrtpProfiles = myoptarg != NULL ? myoptarg : + "SRTP_AES128_CM_SHA1_80"; + printf("Using SRTP Profile(s): %s\n", dtlsSrtpProfiles); + break; + #endif + case 'G' : #ifdef WOLFSSL_SCTP doDTLS = 1; + dtlsUDP = 1; dtlsSCTP = 1; #endif break; @@ -2803,6 +2906,15 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) } #endif +#ifdef WOLFSSL_SRTP + if (dtlsSrtpProfiles != NULL) { + if (wolfSSL_CTX_set_tlsext_use_srtp(ctx, dtlsSrtpProfiles) + != WOLFSSL_SUCCESS) { + err_sys("unable to set DTLS SRTP profile"); + } + } +#endif + #ifdef WOLFSSL_WOLFSENTRY_HOOKS if (wolfsentry_setup(&wolfsentry, wolfsentry_config_path, WOLFSENTRY_ROUTE_FLAG_DIRECTION_OUT) < 0) { @@ -3871,6 +3983,22 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) TEST_DELAY(); #endif /* WOLFSSL_SESSION_EXPORT_DEBUG */ +#ifdef WOLFSSL_SRTP + if (dtlsSrtpProfiles != NULL) { + err = client_srtp_test(ssl, (func_args*)args); + if (err != 0) { + if (exitWithRet) { + ((func_args*)args)->return_code = err; + wolfSSL_free(ssl); ssl = NULL; + wolfSSL_CTX_free(ctx); ctx = NULL; + goto exit; + } + /* else */ + err_sys("SRTP check failed"); + } + } +#endif /* WOLFSSL_SRTP */ + #ifdef WOLFSSL_TLS13 if (updateKeysIVs) wolfSSL_update_keys(ssl); @@ -4222,6 +4350,9 @@ exit: StartTCP(); +#if defined(WOLFSSL_SRTP) && !defined(SINGLE_THREADED) && defined(_POSIX_THREADS) + args.srtp_helper = NULL; +#endif args.argc = argc; args.argv = argv; args.return_code = 0; diff --git a/examples/server/server.c b/examples/server/server.c index 378c360e1..2d08083ab 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -953,10 +953,14 @@ static const char* server_usage_msg[][60] = { " P384_NTRU_HPS_LEVEL3, P521_NTRU_HPS_LEVEL5, P384_NTRU_HRSS_LEVEL3,\n" " P256_SABER_LEVEL1, P384_SABER_LEVEL3, P521_SABER_LEVEL5, P256_KYBER_LEVEL1,\n" " P384_KYBER_LEVEL3, P521_KYBER_LEVEL5, P256_KYBER_90S_LEVEL1, P384_KYBER_90S_LEVEL3,\n" - " P521_KYBER_90S_LEVEL5]\n\n", /* 60 */ + " P521_KYBER_90S_LEVEL5]\n", /* 60 */ #endif +#ifdef WOLFSSL_SRTP + "--srtp (default is SRTP_AES128_CM_SHA1_80)\n", /* 61 */ +#endif + "\n" "For simpler wolfSSL TLS server examples, visit\n" - "https://github.com/wolfSSL/wolfssl-examples/tree/master/tls\n", /* 61 */ + "https://github.com/wolfSSL/wolfssl-examples/tree/master/tls\n", /* 62 */ NULL, }, #ifndef NO_MULTIBYTE_PRINT @@ -1110,17 +1114,21 @@ static const char* server_usage_msg[][60] = { " SSLv3(0) - TLS1.3(4)\n", /* 59 */ #endif #ifdef HAVE_PQC - "--pqc post-quantum 名前付きグループとの鍵共有のみ\n", - "[KYBER_LEVEL1, KYBER_LEVEL3, KYBER_LEVEL5, KYBER_90S_LEVEL1, KYBER_90S_LEVEL3, KYBER_90S_LEVEL5,\n", - " NTRU_HPS_LEVEL1, NTRU_HPS_LEVEL3, NTRU_HPS_LEVEL5, NTRU_HRSS_LEVEL3,\n", - " SABER_LEVEL1, SABER_LEVEL3, SABER_LEVEL5, P256_NTRU_HPS_LEVEL1,\n" - " P384_NTRU_HPS_LEVEL1, P521_NTRU_HPS_LEVEL3, P384_NTRU_HRS_LEVEL5,\n" - " P256_SABER_LEVEL1, P384_SABER_LEVEL3, P521_SABER_LEVEL5, P256_KYBER_LEVEL1,\n" - " P384_KYBER_LEVEL3, P521_KYBER_LEVEL5, P256_KYBER_90S_LEVEL1, P384_KYBER_90S_LEVEL3,\n" - " P521_KYBER_90S_LEVEL5]\n\n", /* 60 */ + "--pqc post-quantum 名前付きグループとの鍵共有のみ [KYBER_LEVEL1, KYBER_LEVEL3,\n", + " KYBER_LEVEL5, KYBER_90S_LEVEL1, KYBER_90S_LEVEL3, KYBER_90S_LEVEL5,\n", + " NTRU_HPS_LEVEL1, NTRU_HPS_LEVEL3, NTRU_HPS_LEVEL5, NTRU_HRSS_LEVEL3,\n", + " SABER_LEVEL1, SABER_LEVEL3, SABER_LEVEL5, P256_NTRU_HPS_LEVEL1,\n" + " P384_NTRU_HPS_LEVEL3, P521_NTRU_HPS_LEVEL5, P384_NTRU_HRSS_LEVEL3,\n" + " P256_SABER_LEVEL1, P384_SABER_LEVEL3, P521_SABER_LEVEL5, P256_KYBER_LEVEL1,\n" + " P384_KYBER_LEVEL3, P521_KYBER_LEVEL5, P256_KYBER_90S_LEVEL1, P384_KYBER_90S_LEVEL3,\n" + " P521_KYBER_90S_LEVEL5]\n", /* 60 */ #endif +#ifdef WOLFSSL_SRTP + "--srtp (default is SRTP_AES128_CM_SHA1_80)\n", /* 61 */ +#endif + "\n" "For simpler wolfSSL TLS server examples, visit\n" - "https://github.com/wolfSSL/wolfssl-examples/tree/master/tls\n", /* 61 */ + "https://github.com/wolfSSL/wolfssl-examples/tree/master/tls\n", /* 62 */ NULL, }, #endif @@ -1266,8 +1274,74 @@ static void Usage(void) printf("%s", msg[++msgId]); /* more --pqc options */ printf("%s", msg[++msgId]); /* more --pqc options */ #endif +#ifdef WOLFSSL_SRTP + printf("%s", msg[++msgId]); /* dtls-srtp */ +#endif } +#ifdef WOLFSSL_SRTP +/** + * server_srtp_test() - print the ekm and share it with the client + * @ssl: ssl context + * @srtp_helper: srtp_test_helper shared struct with the client + * + * if @srtp_helper is NULL the ekm isn't shared, but it is still printed. + * + * calls srtp_helper_set_ekm() to wake the client and share the ekm with + * him. The client will check that the ekm matches the one computed by itself. + */ +static int server_srtp_test(WOLFSSL *ssl, func_args *args) +{ + size_t srtp_secret_length; + byte *srtp_secret, *p; + int ret; +#if !defined(SINGLE_THREADED) && defined(_POSIX_THREADS) + srtp_test_helper *srtp_helper = args->srtp_helper; +#else + (void)args; +#endif + + ret = wolfSSL_export_dtls_srtp_keying_material(ssl, NULL, + &srtp_secret_length); + if (ret != LENGTH_ONLY_E) { + printf("DTLS SRTP: Error getting key material length\n"); + return ret; + } + + srtp_secret = (byte*)XMALLOC(srtp_secret_length, + NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (srtp_secret == NULL) { + err_sys("DTLS SRTP: Memory error"); + } + + ret = wolfSSL_export_dtls_srtp_keying_material(ssl, srtp_secret, + &srtp_secret_length); + if (ret != WOLFSSL_SUCCESS) { + XFREE(srtp_secret, NULL, DYNAMIC_TYPE_TMP_BUFFER); + printf("DTLS SRTP: Error getting key material\n"); + return ret; + } + + printf("DTLS SRTP: Exported key material: "); + for (p = srtp_secret; p < srtp_secret + srtp_secret_length; p++) + printf("%02X", *p); + printf("\n"); + +#if !defined(SINGLE_THREADED) && defined(_POSIX_THREADS) + if (srtp_helper != NULL) { + srtp_helper_set_ekm(srtp_helper, srtp_secret, srtp_secret_length); + + /* client code will free srtp_secret buffer after checking for + correctness */ + return 0; + } +#endif /* _POSIX_THREADS */ + + XFREE(srtp_secret, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return 0; +} +#endif + THREAD_RETURN WOLFSSL_THREAD server_test(void* args) { SOCKET_T sockfd = WOLFSSL_SOCKET_INVALID; @@ -1295,6 +1369,9 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) { "ヘルプ", 0, 258 }, #if defined(HAVE_PQC) { "pqc", 1, 259 }, +#endif +#ifdef WOLFSSL_SRTP + { "srtp", 2, 260 }, /* optional argument */ #endif { 0, 0, 0 } }; @@ -1461,6 +1538,10 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) int useCertFolder = 0; #endif +#ifdef WOLFSSL_SRTP + const char* dtlsSrtpProfiles = NULL; +#endif + ((func_args*)args)->return_code = -1; /* error state */ #ifndef NO_RSA @@ -1584,9 +1665,20 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) #endif break; + #ifdef WOLFSSL_SRTP + case 260: + doDTLS = 1; + dtlsUDP = 1; + dtlsSrtpProfiles = myoptarg != NULL ? myoptarg : + "SRTP_AES128_CM_SHA1_80"; + printf("Using SRTP Profile(s): %s\n", dtlsSrtpProfiles); + break; + #endif + case 'G' : #ifdef WOLFSSL_SCTP doDTLS = 1; + dtlsUDP = 1; dtlsSCTP = 1; #endif break; @@ -2191,6 +2283,15 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_DEFAULT, NULL); #endif +#ifdef WOLFSSL_SRTP + if (dtlsSrtpProfiles != NULL) { + if (wolfSSL_CTX_set_tlsext_use_srtp(ctx, dtlsSrtpProfiles) + != WOLFSSL_SUCCESS) { + err_sys_ex(catastrophic, "unable to set DTLS SRTP profile"); + } + } +#endif + #ifdef WOLFSSL_WOLFSENTRY_HOOKS if (wolfsentry_setup(&wolfsentry, wolfsentry_config_path, WOLFSENTRY_ROUTE_FLAG_DIRECTION_IN) < 0) { @@ -3050,6 +3151,22 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) } #endif +#ifdef WOLFSSL_SRTP + if (dtlsSrtpProfiles != NULL) { + err = server_srtp_test(ssl, (func_args*)args); + if (err != 0) { + if (exitWithRet) { + ((func_args*)args)->return_code = err; + wolfSSL_free(ssl); ssl = NULL; + wolfSSL_CTX_free(ctx); ctx = NULL; + goto exit; + } + /* else */ + err_sys("SRTP check failed"); + } + } +#endif /* WOLFSSL_SRTP */ + #ifdef HAVE_ALPN if (alpnList != NULL) { char *protocol_name = NULL, *list = NULL; @@ -3313,6 +3430,9 @@ exit: args.argv = argv; args.signal = &ready; args.return_code = 0; +#if defined(WOLFSSL_SRTP) && !defined(SINGLE_THREADED) && defined(_POSIX_THREADS) + args.srtp_helper = NULL; +#endif InitTcpReady(&ready); #if defined(DEBUG_WOLFSSL) && !defined(WOLFSSL_MDK_SHELL) diff --git a/scripts/include.am b/scripts/include.am index 2d2ca7948..8771cd3a4 100644 --- a/scripts/include.am +++ b/scripts/include.am @@ -85,6 +85,11 @@ dist_noinst_SCRIPTS+= scripts/unit.test noinst_SCRIPTS+= scripts/unit.test.in endif + +if BUILD_SRTP +dist_noinst_SCRIPTS+= scripts/openssl_srtp.test +endif + endif EXTRA_DIST += scripts/testsuite.pcap \ diff --git a/scripts/openssl_srtp.test b/scripts/openssl_srtp.test new file mode 100755 index 000000000..c362ee0b5 --- /dev/null +++ b/scripts/openssl_srtp.test @@ -0,0 +1,139 @@ +#!/bin/sh +# Test WolfSSL/OpenSSL srtp interoperability +# +# TODO: add OpenSSL client with WolfSSL server + +set -e + +if ! test -n "$WOLFSSL_OPENSSL_TEST"; then + echo "WOLFSSL_OPENSSL_TEST NOT set, won't run" + exit 0 +fi + +OPENSSL=${OPENSSL:="openssl"} +WOLFSSL_CLIENT=${WOLFSSL_CLIENT:="./examples/client/client"} + +# need a unique port since may run the same time as testsuite +generate_port() { + port=$(($(od -An -N2 /dev/random) % (65535-49512) + 49512)) +} + +# get size of key material based on the profile +# $1 srtp profile +get_key_material_size() { + case "$1" in + "SRTP_AES128_CM_SHA1_80") + ekm_size=60 ;; + "SRTP_AES128_CM_SHA1_32") + ekm_size=60 ;; + "SRTP_NULL_SHA1_80") + ekm_size=28 ;; + "SRTP_NULL_SHA1_32") + ekm_size=27 ;; + "SRTP_AEAD_AES_128_GCM") + ekm_size=56;; + "SRTP_AEAD_AES_256_GCM") + ekm_size=88;; + *) + echo "SRTP profile $1 unsupported" + exit 1 + esac +} + + +# Start an OpenSSL server dtls with srtp +# $1: dtsl version [1.0, 1.2] +# $2: srtp profile string +start_openssl_server() { + generate_port + server_port=$port + srtp_profile=$2 + + if [ "$1" = "1.0" ]; then + dtls_version=dtls1 + elif [ "$1" = "1.2" ]; then + dtls_version=dtls1_2 + fi + + get_key_material_size "$srtp_profile" + + server_output_file=/tmp/openssl_srtp_out + + # hackish but OpenSSL doesn't work if input is feeded before handshaking and + # the wolfSSL client needs a reply to stop + (sleep 1;echo -n "I hear you fa shizzle...") | \ + ${OPENSSL} s_server \ + -${dtls_version} \ + -port ${server_port} \ + -debug \ + -use_srtp ${srtp_profile} \ + -keymatexport EXTRACTOR-dtls_srtp \ + -keymatexportlen $ekm_size \ + -cert ./certs/server-cert.pem \ + -key ./certs/server-key.pem >$server_output_file & + + # make sure the server is up + sleep 0.1 +} + +# Start an wolfssl client dtls with srtp +# $1: dtsl version [1.0, 1.2] +# $2: srtp profile string +start_wolfssl_client() { + srtp_profile=$2 + + if [ "$1" = "1.0" ]; then + dtls_version=2 + elif [ "$1" = "1.2" ]; then + dtls_version=3 + fi + + client_output_file=/tmp/wolfssl_srtp_out + ${WOLFSSL_CLIENT} -u\ + -x \ + -v${dtls_version} \ + --srtp ${srtp_profile} \ + -p${server_port} >$client_output_file +} + +# $1 openssl file +# $2 wolfssl file +check_ekm() { + openssl_ekm=$(cat "$1" | grep "Keying material: " | cut -d ':' -f 2) + echo "OPENSSL EKM: $openssl_ekm" + wolfssl_ekm=$(cat "$2" | grep "DTLS SRTP: Exported key material: " | cut -d ':' -f 3) + echo "WOLFSSL EKM: $wolfssl_ekm" + + if [ "$openssl_ekm" = "$wolfssl_ekm" ];then + check_ret=0 + else + check_ret=1 + fi +} + +# $1 dtsl version +# $2 srtp profile +check_dtls_srtp() { + start_openssl_server $1 $2 + start_wolfssl_client $1 $2 + check_ekm $server_output_file $client_output_file + echo -n "check dtls $1 $2... " + if [ $check_ret -ne 0 ];then + echo "failed" + exit -1 + else + echo "ok" + fi +} + +# SRTP_NULL_SHA1_80" and SRTP_NULL_SHA1_32 aren't supported by OpenSSL +PROFILES="SRTP_AES128_CM_SHA1_80 \ + SRTP_AES128_CM_SHA1_32 \ + SRTP_AEAD_AES_128_GCM \ + SRTP_AEAD_AES_256_GCM" + +for DTLS in 1.0 1.2;do + for SRTP_PROF in $PROFILES;do + check_dtls_srtp $DTLS $SRTP_PROF + done +done diff --git a/src/internal.c b/src/internal.c index 9942bf494..f666be9d5 100644 --- a/src/internal.c +++ b/src/internal.c @@ -485,10 +485,11 @@ static WC_INLINE int IsEncryptionOn(WOLFSSL* ssl, int isSend) } -#if defined(WOLFSSL_DTLS) || !defined(WOLFSSL_NO_TLS12) +#ifdef WOLFSSL_DTLS +/* Stream Control Transmission Protocol */ /* If SCTP is not enabled returns the state of the dtls option. * If SCTP is enabled returns dtls && !sctp. */ -static WC_INLINE int IsDtlsNotSctpMode(WOLFSSL* ssl) +int IsDtlsNotSctpMode(WOLFSSL* ssl) { #ifdef WOLFSSL_SCTP return ssl->options.dtls && !ssl->options.dtlsSctp; @@ -496,7 +497,20 @@ static WC_INLINE int IsDtlsNotSctpMode(WOLFSSL* ssl) return ssl->options.dtls; #endif } -#endif /* DTLS || !WOLFSSL_NO_TLS12 */ + +/* Secure Real-time Transport Protocol */ +/* If SRTP is not enabled returns the state of the dtls option. + * If SRTP is enabled returns dtls && !dtlsSrtpProfiles. */ +static WC_INLINE int IsDtlsNotSrtpMode(WOLFSSL* ssl) +{ +#ifdef WOLFSSL_SRTP + return ssl->options.dtls && !ssl->dtlsSrtpProfiles; +#else + return ssl->options.dtls; +#endif +} +#endif /* WOLFSSL_DTLS */ + #ifdef HAVE_LIBZ @@ -6375,6 +6389,9 @@ int InitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup) #ifdef WOLFSSL_SCTP ssl->options.dtlsSctp = ctx->dtlsSctp; #endif + #ifdef WOLFSSL_SRTP + ssl->dtlsSrtpProfiles = ctx->dtlsSrtpProfiles; + #endif #if defined(WOLFSSL_SCTP) || defined(WOLFSSL_DTLS_MTU) ssl->dtlsMtuSz = ctx->dtlsMtuSz; /* Add some bytes so that we can operate with slight difference @@ -14154,8 +14171,10 @@ static int DoHandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, /* hello_request not hashed */ /* Also, skip hashing the client_hello message here for DTLS. It will be * hashed later if the DTLS cookie is correct. */ - if (type != hello_request && - !(IsDtlsNotSctpMode(ssl) && type == client_hello) + if (type != hello_request + #ifdef WOLFSSL_DTLS + && !(IsDtlsNotSctpMode(ssl) && type == client_hello) + #endif #ifdef WOLFSSL_ASYNC_CRYPT && ssl->error != WC_PENDING_E #endif @@ -17242,7 +17261,7 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr) if (ssl->options.tls1_1 && ssl->specs.cipher_type == block) ssl->buffers.inputBuffer.idx += ssl->specs.block_size; #endif - /* go past TLSv1.1 IV */ + /* go past TLSv1.1 IV */ if (CipherHasExpIV(ssl)) ssl->buffers.inputBuffer.idx += AESGCM_EXP_IV_SZ; #endif @@ -19731,7 +19750,7 @@ static int ModifyForMTU(WOLFSSL* ssl, int buffSz, int outputSz, int mtuSz) return buffSz; } -#endif +#endif /* WOLFSSL_DTLS */ int SendData(WOLFSSL* ssl, const void* data, int sz) @@ -29449,7 +29468,8 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, XMEMCPY(&pv, input + i, OPAQUE16_LEN); ssl->chVersion = pv; /* store */ #ifdef WOLFSSL_DTLS - if (IsDtlsNotSctpMode(ssl) && !IsSCR(ssl) && !ssl->options.resuming) { + if (IsDtlsNotSctpMode(ssl) && IsDtlsNotSrtpMode(ssl) && !IsSCR(ssl) && + !ssl->options.resuming) { #if defined(NO_SHA) && defined(NO_SHA256) #error "DTLS needs either SHA or SHA-256" #endif /* NO_SHA && NO_SHA256 */ @@ -29611,7 +29631,8 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, /* random */ XMEMCPY(ssl->arrays->clientRandom, input + i, RAN_LEN); #ifdef WOLFSSL_DTLS - if (IsDtlsNotSctpMode(ssl) && !IsSCR(ssl) && !ssl->options.resuming) { + if (IsDtlsNotSctpMode(ssl) && IsDtlsNotSrtpMode(ssl) && !IsSCR(ssl) && + !ssl->options.resuming) { ret = wc_HmacUpdate(&cookieHmac, input + i, RAN_LEN); if (ret != 0) goto out; } @@ -29646,8 +29667,8 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, XMEMCPY(ssl->arrays->sessionID, input + i, b); #ifdef WOLFSSL_DTLS - if (IsDtlsNotSctpMode(ssl) && !IsSCR(ssl) && - !ssl->options.resuming) { + if (IsDtlsNotSctpMode(ssl) && IsDtlsNotSrtpMode(ssl) && !IsSCR(ssl) + && !ssl->options.resuming) { ret = wc_HmacUpdate(&cookieHmac, input + i - 1, b + 1); if (ret != 0) goto out; } @@ -29752,7 +29773,8 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #endif #ifdef WOLFSSL_DTLS - if (IsDtlsNotSctpMode(ssl) && !IsSCR(ssl) && !ssl->options.resuming) { + if (IsDtlsNotSctpMode(ssl) && IsDtlsNotSrtpMode(ssl) && !IsSCR(ssl) && + !ssl->options.resuming) { ret = wc_HmacUpdate(&cookieHmac, input + i - OPAQUE16_LEN, clSuites.suiteSz + OPAQUE16_LEN); @@ -29781,7 +29803,8 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #ifdef WOLFSSL_DTLS if (IsDtlsNotSctpMode(ssl)) { - if (!IsSCR(ssl) && !ssl->options.resuming) { + if (IsDtlsNotSrtpMode(ssl) && !IsSCR(ssl) && + !ssl->options.resuming) { byte newCookie[MAX_COOKIE_LEN]; ret = wc_HmacUpdate(&cookieHmac, input + i - 1, b + 1); diff --git a/src/ssl.c b/src/ssl.c index 22c489e90..1d53f1a41 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -1277,6 +1277,172 @@ int wolfSSL_dtls_set_mtu(WOLFSSL* ssl, word16 newMtu) #endif /* WOLFSSL_DTLS && (WOLFSSL_SCTP || WOLFSSL_DTLS_MTU) */ +#ifdef WOLFSSL_SRTP + +static const WOLFSSL_SRTP_PROTECTION_PROFILE gSrtpProfiles[] = { + /* AES CCM 128, Salt:112-bits, Auth HMAC-SHA1 Tag: 80-bits + * (master_key:128bits + master_salt:112bits) * 2 = 480 bits (60) */ + {"SRTP_AES128_CM_SHA1_80", SRTP_AES128_CM_SHA1_80, (((128 + 112) * 2) / 8) }, + /* AES CCM 128, Salt:112-bits, Auth HMAC-SHA1 Tag: 32-bits + * (master_key:128bits + master_salt:112bits) * 2 = 480 bits (60) */ + {"SRTP_AES128_CM_SHA1_32", SRTP_AES128_CM_SHA1_32, (((128 + 112) * 2) / 8) }, + /* NULL Cipher, Salt:112-bits, Auth HMAC-SHA1 Tag 80-bits */ + {"SRTP_NULL_SHA1_80", SRTP_NULL_SHA1_80, ((112 * 2) / 8)}, + /* NULL Cipher, Salt:112-bits, Auth HMAC-SHA1 Tag 32-bits */ + {"SRTP_NULL_SHA1_32", SRTP_NULL_SHA1_32, ((112 * 2) / 8)}, + /* AES GCM 128, Salt: 96-bits, Auth GCM Tag 128-bits + * (master_key:128bits + master_salt:96bits) * 2 = 448 bits (56) */ + {"SRTP_AEAD_AES_128_GCM", SRTP_AEAD_AES_128_GCM, (((128 + 96) * 2) / 8) }, + /* AES GCM 256, Salt: 96-bits, Auth GCM Tag 128-bits + * (master_key:256bits + master_salt:96bits) * 2 = 704 bits (88) */ + {"SRTP_AEAD_AES_256_GCM", SRTP_AEAD_AES_256_GCM, (((256 + 96) * 2) / 8) }, +}; + +static const WOLFSSL_SRTP_PROTECTION_PROFILE* DtlsSrtpFindProfile( + const char* profile_str, word32 profile_str_len, unsigned long id) +{ + int i; + const WOLFSSL_SRTP_PROTECTION_PROFILE* profile = NULL; + for (i=0; + i<(int)(sizeof(gSrtpProfiles)/sizeof(WOLFSSL_SRTP_PROTECTION_PROFILE)); + i++) { + if (profile_str != NULL) { + word32 srtp_profile_len = (word32)XSTRLEN(gSrtpProfiles[i].name); + if (srtp_profile_len == profile_str_len && + XMEMCMP(gSrtpProfiles[i].name, profile_str, profile_str_len) + == 0) { + profile = &gSrtpProfiles[i]; + break; + } + } + else if (id != 0 && gSrtpProfiles[i].id == id) { + profile = &gSrtpProfiles[i]; + break; + } + } + return profile; +} + +/* profile_str: accepts ":" colon separated list of SRTP profiles */ +static int DtlsSrtpSelProfiles(word16* id, const char* profile_str) +{ + const WOLFSSL_SRTP_PROTECTION_PROFILE* profile; + const char *current, *next = NULL; + word32 length = 0, current_length; + + *id = 0; /* reset destination ID's */ + + if (profile_str == NULL) { + return WOLFSSL_FAILURE; + } + + /* loop on end of line or colon ":" */ + next = profile_str; + length = (word32)XSTRLEN(profile_str); + do { + current = next; + next = XSTRSTR(current, ":"); + current_length = (!next) ? (word32)XSTRLEN(current) + : (word32)(next - current); + if (current_length < length) + length = current_length; + profile = DtlsSrtpFindProfile(current, current_length, 0); + if (profile != NULL) { + *id |= (1 << profile->id); /* selected bit based on ID */ + } + } while (next != NULL && next++); /* ++ needed to skip ':' */ + return WOLFSSL_SUCCESS; +} + +int wolfSSL_CTX_set_tlsext_use_srtp(WOLFSSL_CTX* ctx, const char* profile_str) +{ + int ret = WOLFSSL_FAILURE; + if (ctx != NULL) { + ret = DtlsSrtpSelProfiles(&ctx->dtlsSrtpProfiles, profile_str); + } + return ret; +} +int wolfSSL_set_tlsext_use_srtp(WOLFSSL* ssl, const char* profile_str) +{ + int ret = WOLFSSL_FAILURE; + if (ssl != NULL) { + ret = DtlsSrtpSelProfiles(&ssl->dtlsSrtpProfiles, profile_str); + } + return ret; +} + +const WOLFSSL_SRTP_PROTECTION_PROFILE* wolfSSL_get_selected_srtp_profile( + WOLFSSL* ssl) +{ + const WOLFSSL_SRTP_PROTECTION_PROFILE* profile = NULL; + if (ssl) { + profile = DtlsSrtpFindProfile(NULL, 0, ssl->dtlsSrtpId); + } + return profile; +} +#ifndef NO_WOLFSSL_STUB +WOLF_STACK_OF(WOLFSSL_SRTP_PROTECTION_PROFILE)* wolfSSL_get_srtp_profiles( + WOLFSSL* ssl) +{ + /* Not yet implemented - should return list of available SRTP profiles + * ssl->dtlsSrtpProfiles */ + (void)ssl; + return NULL; +} +#endif + +int wolfSSL_export_dtls_srtp_keying_material(WOLFSSL* ssl, + unsigned char* out, size_t* olen) +{ + int ret = WOLFSSL_FAILURE; + const char* label = "EXTRACTOR-dtls_srtp"; + const WOLFSSL_SRTP_PROTECTION_PROFILE* profile = NULL; + byte seed[SEED_LEN]; + + if (ssl == NULL || olen == NULL) { + return BAD_FUNC_ARG; + } + + profile = DtlsSrtpFindProfile(NULL, 0, ssl->dtlsSrtpId); + if (profile == NULL) { + WOLFSSL_MSG("Not using DTLS SRTP"); + return EXT_MISSING; + } + if (out == NULL) { + *olen = profile->kdfBits; + return LENGTH_ONLY_E; + } + + if (*olen < (size_t)profile->kdfBits) { + return BUFFER_E; + } + +#ifdef WOLFSSL_HAVE_PRF + XMEMCPY(seed, ssl->arrays->clientRandom, RAN_LEN); + XMEMCPY(seed + RAN_LEN, ssl->arrays->serverRandom, RAN_LEN); + + PRIVATE_KEY_UNLOCK(); + ret = wc_PRF_TLS(out, profile->kdfBits, /* out: generated keys / salt */ + ssl->arrays->masterSecret, SECRET_LEN, /* existing master secret */ + (const byte*)label, (int)XSTRLEN(label),/* label */ + seed, SEED_LEN, /* seed: client/server random */ + IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm, + ssl->heap, INVALID_DEVID); + if (ret == 0) { + *olen = profile->kdfBits; + ret = WOLFSSL_SUCCESS; + } + PRIVATE_KEY_LOCK(); +#else + /* Pseudo random function must be enabled in the configuration */ + ret = PRF_MISSING; +#endif + + return ret; +} + +#endif /* WOLFSSL_SRTP */ + #ifdef WOLFSSL_DTLS_DROP_STATS @@ -14059,26 +14225,6 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, return method; } - - #if defined(WOLFSSL_DTLS) || !defined(WOLFSSL_NO_TLS12) || !defined(NO_OLD_TLS) || \ - defined(WOLFSSL_ALLOW_SSLV3) - /* If SCTP is not enabled returns the state of the dtls option. - * If SCTP is enabled returns dtls && !sctp. */ - static WC_INLINE int IsDtlsNotSctpMode(WOLFSSL* ssl) - { - int result = ssl->options.dtls; - - if (result) { - #ifdef WOLFSSL_SCTP - result = !ssl->options.dtlsSctp; - #endif - } - - return result; - } - #endif /* WOLFSSL_DTLS || !WOLFSSL_NO_TLS12 || !NO_OLD_TLS */ - - /* please see note at top of README if you get an error from connect */ WOLFSSL_ABI int wolfSSL_connect(WOLFSSL* ssl) @@ -14209,10 +14355,12 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, /* if resumption failed, reset needed state */ else if (neededState == SERVER_FINISHED_COMPLETE) if (!ssl->options.resuming) { - if (!IsDtlsNotSctpMode(ssl)) - neededState = SERVER_HELLODONE_COMPLETE; - else + #ifdef WOLFSSL_DTLS + if (IsDtlsNotSctpMode(ssl)) neededState = SERVER_HELLOVERIFYREQUEST_COMPLETE; + else + #endif + neededState = SERVER_HELLODONE_COMPLETE; } } diff --git a/src/tls.c b/src/tls.c index 8af5ae3a2..a9139a47c 100644 --- a/src/tls.c +++ b/src/tls.c @@ -5351,6 +5351,199 @@ int TLSX_EncryptThenMac_Respond(WOLFSSL* ssl) #endif /* HAVE_ENCRYPT_THEN_MAC && !WOLFSSL_AEAD_ONLY */ + +#ifdef WOLFSSL_SRTP + +/******************************************************************************/ +/* DTLS SRTP (Secure Real-time Transport Protocol) */ +/******************************************************************************/ + +/* Only support single SRTP profile */ +typedef struct TlsxSrtp { + word16 profileCount; + word16 ids; /* selected bits */ +} TlsxSrtp; + +static int TLSX_UseSRTP_GetSize(TlsxSrtp *srtp) +{ + /* SRTP Profile Len (2) + * SRTP Profiles (2) + * MKI (master key id) Length */ + return (OPAQUE16_LEN + (srtp->profileCount * OPAQUE16_LEN) + 1); +} + +static TlsxSrtp* TLSX_UseSRTP_New(word16 ids, void* heap) +{ + TlsxSrtp* srtp; + int i; + + srtp = (TlsxSrtp*)XMALLOC(sizeof(TlsxSrtp), heap, DYNAMIC_TYPE_TLSX); + if (srtp == NULL) { + WOLFSSL_MSG("TLSX SRTP Memory failure"); + return NULL; + } + + /* count and test each bit set */ + srtp->profileCount = 0; + for (i=0; i<16; i++) { + if (ids & (1 << i)) { + srtp->profileCount++; + } + } + srtp->ids = ids; + + return srtp; +} + +static void TLSX_UseSRTP_Free(TlsxSrtp *srtp, void* heap) +{ + if (srtp != NULL) { + XFREE(srtp, heap, DYNAMIC_TYPE_TLSX); + } + (void)heap; +} + +static int TLSX_UseSRTP_Parse(WOLFSSL* ssl, const byte* input, word16 length, + byte isRequest) +{ + int ret = BAD_FUNC_ARG; + word16 profile_len = 0; + word16 profile_value = 0; + word16 offset = 0; +#ifndef NO_WOLFSSL_SERVER + int i; + TlsxSrtp* srtp = NULL; +#endif + + if (length < OPAQUE16_LEN) { + return BUFFER_ERROR; + } + + /* reset selected DTLS SRTP profile ID */ + ssl->dtlsSrtpId = 0; + + /* total length, not include itself */ + ato16(input, &profile_len); + offset += OPAQUE16_LEN; + + if (!isRequest) { +#ifndef NO_WOLFSSL_CLIENT + if (length < offset + OPAQUE16_LEN) + return BUFFER_ERROR; + + ato16(input + offset, &profile_value); + + /* check that the profile received was in the ones we support */ + if (profile_value < 16 && + (ssl->dtlsSrtpProfiles & (1 << profile_value))) { + ssl->dtlsSrtpId = profile_value; + ret = 0; /* success */ + } +#endif + } +#ifndef NO_WOLFSSL_SERVER + else { + /* parse remainder one profile at a time, looking for match in CTX */ + ret = 0; + for (i=offset; idtlsSrtpProfiles & (1 << profile_value)) { + ssl->dtlsSrtpId = profile_value; + + /* make sure we respond with selected SRTP id selected */ + srtp = TLSX_UseSRTP_New((1 << profile_value), ssl->heap); + if (srtp != NULL) { + ret = TLSX_Push(&ssl->extensions, TLSX_USE_SRTP, + (void*)srtp, ssl->heap); + if (ret == 0) { + TLSX_SetResponse(ssl, TLSX_USE_SRTP); + /* successfully set extension */ + } + } + else { + ret = MEMORY_E; + } + break; + } + } + } + + if (ret == 0 && ssl->dtlsSrtpId == 0) { + WOLFSSL_MSG("TLSX_UseSRTP_Parse profile not found!"); + /* not fatal */ + } + else if (ret != 0) { + ssl->dtlsSrtpId = 0; + TLSX_UseSRTP_Free(srtp, ssl->heap); + } +#endif + (void)profile_len; + + return ret; +} + +static word16 TLSX_UseSRTP_Write(TlsxSrtp* srtp, byte* output) +{ + word16 offset = 0; + int i, j; + + c16toa(srtp->profileCount*2, output+offset); + offset += OPAQUE16_LEN; + for (i=0; i< srtp->profileCount; i+=2) { + for (j=0; j<16; j++) { + if (srtp->ids & (1 << j)) { + c16toa(j, output+offset); + offset += OPAQUE16_LEN; + } + } + } + output[offset++] = 0x00; /* MKI Length */ + + return offset; +} + +static int TLSX_UseSRTP(TLSX** extensions, word16 profiles, void* heap) +{ + int ret = 0; + TLSX* extension; + + if (extensions == NULL) { + return BAD_FUNC_ARG; + } + + extension = TLSX_Find(*extensions, TLSX_USE_SRTP); + if (extension == NULL) { + TlsxSrtp* srtp = TLSX_UseSRTP_New(profiles, heap); + if (srtp == NULL) { + return MEMORY_E; + } + + ret = TLSX_Push(extensions, TLSX_USE_SRTP, (void*)srtp, heap); + if (ret != 0) { + TLSX_UseSRTP_Free(srtp, heap); + } + } + + return ret; +} + +#ifndef NO_WOLFSSL_SERVER + #define SRTP_FREE TLSX_UseSRTP_Free + #define SRTP_PARSE TLSX_UseSRTP_Parse + #define SRTP_WRITE TLSX_UseSRTP_Write + #define SRTP_GET_SIZE TLSX_UseSRTP_GetSize +#else + #define SRTP_FREE(a, b) + #define SRTP_PARSE(a, b, c, d) 0 + #define SRTP_WRITE(a, b) 0 + #define SRTP_GET_SIZE(a) 0 +#endif + +#endif /* WOLFSSL_SRTP */ + + /******************************************************************************/ /* Supported Versions */ /******************************************************************************/ @@ -9630,6 +9823,11 @@ void TLSX_FreeAll(TLSX* list, void* heap) KS_FREE_ALL((KeyShareEntry*)extension->data, heap); break; #endif +#ifdef WOLFSSL_SRTP + case TLSX_USE_SRTP: + SRTP_FREE((TlsxSrtp*)extension->data, heap); + break; +#endif default: break; @@ -9780,6 +9978,11 @@ static int TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType, case TLSX_KEY_SHARE: length += KS_GET_SIZE((KeyShareEntry*)extension->data, msgType); break; +#endif +#ifdef WOLFSSL_SRTP + case TLSX_USE_SRTP: + length += SRTP_GET_SIZE((TlsxSrtp*)extension->data); + break; #endif default: break; @@ -9963,6 +10166,11 @@ static int TLSX_Write(TLSX* list, byte* output, byte* semaphore, offset += KS_WRITE((KeyShareEntry*)extension->data, output + offset, msgType); break; +#endif +#ifdef WOLFSSL_SRTP + case TLSX_USE_SRTP: + offset += SRTP_WRITE((TlsxSrtp*)extension->data, output+offset); + break; #endif default: break; @@ -10339,6 +10547,16 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) return ret; } #endif /* (HAVE_ECC || CURVE25519 || CURVE448) && HAVE_SUPPORTED_CURVES */ + +#ifdef WOLFSSL_SRTP + if (ssl->options.dtls && ssl->dtlsSrtpProfiles != 0) { + WOLFSSL_MSG("Adding DTLS SRTP extension"); + if ((ret = TLSX_UseSRTP(&ssl->extensions, ssl->dtlsSrtpProfiles, + ssl->heap)) != 0) { + return ret; + } + } +#endif } /* is not server */ #if !defined(NO_CERTS) && !defined(WOLFSSL_NO_SIGALG) @@ -11562,6 +11780,12 @@ int TLSX_Parse(WOLFSSL* ssl, const byte* input, word16 length, byte msgType, ret = KS_PARSE(ssl, input + offset, size, msgType); break; +#endif +#ifdef WOLFSSL_SRTP + case TLSX_USE_SRTP: + WOLFSSL_MSG("Use SRTP extension received"); + ret = SRTP_PARSE(ssl, input + offset, size, isRequest); + break; #endif default: WOLFSSL_MSG("Unknown TLS extension type"); diff --git a/tests/include.am b/tests/include.am index 6c5331600..daf96c814 100644 --- a/tests/include.am +++ b/tests/include.am @@ -37,6 +37,8 @@ EXTRA_DIST += tests/unit.h \ tests/test-dtls-reneg-server.conf \ tests/test-dtls-resume.conf \ tests/test-dtls-sha2.conf \ + tests/test-dtls-srtp.conf \ + tests/test-dtls-srtp-fails.conf \ tests/test-sctp.conf \ tests/test-sctp-sha2.conf \ tests/test-sig.conf \ diff --git a/tests/suites.c b/tests/suites.c index f410fb5d6..d42040ada 100644 --- a/tests/suites.c +++ b/tests/suites.c @@ -294,7 +294,7 @@ static int execute_test_case(int svr_argc, char** svr_argv, int addDisableEMS, int forceSrvDefCipherList, int forceCliDefCipherList) { -#ifdef WOLFSSL_TIRTOS +#if defined(WOLFSSL_TIRTOS) || defined(WOLFSSL_SRTP) func_args cliArgs = {0}; func_args svrArgs = {0}; cliArgs.argc = cli_argc; @@ -321,6 +321,9 @@ static int execute_test_case(int svr_argc, char** svr_argv, int reqClientCert; #endif +#if defined(WOLFSSL_SRTP) && !defined(SINGLE_THREADED) && defined(_POSIX_THREADS) + srtp_test_helper srtp_helper; +#endif /* Is Valid Cipher and Version Checks */ /* build command list for the Is checks below */ commandLine[0] = '\0'; @@ -449,6 +452,12 @@ static int execute_test_case(int svr_argc, char** svr_argv, InitTcpReady(&ready); +#if defined(WOLFSSL_SRTP) && !defined(SINGLE_THREADED) && defined(_POSIX_THREADS) + srtp_helper_init(&srtp_helper); + cliArgs.srtp_helper = &srtp_helper; + svrArgs.srtp_helper = &srtp_helper; +#endif + #ifdef WOLFSSL_TIRTOS fdOpenSession(Task_self()); #endif @@ -562,6 +571,10 @@ static int execute_test_case(int svr_argc, char** svr_argv, #endif FreeTcpReady(&ready); +#if defined (WOLFSSL_SRTP) &&!defined(SINGLE_THREADED) && defined(_POSIX_THREADS) + srtp_helper_free(&srtp_helper); +#endif + /* only run the first test for expected failure cases */ /* the example server/client are not designed to handle expected failure in all cases, such as non-blocking, etc... */ @@ -1041,6 +1054,32 @@ int SuiteTest(int argc, char** argv) } strcpy(argv0[2], ""); #endif + +#ifdef WOLFSSL_SRTP + args.argc = 2; + strcpy(argv0[1], "tests/test-dtls-srtp.conf"); + printf("starting dtls srtp suite tests\n"); + test_harness(&args); + if (args.return_code != 0) { + printf("error from script %d\n", args.return_code); + args.return_code = EXIT_FAILURE; + goto exit; + } + + /* failure tests */ + args.argc = 3; + strcpy(argv0[1], "tests/test-dtls-srtp-fails.conf"); + strcpy(argv0[2], "expFail"); /* tests are expected to fail */ + printf("starting dtls srtp profile mismatch tests that expect failure\n"); + test_harness(&args); + if (args.return_code != 0) { + printf("error from script %d\n", args.return_code); + args.return_code = EXIT_FAILURE; + goto exit; + } + strcpy(argv0[2], ""); +#endif + #endif #ifdef WOLFSSL_SCTP /* add dtls-sctp extra suites */ diff --git a/tests/test-dtls-srtp-fails.conf b/tests/test-dtls-srtp-fails.conf new file mode 100644 index 000000000..3cde23308 --- /dev/null +++ b/tests/test-dtls-srtp-fails.conf @@ -0,0 +1,11 @@ +# server DTLSv1.2 all but SRTP_AEAD_AES_256_GCM +-u +-d +-l ECDHE-RSA-AES256-GCM-SHA384 +--srtp SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32:SRTP_NULL_SHA1_80:SRTP_NULL_SHA1_32:SRTP_AEAD_AES_128_GCM + +# client DTLSv1.2 SRTP_AEAD_AES_256_GCM profile +-u +-x +-l ECDHE-RSA-AES256-GCM-SHA384 +--srtp SRTP_AEAD_AES_256_GCM diff --git a/tests/test-dtls-srtp.conf b/tests/test-dtls-srtp.conf new file mode 100644 index 000000000..071da218c --- /dev/null +++ b/tests/test-dtls-srtp.conf @@ -0,0 +1,192 @@ +# server DTLSv1.2 SRTP default profile +-u +-d +-l ECDHE-RSA-AES256-GCM-SHA384 +--srtp + +# client DTLSv1.2 SRTP default profile +-u +-x +--srtp +-l ECDHE-RSA-AES256-GCM-SHA384 + +# server DTLSv1.0 SRTP default profile +-u +-d +-v 2 +-l TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA +--srtp + +# client DTLSv1.0 SRTP default profile +-u +-x +-v 2 +-l TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA +--srtp + +# server DTLSv1.2 SRTP_AES128_CM_SHA1_32 profile +-u +-d +-l ECDHE-RSA-AES256-GCM-SHA384 +--srtp SRTP_AES128_CM_SHA1_32 + +# client DTLSv1.2 SRTP_AES128_CM_SHA1_32 profile +-u +-x +-l ECDHE-RSA-AES256-GCM-SHA384 +--srtp SRTP_AES128_CM_SHA1_32 + +# server DTLSv1.0 SRTP_AES128_CM_SHA1_32 profile +-u +-d +-v 2 +-l TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA +--srtp SRTP_AES128_CM_SHA1_32 + +# client DTLSv1.0 SRTP_AES128_CM_SHA1_32 profile +-u +-x +-v 2 +-l TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA +--srtp SRTP_AES128_CM_SHA1_32 + + +# server DTLSv1.2 SRTP_NULL_SHA1_32 profile +-u +-d +-l ECDHE-RSA-AES256-GCM-SHA384 +--srtp SRTP_NULL_SHA1_32 + +# client DTLSv1.2 SRTP_NULL_SHA1_32 profile +-u +-x +-l ECDHE-RSA-AES256-GCM-SHA384 +--srtp SRTP_NULL_SHA1_32 + +# server DTLSv1.0 SRTP_NULL_SHA1_32 profile +-u +-d +-v 2 +-l TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA +--srtp SRTP_NULL_SHA1_32 + +# client DTLSv1.0 SRTP_NULL_SHA1_32 profile +-u +-x +-v 2 +-l TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA +--srtp SRTP_NULL_SHA1_32 + +# server DTLSv1.2 SRTP_NULL_SHA1_80 profile +-u +-d +-l ECDHE-RSA-AES256-GCM-SHA384 +--srtp SRTP_NULL_SHA1_80 + +# client DTLSv1.2 SRTP_NULL_SHA1_80 profile +-u +-x +-l ECDHE-RSA-AES256-GCM-SHA384 +--srtp SRTP_NULL_SHA1_80 + +# server DTLSv1.0 SRTP_NULL_SHA1_80 profile +-u +-d +-v 2 +-l TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA +--srtp SRTP_NULL_SHA1_80 + +# client DTLSv1.0 SRTP_NULL_SHA1_80 profile +-u +-x +-v 2 +-l TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA +--srtp SRTP_NULL_SHA1_80 + +# server DTLSv1.2 SRTP_AEAD_AES_128_GCM profile +-u +-d +-l ECDHE-RSA-AES256-GCM-SHA384 +--srtp SRTP_AEAD_AES_128_GCM + +# client DTLSv1.2 SRTP_AEAD_AES_128_GCM profile +-u +-x +-l ECDHE-RSA-AES256-GCM-SHA384 +--srtp SRTP_AEAD_AES_128_GCM + +# server DTLSv1.0 SRTP_AEAD_AES_128_GCM profile +-u +-d +-v 2 +-l TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA +--srtp SRTP_AEAD_AES_128_GCM + +# client DTLSv1.0 SRTP_AEAD_AES_128_GCM profile +-u +-x +-v 2 +-l TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA +--srtp SRTP_AEAD_AES_128_GCM + +# server DTLSv1.2 SRTP_AEAD_AES_256_GCM profile +-u +-d +-l ECDHE-RSA-AES256-GCM-SHA384 +--srtp SRTP_AEAD_AES_256_GCM + +# client DTLSv1.2 SRTP_AEAD_AES_256_GCM profile +-u +-x +-l ECDHE-RSA-AES256-GCM-SHA384 +--srtp SRTP_AEAD_AES_256_GCM + +# server DTLSv1.0 SRTP_AEAD_AES_256_GCM profile +-u +-d +-v 2 +-l TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA +--srtp SRTP_AEAD_AES_256_GCM + +# client DTLSv1.0 SRTP_AEAD_AES_256_GCM profile +-u +-x +-v 2 +-l TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA +--srtp SRTP_AEAD_AES_256_GCM + +# server DTLSv1.2 SRTP_AEAD_AES_256_GCM profile +-u +-d +-l ECDHE-RSA-AES256-GCM-SHA384 +--srtp SRTP_AEAD_AES_256_GCM:SRTP_NULL_SHA1_32 + +# client DTLSv1.2 SRTP_AEAD_AES_256_GCM profile +-u +-x +-l ECDHE-RSA-AES256-GCM-SHA384 +--srtp SRTP_NULL_SHA1_32 + +# server DTLSv1.2 SRTP_AEAD_AES_256_GCM profile +-u +-d +-l ECDHE-RSA-AES256-GCM-SHA384 +--srtp SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32:SRTP_NULL_SHA1_80:SRTP_NULL_SHA1_32:SRTP_AEAD_AES_128_GCM:SRTP_AEAD_AES_256_GCM + +# client DTLSv1.2 SRTP_AEAD_AES_256_GCM profile +-u +-x +-l ECDHE-RSA-AES256-GCM-SHA384 +--srtp SRTP_NULL_SHA1_32 + +# server DTLSv1.2 SRTP_AEAD_AES_256_GCM profile +-u +-d +-l ECDHE-RSA-AES256-GCM-SHA384 +--srtp SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32:SRTP_NULL_SHA1_80:SRTP_NULL_SHA1_32:SRTP_AEAD_AES_128_GCM:SRTP_AEAD_AES_256_GCM + +# client DTLSv1.2 SRTP_AEAD_AES_256_GCM profile +-u +-x +-l ECDHE-RSA-AES256-GCM-SHA384 +--srtp SRTP_AEAD_AES_256_GCM diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 2ee009069..45b6fb644 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -2262,6 +2262,9 @@ typedef enum { TLSX_EC_POINT_FORMATS = 0x000b, #if !defined(NO_CERTS) && !defined(WOLFSSL_NO_SIGALG) TLSX_SIGNATURE_ALGORITHMS = 0x000d, /* HELLO_EXT_SIG_ALGO */ +#endif +#ifdef WOLFSSL_SRTP + TLSX_USE_SRTP = 0x000e, /* 14 */ #endif TLSX_APPLICATION_LAYER_PROTOCOL = 0x0010, /* a.k.a. ALPN */ TLSX_STATUS_REQUEST_V2 = 0x0011, /* a.k.a. OCSP stapling v2 */ @@ -2833,16 +2836,22 @@ struct WOLFSSL_CTX { #if defined(WOLFSSL_STATIC_EPHEMERAL) && !defined(SINGLE_THREADED) byte staticKELockInit:1; #endif +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_SCTP) + byte dtlsSctp:1; /* DTLS-over-SCTP mode */ +#endif + word16 minProto:1; /* sets min to min available */ + word16 maxProto:1; /* sets max to max available */ -#ifdef WOLFSSL_MULTICAST +#ifdef WOLFSSL_SRTP + word16 dtlsSrtpProfiles; /* DTLS-with-SRTP mode + * (list of selected profiles - up to 16) */ +#endif +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_MULTICAST) byte haveMcast; /* multicast requested */ byte mcastID; /* multicast group ID */ #endif -#if defined(WOLFSSL_SCTP) && defined(WOLFSSL_DTLS) - byte dtlsSctp; /* DTLS-over-SCTP mode */ -#endif -#if (defined(WOLFSSL_SCTP) || defined(WOLFSSL_DTLS_MTU)) && \ - defined(WOLFSSL_DTLS) +#if defined(WOLFSSL_DTLS) && \ + (defined(WOLFSSL_SCTP) || defined(WOLFSSL_DTLS_MTU)) word16 dtlsMtuSz; /* DTLS MTU size */ #endif #ifndef NO_DH @@ -2859,8 +2868,6 @@ struct WOLFSSL_CTX { short minFalconKeySz; /* minimum Falcon key size */ #endif unsigned long mask; /* store SSL_OP_ flags */ - word16 minProto:1; /* sets min to min available */ - word16 maxProto:1; /* sets max to max available */ #ifdef OPENSSL_EXTRA byte sessionCtx[ID_LEN]; /* app session context ID */ word32 disabledCurves; /* curves disabled by user */ @@ -3683,7 +3690,7 @@ typedef struct Options { #ifdef WOLFSSL_SCTP word16 dtlsSctp:1; /* DTLS-over-SCTP mode */ #endif -#endif +#endif /* WOLFSSL_DTLS */ #if defined(HAVE_TLS_EXTENSIONS) && defined(HAVE_SUPPORTED_CURVES) word16 userCurves:1; /* indicates user called wolfSSL_UseSupportedCurve */ #endif @@ -4376,6 +4383,11 @@ struct WOLFSSL { word32 macDropCount; word32 replayDropCount; #endif /* WOLFSSL_DTLS_DROP_STATS */ +#ifdef WOLFSSL_SRTP + word16 dtlsSrtpProfiles; /* DTLS-with-SRTP profiles list + * (selected profiles - up to 16) */ + word16 dtlsSrtpId; /* DTLS-with-SRTP profile ID selected */ +#endif #endif /* WOLFSSL_DTLS */ #ifdef WOLFSSL_CALLBACKS TimeoutInfo timeoutInfo; /* info saved during handshake */ @@ -4911,6 +4923,7 @@ WOLFSSL_LOCAL int GrowInputBuffer(WOLFSSL* ssl, int size, int usedLength); WOLFSSL_LOCAL int DtlsCheckOrder(WOLFSSL* ssl, int order); #endif WOLFSSL_LOCAL int IsSCR(WOLFSSL* ssl); + WOLFSSL_LOCAL int IsDtlsNotSctpMode(WOLFSSL* ssl); WOLFSSL_LOCAL void WriteSEQ(WOLFSSL* ssl, int verifyOrder, byte* out); diff --git a/wolfssl/openssl/ssl.h b/wolfssl/openssl/ssl.h index cad636554..39a9f972c 100644 --- a/wolfssl/openssl/ssl.h +++ b/wolfssl/openssl/ssl.h @@ -331,7 +331,6 @@ typedef STACK_OF(ACCESS_DESCRIPTION) AUTHORITY_INFO_ACCESS; /* wolfSSL does not support security levels */ #define SSL_CTX_set_security_level wolfSSL_CTX_set_security_level #define SSL_CTX_get_security_level wolfSSL_CTX_get_security_level -/* wolfSSL does not support exporting keying material */ #define SSL_export_keying_material wolfSSL_export_keying_material #define SSL_CTX_set1_sigalgs_list wolfSSL_CTX_set1_sigalgs_list @@ -1080,6 +1079,15 @@ wolfSSL_X509_STORE_set_verify_cb((WOLFSSL_X509_STORE *)(s), (WOLFSSL_X509_STORE_ #define DTLSv1_handle_timeout wolfSSL_DTLSv1_handle_timeout #define DTLSv1_set_initial_timeout_duration wolfSSL_DTLSv1_set_initial_timeout_duration +/* DTLS SRTP */ +#ifdef WOLFSSL_SRTP +typedef WOLFSSL_SRTP_PROTECTION_PROFILE SRTP_PROTECTION_PROFILE; +#endif +#define SSL_CTX_set_tlsext_use_srtp wolfSSL_CTX_set_tlsext_use_srtp +#define SSL_set_tlsext_use_srtp wolfSSL_set_tlsext_use_srtp +#define SSL_get_selected_srtp_profile wolfSSL_get_selected_srtp_profile +#define SSL_get_srtp_profiles wolfSSL_get_srtp_profiles + #ifndef NO_WOLFSSL_STUB #define SSL_CTX_set_current_time_cb(ssl, cb) ({ (void)ssl; (void)cb; }) #endif diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 464f3b26f..ec89cfda9 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -1292,6 +1292,39 @@ WOLFSSL_API int wolfSSL_dtls_set_sctp(WOLFSSL*); WOLFSSL_API int wolfSSL_CTX_dtls_set_mtu(WOLFSSL_CTX*, unsigned short); WOLFSSL_API int wolfSSL_dtls_set_mtu(WOLFSSL*, unsigned short); +#ifdef WOLFSSL_SRTP + +/* SRTP Profile ID's from RFC 5764 and RFC 7714 */ +/* For WebRTC support for profile SRTP_AES128_CM_SHA1_80 is required per + * draft-ietf-rtcweb-security-arch) */ +#define SRTP_AES128_CM_SHA1_80 0x0001 +#define SRTP_AES128_CM_SHA1_32 0x0002 +#define SRTP_AES128_F8_SHA1_80 0x0003 /* not supported */ +#define SRTP_AES128_F8_SHA1_32 0x0004 /* not supported */ +#define SRTP_NULL_SHA1_80 0x0005 +#define SRTP_NULL_SHA1_32 0x0006 +#define SRTP_AEAD_AES_128_GCM 0x0007 +#define SRTP_AEAD_AES_256_GCM 0x0008 + +typedef struct WOLFSSL_SRTP_PROTECTION_PROFILE { + const char* name; + unsigned long id; + int kdfBits; +} WOLFSSL_SRTP_PROTECTION_PROFILE; + +/* Compatibility API's for SRTP */ +WOLFSSL_API int wolfSSL_CTX_set_tlsext_use_srtp(WOLFSSL_CTX*, const char*); +WOLFSSL_API int wolfSSL_set_tlsext_use_srtp(WOLFSSL*, const char*); +WOLFSSL_API const WOLFSSL_SRTP_PROTECTION_PROFILE* + wolfSSL_get_selected_srtp_profile(WOLFSSL*); +WOLFSSL_API WOLF_STACK_OF(WOLFSSL_SRTP_PROTECTION_PROFILE)* + wolfSSL_get_srtp_profiles(WOLFSSL*); + +/* Non standard API for getting the SRTP session keys using KDF */ +WOLFSSL_API int wolfSSL_export_dtls_srtp_keying_material(WOLFSSL*, + unsigned char*, size_t*); +#endif /* WOLFSSL_SRTP */ + WOLFSSL_API int wolfSSL_dtls_get_drop_stats(WOLFSSL*, unsigned int*, unsigned int*); WOLFSSL_API int wolfSSL_CTX_mcast_set_member_id(WOLFSSL_CTX*, unsigned short); diff --git a/wolfssl/test.h b/wolfssl/test.h index 2bb13c454..33de44eb6 100644 --- a/wolfssl/test.h +++ b/wolfssl/test.h @@ -520,12 +520,24 @@ typedef struct callback_functions { unsigned char loadToSSL:1; } callback_functions; +#if defined(WOLFSSL_SRTP) && !defined(SINGLE_THREADED) && defined(_POSIX_THREADS) +typedef struct srtp_test_helper { + pthread_mutex_t mutex; + pthread_cond_t cond; + uint8_t* server_srtp_ekm; + size_t server_srtp_ekm_size; +} srtp_test_helper; +#endif + typedef struct func_args { int argc; char** argv; int return_code; tcp_ready* signal; callback_functions *callbacks; +#if defined(WOLFSSL_SRTP) && !defined(SINGLE_THREADED) && defined(_POSIX_THREADS) + srtp_test_helper* srtp_helper; +#endif } func_args; #ifdef NETOS @@ -629,6 +641,75 @@ err_sys_with_errno(const char* msg) extern int myoptind; extern char* myoptarg; +#if defined(WOLFSSL_SRTP) && !defined(SINGLE_THREADED) && defined(_POSIX_THREADS) + +static WC_INLINE void srtp_helper_init(srtp_test_helper *srtp) +{ + srtp->server_srtp_ekm_size = 0; + srtp->server_srtp_ekm = NULL; + + pthread_mutex_init(&srtp->mutex, 0); + pthread_cond_init(&srtp->cond, 0); +} + +/** + * strp_helper_get_ekm() - get exported key material of other peer + * @srtp: srtp_test_helper struct shared with other peer [in] + * @ekm: where to store the shared buffer pointer [out] + * @size: size of the shared buffer returned [out] + * + * This function wait that the other peer calls strp_helper_set_ekm() and then + * store the buffer pointer/size in @ekm and @size. + */ +static WC_INLINE void srtp_helper_get_ekm(srtp_test_helper *srtp, + uint8_t **ekm, size_t *size) +{ + pthread_mutex_lock(&srtp->mutex); + + if (srtp->server_srtp_ekm == NULL) + pthread_cond_wait(&srtp->cond, &srtp->mutex); + + *ekm = srtp->server_srtp_ekm; + *size = srtp->server_srtp_ekm_size; + + /* reset */ + srtp->server_srtp_ekm = NULL; + srtp->server_srtp_ekm_size = 0; + + pthread_mutex_unlock(&srtp->mutex); +} + +/** + * strp_helper_set_ekm() - set exported key material of other peer + * @srtp: srtp_test_helper struct shared with other peer [in] + * @ekm: pointer to the shared buffer [in] + * @size: size of the shared buffer [in] + * + * This function set the @ekm and wakes up a peer waiting in + * srtp_helper_get_ekm(). + * + * used in client_srtp_test()/server_srtp_test() + */ +static WC_INLINE void srtp_helper_set_ekm(srtp_test_helper *srtp, + uint8_t *ekm, size_t size) +{ + pthread_mutex_lock(&srtp->mutex); + + srtp->server_srtp_ekm_size = size; + srtp->server_srtp_ekm = ekm; + pthread_cond_signal(&srtp->cond); + + pthread_mutex_unlock(&srtp->mutex); +} + +static WC_INLINE void srtp_helper_free(srtp_test_helper *srtp) +{ + pthread_mutex_destroy(&srtp->mutex); + pthread_cond_destroy(&srtp->cond); +} + +#endif /* WOLFSSL_SRTP && !SINGLE_THREADED && POSIX_THREADS */ + /** * * @param argc Number of argv strings @@ -726,7 +807,7 @@ static WC_INLINE int mygetopt(int argc, char** argv, const char* optstring) struct mygetopt_long_config { const char *name; - int takes_arg; + int takes_arg; /* 0=no arg, 1=required arg, 2=optional arg */ int value; }; @@ -794,10 +875,13 @@ static WC_INLINE int mygetopt_long(int argc, char** argv, const char* optstring, *longindex = (int)((i - longopts) / sizeof *i); if (i->takes_arg) { if (myoptind < argc) { - myoptarg = argv[myoptind]; - myoptind++; - } else + if (i->takes_arg == 1 || argv[myoptind][0] != '-') { + myoptarg = argv[myoptind]; + myoptind++; + } + } else if (i->takes_arg != 2) { return -1; + } } break; } diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index 75721c49b..0c81cf052 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -2431,7 +2431,8 @@ extern void uITRON4_free(void *p) ; #define WOLFSSL_NO_WORD64_OPS #endif -#if !defined(WOLFCRYPT_ONLY) && !defined(WOLFSSL_NO_TLS12) +#if !defined(WOLFCRYPT_ONLY) && \ + (!defined(WOLFSSL_NO_TLS12) || defined(HAVE_KEYING_MATERIAL)) #undef WOLFSSL_HAVE_PRF #define WOLFSSL_HAVE_PRF #endif @@ -2602,6 +2603,14 @@ extern void uITRON4_free(void *p) ; #error "You must have a post-quantum cryptography implementation to use PQC." #endif + +/* SRTP requires DTLS */ +#if defined(WOLFSSL_SRTP) && !defined(WOLFSSL_DTLS) + #error The SRTP extension requires DTLS +#endif + + + /* --------------------------------------------------------------------------- * Depricated Algorithm Handling * Unless allowed via a build macro, disable support