Browse Source

tests: support test for SRTP

the test will check that the same Exported Keying Material is generated between
client and server
Marco Oliverio 2 years ago
parent
commit
86ba0ef643
7 changed files with 489 additions and 1 deletions
  1. 82 0
      examples/client/client.c
  2. 73 0
      examples/server/server.c
  3. 2 0
      tests/include.am
  4. 39 1
      tests/suites.c
  5. 11 0
      tests/test-dtls-srtp-fails.conf
  6. 192 0
      tests/test-dtls-srtp.conf
  7. 90 0
      wolfssl/test.h

+ 82 - 0
examples/client/client.c

@@ -1759,6 +1759,69 @@ static void Usage(void)
 #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, struct srtp_test_helper *srtp_helper)
+{
+    uint8_t *srtp_secret, *other_secret, *p;
+    size_t srtp_secret_length, other_size;
+    int ret;
+
+    ret = wolfSSL_export_dtls_srtp_keying_material(ssl, NULL,
+                                                   &srtp_secret_length);
+    if (ret != LENGTH_ONLY_E) {
+        printf("SRTP: can't get dtsl_srtp keying material");
+        return ret;
+    }
+
+    srtp_secret = (uint8_t*)XMALLOC(srtp_secret_length,
+                                    NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (srtp_secret == NULL)
+        err_sys("SRTP: low memory");
+
+    ret = wolfSSL_export_dtls_srtp_keying_material(ssl, srtp_secret,
+                                                   &srtp_secret_length);
+    if (ret != WOLFSSL_SUCCESS) {
+        printf("SRTP: can't get dtsl_srtp keying material");
+        return ret;
+    }
+
+    printf("DTLS-SRTP exported key material:\n");
+    for (p = srtp_secret; p < srtp_secret + srtp_secret_length; p++)
+        printf("%02X", *p);
+    printf("\n");
+
+    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("SRTP: Exported Keying Material mismatch");
+            return WOLFSSL_UNKNOWN;
+        }
+
+        /* we are delegated from server to free this buffer  */
+        XFREE(other_secret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    }
+
+    XFREE(srtp_secret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+    return 0;
+}
+#endif
+
 THREAD_RETURN WOLFSSL_THREAD client_test(void* args)
 {
     SOCKET_T sockfd = WOLFSSL_SOCKET_INVALID;
@@ -3909,6 +3972,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)->srtp_test_helper);
+        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
+
 #ifdef WOLFSSL_TLS13
     if (updateKeysIVs)
         wolfSSL_update_keys(ssl);
@@ -4260,6 +4339,9 @@ exit:
 
         StartTCP();
 
+#ifdef WOLFSSL_SRTP
+        args.srtp_test_helper = NULL;
+#endif
         args.argc = argc;
         args.argv = argv;
         args.return_code = 0;

+ 73 - 0
examples/server/server.c

@@ -1279,6 +1279,59 @@ static void Usage(void)
 #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, struct srtp_test_helper *srtp_helper)
+{
+    size_t srtp_secret_length;
+    uint8_t *srtp_secret, *p;
+    int ret;
+
+    ret = wolfSSL_export_dtls_srtp_keying_material(ssl, NULL,
+                                                   &srtp_secret_length);
+    if (ret != LENGTH_ONLY_E) {
+        printf("SRTP: can't get dtsl_srtp keying material");
+        return ret;
+    }
+
+    srtp_secret = (uint8_t*)XMALLOC(srtp_secret_length,
+                                    NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (srtp_secret == NULL)
+        err_sys("SRTP: low memory");
+
+    ret = wolfSSL_export_dtls_srtp_keying_material(ssl, srtp_secret,
+                                                   &srtp_secret_length);
+    if (ret != WOLFSSL_SUCCESS) {
+        printf("SRTP: can't get dtsl_srtp keying material");
+        return ret;
+    }
+
+    printf("DTLS-SRTP exported key material:\n");
+    for (p = srtp_secret; p < srtp_secret + srtp_secret_length; p++)
+        printf("%02X", *p);
+    printf("\n");
+
+     if (srtp_helper != NULL) {
+        srtp_helper_set_ekm(srtp_helper, srtp_secret, srtp_secret_length);
+        /* client code will free srtp_sercret buffer after checking for
+           correctness */
+    } else {
+        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;
@@ -3088,6 +3141,23 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args)
     }
 #endif
 
+#ifdef WOLFSSL_SRTP
+    if (dtlsSrtpProfiles != NULL) {
+        err = server_srtp_test(ssl, ((func_args*)args)->srtp_test_helper);
+        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
+
 #ifdef HAVE_ALPN
         if (alpnList != NULL) {
             char *protocol_name = NULL, *list = NULL;
@@ -3351,6 +3421,9 @@ exit:
         args.argv = argv;
         args.signal = &ready;
         args.return_code = 0;
+#ifdef WOLFSSL_SRTP
+        args.srtp_test_helper = NULL;
+#endif
         InitTcpReady(&ready);
 
 #if defined(DEBUG_WOLFSSL) && !defined(WOLFSSL_MDK_SHELL)

+ 2 - 0
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 \

+ 39 - 1
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
 
+#ifdef WOLFSSL_SRTP
+    struct 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,11 @@ static int execute_test_case(int svr_argc, char** svr_argv,
 
     InitTcpReady(&ready);
 
+#ifdef WOLFSSL_SRTP
+    srtp_helper_init(&srtp_helper);
+    cliArgs.srtp_test_helper = &srtp_helper;
+    svrArgs.srtp_test_helper = &srtp_helper;
+#endif
 #ifdef WOLFSSL_TIRTOS
     fdOpenSession(Task_self());
 #endif
@@ -562,6 +570,10 @@ static int execute_test_case(int svr_argc, char** svr_argv,
 #endif
     FreeTcpReady(&ready);
 
+#ifdef WOLFSSL_SRTP
+    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 +1053,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 */

+ 11 - 0
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

+ 192 - 0
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

+ 90 - 0
wolfssl/test.h

@@ -520,12 +520,26 @@ typedef struct callback_functions {
     unsigned char loadToSSL:1;
 } callback_functions;
 
+#ifdef WOLFSSL_SRTP
+struct srtp_test_helper {
+#if defined(_POSIX_THREADS) && !defined(__MINGW32__)
+    pthread_mutex_t mutex;
+    pthread_cond_t  cond;
+#endif
+    uint8_t *server_srtp_ekm;
+    size_t server_srtp_ekm_size;
+};
+#endif
+
 typedef struct func_args {
     int    argc;
     char** argv;
     int    return_code;
     tcp_ready* signal;
     callback_functions *callbacks;
+#ifdef WOLFSSL_SRTP
+    struct srtp_test_helper *srtp_test_helper;
+#endif
 } func_args;
 
 #ifdef NETOS
@@ -629,6 +643,82 @@ err_sys_with_errno(const char* msg)
 extern int   myoptind;
 extern char* myoptarg;
 
+#ifdef WOLFSSL_SRTP
+
+static WC_INLINE void srtp_helper_init(struct srtp_test_helper *srtp)
+{
+    srtp->server_srtp_ekm_size = 0;
+    srtp->server_srtp_ekm = NULL;
+#if defined(_POSIX_THREADS) && !defined(__MINGW32__)
+    pthread_mutex_init(&srtp->mutex, 0);
+    pthread_cond_init(&srtp->cond, 0);
+#endif
+}
+
+/**
+ * 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(struct srtp_test_helper *srtp,
+                                          uint8_t **ekm, size_t *size)
+{
+#if defined(_POSIX_THREADS) && !defined(__MINGW32__)
+    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);
+#endif
+}
+
+/**
+ * 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(struct srtp_test_helper *srtp,
+                                          uint8_t *ekm, size_t size)
+{
+#if defined(_POSIX_THREADS) && !defined(__MINGW32__)
+    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);
+#endif
+}
+
+static WC_INLINE void srtp_helper_free(struct srtp_test_helper *srtp)
+{
+#if defined(_POSIX_THREADS) && !defined(__MINGW32__)
+    pthread_mutex_destroy(&srtp->mutex);
+    pthread_cond_destroy(&srtp->cond);
+#endif
+}
+
+#endif
+
 /**
  *
  * @param argc Number of argv strings