tests: support test for SRTP

the test will check that the same Exported Keying Material is generated between
client and server
This commit is contained in:
Marco Oliverio
2022-01-19 13:03:29 +01:00
parent 9b69f693e4
commit 86ba0ef643
7 changed files with 489 additions and 1 deletions

View File

@@ -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;

View File

@@ -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)

View File

@@ -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 \

View File

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

View File

@@ -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
tests/test-dtls-srtp.conf Normal file
View File

@@ -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

View File

@@ -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