diff options
author | Erwin Nindl <nine@wirdorange.org> | 2007-06-22 13:59:20 +0000 |
---|---|---|
committer | Erwin Nindl <nine@wirdorange.org> | 2007-06-22 13:59:20 +0000 |
commit | 0275479cb56c7f562f3513fef66c83fc44d1d8c9 (patch) | |
tree | f6fbb703cebf62d18b05e2a5e7591ac08c5b6702 /srtp/test | |
parent | satp internet draft 00 final ietf version (diff) |
added libsrtp to svn
Diffstat (limited to 'srtp/test')
-rw-r--r-- | srtp/test/.cvsignore | 12 | ||||
-rw-r--r-- | srtp/test/CVS/Entries | 12 | ||||
-rw-r--r-- | srtp/test/CVS/Repository | 1 | ||||
-rw-r--r-- | srtp/test/CVS/Root | 1 | ||||
-rwxr-xr-x | srtp/test/dtls_srtp_driver | bin | 0 -> 98864 bytes | |||
-rw-r--r-- | srtp/test/dtls_srtp_driver.c | 245 | ||||
-rw-r--r-- | srtp/test/getopt_s.c | 112 | ||||
-rw-r--r-- | srtp/test/lfsr.c | 310 | ||||
-rwxr-xr-x | srtp/test/rdbx_driver | bin | 0 -> 22096 bytes | |||
-rw-r--r-- | srtp/test/rdbx_driver.c | 306 | ||||
-rwxr-xr-x | srtp/test/replay_driver | bin | 0 -> 20687 bytes | |||
-rw-r--r-- | srtp/test/replay_driver.c | 209 | ||||
-rwxr-xr-x | srtp/test/roc_driver | bin | 0 -> 20511 bytes | |||
-rw-r--r-- | srtp/test/roc_driver.c | 165 | ||||
-rw-r--r-- | srtp/test/rtp.c | 167 | ||||
-rwxr-xr-x | srtp/test/rtpw | bin | 0 -> 103664 bytes | |||
-rw-r--r-- | srtp/test/rtpw.c | 519 | ||||
-rwxr-xr-x | srtp/test/rtpw_test.sh | 77 | ||||
-rwxr-xr-x | srtp/test/srtp_driver | bin | 0 -> 117098 bytes | |||
-rw-r--r-- | srtp/test/srtp_driver.c | 1491 |
20 files changed, 3627 insertions, 0 deletions
diff --git a/srtp/test/.cvsignore b/srtp/test/.cvsignore new file mode 100644 index 0000000..2b9f0e7 --- /dev/null +++ b/srtp/test/.cvsignore @@ -0,0 +1,12 @@ +aes_calc +cipher_driver +datatypes_driver +kernel_driver +rand_gen +rdbx_driver +replay_driver +roc_driver +rtpw +sha1_driver +srtp_driver +stat_driver diff --git a/srtp/test/CVS/Entries b/srtp/test/CVS/Entries new file mode 100644 index 0000000..1e3e6ac --- /dev/null +++ b/srtp/test/CVS/Entries @@ -0,0 +1,12 @@ +/.cvsignore/1.1/Thu Sep 29 11:59:01 2005// +/dtls_srtp_driver.c/1.3/Mon Jul 17 20:41:22 2006// +/getopt_s.c/1.1/Mon Jul 17 20:41:22 2006// +/lfsr.c/1.1.1.1/Wed Sep 21 22:51:46 2005// +/rdbx_driver.c/1.4/Mon Jul 17 20:41:22 2006// +/replay_driver.c/1.5/Thu Jun 8 17:00:30 2006// +/roc_driver.c/1.3/Thu Jun 8 17:00:30 2006// +/rtp.c/1.7/Thu Jul 13 19:04:53 2006// +/rtpw.c/1.12/Mon Jul 17 20:41:22 2006// +/rtpw_test.sh/1.1/Tue Jun 13 15:17:57 2006// +/srtp_driver.c/1.13/Mon Sep 18 13:41:35 2006// +D diff --git a/srtp/test/CVS/Repository b/srtp/test/CVS/Repository new file mode 100644 index 0000000..ef6b44c --- /dev/null +++ b/srtp/test/CVS/Repository @@ -0,0 +1 @@ +srtp/test diff --git a/srtp/test/CVS/Root b/srtp/test/CVS/Root new file mode 100644 index 0000000..05e15d8 --- /dev/null +++ b/srtp/test/CVS/Root @@ -0,0 +1 @@ +srtp.cvs.sourceforge.net:/cvsroot/srtp diff --git a/srtp/test/dtls_srtp_driver b/srtp/test/dtls_srtp_driver Binary files differnew file mode 100755 index 0000000..471706e --- /dev/null +++ b/srtp/test/dtls_srtp_driver diff --git a/srtp/test/dtls_srtp_driver.c b/srtp/test/dtls_srtp_driver.c new file mode 100644 index 0000000..a8eddc0 --- /dev/null +++ b/srtp/test/dtls_srtp_driver.c @@ -0,0 +1,245 @@ +/* + * dtls_srtp_driver.c + * + * test driver for DTLS-SRTP functions + * + * David 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 <stdio.h> /* for printf() */ +#include "getopt_s.h" /* for local getopt() */ +#include "srtp_priv.h" + +err_status_t +test_dtls_srtp(); + +srtp_hdr_t * +srtp_create_test_packet(int pkt_octet_len, uint32_t ssrc); + +void +usage(char *prog_name) { + printf("usage: %s [ -t ][ -c ][ -v ][-d <debug_module> ]* [ -l ]\n" + " -d <mod> turn on debugging module <mod>\n" + " -l list debugging modules\n", prog_name); + exit(1); +} + +int +main(int argc, char *argv[]) { + unsigned do_list_mods = 0; + char q; + err_status_t err; + + printf("dtls_srtp_driver\n"); + + /* initialize srtp library */ + err = srtp_init(); + if (err) { + printf("error: srtp init failed with error code %d\n", err); + exit(1); + } + + /* process input arguments */ + while (1) { + q = getopt_s(argc, argv, "ld:"); + if (q == -1) + break; + switch (q) { + case 'l': + do_list_mods = 1; + break; + case 'd': + err = crypto_kernel_set_debug_module(optarg_s, 1); + if (err) { + printf("error: set debug module (%s) failed\n", optarg_s); + exit(1); + } + break; + default: + usage(argv[0]); + } + } + + if (do_list_mods) { + err = crypto_kernel_list_debug_modules(); + if (err) { + printf("error: list of debug modules failed\n"); + exit(1); + } + } + + printf("testing dtls_srtp..."); + err = test_dtls_srtp(); + if (err) { + printf("\nerror (code %d)\n", err); + exit(1); + } + printf("passed\n"); + + return 0; +} + + +err_status_t +test_dtls_srtp() { + srtp_hdr_t *test_packet; + int test_packet_len = 80; + srtp_t s; + srtp_policy_t policy; + uint8_t key[SRTP_MAX_KEY_LEN]; + uint8_t salt[SRTP_MAX_KEY_LEN]; + unsigned int key_len, salt_len; + srtp_profile_t profile; + err_status_t err; + + /* create a 'null' SRTP session */ + err = srtp_create(&s, NULL); + if (err) + return err; + + /* + * verify that packet-processing functions behave properly - we + * expect that these functions will return err_status_no_ctx + */ + test_packet = srtp_create_test_packet(80, 0xa5a5a5a5); + if (test_packet == NULL) + return err_status_alloc_fail; + err = srtp_protect(s, test_packet, &test_packet_len); + if (err != err_status_no_ctx) { + printf("wrong return value from srtp_protect() (got code %d)\n", + err); + return err_status_fail; + } + err = srtp_unprotect(s, test_packet, &test_packet_len); + if (err != err_status_no_ctx) { + printf("wrong return value from srtp_unprotect() (got code %d)\n", + err); + return err_status_fail; + } + err = srtp_protect_rtcp(s, test_packet, &test_packet_len); + if (err != err_status_no_ctx) { + printf("wrong return value from srtp_protect_rtcp() (got code %d)\n", + err); + return err_status_fail; + } + err = srtp_unprotect_rtcp(s, test_packet, &test_packet_len); + if (err != err_status_no_ctx) { + printf("wrong return value from srtp_unprotect_rtcp() (got code %d)\n", + err); + return err_status_fail; + } + + + /* + * set keys to known values for testing + */ + profile = srtp_profile_aes128_cm_sha1_80; + key_len = srtp_profile_get_master_key_length(profile); + salt_len = srtp_profile_get_master_salt_length(profile); + memset(key, 0xff, key_len); + memset(salt, 0xee, salt_len); + append_salt_to_key(key, key_len, salt, salt_len); + policy.key = key; + + /* initialize SRTP policy from profile */ + err = crypto_policy_set_from_profile_for_rtp(&policy.rtp, profile); + if (err) return err; + err = crypto_policy_set_from_profile_for_rtcp(&policy.rtcp, profile); + if (err) return err; + policy.ssrc.type = ssrc_any_inbound; + policy.next = NULL; + + err = srtp_add_stream(s, &policy); + if (err) + return err; + + return err_status_ok; +} + + + +/* + * 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 = 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; +} diff --git a/srtp/test/getopt_s.c b/srtp/test/getopt_s.c new file mode 100644 index 0000000..243ad6e --- /dev/null +++ b/srtp/test/getopt_s.c @@ -0,0 +1,112 @@ +/* + * getopt.c + * + * a minimal implementation of the getopt() function, written so that + * test applications that use that function can run on non-POSIX + * platforms + * + */ +/* + * + * 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 <stdlib.h> /* for NULL */ + +int optind_s = 0; + +char *optarg_s; + +#define GETOPT_FOUND_WITHOUT_ARGUMENT 2 +#define GETOPT_FOUND_WITH_ARGUMENT 1 +#define GETOPT_NOT_FOUND 0 + +static int +getopt_check_character(char c, const char *string) { + unsigned int max_string_len = 128; + + while (*string != 0) { + if (max_string_len == 0) { + return '?'; + } + if (*string++ == c) { + if (*string == ':') { + return GETOPT_FOUND_WITH_ARGUMENT; + } else { + return GETOPT_FOUND_WITHOUT_ARGUMENT; + } + } + } + return GETOPT_NOT_FOUND; +} + +int +getopt_s(int argc, + char * const argv[], + const char *optstring) { + + + while (optind_s + 1 < argc) { + char *string; + + /* move 'string' on to next argument */ + optind_s++; + string = argv[optind_s]; + + if (string == NULL) + return '?'; /* NULL argument string */ + + if (string[0] != '-') + return -1; /* found an unexpected character */ + + switch(getopt_check_character(string[1], optstring)) { + case GETOPT_FOUND_WITH_ARGUMENT: + if (optind_s + 1 < argc) { + optind_s++; + optarg_s = argv[optind_s]; + return string[1]; + } else { + return '?'; /* argument missing */ + } + case GETOPT_FOUND_WITHOUT_ARGUMENT: + return string[1]; + case GETOPT_NOT_FOUND: + default: + return '?'; /* didn't find expected character */ + break; + } + } + + return -1; +} diff --git a/srtp/test/lfsr.c b/srtp/test/lfsr.c new file mode 100644 index 0000000..28ea02e --- /dev/null +++ b/srtp/test/lfsr.c @@ -0,0 +1,310 @@ +/* + * lfsr.c + * + */ + + +#include <stdio.h> +#include "datatypes.h" + +uint32_t +parity(uint32_t x) { + + x ^= (x >> 16); + x ^= (x >> 8); + x ^= (x >> 4); + x ^= (x >> 2); + x ^= (x >> 1); + + return x & 1; +} + + +/* typedef struct { */ +/* uint32_t register[8]; */ +/* } lfsr_t; */ + +void +compute_period(uint32_t feedback_polynomial) { + int i; + v32_t lfsr; + v32_t mask; + + mask.value = feedback_polynomial; + lfsr.value = 1; + + printf("polynomial: %s\t", v32_bit_string(mask)); + + for (i=0; i < 256; i++) { +/* printf("%s\n", v32_bit_string(lfsr)); */ + if (parity(mask.value & lfsr.value)) + lfsr.value = ((lfsr.value << 1) | 1) & 0xff; + else + lfsr.value = (lfsr.value << 1) & 0xff; + + /* now halt if we're back at the initial state */ + if (lfsr.value == 1) { + printf("period: %d\n", i); + break; + } + } +} + +uint32_t poly0 = 223; + + +uint32_t polynomials[39] = { +31, +47, +55, +59, +61, +79, +87, +91, +103, +107, +109, +115, +117, +121, +143, +151, +157, +167, +171, +173, +179, +181, +185, +199, +203, +205, +211, +213, +227, +229, +233, +241, +127, +191, +223, +239, +247, +251, +253 +}; + +char binary_string[32]; + +char * +u32_bit_string(uint32_t x, unsigned int length) { + unsigned int mask; + int index; + + mask = 1 << length; + index = 0; + for (; mask > 0; mask >>= 1) + if ((x & mask) == 0) + binary_string[index++] = '0'; + else + binary_string[index++] = '1'; + + binary_string[index++] = 0; /* NULL terminate string */ + return binary_string; +} + +extern int octet_weight[256]; + +unsigned int +weight(uint32_t poly) { + int wt = 0; + + /* note: endian-ness makes no difference */ + wt += octet_weight[poly & 0xff]; + wt += octet_weight[(poly >> 8) & 0xff]; + wt += octet_weight[(poly >> 16) & 0xff]; + wt += octet_weight[(poly >> 24)]; + + return wt; +} + +#define MAX_PERIOD 65535 + +#define debug_print 0 + +int +period(uint32_t poly) { + int i; + uint32_t x; + + + /* set lfsr to 1 */ + x = 1; +#if debug_print + printf("%d:\t%s\n", 0, u32_bit_string(x,8)); +#endif + for (i=1; i < MAX_PERIOD; i++) { + if (x & 1) + x = (x >> 1) ^ poly; + else + x = (x >> 1); + +#if debug_print + /* print for a sanity check */ + printf("%d:\t%s\n", i, u32_bit_string(x,8)); +#endif + + /* check for return to original value */ + if (x == 1) + return i; + } + return i; +} + +/* + * weight distribution computes the weight distribution of the + * code generated by the polynomial poly + */ + +#define MAX_LEN 8 +#define MAX_WEIGHT (1 << MAX_LEN) + +int A[MAX_WEIGHT+1]; + +void +weight_distribution2(uint32_t poly, int *A) { + int i; + uint32_t x; + + /* zeroize array */ + for (i=0; i < MAX_WEIGHT+1; i++) + A[i] = 0; + + /* loop over all input sequences */ + + + /* set lfsr to 1 */ + x = 1; +#if debug_print + printf("%d:\t%s\n", 0, u32_bit_string(x,8)); +#endif + for (i=1; i < MAX_PERIOD; i++) { + if (x & 1) + x = (x >> 1) ^ poly; + else + x = (x >> 1); + +#if debug_print + /* print for a sanity check */ + printf("%d:\t%s\n", i, u32_bit_string(x,8)); +#endif + + /* increment weight */ + wt += (x & 1); + + /* check for return to original value */ + if (x == 1) + break; + } + + /* set zero */ + A[0] = 0; +} + + +void +weight_distribution(uint32_t poly, int *A) { + int i; + uint32_t x; + + /* zeroize array */ + for (i=0; i < MAX_WEIGHT+1; i++) + A[i] = 0; + + /* set lfsr to 1 */ + x = 1; +#if debug_print + printf("%d:\t%s\n", 0, u32_bit_string(x,8)); +#endif + for (i=1; i < MAX_PERIOD; i++) { + if (x & 1) + x = (x >> 1) ^ poly; + else + x = (x >> 1); + +#if debug_print + /* print for a sanity check */ + printf("%d:\t%s\n", i, u32_bit_string(x,8)); +#endif + + /* compute weight, increment proper element */ + A[weight(x)]++; + + /* check for return to original value */ + if (x == 1) + break; + } + + /* set zero */ + A[0] = 0; +} + + + + +int +main () { + + int i,j; + v32_t x; + v32_t p; + + /* originally 0xaf */ + p.value = 0x9; + + printf("polynomial: %s\tperiod: %d\n", + u32_bit_string(p.value,8), period(p.value)); + + /* compute weight distribution */ + weight_distribution(p.value, A); + + /* print weight distribution */ + for (i=0; i <= 8; i++) { + printf("A[%d]: %d\n", i, A[i]); + } + +#if 0 + for (i=0; i < 39; i++) { + printf("polynomial: %s\tperiod: %d\n", + u32_bit_string(polynomials[i],8), period(polynomials[i])); + + /* compute weight distribution */ + weight_distribution(p.value, A); + + /* print weight distribution */ + for (j=0; j <= 8; j++) { + printf("A[%d]: %d\n", j, A[j]); + } + } +#endif + + { + int bits = 8; + uint32_t y; + for (y=0; y < (1 << bits); y++) { + printf("polynomial: %s\tweight: %d\tperiod: %d\n", + u32_bit_string(y,bits), weight(y), period(y)); + + /* compute weight distribution */ + weight_distribution(y, A); + + /* print weight distribution */ + for (j=0; j <= 8; j++) { + printf("A[%d]: %d\n", j, A[j]); + } + } + } + + return 0; +} diff --git a/srtp/test/rdbx_driver b/srtp/test/rdbx_driver Binary files differnew file mode 100755 index 0000000..b98543d --- /dev/null +++ b/srtp/test/rdbx_driver diff --git a/srtp/test/rdbx_driver.c b/srtp/test/rdbx_driver.c new file mode 100644 index 0000000..7db67a2 --- /dev/null +++ b/srtp/test/rdbx_driver.c @@ -0,0 +1,306 @@ +/* + * rdbx_driver.c + * + * driver for the rdbx implementation (replay database with extended range) + * + * 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 <stdio.h> /* for printf() */ +#include "getopt_s.h" /* for local getopt() */ + +#include "rdbx.h" + +#ifdef ROC_TEST +#error "rdbx_t won't work with ROC_TEST - bitmask same size as seq_median" +#endif + +#include "ut_sim.h" + +err_status_t +test_replay_dbx(int num_trials); + +double +rdbx_check_adds_per_second(int num_trials); + +void +usage(char *prog_name) { + printf("usage: %s [ -t | -v ]\n", prog_name); + exit(255); +} + +int +main (int argc, char *argv[]) { + double rate; + err_status_t status; + char q; + unsigned do_timing_test = 0; + unsigned do_validation = 0; + + /* process input arguments */ + while (1) { + q = getopt_s(argc, argv, "tv"); + if (q == -1) + break; + switch (q) { + case 't': + do_timing_test = 1; + break; + case 'v': + do_validation = 1; + break; + default: + usage(argv[0]); + } + } + + printf("rdbx (replay database w/ extended range) test driver\n" + "David A. McGrew\n" + "Cisco Systems, Inc.\n"); + + if (!do_validation && !do_timing_test) + usage(argv[0]); + + if (do_validation) { + printf("testing rdbx_t...\n"); + + status = test_replay_dbx(1 << 12); + if (status) { + printf("failed\n"); + exit(1); + } + printf("passed\n"); + } + + if (do_timing_test) { + rate = rdbx_check_adds_per_second(1 << 18); + printf("rdbx_check/replay_adds per second: %e\n", rate); + } + + return 0; +} + +void +print_rdbx(rdbx_t *rdbx) { + printf("rdbx: {%llu, %s}\n", + (unsigned long long)(rdbx->index), v128_bit_string(&rdbx->bitmask)); +} + + +/* + * rdbx_check_add(rdbx, idx) checks a known-to-be-good idx against + * rdbx, then adds it. if a failure is detected (i.e., the check + * indicates that the value is already in rdbx) then + * err_status_algo_fail is returned. + * + */ + +err_status_t +rdbx_check_add(rdbx_t *rdbx, uint32_t idx) { + int delta; + xtd_seq_num_t est; + + delta = index_guess(&rdbx->index, &est, idx); + + if (rdbx_check(rdbx, delta) != err_status_ok) { + printf("replay_check failed at index %u\n", idx); + return err_status_algo_fail; + } + + /* + * in practice, we'd authenticate the packet containing idx, using + * the estimated value est, at this point + */ + + if (rdbx_add_index(rdbx, delta) != err_status_ok) { + printf("rdbx_add_index failed at index %u\n", idx); + return err_status_algo_fail; + } + + return err_status_ok; +} + +/* + * rdbx_check_expect_failure(rdbx_t *rdbx, uint32_t idx) + * + * checks that a sequence number idx is in the replay database + * and thus will be rejected + */ + +err_status_t +rdbx_check_expect_failure(rdbx_t *rdbx, uint32_t idx) { + int delta; + xtd_seq_num_t est; + err_status_t status; + + delta = index_guess(&rdbx->index, &est, idx); + + status = rdbx_check(rdbx, delta); + if (status == err_status_ok) { + printf("delta: %d ", delta); + printf("replay_check failed at index %u (false positive)\n", idx); + return err_status_algo_fail; + } + + return err_status_ok; +} + +err_status_t +rdbx_check_unordered(rdbx_t *rdbx, uint32_t idx) { + err_status_t rstat; + + rstat = rdbx_check(rdbx, idx); + if ((rstat != err_status_ok) && (rstat != err_status_replay_old)) { + printf("replay_check_unordered failed at index %u\n", idx); + return err_status_algo_fail; + } + return err_status_ok; +} + +#define MAX_IDX 160 + +err_status_t +test_replay_dbx(int num_trials) { + rdbx_t rdbx; + uint32_t idx, ircvd; + ut_connection utc; + err_status_t status; + int num_fp_trials; + + status = rdbx_init(&rdbx); + if (status) { + printf("replay_init failed with error code %d\n", status); + exit(1); + } + + /* + * test sequential insertion + */ + printf("\ttesting sequential insertion..."); + for (idx=0; idx < num_trials; idx++) { + status = rdbx_check_add(&rdbx, idx); + if (status) + return status; + } + printf("passed\n"); + + /* + * test for false positives by checking all of the index + * values which we've just added + * + * note that we limit the number of trials here, since allowing the + * rollover counter to roll over would defeat this test + */ + num_fp_trials = num_trials % 0x10000; + if (num_fp_trials == 0) { + printf("warning: no false positive tests performed\n"); + } + printf("\ttesting for false positives..."); + for (idx=0; idx < num_fp_trials; idx++) { + status = rdbx_check_expect_failure(&rdbx, idx); + if (status) + return status; + } + printf("passed\n"); + + /* re-initialize */ + if (rdbx_init(&rdbx) != err_status_ok) { + printf("replay_init failed\n"); + return err_status_init_fail; + } + + /* + * test non-sequential insertion + * + * this test covers only fase negatives, since the values returned + * by ut_next_index(...) are distinct + */ + ut_init(&utc); + + printf("\ttesting non-sequential insertion..."); + for (idx=0; idx < num_trials; idx++) { + ircvd = ut_next_index(&utc); + status = rdbx_check_unordered(&rdbx, ircvd); + if (status) + return status; + } + printf("passed\n"); + + return err_status_ok; +} + + + +#include <time.h> /* for clock() */ +#include <stdlib.h> /* for random() */ + +double +rdbx_check_adds_per_second(int num_trials) { + uint32_t i; + int delta; + rdbx_t rdbx; + xtd_seq_num_t est; + clock_t timer; + int failures; /* count number of failures */ + + if (rdbx_init(&rdbx) != err_status_ok) { + printf("replay_init failed\n"); + exit(1); + } + + failures = 0; + timer = clock(); + for(i=0; i < num_trials; i++) { + + delta = index_guess(&rdbx.index, &est, i); + + if (rdbx_check(&rdbx, delta) != err_status_ok) + ++failures; + else + if (rdbx_add_index(&rdbx, delta) != err_status_ok) + ++failures; + } + timer = clock() - timer; + + printf("number of failures: %d \n", failures); + + return (double) CLOCKS_PER_SEC * num_trials / timer; +} + diff --git a/srtp/test/replay_driver b/srtp/test/replay_driver Binary files differnew file mode 100755 index 0000000..e0d0b20 --- /dev/null +++ b/srtp/test/replay_driver diff --git a/srtp/test/replay_driver.c b/srtp/test/replay_driver.c new file mode 100644 index 0000000..369a77a --- /dev/null +++ b/srtp/test/replay_driver.c @@ -0,0 +1,209 @@ +/* + * replay_driver.c + * + * A driver for the replay_database implementation + * + * 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 <stdio.h> + +#include "rdb.h" +#include "ut_sim.h" + +/* + * num_trials defines the number of trials that are used in the + * validation functions below + */ + +unsigned num_trials = 1 << 16; + +err_status_t +test_rdb_db(void); + +double +rdb_check_adds_per_second(void); + +int +main (void) { + err_status_t err; + + printf("testing anti-replay database (rdb_t)...\n"); + err = test_rdb_db(); + if (err) { + printf("failed\n"); + exit(1); + } + printf("done\n"); + + printf("rdb_check/rdb_adds per second: %e\n", + rdb_check_adds_per_second()); + + return 0; +} + + +void +print_rdb(rdb_t *rdb) { + printf("rdb: {%u, %s}\n", rdb->window_start, v128_bit_string(&rdb->bitmask)); +} + +err_status_t +rdb_check_add(rdb_t *rdb, uint32_t idx) { + + if (rdb_check(rdb, idx) != err_status_ok) { + printf("rdb_check failed at index %u\n", idx); + return err_status_fail; + } + if (rdb_add_index(rdb, idx) != err_status_ok) { + printf("rdb_add_index failed at index %u\n", idx); + return err_status_fail; + } + + return err_status_ok; +} + +err_status_t +rdb_check_expect_failure(rdb_t *rdb, uint32_t idx) { + err_status_t err; + + err = rdb_check(rdb, idx); + if ((err != err_status_replay_old) && (err != err_status_replay_fail)) { + printf("rdb_check failed at index %u (false positive)\n", idx); + return err_status_fail; + } + + return err_status_ok; +} + +err_status_t +rdb_check_unordered(rdb_t *rdb, uint32_t idx) { + err_status_t rstat; + + /* printf("index: %u\n", idx); */ + rstat = rdb_check(rdb, idx); + if ((rstat != err_status_ok) && (rstat != err_status_replay_old)) { + printf("rdb_check_unordered failed at index %u\n", idx); + return rstat; + } + return err_status_ok; +} + +err_status_t +test_rdb_db() { + rdb_t rdb; + uint32_t idx, ircvd; + ut_connection utc; + err_status_t err; + + if (rdb_init(&rdb) != err_status_ok) { + printf("rdb_init failed\n"); + return err_status_init_fail; + } + + /* test sequential insertion */ + for (idx=0; idx < num_trials; idx++) { + err = rdb_check_add(&rdb, idx); + if (err) + return err; + } + + /* test for false positives */ + for (idx=0; idx < num_trials; idx++) { + err = rdb_check_expect_failure(&rdb, idx); + if (err) + return err; + } + + /* re-initialize */ + if (rdb_init(&rdb) != err_status_ok) { + printf("rdb_init failed\n"); + return err_status_fail; + } + + /* test non-sequential insertion */ + ut_init(&utc); + + for (idx=0; idx < num_trials; idx++) { + ircvd = ut_next_index(&utc); + err = rdb_check_unordered(&rdb, ircvd); + if (err) + return err; + } + + return err_status_ok; +} + +#include <time.h> /* for clock() */ +#include <stdlib.h> /* for random() */ + +#define REPLAY_NUM_TRIALS 10000000 + +double +rdb_check_adds_per_second(void) { + uint32_t i; + rdb_t rdb; + clock_t timer; + int failures; /* count number of failures */ + + if (rdb_init(&rdb) != err_status_ok) { + printf("rdb_init failed\n"); + exit(1); + } + + timer = clock(); + for(i=0; i < REPLAY_NUM_TRIALS; i+=3) { + if (rdb_check(&rdb, i+2) != err_status_ok) + ++failures; + if (rdb_add_index(&rdb, i+2) != err_status_ok) + ++failures; + if (rdb_check(&rdb, i+1) != err_status_ok) + ++failures; + if (rdb_add_index(&rdb, i+1) != err_status_ok) + ++failures; + if (rdb_check(&rdb, i) != err_status_ok) + ++failures; + if (rdb_add_index(&rdb, i) != err_status_ok) + ++failures; + } + timer = clock() - timer; + + return (double) CLOCKS_PER_SEC * REPLAY_NUM_TRIALS / timer; +} diff --git a/srtp/test/roc_driver b/srtp/test/roc_driver Binary files differnew file mode 100755 index 0000000..f013e90 --- /dev/null +++ b/srtp/test/roc_driver diff --git a/srtp/test/roc_driver.c b/srtp/test/roc_driver.c new file mode 100644 index 0000000..396c9a7 --- /dev/null +++ b/srtp/test/roc_driver.c @@ -0,0 +1,165 @@ +/* + * roc_driver.c + * + * test driver for rollover counter replay implementation + * + * 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 <stdio.h> + +/* + * defining ROC_TEST causes small datatypes to be used in + * xtd_seq_num_t - this allows the functions to be exhaustively tested. + */ +#if ROC_NEEDS_TO_BE_TESTED +#define ROC_TEST +#endif + +#include "rdbx.h" +#include "ut_sim.h" + +err_status_t +roc_test(int num_trials); + +int +main (void) { + err_status_t status; + + printf("rollover counter test driver\n" + "David A. McGrew\n" + "Cisco Systems, Inc.\n"); + + printf("testing index functions..."); + status = roc_test(1 << 18); + if (status) { + printf("failed\n"); + exit(status); + } + printf("passed\n"); + return 0; +} + + +#define ROC_VERBOSE 0 + +err_status_t +roc_test(int num_trials) { + xtd_seq_num_t local, est, ref; + ut_connection utc; + int i, num_bad_est = 0; + int delta; + uint32_t ircvd; + double failure_rate; + + index_init(&local); + index_init(&ref); + index_init(&est); + + printf("\n\ttesting sequential insertion..."); + for (i=0; i < 2048; i++) { + delta = index_guess(&local, &est, (uint16_t) ref); +#if ROC_VERBOSE + printf("%lld, %lld, %d\n", ref, est, i); +#endif + if (ref != est) { +#if ROC_VERBOSE + printf(" *bad estimate*\n"); +#endif + ++num_bad_est; + } + index_advance(&ref, 1); + } + failure_rate = (double) num_bad_est / num_trials; + if (failure_rate > 0.01) { + printf("error: failure rate too high (%d bad estimates in %d trials)\n", + num_bad_est, num_trials); + return err_status_algo_fail; + } + printf("done\n"); + + + printf("\ttesting non-sequential insertion..."); + index_init(&local); + index_init(&ref); + index_init(&est); + ut_init(&utc); + + for (i=0; i < num_trials; i++) { + + /* get next seq num from unreliable transport simulator */ + ircvd = ut_next_index(&utc); + + /* set ref to value of ircvd */ + ref = ircvd; + + /* estimate index based on low bits of ircvd */ + delta = index_guess(&local, &est, (uint16_t) ref); +#if ROC_VERBOSE + printf("ref: %lld, local: %lld, est: %lld, ircvd: %d, delta: %d\n", + ref, local, est, ircvd, delta); +#endif + + /* now update local xtd_seq_num_t as necessary */ + if (delta > 0) + index_advance(&local, delta); + + if (ref != est) { +#if ROC_VERBOSE + printf(" *bad estimate*\n"); +#endif + /* record failure event */ + ++num_bad_est; + + /* reset local value to correct value */ + local = ref; + } + } + failure_rate = (double) num_bad_est / num_trials; + if (failure_rate > 0.01) { + printf("error: failure rate too high (%d bad estimates in %d trials)\n", + num_bad_est, num_trials); + return err_status_algo_fail; + } + printf("done\n"); + + return err_status_ok; +} diff --git a/srtp/test/rtp.c b/srtp/test/rtp.c new file mode 100644 index 0000000..69968f3 --- /dev/null +++ b/srtp/test/rtp.c @@ -0,0 +1,167 @@ +/* + * rtp.c + * + * library functions for the real-time transport protocol + * + * David A. McGrew + * Cisco Systems, Inc. + */ + + +#include "rtp_priv.h" + +#include <stdio.h> +#include <string.h> + +#include <sys/types.h> +#ifdef HAVE_SYS_SOCKET_H +# include <sys/socket.h> +#endif + +#define PRINT_DEBUG 0 /* set to 1 to print out debugging data */ +#define VERBOSE_DEBUG 0 /* set to 1 to print out more data */ + +unsigned int +rtp_sendto(rtp_sender_t sender, const void* msg, int len) { + int octets_sent; + err_status_t stat; + int pkt_len = len + RTP_HEADER_LEN; + + /* marshal data */ + strncpy(sender->message.body, msg, len); + + /* update header */ + sender->message.header.seq = ntohs(sender->message.header.seq) + 1; + sender->message.header.seq = htons(sender->message.header.seq); + sender->message.header.ts = ntohl(sender->message.header.ts) + 1; + sender->message.header.ts = htonl(sender->message.header.ts); + + /* apply srtp */ + stat = srtp_protect(sender->srtp_ctx, &sender->message.header, &pkt_len); + if (stat) { +#if PRINT_DEBUG + fprintf(stderr, "error: srtp protection failed with code %d\n", stat); +#endif + return -1; + } +#if VERBOSE_DEBUG + srtp_print_packet(&sender->message.header, pkt_len); +#endif + octets_sent = sendto(sender->socket, (void*)&sender->message, + pkt_len, 0, (struct sockaddr *)&sender->addr, + sizeof (struct sockaddr_in)); + + if (octets_sent != pkt_len) { +#if PRINT_DEBUG + fprintf(stderr, "error: couldn't send message %s", (char *)msg); + perror(""); +#endif + } + + return octets_sent; +} + +unsigned int +rtp_recvfrom(rtp_receiver_t receiver, void *msg, int *len) { + int octets_recvd; + err_status_t stat; + + octets_recvd = recvfrom(receiver->socket, (void *)&receiver->message, + *len, 0, (struct sockaddr *) NULL, 0); + + /* verify rtp header */ + if (receiver->message.header.version != 2) { + *len = 0; + return -1; + } + +#if PRINT_DEBUG + fprintf(stderr, "%d octets received from SSRC %u\n", + octets_recvd, receiver->message.header.ssrc); +#endif +#if VERBOSE_DEBUG + srtp_print_packet(&receiver->message.header, octets_recvd); +#endif + + /* apply srtp */ + stat = srtp_unprotect(receiver->srtp_ctx, + &receiver->message.header, &octets_recvd); + if (stat) { + fprintf(stderr, + "error: srtp unprotection failed with code %d%s\n", stat, + stat == err_status_replay_fail ? " (replay check failed)" : + stat == err_status_auth_fail ? " (auth check failed)" : ""); + return -1; + } + strncpy(msg, receiver->message.body, octets_recvd); + + return octets_recvd; +} + +int +rtp_sender_init(rtp_sender_t sender, + int socket, + struct sockaddr_in addr, + unsigned int ssrc) { + + /* set header values */ + sender->message.header.ssrc = htonl(ssrc); + sender->message.header.ts = 0; + sender->message.header.seq = (uint16_t) rand(); + sender->message.header.m = 0; + sender->message.header.pt = 0x1; + sender->message.header.version = 2; + sender->message.header.p = 0; + sender->message.header.x = 0; + sender->message.header.cc = 0; + + /* set other stuff */ + sender->socket = socket; + sender->addr = addr; + + return 0; +} + +int +rtp_receiver_init(rtp_receiver_t rcvr, + int socket, + struct sockaddr_in addr, + unsigned int ssrc) { + + /* set header values */ + rcvr->message.header.ssrc = htonl(ssrc); + rcvr->message.header.ts = 0; + rcvr->message.header.seq = 0; + rcvr->message.header.m = 0; + rcvr->message.header.pt = 0x1; + rcvr->message.header.version = 2; + rcvr->message.header.p = 0; + rcvr->message.header.x = 0; + rcvr->message.header.cc = 0; + + /* set other stuff */ + rcvr->socket = socket; + rcvr->addr = addr; + + return 0; +} + +int +rtp_sender_init_srtp(rtp_sender_t sender, const srtp_policy_t *policy) { + return srtp_create(&sender->srtp_ctx, policy); +} + +int +rtp_receiver_init_srtp(rtp_receiver_t sender, const srtp_policy_t *policy) { + return srtp_create(&sender->srtp_ctx, policy); +} + +rtp_sender_t +rtp_sender_alloc() { + return (rtp_sender_t)malloc(sizeof(rtp_sender_ctx_t)); +} + +rtp_receiver_t +rtp_receiver_alloc() { + return (rtp_receiver_t)malloc(sizeof(rtp_receiver_ctx_t)); +} diff --git a/srtp/test/rtpw b/srtp/test/rtpw Binary files differnew file mode 100755 index 0000000..5636a01 --- /dev/null +++ b/srtp/test/rtpw diff --git a/srtp/test/rtpw.c b/srtp/test/rtpw.c new file mode 100644 index 0000000..e477a77 --- /dev/null +++ b/srtp/test/rtpw.c @@ -0,0 +1,519 @@ +/* + * rtpw.c + * + * rtp word sender/receiver + * + * David A. McGrew + * Cisco Systems, Inc. + * + * This app is a simple RTP application intended only for testing + * libsrtp. It reads one word at a time from /usr/dict/words (or + * whatever file is specified as DICT_FILE), and sends one word out + * each USEC_RATE microseconds. Secure RTP protections can be + * applied. See the usage() function for more details. + * + */ + +/* + * + * 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 "datatypes.h" +#include "getopt_s.h" /* for local getopt() */ + +#include <stdio.h> /* for printf, fprintf */ +#include <stdlib.h> /* for atoi() */ +#include <errno.h> +#include <unistd.h> /* for close() */ + +#include <string.h> /* for strncpy() */ +#include <time.h> /* for usleep() */ +#ifdef HAVE_SYS_SOCKET_H +# include <sys/socket.h> +#endif +#ifdef HAVE_NETINET_IN_H +# include <netinet/in.h> +#elif defined HAVE_WINSOCK2_H +# include <winsock2.h> +# include <ws2tcpip.h> +# define RTPW_USE_WINSOCK2 1 +#endif +#ifdef HAVE_ARPA_INET_H +# include <arpa/inet.h> +#endif + +#include "srtp.h" +#include "rtp.h" + +#ifdef RTPW_USE_WINSOCK2 +# define DICT_FILE "words.txt" +#else +# define DICT_FILE "/usr/share/dict/words" +#endif +#define USEC_RATE (5e5) +#define MAX_WORD_LEN 128 +#define ADDR_IS_MULTICAST(a) IN_MULTICAST(htonl(a)) +#define MAX_KEY_LEN 64 +#define MASTER_KEY_LEN 30 + + +#ifndef HAVE_USLEEP +# ifdef HAVE_WINDOWS_H +# define usleep(us) Sleep((us)/1000) +# else +# define usleep(us) sleep((us)/1000000) +# endif +#endif + + +/* + * the function usage() prints an error message describing how this + * program should be called, then calls exit() + */ + +void +usage(char *prog_name); + +/* + * leave_group(...) de-registers from a multicast group + */ + +void +leave_group(int sock, struct ip_mreq mreq, char *name); + + +/* + * program_type distinguishes the [s]rtp sender and receiver cases + */ + +typedef enum { sender, receiver, unknown } program_type; + +int +main (int argc, char *argv[]) { + char *dictfile = DICT_FILE; + FILE *dict; + char word[MAX_WORD_LEN]; + int sock, ret; + struct in_addr rcvr_addr; + struct sockaddr_in name; + struct ip_mreq mreq; +#if BEW + struct sockaddr_in local; +#endif + program_type prog_type = unknown; + sec_serv_t sec_servs = sec_serv_none; + unsigned char ttl = 5; + int c; + char *input_key = NULL; + char *address = NULL; + char key[MAX_KEY_LEN]; + unsigned short port = 0; + rtp_sender_t snd; + srtp_policy_t policy; + err_status_t status; + int len; + int do_list_mods = 0; + uint32_t ssrc = 0xdeadbeef; /* ssrc value hardcoded for now */ +#ifdef RTPW_USE_WINSOCK2 + WORD wVersionRequested = MAKEWORD(2, 0); + WSADATA wsaData; + + ret = WSAStartup(wVersionRequested, &wsaData); + if (ret != 0) { + fprintf(stderr, "error: WSAStartup() failed: %d\n", ret); + exit(1); + } +#endif + + /* initialize srtp library */ + status = srtp_init(); + if (status) { + printf("error: srtp initialization failed with error code %d\n", status); + exit(1); + } + + /* check args */ + while (1) { + c = getopt_s(argc, argv, "k:rsaeld:"); + if (c == -1) { + break; + } + switch (c) { + case 'k': + input_key = optarg_s; + break; + case 'e': + sec_servs |= sec_serv_conf; + break; + case 'a': + sec_servs |= sec_serv_auth; + break; + case 'r': + prog_type = receiver; + break; + case 's': + prog_type = sender; + 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; + case 'l': + do_list_mods = 1; + break; + default: + usage(argv[0]); + } + } + + if (prog_type == unknown) { + if (do_list_mods) { + status = crypto_kernel_list_debug_modules(); + if (status) { + printf("error: list of debug modules failed\n"); + exit(1); + } + return 0; + } else { + printf("error: neither sender [-s] nor receiver [-r] specified\n"); + usage(argv[0]); + } + } + + if ((sec_servs && !input_key) || (!sec_servs && input_key)) { + /* + * a key must be provided if and only if security services have + * been requested + */ + usage(argv[0]); + } + + if (argc != optind_s + 2) { + /* wrong number of arguments */ + usage(argv[0]); + } + + /* get address from arg */ + address = argv[optind_s++]; + + /* get port from arg */ + port = atoi(argv[optind_s++]); + + /* set address */ +#ifdef HAVE_INET_ATON + if (0 == inet_aton(address, &rcvr_addr)) { + fprintf(stderr, "%s: cannot parse IP v4 address %s\n", argv[0], address); + exit(1); + } + if (rcvr_addr.s_addr == INADDR_NONE) { + fprintf(stderr, "%s: address error", argv[0]); + exit(1); + } +#else + rcvr_addr.s_addr = inet_addr(address); + if (0xffffffff == rcvr_addr.s_addr) { + fprintf(stderr, "%s: cannot parse IP v4 address %s\n", argv[0], address); + exit(1); + } +#endif + + /* open socket */ + sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sock < 0) { + int err; +#ifdef RTPW_USE_WINSOCK2 + err = WSAGetLastError(); +#else + err = errno; +#endif + fprintf(stderr, "%s: couldn't open socket: %d\n", argv[0], err); + exit(1); + } + + name.sin_addr = rcvr_addr; + name.sin_family = PF_INET; + name.sin_port = htons(port); + + if (ADDR_IS_MULTICAST(rcvr_addr.s_addr)) { + if (prog_type == sender) { + ret = setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, + sizeof(ttl)); + if (ret < 0) { + fprintf(stderr, "%s: Failed to set TTL for multicast group", argv[0]); + perror(""); + exit(1); + } + } + + mreq.imr_multiaddr.s_addr = rcvr_addr.s_addr; + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + ret = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void*)&mreq, + sizeof(mreq)); + if (ret < 0) { + fprintf(stderr, "%s: Failed to join multicast group", argv[0]); + perror(""); + exit(1); + } + } + + /* report security services selected on the command line */ + printf("security services: "); + if (sec_servs & sec_serv_conf) + printf("confidentiality "); + if (sec_servs & sec_serv_auth) + printf("message authentication"); + if (sec_servs == sec_serv_none) + printf("none"); + printf("\n"); + + /* set up the srtp policy and master key */ + if (sec_servs) { + /* + * create policy structure, using the default mechanisms but + * with only the security services requested on the command line, + * using the right SSRC value + */ + switch (sec_servs) { + case sec_serv_conf_and_auth: + crypto_policy_set_rtp_default(&policy.rtp); + crypto_policy_set_rtcp_default(&policy.rtcp); + break; + case sec_serv_conf: + crypto_policy_set_aes_cm_128_null_auth(&policy.rtp); + crypto_policy_set_rtcp_default(&policy.rtcp); + break; + case sec_serv_auth: + crypto_policy_set_null_cipher_hmac_sha1_80(&policy.rtp); + crypto_policy_set_rtcp_default(&policy.rtcp); + break; + default: + printf("error: unknown security service requested\n"); + return -1; + } + policy.ssrc.type = ssrc_specific; + policy.ssrc.value = ssrc; + policy.key = (uint8_t *) key; + policy.next = NULL; + policy.rtp.sec_serv = sec_servs; + policy.rtcp.sec_serv = sec_serv_none; /* we don't do RTCP anyway */ + + /* + * read key from hexadecimal on command line into an octet string + */ + len = hex_string_to_octet_string(key, input_key, MASTER_KEY_LEN*2); + + /* check that hex string is the right length */ + if (len < MASTER_KEY_LEN*2) { + fprintf(stderr, + "error: too few digits in key/salt " + "(should be %d hexadecimal digits, found %d)\n", + MASTER_KEY_LEN*2, len); + exit(1); + } + if (strlen(input_key) > MASTER_KEY_LEN*2) { + fprintf(stderr, + "error: too many digits in key/salt " + "(should be %d hexadecimal digits, found %u)\n", + MASTER_KEY_LEN*2, (unsigned)strlen(input_key)); + exit(1); + } + + printf("set master key/salt to %s/", octet_string_hex_string(key, 16)); + printf("%s\n", octet_string_hex_string(key+16, 14)); + + } else { + /* + * we're not providing security services, so set the policy to the + * null policy + * + * Note that this policy does not conform to the SRTP + * specification, since RTCP authentication is required. However, + * the effect of this policy is to turn off SRTP, so that this + * application is now a vanilla-flavored RTP application. + */ + policy.key = (uint8_t *)key; + policy.ssrc.type = ssrc_specific; + policy.ssrc.value = ssrc; + policy.rtp.cipher_type = NULL_CIPHER; + policy.rtp.cipher_key_len = 0; + policy.rtp.auth_type = NULL_AUTH; + policy.rtp.auth_key_len = 0; + policy.rtp.auth_tag_len = 0; + policy.rtp.sec_serv = sec_serv_none; + policy.rtcp.cipher_type = NULL_CIPHER; + policy.rtcp.cipher_key_len = 0; + policy.rtcp.auth_type = NULL_AUTH; + policy.rtcp.auth_key_len = 0; + policy.rtcp.auth_tag_len = 0; + policy.rtcp.sec_serv = sec_serv_none; + policy.next = NULL; + } + + if (prog_type == sender) { + +#if BEW + /* bind to local socket (to match crypto policy, if need be) */ + memset(&local, 0, sizeof(struct sockaddr_in)); + local.sin_addr.s_addr = htonl(INADDR_ANY); + local.sin_port = htons(port); + ret = bind(sock, (struct sockaddr *) &local, sizeof(struct sockaddr_in)); + if (ret < 0) { + fprintf(stderr, "%s: bind failed\n", argv[0]); + perror(""); + exit(1); + } +#endif /* BEW */ + + /* initialize sender's rtp and srtp contexts */ + snd = rtp_sender_alloc(); + if (snd == NULL) { + fprintf(stderr, "error: malloc() failed\n"); + exit(1); + } + rtp_sender_init(snd, sock, name, ssrc); + status = rtp_sender_init_srtp(snd, &policy); + if (status) { + fprintf(stderr, + "error: srtp_create() failed with code %d\n", + status); + exit(1); + } + + /* open dictionary */ + dict = fopen (dictfile, "r"); + if (dict == NULL) { + fprintf(stderr, "%s: couldn't open file %s\n", argv[0], dictfile); + if (ADDR_IS_MULTICAST(rcvr_addr.s_addr)) { + leave_group(sock, mreq, argv[0]); + } + exit(1); + } + + /* read words from dictionary, then send them off */ + while (fgets(word, MAX_WORD_LEN, dict) != NULL) { + len = strlen(word) + 1; /* plus one for null */ + + if (len > MAX_WORD_LEN) + printf("error: word %s too large to send\n", word); + else { + rtp_sendto(snd, word, len); + printf("sending word: %s", word); + } + usleep(USEC_RATE); + } + + } else { /* prog_type == receiver */ + rtp_receiver_t rcvr; + + if (bind(sock, (struct sockaddr *)&name, sizeof(name)) < 0) { + close(sock); + fprintf(stderr, "%s: socket bind error\n", argv[0]); + perror(NULL); + if (ADDR_IS_MULTICAST(rcvr_addr.s_addr)) { + leave_group(sock, mreq, argv[0]); + } + exit(1); + } + + rcvr = rtp_receiver_alloc(); + if (rcvr == NULL) { + fprintf(stderr, "error: malloc() failed\n"); + exit(1); + } + rtp_receiver_init(rcvr, sock, name, ssrc); + status = rtp_receiver_init_srtp(rcvr, &policy); + if (status) { + fprintf(stderr, + "error: srtp_create() failed with code %d\n", + status); + exit(1); + } + + /* get next word and loop */ + while (1) { + len = MAX_WORD_LEN; + if (rtp_recvfrom(rcvr, word, &len) > -1) + printf("\tword: %s", word); + } + + } + + if (ADDR_IS_MULTICAST(rcvr_addr.s_addr)) { + leave_group(sock, mreq, argv[0]); + } + +#ifdef RTPW_USE_WINSOCK2 + WSACleanup(); +#endif + + return 0; +} + + +void +usage(char *string) { + + printf("usage: %s [-d <debug>]* [-k <key> [-a][-e]] " + "[-s | -r] dest_ip dest_port\n" + "or %s -l\n" + "where -a use message authentication\n" + " -e use encryption\n" + " -k <key> sets the srtp master key\n" + " -s act as rtp sender\n" + " -r act as rtp receiver\n" + " -l list debug modules\n" + " -d <debug> turn on debugging for module <debug>\n", + string, string); + exit(1); + +} + + +void +leave_group(int sock, struct ip_mreq mreq, char *name) { + int ret; + + ret = setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, (void*)&mreq, + sizeof(mreq)); + if (ret < 0) { + fprintf(stderr, "%s: Failed to leave multicast group", name); + perror(""); + } +} + diff --git a/srtp/test/rtpw_test.sh b/srtp/test/rtpw_test.sh new file mode 100755 index 0000000..f82e937 --- /dev/null +++ b/srtp/test/rtpw_test.sh @@ -0,0 +1,77 @@ +#!/bin/sh +# +# usage: rtpw_test <rtpw_commands> +# +# tests the rtpw sender and receiver functions + +RTPW=rtpw +DEST_PORT=9999 +DURATION=3 + +key=2b2edc5034f61a72345ca5986d7bfd0189aa6dc2ecab32fd9af74df6dfc6 + +ARGS="-k $key -ae" + +# First, we run "killall" to get rid of all existing rtpw processes. +# This step also enables this script to clean up after itself; if this +# script is interrupted after the rtpw processes are started but before +# they are killed, those processes will linger. Re-running the script +# will get rid of them. + +killall rtpw 2&>/dev/null + +if test -x $RTPW; then + +echo $0 ": starting rtpw receiver process... " + +$RTPW $* $ARGS -r 0.0.0.0 $DEST_PORT & + +receiver_pid=$! + +echo $0 ": receiver PID = $receiver_pid" + +sleep 1 + +# verify that the background job is running +ps | grep -q $receiver_pid +retval=$? +echo $retval +if [ $retval != 0 ]; then + echo $0 ": error" + exit 254 +fi + +echo $0 ": starting rtpw sender process..." + +$RTPW $* $ARGS -s 127.0.0.1 $DEST_PORT & + +sender_pid=$! + +echo $0 ": sender PID = $sender_pid" + +# verify that the background job is running +ps | grep -q $sender_pid +retval=$? +echo $retval +if [ $retval != 0 ]; then + echo $0 ": error" + exit 255 +fi + +sleep $DURATION + +kill $receiver_pid +kill $sender_pid + +echo $0 ": done (test passed)" + +else + +echo "error: can't find executable" $RTPW +exit 1 + +fi + +# EOF + + diff --git a/srtp/test/srtp_driver b/srtp/test/srtp_driver Binary files differnew file mode 100755 index 0000000..39f6c3a --- /dev/null +++ b/srtp/test/srtp_driver 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 +}; |