summaryrefslogtreecommitdiff
path: root/srtp/test/srtp_driver.c
diff options
context:
space:
mode:
authorErwin Nindl <nine@wirdorange.org>2007-06-22 13:59:20 +0000
committerErwin Nindl <nine@wirdorange.org>2007-06-22 13:59:20 +0000
commit0275479cb56c7f562f3513fef66c83fc44d1d8c9 (patch)
treef6fbb703cebf62d18b05e2a5e7591ac08c5b6702 /srtp/test/srtp_driver.c
parentsatp internet draft 00 final ietf version (diff)
added libsrtp to svn
Diffstat (limited to 'srtp/test/srtp_driver.c')
-rw-r--r--srtp/test/srtp_driver.c1491
1 files changed, 1491 insertions, 0 deletions
diff --git a/srtp/test/srtp_driver.c b/srtp/test/srtp_driver.c
new file mode 100644
index 0000000..12d1c8c
--- /dev/null
+++ b/srtp/test/srtp_driver.c
@@ -0,0 +1,1491 @@
+/*
+ * srtp_driver.c
+ *
+ * a test driver for libSRTP
+ *
+ * David A. McGrew
+ * Cisco Systems, Inc.
+ */
+/*
+ *
+ * Copyright (c) 2001-2006, Cisco Systems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * Neither the name of the Cisco Systems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include <string.h> /* for memcpy() */
+#include <time.h> /* for clock() */
+#include <stdlib.h> /* for malloc(), free() */
+#include <stdio.h> /* for print(), fflush() */
+#include "getopt_s.h" /* for local getopt() */
+
+#include "srtp_priv.h"
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#elif defined HAVE_WINSOCK2_H
+# include <winsock2.h>
+#endif
+
+#define PRINT_REFERENCE_PACKET 1
+
+err_status_t
+srtp_validate(void);
+
+err_status_t
+srtp_create_big_policy(srtp_policy_t **list);
+
+err_status_t
+srtp_test_remove_stream(void);
+
+double
+srtp_bits_per_second(int msg_len_octets, const srtp_policy_t *policy);
+
+double
+srtp_rejections_per_second(int msg_len_octets, const srtp_policy_t *policy);
+
+void
+srtp_do_timing(const srtp_policy_t *policy);
+
+void
+srtp_do_rejection_timing(const srtp_policy_t *policy);
+
+err_status_t
+srtp_test(const srtp_policy_t *policy);
+
+err_status_t
+srtcp_test(const srtp_policy_t *policy);
+
+err_status_t
+srtp_session_print_policy(srtp_t srtp);
+
+err_status_t
+srtp_print_policy(const srtp_policy_t *policy);
+
+char *
+srtp_packet_to_string(srtp_hdr_t *hdr, int packet_len);
+
+double
+mips_estimate(int num_trials, int *ignore);
+
+extern uint8_t test_key[30];
+
+void
+usage(char *prog_name) {
+ printf("usage: %s [ -t ][ -c ][ -v ][-d <debug_module> ]* [ -l ]\n"
+ " -t run timing test\n"
+ " -r run rejection timing test\n"
+ " -c run codec timing test\n"
+ " -v run validation tests\n"
+ " -d <mod> turn on debugging module <mod>\n"
+ " -l list debugging modules\n", prog_name);
+ exit(1);
+}
+
+/*
+ * The policy_array is a null-terminated array of policy structs. it
+ * is declared at the end of this file
+ */
+
+extern const srtp_policy_t *policy_array[];
+
+
+/* the wildcard_policy is declared below; it has a wildcard ssrc */
+
+extern const srtp_policy_t wildcard_policy;
+
+/*
+ * mod_driver debug module - debugging module for this test driver
+ *
+ * we use the crypto_kernel debugging system in this driver, which
+ * makes the interface uniform and increases portability
+ */
+
+debug_module_t mod_driver = {
+ 0, /* debugging is off by default */
+ "driver" /* printable name for module */
+};
+
+int
+main (int argc, char *argv[]) {
+ char q;
+ unsigned do_timing_test = 0;
+ unsigned do_rejection_test = 0;
+ unsigned do_codec_timing = 0;
+ unsigned do_validation = 0;
+ unsigned do_list_mods = 0;
+ err_status_t status;
+
+ /*
+ * verify that the compiler has interpreted the header data
+ * structure srtp_hdr_t correctly
+ */
+ if (sizeof(srtp_hdr_t) != 12) {
+ printf("error: srtp_hdr_t has incorrect size"
+ "(size is %ld bytes, expected 12)\n",
+ sizeof(srtp_hdr_t));
+ exit(1);
+ }
+
+ /* initialize srtp library */
+ status = srtp_init();
+ if (status) {
+ printf("error: srtp init failed with error code %d\n", status);
+ exit(1);
+ }
+
+ /* load srtp_driver debug module */
+ status = crypto_kernel_load_debug_module(&mod_driver);
+ if (status) {
+ printf("error: load of srtp_driver debug module failed "
+ "with error code %d\n", status);
+ exit(1);
+ }
+
+ /* process input arguments */
+ while (1) {
+ q = getopt_s(argc, argv, "trcvld:");
+ if (q == -1)
+ break;
+ switch (q) {
+ case 't':
+ do_timing_test = 1;
+ break;
+ case 'r':
+ do_rejection_test = 1;
+ break;
+ case 'c':
+ do_codec_timing = 1;
+ break;
+ case 'v':
+ do_validation = 1;
+ break;
+ case 'l':
+ do_list_mods = 1;
+ break;
+ case 'd':
+ status = crypto_kernel_set_debug_module(optarg_s, 1);
+ if (status) {
+ printf("error: set debug module (%s) failed\n", optarg_s);
+ exit(1);
+ }
+ break;
+ default:
+ usage(argv[0]);
+ }
+ }
+
+ if (!do_validation && !do_timing_test && !do_codec_timing
+ && !do_list_mods && !do_rejection_test)
+ usage(argv[0]);
+
+ if (do_list_mods) {
+ status = crypto_kernel_list_debug_modules();
+ if (status) {
+ printf("error: list of debug modules failed\n");
+ exit(1);
+ }
+ }
+
+ if (do_validation) {
+ const srtp_policy_t **policy = policy_array;
+ srtp_policy_t *big_policy;
+
+ /* loop over policy array, testing srtp and srtcp for each policy */
+ while (*policy != NULL) {
+ printf("testing srtp_protect and srtp_unprotect\n");
+ if (srtp_test(*policy) == err_status_ok)
+ printf("passed\n\n");
+ else {
+ printf("failed\n");
+ exit(1);
+ }
+ printf("testing srtp_protect_rtcp and srtp_unprotect_rtcp\n");
+ if (srtcp_test(*policy) == err_status_ok)
+ printf("passed\n\n");
+ else {
+ printf("failed\n");
+ exit(1);
+ }
+ policy++;
+ }
+
+ /* create a big policy list and run tests on it */
+ status = srtp_create_big_policy(&big_policy);
+ if (status) {
+ printf("unexpected failure with error code %d\n", status);
+ exit(1);
+ }
+ printf("testing srtp_protect and srtp_unprotect with big policy\n");
+ if (srtp_test(big_policy) == err_status_ok)
+ printf("passed\n\n");
+ else {
+ printf("failed\n");
+ exit(1);
+ }
+
+ /* run test on wildcard policy */
+ printf("testing srtp_protect and srtp_unprotect on "
+ "wildcard ssrc policy\n");
+ if (srtp_test(&wildcard_policy) == err_status_ok)
+ printf("passed\n\n");
+ else {
+ printf("failed\n");
+ exit(1);
+ }
+
+ /*
+ * run validation test against the reference packets - note
+ * that this test only covers the default policy
+ */
+ printf("testing srtp_protect and srtp_unprotect against "
+ "reference packets\n");
+ if (srtp_validate() == err_status_ok)
+ printf("passed\n\n");
+ else {
+ printf("failed\n");
+ exit(1);
+ }
+
+ /*
+ * test the function srtp_remove_stream()
+ */
+ printf("testing srtp_remove_stream()...");
+ if (srtp_test_remove_stream() == err_status_ok)
+ printf("passed\n");
+ else {
+ printf("failed\n");
+ exit(1);
+ }
+ }
+
+ if (do_timing_test) {
+ const srtp_policy_t **policy = policy_array;
+
+ /* loop over policies, run timing test for each */
+ while (*policy != NULL) {
+ srtp_print_policy(*policy);
+ srtp_do_timing(*policy);
+ policy++;
+ }
+ }
+
+ if (do_rejection_test) {
+ const srtp_policy_t **policy = policy_array;
+
+ /* loop over policies, run rejection timing test for each */
+ while (*policy != NULL) {
+ srtp_print_policy(*policy);
+ srtp_do_rejection_timing(*policy);
+ policy++;
+ }
+ }
+
+ if (do_codec_timing) {
+ srtp_policy_t policy;
+ int ignore;
+ double mips = mips_estimate(1000000000, &ignore);
+
+ crypto_policy_set_rtp_default(&policy.rtp);
+ crypto_policy_set_rtcp_default(&policy.rtcp);
+ policy.ssrc.type = ssrc_specific;
+ policy.ssrc.value = 0xdecafbad;
+ policy.key = test_key;
+ policy.next = NULL;
+
+ printf("mips estimate: %e\n", mips);
+
+ printf("testing srtp processing time for voice codecs:\n");
+ printf("codec\t\tlength (octets)\t\tsrtp instructions/second\n");
+ printf("G.711\t\t%d\t\t\t%e\n", 80,
+ (double) mips * (80 * 8) /
+ srtp_bits_per_second(80, &policy) / .01 );
+ printf("G.711\t\t%d\t\t\t%e\n", 160,
+ (double) mips * (160 * 8) /
+ srtp_bits_per_second(160, &policy) / .02);
+ printf("G.726-32\t%d\t\t\t%e\n", 40,
+ (double) mips * (40 * 8) /
+ srtp_bits_per_second(40, &policy) / .01 );
+ printf("G.726-32\t%d\t\t\t%e\n", 80,
+ (double) mips * (80 * 8) /
+ srtp_bits_per_second(80, &policy) / .02);
+ printf("G.729\t\t%d\t\t\t%e\n", 10,
+ (double) mips * (10 * 8) /
+ srtp_bits_per_second(10, &policy) / .01 );
+ printf("G.729\t\t%d\t\t\t%e\n", 20,
+ (double) mips * (20 * 8) /
+ srtp_bits_per_second(20, &policy) / .02 );
+ printf("Wideband\t%d\t\t\t%e\n", 320,
+ (double) mips * (320 * 8) /
+ srtp_bits_per_second(320, &policy) / .01 );
+ printf("Wideband\t%d\t\t\t%e\n", 640,
+ (double) mips * (640 * 8) /
+ srtp_bits_per_second(640, &policy) / .02 );
+ }
+
+ return 0;
+}
+
+
+
+/*
+ * srtp_create_test_packet(len, ssrc) returns a pointer to a
+ * (malloced) example RTP packet whose data field has the length given
+ * by pkt_octet_len and the SSRC value ssrc. The total length of the
+ * packet is twelve octets longer, since the header is at the
+ * beginning. There is room at the end of the packet for a trailer,
+ * and the four octets following the packet are filled with 0xff
+ * values to enable testing for overwrites.
+ *
+ * note that the location of the test packet can (and should) be
+ * deallocated with the free() call once it is no longer needed.
+ */
+
+srtp_hdr_t *
+srtp_create_test_packet(int pkt_octet_len, uint32_t ssrc) {
+ int i;
+ uint8_t *buffer;
+ srtp_hdr_t *hdr;
+ int bytes_in_hdr = 12;
+
+ /* allocate memory for test packet */
+ hdr = (srtp_hdr_t*) malloc(pkt_octet_len + bytes_in_hdr
+ + SRTP_MAX_TRAILER_LEN + 4);
+ if (!hdr)
+ return NULL;
+
+ hdr->version = 2; /* RTP version two */
+ hdr->p = 0; /* no padding needed */
+ hdr->x = 0; /* no header extension */
+ hdr->cc = 0; /* no CSRCs */
+ hdr->m = 0; /* marker bit */
+ hdr->pt = 0xf; /* payload type */
+ hdr->seq = htons(0x1234); /* sequence number */
+ hdr->ts = htonl(0xdecafbad); /* timestamp */
+ hdr->ssrc = htonl(ssrc); /* synch. source */
+
+ buffer = (uint8_t *)hdr;
+ buffer += bytes_in_hdr;
+
+ /* set RTP data to 0xab */
+ for (i=0; i < pkt_octet_len; i++)
+ *buffer++ = 0xab;
+
+ /* set post-data value to 0xffff to enable overrun checking */
+ for (i=0; i < SRTP_MAX_TRAILER_LEN+4; i++)
+ *buffer++ = 0xff;
+
+ return hdr;
+}
+
+void
+srtp_do_timing(const srtp_policy_t *policy) {
+ int len;
+
+ /*
+ * note: the output of this function is formatted so that it
+ * can be used in gnuplot. '#' indicates a comment, and "\r\n"
+ * terminates a record
+ */
+
+ printf("# testing srtp throughput:\r\n");
+ printf("# mesg length (octets)\tthroughput (megabits per second)\r\n");
+
+ for (len=16; len <= 2048; len *= 2)
+ printf("%d\t\t\t%f\r\n", len,
+ srtp_bits_per_second(len, policy) / 1.0E6);
+
+ /* these extra linefeeds let gnuplot know that a dataset is done */
+ printf("\r\n\r\n");
+
+}
+
+void
+srtp_do_rejection_timing(const srtp_policy_t *policy) {
+ int len;
+
+ /*
+ * note: the output of this function is formatted so that it
+ * can be used in gnuplot. '#' indicates a comment, and "\r\n"
+ * terminates a record
+ */
+
+ printf("# testing srtp rejection throughput:\r\n");
+ printf("# mesg length (octets)\trejections per second\r\n");
+
+ for (len=8; len <= 2048; len *= 2)
+ printf("%d\t\t\t%e\r\n", len, srtp_rejections_per_second(len, policy));
+
+ /* these extra linefeeds let gnuplot know that a dataset is done */
+ printf("\r\n\r\n");
+
+}
+
+
+#define MAX_MSG_LEN 1024
+
+double
+srtp_bits_per_second(int msg_len_octets, const srtp_policy_t *policy) {
+ srtp_t srtp;
+ srtp_hdr_t *mesg;
+ int i;
+ clock_t timer;
+ int num_trials = 100000;
+ int len;
+ uint32_t ssrc;
+ err_status_t status;
+
+ /*
+ * allocate and initialize an srtp session
+ */
+ status = srtp_create(&srtp, policy);
+ if (status) {
+ printf("error: srtp_create() failed with error code %d\n", status);
+ exit(1);
+ }
+
+ /*
+ * if the ssrc is unspecified, use a predetermined one
+ */
+ if (policy->ssrc.type != ssrc_specific) {
+ ssrc = 0xdeadbeef;
+ } else {
+ ssrc = policy->ssrc.value;
+ }
+
+ /*
+ * create a test packet
+ */
+ mesg = srtp_create_test_packet(msg_len_octets, ssrc);
+ if (mesg == NULL)
+ return 0.0; /* indicate failure by returning zero */
+
+ timer = clock();
+ for (i=0; i < num_trials; i++) {
+ err_status_t status;
+ len = msg_len_octets + 12; /* add in rtp header length */
+
+ /* srtp protect message */
+ status = srtp_protect(srtp, mesg, &len);
+ if (status) {
+ printf("error: srtp_protect() failed with error code %d\n", status);
+ exit(1);
+ }
+
+ /* increment message number */
+ mesg->seq = htons(ntohs(mesg->seq) + 1);
+
+ }
+ timer = clock() - timer;
+
+ free(mesg);
+
+ return (double) (msg_len_octets) * 8 *
+ num_trials * CLOCKS_PER_SEC / timer;
+}
+
+double
+srtp_rejections_per_second(int msg_len_octets, const srtp_policy_t *policy) {
+ srtp_ctx_t *srtp;
+ srtp_hdr_t *mesg;
+ int i;
+ int len;
+ clock_t timer;
+ int num_trials = 1000000;
+ uint32_t ssrc = policy->ssrc.value;
+ err_status_t status;
+
+ /*
+ * allocate and initialize an srtp session
+ */
+ status = srtp_create(&srtp, policy);
+ if (status) {
+ printf("error: srtp_create() failed with error code %d\n", status);
+ exit(1);
+ }
+
+ mesg = srtp_create_test_packet(msg_len_octets, ssrc);
+ if (mesg == NULL)
+ return 0.0; /* indicate failure by returning zero */
+
+ len = msg_len_octets;
+ srtp_protect(srtp, (srtp_hdr_t *)mesg, &len);
+
+ timer = clock();
+ for (i=0; i < num_trials; i++) {
+ len = msg_len_octets;
+ srtp_unprotect(srtp, (srtp_hdr_t *)mesg, &len);
+ }
+ timer = clock() - timer;
+
+ free(mesg);
+
+ return (double) num_trials * CLOCKS_PER_SEC / timer;
+}
+
+
+void
+err_check(err_status_t s) {
+ if (s == err_status_ok)
+ return;
+ else
+ fprintf(stderr, "error: unexpected srtp failure (code %d)\n", s);
+ exit (1);
+}
+
+err_status_t
+srtp_test(const srtp_policy_t *policy) {
+ int i;
+ srtp_t srtp_sender;
+ srtp_t srtp_rcvr;
+ err_status_t status = err_status_ok;
+ srtp_hdr_t *hdr, *hdr2;
+ uint8_t hdr_enc[64];
+ uint8_t *pkt_end;
+ int msg_len_octets, msg_len_enc;
+ int len;
+ int tag_length = policy->rtp.auth_tag_len;
+ uint32_t ssrc;
+ srtp_policy_t *rcvr_policy;
+
+ err_check(srtp_create(&srtp_sender, policy));
+
+ /* print out policy */
+ err_check(srtp_session_print_policy(srtp_sender));
+
+ /*
+ * initialize data buffer, using the ssrc in the policy unless that
+ * value is a wildcard, in which case we'll just use an arbitrary
+ * one
+ */
+ if (policy->ssrc.type != ssrc_specific)
+ ssrc = 0xdecafbad;
+ else
+ ssrc = policy->ssrc.value;
+ msg_len_octets = 28;
+ hdr = srtp_create_test_packet(msg_len_octets, ssrc);
+
+ if (hdr == NULL)
+ return err_status_alloc_fail;
+ hdr2 = srtp_create_test_packet(msg_len_octets, ssrc);
+ if (hdr2 == NULL) {
+ free(hdr);
+ return err_status_alloc_fail;
+ }
+
+ /* set message length */
+ len = msg_len_octets;
+
+ debug_print(mod_driver, "before protection:\n%s",
+ srtp_packet_to_string(hdr, len));
+
+#if PRINT_REFERENCE_PACKET
+ debug_print(mod_driver, "reference packet before protection:\n%s",
+ octet_string_hex_string((uint8_t *)hdr, len));
+#endif
+ err_check(srtp_protect(srtp_sender, hdr, &len));
+
+ debug_print(mod_driver, "after protection:\n%s",
+ srtp_packet_to_string(hdr, len));
+#if PRINT_REFERENCE_PACKET
+ debug_print(mod_driver, "after protection:\n%s",
+ octet_string_hex_string((uint8_t *)hdr, len));
+#endif
+
+ /* save protected message and length */
+ memcpy(hdr_enc, hdr, len);
+ msg_len_enc = len;
+
+ /*
+ * check for overrun of the srtp_protect() function
+ *
+ * The packet is followed by a value of 0xfffff; if the value of the
+ * data following the packet is different, then we know that the
+ * protect function is overwriting the end of the packet.
+ */
+ pkt_end = (uint8_t *)hdr + sizeof(srtp_hdr_t)
+ + msg_len_octets + tag_length;
+ for (i = 0; i < 4; i++)
+ if (pkt_end[i] != 0xff) {
+ fprintf(stdout, "overwrite in srtp_protect() function "
+ "(expected %x, found %x in trailing octet %d)\n",
+ 0xff, ((uint8_t *)hdr)[i], i);
+ free(hdr);
+ free(hdr2);
+ return err_status_algo_fail;
+ }
+
+ /*
+ * if the policy includes confidentiality, check that ciphertext is
+ * different than plaintext
+ *
+ * Note that this check will give false negatives, with some small
+ * probability, especially if the packets are short. For that
+ * reason, we skip this check if the plaintext is less than four
+ * octets long.
+ */
+ if ((policy->rtp.sec_serv & sec_serv_conf) && (msg_len_octets >= 4)) {
+ printf("testing that ciphertext is distinct from plaintext...");
+ status = err_status_algo_fail;
+ for (i=12; i < msg_len_octets+12; i++)
+ if (((uint8_t *)hdr)[i] != ((uint8_t *)hdr2)[i]) {
+ status = err_status_ok;
+ }
+ if (status) {
+ printf("failed\n");
+ free(hdr);
+ free(hdr2);
+ return status;
+ }
+ printf("passed\n");
+ }
+
+ /*
+ * if the policy uses a 'wildcard' ssrc, then we need to make a copy
+ * of the policy that changes the direction to inbound
+ *
+ * we always copy the policy into the rcvr_policy, since otherwise
+ * the compiler would fret about the constness of the policy
+ */
+ rcvr_policy = (srtp_policy_t*) malloc(sizeof(srtp_policy_t));
+ if (rcvr_policy == NULL)
+ return err_status_alloc_fail;
+ memcpy(rcvr_policy, policy, sizeof(srtp_policy_t));
+ if (policy->ssrc.type == ssrc_any_outbound) {
+ rcvr_policy->ssrc.type = ssrc_any_inbound;
+ }
+
+ err_check(srtp_create(&srtp_rcvr, rcvr_policy));
+
+ err_check(srtp_unprotect(srtp_rcvr, hdr, &len));
+
+ debug_print(mod_driver, "after unprotection:\n%s",
+ srtp_packet_to_string(hdr, len));
+
+ /* verify that the unprotected packet matches the origial one */
+ for (i=0; i < msg_len_octets; i++)
+ if (((uint8_t *)hdr)[i] != ((uint8_t *)hdr2)[i]) {
+ fprintf(stdout, "mismatch at octet %d\n", i);
+ status = err_status_algo_fail;
+ }
+ if (status) {
+ free(hdr);
+ free(hdr2);
+ return status;
+ }
+
+ /*
+ * if the policy includes authentication, then test for false positives
+ */
+ if (policy->rtp.sec_serv & sec_serv_auth) {
+ char *data = ((char *)hdr) + 12;
+
+ printf("testing for false positives in replay check...");
+
+ /* set message length */
+ len = msg_len_enc;
+
+ /* unprotect a second time - should fail with a replay error */
+ status = srtp_unprotect(srtp_rcvr, hdr_enc, &len);
+ if (status != err_status_replay_fail) {
+ printf("failed with error code %d\n", status);
+ free(hdr);
+ free(hdr2);
+ return status;
+ } else {
+ printf("passed\n");
+ }
+
+ printf("testing for false positives in auth check...");
+
+ /* increment sequence number in header */
+ hdr->seq++;
+
+ /* set message length */
+ len = msg_len_octets;
+
+ /* apply protection */
+ err_check(srtp_protect(srtp_sender, hdr, &len));
+
+ /* flip bits in packet */
+ data[0] ^= 0xff;
+
+ /* unprotect, and check for authentication failure */
+ status = srtp_unprotect(srtp_rcvr, hdr, &len);
+ if (status != err_status_auth_fail) {
+ printf("failed\n");
+ free(hdr);
+ free(hdr2);
+ return status;
+ } else {
+ printf("passed\n");
+ }
+
+ }
+
+ err_check(srtp_dealloc(srtp_sender));
+ err_check(srtp_dealloc(srtp_rcvr));
+
+ free(hdr);
+ free(hdr2);
+ return err_status_ok;
+}
+
+
+err_status_t
+srtcp_test(const srtp_policy_t *policy) {
+ int i;
+ srtp_t srtcp_sender;
+ srtp_t srtcp_rcvr;
+ err_status_t status = err_status_ok;
+ srtp_hdr_t *hdr, *hdr2;
+ uint8_t hdr_enc[64];
+ uint8_t *pkt_end;
+ int msg_len_octets, msg_len_enc;
+ int len;
+ int tag_length = policy->rtp.auth_tag_len;
+ uint32_t ssrc;
+ srtp_policy_t *rcvr_policy;
+
+ err_check(srtp_create(&srtcp_sender, policy));
+
+ /* print out policy */
+ err_check(srtp_session_print_policy(srtcp_sender));
+
+ /*
+ * initialize data buffer, using the ssrc in the policy unless that
+ * value is a wildcard, in which case we'll just use an arbitrary
+ * one
+ */
+ if (policy->ssrc.type != ssrc_specific)
+ ssrc = 0xdecafbad;
+ else
+ ssrc = policy->ssrc.value;
+ msg_len_octets = 28;
+ hdr = srtp_create_test_packet(msg_len_octets, ssrc);
+
+ if (hdr == NULL)
+ return err_status_alloc_fail;
+ hdr2 = srtp_create_test_packet(msg_len_octets, ssrc);
+ if (hdr2 == NULL) {
+ free(hdr);
+ return err_status_alloc_fail;
+ }
+
+ /* set message length */
+ len = msg_len_octets;
+
+ debug_print(mod_driver, "before protection:\n%s",
+ srtp_packet_to_string(hdr, len));
+
+#if PRINT_REFERENCE_PACKET
+ debug_print(mod_driver, "reference packet before protection:\n%s",
+ octet_string_hex_string((uint8_t *)hdr, len));
+#endif
+ err_check(srtp_protect_rtcp(srtcp_sender, hdr, &len));
+
+ debug_print(mod_driver, "after protection:\n%s",
+ srtp_packet_to_string(hdr, len));
+#if PRINT_REFERENCE_PACKET
+ debug_print(mod_driver, "after protection:\n%s",
+ octet_string_hex_string((uint8_t *)hdr, len));
+#endif
+
+ /* save protected message and length */
+ memcpy(hdr_enc, hdr, len);
+ msg_len_enc = len;
+
+ /*
+ * check for overrun of the srtp_protect() function
+ *
+ * The packet is followed by a value of 0xfffff; if the value of the
+ * data following the packet is different, then we know that the
+ * protect function is overwriting the end of the packet.
+ */
+ pkt_end = (uint8_t *)hdr + sizeof(srtp_hdr_t)
+ + msg_len_octets + tag_length;
+ for (i = 0; i < 4; i++)
+ if (pkt_end[i] != 0xff) {
+ fprintf(stdout, "overwrite in srtp_protect_rtcp() function "
+ "(expected %x, found %x in trailing octet %d)\n",
+ 0xff, ((uint8_t *)hdr)[i], i);
+ free(hdr);
+ free(hdr2);
+ return err_status_algo_fail;
+ }
+
+ /*
+ * if the policy includes confidentiality, check that ciphertext is
+ * different than plaintext
+ *
+ * Note that this check will give false negatives, with some small
+ * probability, especially if the packets are short. For that
+ * reason, we skip this check if the plaintext is less than four
+ * octets long.
+ */
+ if ((policy->rtp.sec_serv & sec_serv_conf) && (msg_len_octets >= 4)) {
+ printf("testing that ciphertext is distinct from plaintext...");
+ status = err_status_algo_fail;
+ for (i=12; i < msg_len_octets+12; i++)
+ if (((uint8_t *)hdr)[i] != ((uint8_t *)hdr2)[i]) {
+ status = err_status_ok;
+ }
+ if (status) {
+ printf("failed\n");
+ free(hdr);
+ free(hdr2);
+ return status;
+ }
+ printf("passed\n");
+ }
+
+ /*
+ * if the policy uses a 'wildcard' ssrc, then we need to make a copy
+ * of the policy that changes the direction to inbound
+ *
+ * we always copy the policy into the rcvr_policy, since otherwise
+ * the compiler would fret about the constness of the policy
+ */
+ rcvr_policy = (srtp_policy_t*) malloc(sizeof(srtp_policy_t));
+ if (rcvr_policy == NULL)
+ return err_status_alloc_fail;
+ memcpy(rcvr_policy, policy, sizeof(srtp_policy_t));
+ if (policy->ssrc.type == ssrc_any_outbound) {
+ rcvr_policy->ssrc.type = ssrc_any_inbound;
+ }
+
+ err_check(srtp_create(&srtcp_rcvr, rcvr_policy));
+
+ err_check(srtp_unprotect_rtcp(srtcp_rcvr, hdr, &len));
+
+ debug_print(mod_driver, "after unprotection:\n%s",
+ srtp_packet_to_string(hdr, len));
+
+ /* verify that the unprotected packet matches the origial one */
+ for (i=0; i < msg_len_octets; i++)
+ if (((uint8_t *)hdr)[i] != ((uint8_t *)hdr2)[i]) {
+ fprintf(stdout, "mismatch at octet %d\n", i);
+ status = err_status_algo_fail;
+ }
+ if (status) {
+ free(hdr);
+ free(hdr2);
+ return status;
+ }
+
+ /*
+ * if the policy includes authentication, then test for false positives
+ */
+ if (policy->rtp.sec_serv & sec_serv_auth) {
+ char *data = ((char *)hdr) + 12;
+
+ printf("testing for false positives in replay check...");
+
+ /* set message length */
+ len = msg_len_enc;
+
+ /* unprotect a second time - should fail with a replay error */
+ status = srtp_unprotect_rtcp(srtcp_rcvr, hdr_enc, &len);
+ if (status != err_status_replay_fail) {
+ printf("failed with error code %d\n", status);
+ free(hdr);
+ free(hdr2);
+ return status;
+ } else {
+ printf("passed\n");
+ }
+
+ printf("testing for false positives in auth check...");
+
+ /* increment sequence number in header */
+ hdr->seq++;
+
+ /* set message length */
+ len = msg_len_octets;
+
+ /* apply protection */
+ err_check(srtp_protect_rtcp(srtcp_sender, hdr, &len));
+
+ /* flip bits in packet */
+ data[0] ^= 0xff;
+
+ /* unprotect, and check for authentication failure */
+ status = srtp_unprotect_rtcp(srtcp_rcvr, hdr, &len);
+ if (status != err_status_auth_fail) {
+ printf("failed\n");
+ free(hdr);
+ free(hdr2);
+ return status;
+ } else {
+ printf("passed\n");
+ }
+
+ }
+
+ err_check(srtp_dealloc(srtcp_sender));
+ err_check(srtp_dealloc(srtcp_rcvr));
+
+ free(hdr);
+ free(hdr2);
+ return err_status_ok;
+}
+
+
+err_status_t
+srtp_session_print_policy(srtp_t srtp) {
+ char *serv_descr[4] = {
+ "none",
+ "confidentiality",
+ "authentication",
+ "confidentiality and authentication"
+ };
+ char *direction[3] = {
+ "unknown",
+ "outbound",
+ "inbound"
+ };
+ srtp_stream_t stream;
+
+ /* sanity checking */
+ if (srtp == NULL)
+ return err_status_fail;
+
+ /* if there's a template stream, print it out */
+ if (srtp->stream_template != NULL) {
+ stream = srtp->stream_template;
+ printf("# SSRC: any %s\r\n"
+ "# rtp cipher: %s\r\n"
+ "# rtp auth: %s\r\n"
+ "# rtp services: %s\r\n"
+ "# rtcp cipher: %s\r\n"
+ "# rtcp auth: %s\r\n"
+ "# rtcp services: %s\r\n",
+ direction[stream->direction],
+ stream->rtp_cipher->type->description,
+ stream->rtp_auth->type->description,
+ serv_descr[stream->rtp_services],
+ stream->rtcp_cipher->type->description,
+ stream->rtcp_auth->type->description,
+ serv_descr[stream->rtcp_services]);
+ }
+
+ /* loop over streams in session, printing the policy of each */
+ stream = srtp->stream_list;
+ while (stream != NULL) {
+ if (stream->rtp_services > sec_serv_conf_and_auth)
+ return err_status_bad_param;
+
+ printf("# SSRC: 0x%08x\r\n"
+ "# rtp cipher: %s\r\n"
+ "# rtp auth: %s\r\n"
+ "# rtp services: %s\r\n"
+ "# rtcp cipher: %s\r\n"
+ "# rtcp auth: %s\r\n"
+ "# rtcp services: %s\r\n",
+ stream->ssrc,
+ stream->rtp_cipher->type->description,
+ stream->rtp_auth->type->description,
+ serv_descr[stream->rtp_services],
+ stream->rtcp_cipher->type->description,
+ stream->rtcp_auth->type->description,
+ serv_descr[stream->rtcp_services]);
+
+ /* advance to next stream in the list */
+ stream = stream->next;
+ }
+ return err_status_ok;
+}
+
+err_status_t
+srtp_print_policy(const srtp_policy_t *policy) {
+ err_status_t status;
+ srtp_t session;
+
+ status = srtp_create(&session, policy);
+ if (status)
+ return status;
+ status = srtp_session_print_policy(session);
+ if (status)
+ return status;
+ status = srtp_dealloc(session);
+ if (status)
+ return status;
+ return err_status_ok;
+}
+
+/*
+ * srtp_print_packet(...) is for debugging only
+ * it prints an RTP packet to the stdout
+ *
+ * note that this function is *not* threadsafe
+ */
+
+#include <stdio.h>
+
+#define MTU 2048
+
+char packet_string[MTU];
+
+char *
+srtp_packet_to_string(srtp_hdr_t *hdr, int pkt_octet_len) {
+ int octets_in_rtp_header = 12;
+ uint8_t *data = ((uint8_t *)hdr)+octets_in_rtp_header;
+ int hex_len = pkt_octet_len-octets_in_rtp_header;
+
+ /* sanity checking */
+ if ((hdr == NULL) || (pkt_octet_len > MTU))
+ return NULL;
+
+ /* write packet into string */
+ sprintf(packet_string,
+ "(s)rtp packet: {\n"
+ " version:\t%d\n"
+ " p:\t\t%d\n"
+ " x:\t\t%d\n"
+ " cc:\t\t%d\n"
+ " m:\t\t%d\n"
+ " pt:\t\t%x\n"
+ " seq:\t\t%x\n"
+ " ts:\t\t%x\n"
+ " ssrc:\t%x\n"
+ " data:\t%s\n"
+ "} (%d octets in total)\n",
+ hdr->version,
+ hdr->p,
+ hdr->x,
+ hdr->cc,
+ hdr->m,
+ hdr->pt,
+ hdr->seq,
+ hdr->ts,
+ hdr->ssrc,
+ octet_string_hex_string(data, hex_len),
+ pkt_octet_len);
+
+ return packet_string;
+}
+
+/*
+ * mips_estimate() is a simple function to estimate the number of
+ * instructions per second that the host can perform. note that this
+ * function can be grossly wrong; you may want to have a manual sanity
+ * check of its output!
+ *
+ * the 'ignore' pointer is there to convince the compiler to not just
+ * optimize away the function
+ */
+
+double
+mips_estimate(int num_trials, int *ignore) {
+ clock_t t;
+ int i, sum;
+
+ sum = 0;
+ t = clock();
+ for (i=0; i<num_trials; i++)
+ sum += i;
+ t = clock() - t;
+
+/* printf("%d\n", sum); */
+ *ignore = sum;
+
+ return (double) num_trials * CLOCKS_PER_SEC / t;
+}
+
+
+/*
+ * srtp_validate() verifies the correctness of libsrtp by comparing
+ * some computed packets against some pre-computed reference values.
+ * These packets were made with the default SRTP policy.
+ */
+
+
+err_status_t
+srtp_validate() {
+ unsigned char test_key[30] = {
+ 0xe1, 0xf9, 0x7a, 0x0d, 0x3e, 0x01, 0x8b, 0xe0,
+ 0xd6, 0x4f, 0xa3, 0x2c, 0x06, 0xde, 0x41, 0x39,
+ 0x0e, 0xc6, 0x75, 0xad, 0x49, 0x8a, 0xfe, 0xeb,
+ 0xb6, 0x96, 0x0b, 0x3a, 0xab, 0xe6
+ };
+ uint8_t srtp_plaintext_ref[28] = {
+ 0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
+ 0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab,
+ 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
+ 0xab, 0xab, 0xab, 0xab
+ };
+ uint8_t srtp_plaintext[38] = {
+ 0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
+ 0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab,
+ 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
+ 0xab, 0xab, 0xab, 0xab, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ uint8_t srtp_ciphertext[38] = {
+ 0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
+ 0xca, 0xfe, 0xba, 0xbe, 0x4e, 0x55, 0xdc, 0x4c,
+ 0xe7, 0x99, 0x78, 0xd8, 0x8c, 0xa4, 0xd2, 0x15,
+ 0x94, 0x9d, 0x24, 0x02, 0xb7, 0x8d, 0x6a, 0xcc,
+ 0x99, 0xea, 0x17, 0x9b, 0x8d, 0xbb
+ };
+ srtp_t srtp_snd, srtp_recv;
+ err_status_t status;
+ int len;
+ srtp_policy_t policy;
+
+ /*
+ * create a session with a single stream using the default srtp
+ * policy and with the SSRC value 0xcafebabe
+ */
+ crypto_policy_set_rtp_default(&policy.rtp);
+ crypto_policy_set_rtcp_default(&policy.rtcp);
+ policy.ssrc.type = ssrc_specific;
+ policy.ssrc.value = 0xcafebabe;
+ policy.key = test_key;
+ policy.next = NULL;
+
+ status = srtp_create(&srtp_snd, &policy);
+ if (status)
+ return status;
+
+ /*
+ * protect plaintext, then compare with ciphertext
+ */
+ len = 28;
+ status = srtp_protect(srtp_snd, srtp_plaintext, &len);
+ if (status || (len != 38))
+ return err_status_fail;
+
+ debug_print(mod_driver, "ciphertext:\n %s",
+ octet_string_hex_string(srtp_plaintext, len));
+ debug_print(mod_driver, "ciphertext reference:\n %s",
+ octet_string_hex_string(srtp_ciphertext, len));
+
+ if (octet_string_is_eq(srtp_plaintext, srtp_ciphertext, len))
+ return err_status_fail;
+
+ /*
+ * create a receiver session context comparable to the one created
+ * above - we need to do this so that the replay checking doesn't
+ * complain
+ */
+ status = srtp_create(&srtp_recv, &policy);
+ if (status)
+ return status;
+
+ /*
+ * unprotect ciphertext, then compare with plaintext
+ */
+ status = srtp_unprotect(srtp_recv, srtp_ciphertext, &len);
+ if (status || (len != 28))
+ return status;
+
+ if (octet_string_is_eq(srtp_ciphertext, srtp_plaintext_ref, len))
+ return err_status_fail;
+
+ return err_status_ok;
+}
+
+
+err_status_t
+srtp_create_big_policy(srtp_policy_t **list) {
+ extern const srtp_policy_t *policy_array[];
+ srtp_policy_t *p, *tmp;
+ int i = 0;
+ uint32_t ssrc = 0;
+
+ /* sanity checking */
+ if ((list == NULL) || (policy_array[0] == NULL))
+ return err_status_bad_param;
+
+ /*
+ * loop over policy list, mallocing a new list and copying values
+ * into it (and incrementing the SSRC value as we go along)
+ */
+ tmp = NULL;
+ while (policy_array[i] != NULL) {
+ p = (srtp_policy_t*) malloc(sizeof(srtp_policy_t));
+ if (p == NULL)
+ return err_status_bad_param;
+ memcpy(p, policy_array[i], sizeof(srtp_policy_t));
+ p->ssrc.type = ssrc_specific;
+ p->ssrc.value = ssrc++;
+ p->next = tmp;
+ tmp = p;
+ i++;
+ }
+ *list = p;
+
+ return err_status_ok;
+}
+
+err_status_t
+srtp_test_remove_stream() {
+ err_status_t status;
+ srtp_policy_t *policy_list;
+ srtp_t session;
+ srtp_stream_t stream;
+ /*
+ * srtp_get_stream() is a libSRTP internal function that we declare
+ * here so that we can use it to verify the correct operation of the
+ * library
+ */
+ extern srtp_stream_t srtp_get_stream(srtp_t srtp, uint32_t ssrc);
+
+
+ status = srtp_create_big_policy(&policy_list);
+ if (status)
+ return status;
+
+ status = srtp_create(&session, policy_list);
+ if (status)
+ return status;
+
+ /*
+ * check for false positives by trying to remove a stream that's not
+ * in the session
+ */
+ status = srtp_remove_stream(session, htonl(0xaaaaaaaa));
+ if (status != err_status_no_ctx)
+ return err_status_fail;
+
+ /*
+ * check for false negatives by removing stream 0x1, then
+ * searching for streams 0x0 and 0x2
+ */
+ status = srtp_remove_stream(session, htonl(0x1));
+ if (status != err_status_ok)
+ return err_status_fail;
+ stream = srtp_get_stream(session, htonl(0x0));
+ if (stream == NULL)
+ return err_status_fail;
+ stream = srtp_get_stream(session, htonl(0x2));
+ if (stream == NULL)
+ return err_status_fail;
+
+ return err_status_ok;
+}
+
+/*
+ * srtp policy definitions - these definitions are used above
+ */
+
+unsigned char test_key[30] = {
+ 0xe1, 0xf9, 0x7a, 0x0d, 0x3e, 0x01, 0x8b, 0xe0,
+ 0xd6, 0x4f, 0xa3, 0x2c, 0x06, 0xde, 0x41, 0x39,
+ 0x0e, 0xc6, 0x75, 0xad, 0x49, 0x8a, 0xfe, 0xeb,
+ 0xb6, 0x96, 0x0b, 0x3a, 0xab, 0xe6
+};
+
+
+const srtp_policy_t default_policy = {
+ { ssrc_any_outbound, 0 }, /* SSRC */
+ { /* SRTP policy */
+ AES_128_ICM, /* cipher type */
+ 30, /* cipher key length in octets */
+ HMAC_SHA1, /* authentication func type */
+ 16, /* auth key length in octets */
+ 10, /* auth tag length in octets */
+ sec_serv_conf_and_auth /* security services flag */
+ },
+ { /* SRTCP policy */
+ AES_128_ICM, /* cipher type */
+ 30, /* cipher key length in octets */
+ HMAC_SHA1, /* authentication func type */
+ 16, /* auth key length in octets */
+ 10, /* auth tag length in octets */
+ sec_serv_conf_and_auth /* security services flag */
+ },
+ test_key,
+ NULL
+};
+
+const srtp_policy_t aes_tmmh_policy = {
+ { ssrc_any_outbound, 0 }, /* SSRC */
+ {
+ AES_128_ICM, /* cipher type */
+ 30, /* cipher key length in octets */
+ UST_TMMHv2, /* authentication func type */
+ 94, /* auth key length in octets */
+ 4, /* auth tag length in octets */
+ sec_serv_conf_and_auth /* security services flag */
+ },
+ {
+ AES_128_ICM, /* cipher type */
+ 30, /* cipher key length in octets */
+ UST_TMMHv2, /* authentication func type */
+ 94, /* auth key length in octets */
+ 4, /* auth tag length in octets */
+ sec_serv_conf_and_auth /* security services flag */
+ },
+ test_key,
+ NULL
+};
+
+const srtp_policy_t tmmh_only_policy = {
+ { ssrc_any_outbound, 0 }, /* SSRC */
+ {
+ AES_128_ICM, /* cipher type */
+ 30, /* cipher key length in octets */
+ UST_TMMHv2, /* authentication func type */
+ 94, /* auth key length in octets */
+ 4, /* auth tag length in octets */
+ sec_serv_auth /* security services flag */
+ },
+ {
+ AES_128_ICM, /* cipher type */
+ 30, /* cipher key length in octets */
+ UST_TMMHv2, /* authentication func type */
+ 94, /* auth key length in octets */
+ 4, /* auth tag length in octets */
+ sec_serv_auth /* security services flag */
+ },
+ test_key,
+ NULL
+};
+
+const srtp_policy_t aes_only_policy = {
+ { ssrc_any_outbound, 0 }, /* SSRC */
+ {
+ AES_128_ICM, /* cipher type */
+ 30, /* cipher key length in octets */
+ NULL_AUTH, /* authentication func type */
+ 0, /* auth key length in octets */
+ 0, /* auth tag length in octets */
+ sec_serv_conf /* security services flag */
+ },
+ {
+ AES_128_ICM, /* cipher type */
+ 30, /* cipher key length in octets */
+ NULL_AUTH, /* authentication func type */
+ 0, /* auth key length in octets */
+ 0, /* auth tag length in octets */
+ sec_serv_conf /* security services flag */
+ },
+ test_key,
+ NULL
+};
+
+const srtp_policy_t hmac_only_policy = {
+ { ssrc_any_outbound, 0 }, /* SSRC */
+ {
+ NULL_CIPHER, /* cipher type */
+ 0, /* cipher key length in octets */
+ HMAC_SHA1, /* authentication func type */
+ 20, /* auth key length in octets */
+ 4, /* auth tag length in octets */
+ sec_serv_auth /* security services flag */
+ },
+ {
+ NULL_CIPHER, /* cipher type */
+ 0, /* cipher key length in octets */
+ HMAC_SHA1, /* authentication func type */
+ 20, /* auth key length in octets */
+ 4, /* auth tag length in octets */
+ sec_serv_auth /* security services flag */
+ },
+ test_key,
+ NULL
+};
+
+const srtp_policy_t null_policy = {
+ { ssrc_any_outbound, 0 }, /* SSRC */
+ {
+ NULL_CIPHER, /* cipher type */
+ 0, /* cipher key length in octets */
+ NULL_AUTH, /* authentication func type */
+ 0, /* auth key length in octets */
+ 0, /* auth tag length in octets */
+ sec_serv_none /* security services flag */
+ },
+ {
+ NULL_CIPHER, /* cipher type */
+ 0, /* cipher key length in octets */
+ NULL_AUTH, /* authentication func type */
+ 0, /* auth key length in octets */
+ 0, /* auth tag length in octets */
+ sec_serv_none /* security services flag */
+ },
+ test_key,
+ NULL
+};
+
+
+/*
+ * an array of pointers to the policies listed above
+ *
+ * This array is used to test various aspects of libSRTP for
+ * different cryptographic policies. The order of the elements
+ * matters - the timing test generates output that can be used
+ * in a plot (see the gnuplot script file 'timing'). If you
+ * add to this list, you should do it at the end.
+ */
+
+#define USE_TMMH 0
+
+const srtp_policy_t *
+policy_array[] = {
+ &hmac_only_policy,
+#if USE_TMMH
+ &tmmh_only_policy,
+#endif
+ &aes_only_policy,
+#if USE_TMMH
+ &aes_tmmh_policy,
+#endif
+ &default_policy,
+ &null_policy,
+ NULL
+};
+
+const srtp_policy_t wildcard_policy = {
+ { ssrc_any_outbound, 0 }, /* SSRC */
+ { /* SRTP policy */
+ AES_128_ICM, /* cipher type */
+ 30, /* cipher key length in octets */
+ HMAC_SHA1, /* authentication func type */
+ 16, /* auth key length in octets */
+ 10, /* auth tag length in octets */
+ sec_serv_conf_and_auth /* security services flag */
+ },
+ { /* SRTCP policy */
+ AES_128_ICM, /* cipher type */
+ 30, /* cipher key length in octets */
+ HMAC_SHA1, /* authentication func type */
+ 16, /* auth key length in octets */
+ 10, /* auth tag length in octets */
+ sec_serv_conf_and_auth /* security services flag */
+ },
+ test_key,
+ NULL
+};