blob: 5e397d26e66d87a5a0845cb9ea6f7981db760507 [file] [log] [blame]
Cullen Jennings235513a2005-09-21 22:51:36 +00001/*
2 * srtp_driver.c
3 *
4 * a test driver for libSRTP
5 *
6 * David A. McGrew
7 * Cisco Systems, Inc.
8 */
9/*
10 *
David McGrew7629bf22006-06-08 17:00:25 +000011 * Copyright (c) 2001-2006, Cisco Systems, Inc.
Cullen Jennings235513a2005-09-21 22:51:36 +000012 * All rights reserved.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 *
18 * Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
20 *
21 * Redistributions in binary form must reproduce the above
22 * copyright notice, this list of conditions and the following
23 * disclaimer in the documentation and/or other materials provided
24 * with the distribution.
25 *
26 * Neither the name of the Cisco Systems, Inc. nor the names of its
27 * contributors may be used to endorse or promote products derived
28 * from this software without specific prior written permission.
29 *
30 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
31 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
32 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
33 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
34 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
35 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
36 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
37 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
41 * OF THE POSSIBILITY OF SUCH DAMAGE.
42 *
43 */
44
45
46#include <string.h> /* for memcpy() */
47#include <time.h> /* for clock() */
48#include <stdlib.h> /* for malloc(), free() */
49#include <stdio.h> /* for print(), fflush() */
David McGrew79bd3012006-07-17 20:41:21 +000050#include "getopt_s.h" /* for local getopt() */
Cullen Jennings235513a2005-09-21 22:51:36 +000051
David McGrew3c45e0c2006-07-12 00:50:56 +000052#include "srtp_priv.h"
Cullen Jennings235513a2005-09-21 22:51:36 +000053
Marcus Sundberg1cbca882005-10-02 20:50:06 +000054#ifdef HAVE_NETINET_IN_H
55# include <netinet/in.h>
56#elif defined HAVE_WINSOCK2_H
57# include <winsock2.h>
58#endif
59
Cullen Jennings235513a2005-09-21 22:51:36 +000060#define PRINT_REFERENCE_PACKET 1
61
62err_status_t
Marcus Sundberga3f95fe2005-09-29 12:48:41 +000063srtp_validate(void);
Cullen Jennings235513a2005-09-21 22:51:36 +000064
65err_status_t
Jonathan Lennox5df951a2010-05-20 20:55:54 +000066srtp_validate_aes_256(void);
67
68err_status_t
Cullen Jennings235513a2005-09-21 22:51:36 +000069srtp_create_big_policy(srtp_policy_t **list);
70
71err_status_t
Jonathan Lennox80c4c832010-05-17 19:30:28 +000072srtp_dealloc_big_policy(srtp_policy_t *list);
73
74err_status_t
Marcus Sundberga3f95fe2005-09-29 12:48:41 +000075srtp_test_remove_stream(void);
Cullen Jennings235513a2005-09-21 22:51:36 +000076
77double
78srtp_bits_per_second(int msg_len_octets, const srtp_policy_t *policy);
79
80double
81srtp_rejections_per_second(int msg_len_octets, const srtp_policy_t *policy);
82
83void
84srtp_do_timing(const srtp_policy_t *policy);
85
86void
87srtp_do_rejection_timing(const srtp_policy_t *policy);
88
89err_status_t
Marcus Sundberga3f95fe2005-09-29 12:48:41 +000090srtp_test(const srtp_policy_t *policy);
Cullen Jennings235513a2005-09-21 22:51:36 +000091
92err_status_t
David McGrew9c70f292006-05-03 19:38:38 +000093srtcp_test(const srtp_policy_t *policy);
94
95err_status_t
Cullen Jennings235513a2005-09-21 22:51:36 +000096srtp_session_print_policy(srtp_t srtp);
97
98err_status_t
99srtp_print_policy(const srtp_policy_t *policy);
100
101char *
102srtp_packet_to_string(srtp_hdr_t *hdr, int packet_len);
103
104double
105mips_estimate(int num_trials, int *ignore);
106
Marcus Sundberg410faaa2005-09-29 12:36:43 +0000107extern uint8_t test_key[30];
Cullen Jennings235513a2005-09-21 22:51:36 +0000108
109void
110usage(char *prog_name) {
111 printf("usage: %s [ -t ][ -c ][ -v ][-d <debug_module> ]* [ -l ]\n"
112 " -t run timing test\n"
113 " -r run rejection timing test\n"
114 " -c run codec timing test\n"
115 " -v run validation tests\n"
116 " -d <mod> turn on debugging module <mod>\n"
117 " -l list debugging modules\n", prog_name);
118 exit(1);
119}
120
121/*
122 * The policy_array is a null-terminated array of policy structs. it
123 * is declared at the end of this file
124 */
125
126extern const srtp_policy_t *policy_array[];
127
128
129/* the wildcard_policy is declared below; it has a wildcard ssrc */
130
131extern const srtp_policy_t wildcard_policy;
132
133/*
134 * mod_driver debug module - debugging module for this test driver
135 *
136 * we use the crypto_kernel debugging system in this driver, which
137 * makes the interface uniform and increases portability
138 */
139
140debug_module_t mod_driver = {
141 0, /* debugging is off by default */
142 "driver" /* printable name for module */
143};
144
145int
146main (int argc, char *argv[]) {
Jonathan Lennoxb4842bf2010-05-15 03:55:24 +0000147 int q;
Cullen Jennings235513a2005-09-21 22:51:36 +0000148 unsigned do_timing_test = 0;
149 unsigned do_rejection_test = 0;
150 unsigned do_codec_timing = 0;
151 unsigned do_validation = 0;
152 unsigned do_list_mods = 0;
153 err_status_t status;
154
155 /*
156 * verify that the compiler has interpreted the header data
157 * structure srtp_hdr_t correctly
158 */
159 if (sizeof(srtp_hdr_t) != 12) {
David McGrew1a2ab2c2006-07-12 22:48:44 +0000160 printf("error: srtp_hdr_t has incorrect size"
161 "(size is %ld bytes, expected 12)\n",
Jonathan Lennoxf3132b92010-05-14 22:54:10 +0000162 (long)sizeof(srtp_hdr_t));
Cullen Jennings235513a2005-09-21 22:51:36 +0000163 exit(1);
164 }
165
166 /* initialize srtp library */
167 status = srtp_init();
168 if (status) {
169 printf("error: srtp init failed with error code %d\n", status);
170 exit(1);
171 }
172
173 /* load srtp_driver debug module */
174 status = crypto_kernel_load_debug_module(&mod_driver);
175 if (status) {
176 printf("error: load of srtp_driver debug module failed "
177 "with error code %d\n", status);
178 exit(1);
179 }
180
181 /* process input arguments */
182 while (1) {
David McGrew79bd3012006-07-17 20:41:21 +0000183 q = getopt_s(argc, argv, "trcvld:");
Cullen Jennings235513a2005-09-21 22:51:36 +0000184 if (q == -1)
185 break;
186 switch (q) {
187 case 't':
188 do_timing_test = 1;
189 break;
190 case 'r':
191 do_rejection_test = 1;
192 break;
193 case 'c':
194 do_codec_timing = 1;
195 break;
196 case 'v':
197 do_validation = 1;
198 break;
199 case 'l':
200 do_list_mods = 1;
201 break;
202 case 'd':
David McGrew79bd3012006-07-17 20:41:21 +0000203 status = crypto_kernel_set_debug_module(optarg_s, 1);
Cullen Jennings235513a2005-09-21 22:51:36 +0000204 if (status) {
David McGrew79bd3012006-07-17 20:41:21 +0000205 printf("error: set debug module (%s) failed\n", optarg_s);
Cullen Jennings235513a2005-09-21 22:51:36 +0000206 exit(1);
207 }
208 break;
209 default:
210 usage(argv[0]);
211 }
212 }
213
214 if (!do_validation && !do_timing_test && !do_codec_timing
215 && !do_list_mods && !do_rejection_test)
216 usage(argv[0]);
217
218 if (do_list_mods) {
219 status = crypto_kernel_list_debug_modules();
220 if (status) {
221 printf("error: list of debug modules failed\n");
222 exit(1);
223 }
224 }
225
226 if (do_validation) {
227 const srtp_policy_t **policy = policy_array;
228 srtp_policy_t *big_policy;
229
David McGrew9c70f292006-05-03 19:38:38 +0000230 /* loop over policy array, testing srtp and srtcp for each policy */
Cullen Jennings235513a2005-09-21 22:51:36 +0000231 while (*policy != NULL) {
232 printf("testing srtp_protect and srtp_unprotect\n");
233 if (srtp_test(*policy) == err_status_ok)
234 printf("passed\n\n");
235 else {
236 printf("failed\n");
237 exit(1);
238 }
David McGrew9c70f292006-05-03 19:38:38 +0000239 printf("testing srtp_protect_rtcp and srtp_unprotect_rtcp\n");
240 if (srtcp_test(*policy) == err_status_ok)
241 printf("passed\n\n");
242 else {
243 printf("failed\n");
244 exit(1);
245 }
Cullen Jennings235513a2005-09-21 22:51:36 +0000246 policy++;
247 }
248
249 /* create a big policy list and run tests on it */
250 status = srtp_create_big_policy(&big_policy);
251 if (status) {
252 printf("unexpected failure with error code %d\n", status);
253 exit(1);
254 }
255 printf("testing srtp_protect and srtp_unprotect with big policy\n");
256 if (srtp_test(big_policy) == err_status_ok)
257 printf("passed\n\n");
258 else {
259 printf("failed\n");
260 exit(1);
261 }
Jonathan Lennox80c4c832010-05-17 19:30:28 +0000262 status = srtp_dealloc_big_policy(big_policy);
263 if (status) {
264 printf("unexpected failure with error code %d\n", status);
265 exit(1);
266 }
Cullen Jennings235513a2005-09-21 22:51:36 +0000267
268 /* run test on wildcard policy */
269 printf("testing srtp_protect and srtp_unprotect on "
270 "wildcard ssrc policy\n");
271 if (srtp_test(&wildcard_policy) == err_status_ok)
272 printf("passed\n\n");
273 else {
274 printf("failed\n");
275 exit(1);
276 }
277
278 /*
279 * run validation test against the reference packets - note
280 * that this test only covers the default policy
281 */
282 printf("testing srtp_protect and srtp_unprotect against "
283 "reference packets\n");
284 if (srtp_validate() == err_status_ok)
285 printf("passed\n\n");
286 else {
287 printf("failed\n");
288 exit(1);
289 }
290
291 /*
Jonathan Lennox5df951a2010-05-20 20:55:54 +0000292 * run validation test against the reference packets for
293 * AES-256
294 */
295 printf("testing srtp_protect and srtp_unprotect against "
296 "reference packets (AES-256)\n");
297 if (srtp_validate_aes_256() == err_status_ok)
298 printf("passed\n\n");
299 else {
300 printf("failed\n");
301 exit(1);
302 }
303
304 /*
Cullen Jennings235513a2005-09-21 22:51:36 +0000305 * test the function srtp_remove_stream()
306 */
307 printf("testing srtp_remove_stream()...");
308 if (srtp_test_remove_stream() == err_status_ok)
309 printf("passed\n");
310 else {
311 printf("failed\n");
312 exit(1);
313 }
314 }
315
316 if (do_timing_test) {
317 const srtp_policy_t **policy = policy_array;
318
319 /* loop over policies, run timing test for each */
320 while (*policy != NULL) {
321 srtp_print_policy(*policy);
322 srtp_do_timing(*policy);
323 policy++;
324 }
325 }
326
327 if (do_rejection_test) {
328 const srtp_policy_t **policy = policy_array;
329
330 /* loop over policies, run rejection timing test for each */
331 while (*policy != NULL) {
332 srtp_print_policy(*policy);
333 srtp_do_rejection_timing(*policy);
334 policy++;
335 }
336 }
337
338 if (do_codec_timing) {
339 srtp_policy_t policy;
340 int ignore;
341 double mips = mips_estimate(1000000000, &ignore);
342
343 crypto_policy_set_rtp_default(&policy.rtp);
344 crypto_policy_set_rtcp_default(&policy.rtcp);
345 policy.ssrc.type = ssrc_specific;
346 policy.ssrc.value = 0xdecafbad;
347 policy.key = test_key;
Jonathan Lennoxa1242f82010-05-17 21:46:04 +0000348 policy.ekt = NULL;
349 policy.window_size = 128;
Jonathan Lennoxdcee5c62010-05-17 22:08:40 +0000350 policy.allow_repeat_tx = 0;
Cullen Jennings235513a2005-09-21 22:51:36 +0000351 policy.next = NULL;
352
353 printf("mips estimate: %e\n", mips);
354
355 printf("testing srtp processing time for voice codecs:\n");
356 printf("codec\t\tlength (octets)\t\tsrtp instructions/second\n");
357 printf("G.711\t\t%d\t\t\t%e\n", 80,
358 (double) mips * (80 * 8) /
359 srtp_bits_per_second(80, &policy) / .01 );
360 printf("G.711\t\t%d\t\t\t%e\n", 160,
361 (double) mips * (160 * 8) /
362 srtp_bits_per_second(160, &policy) / .02);
363 printf("G.726-32\t%d\t\t\t%e\n", 40,
364 (double) mips * (40 * 8) /
365 srtp_bits_per_second(40, &policy) / .01 );
366 printf("G.726-32\t%d\t\t\t%e\n", 80,
367 (double) mips * (80 * 8) /
368 srtp_bits_per_second(80, &policy) / .02);
369 printf("G.729\t\t%d\t\t\t%e\n", 10,
370 (double) mips * (10 * 8) /
371 srtp_bits_per_second(10, &policy) / .01 );
372 printf("G.729\t\t%d\t\t\t%e\n", 20,
373 (double) mips * (20 * 8) /
374 srtp_bits_per_second(20, &policy) / .02 );
David McGrew93451082006-09-18 13:41:35 +0000375 printf("Wideband\t%d\t\t\t%e\n", 320,
376 (double) mips * (320 * 8) /
377 srtp_bits_per_second(320, &policy) / .01 );
378 printf("Wideband\t%d\t\t\t%e\n", 640,
379 (double) mips * (640 * 8) /
380 srtp_bits_per_second(640, &policy) / .02 );
Cullen Jennings235513a2005-09-21 22:51:36 +0000381 }
382
Jonathan Lennoxdfb30842010-05-15 04:52:01 +0000383 status = srtp_shutdown();
384 if (status) {
385 printf("error: srtp shutdown failed with error code %d\n", status);
386 exit(1);
387 }
388
Cullen Jennings235513a2005-09-21 22:51:36 +0000389 return 0;
390}
391
392
393
394/*
395 * srtp_create_test_packet(len, ssrc) returns a pointer to a
396 * (malloced) example RTP packet whose data field has the length given
397 * by pkt_octet_len and the SSRC value ssrc. The total length of the
398 * packet is twelve octets longer, since the header is at the
399 * beginning. There is room at the end of the packet for a trailer,
400 * and the four octets following the packet are filled with 0xff
401 * values to enable testing for overwrites.
402 *
403 * note that the location of the test packet can (and should) be
404 * deallocated with the free() call once it is no longer needed.
405 */
406
407srtp_hdr_t *
408srtp_create_test_packet(int pkt_octet_len, uint32_t ssrc) {
409 int i;
Marcus Sundberg410faaa2005-09-29 12:36:43 +0000410 uint8_t *buffer;
Cullen Jennings235513a2005-09-21 22:51:36 +0000411 srtp_hdr_t *hdr;
412 int bytes_in_hdr = 12;
413
414 /* allocate memory for test packet */
Derek MacDonald17127da2006-07-12 22:22:08 +0000415 hdr = (srtp_hdr_t*) malloc(pkt_octet_len + bytes_in_hdr
Cullen Jennings235513a2005-09-21 22:51:36 +0000416 + SRTP_MAX_TRAILER_LEN + 4);
417 if (!hdr)
418 return NULL;
419
420 hdr->version = 2; /* RTP version two */
421 hdr->p = 0; /* no padding needed */
422 hdr->x = 0; /* no header extension */
423 hdr->cc = 0; /* no CSRCs */
424 hdr->m = 0; /* marker bit */
425 hdr->pt = 0xf; /* payload type */
426 hdr->seq = htons(0x1234); /* sequence number */
427 hdr->ts = htonl(0xdecafbad); /* timestamp */
428 hdr->ssrc = htonl(ssrc); /* synch. source */
429
Marcus Sundberg410faaa2005-09-29 12:36:43 +0000430 buffer = (uint8_t *)hdr;
Cullen Jennings235513a2005-09-21 22:51:36 +0000431 buffer += bytes_in_hdr;
432
433 /* set RTP data to 0xab */
434 for (i=0; i < pkt_octet_len; i++)
435 *buffer++ = 0xab;
436
437 /* set post-data value to 0xffff to enable overrun checking */
438 for (i=0; i < SRTP_MAX_TRAILER_LEN+4; i++)
439 *buffer++ = 0xff;
440
441 return hdr;
442}
443
444void
445srtp_do_timing(const srtp_policy_t *policy) {
446 int len;
447
448 /*
449 * note: the output of this function is formatted so that it
450 * can be used in gnuplot. '#' indicates a comment, and "\r\n"
451 * terminates a record
452 */
453
454 printf("# testing srtp throughput:\r\n");
455 printf("# mesg length (octets)\tthroughput (megabits per second)\r\n");
456
457 for (len=16; len <= 2048; len *= 2)
458 printf("%d\t\t\t%f\r\n", len,
459 srtp_bits_per_second(len, policy) / 1.0E6);
460
461 /* these extra linefeeds let gnuplot know that a dataset is done */
462 printf("\r\n\r\n");
463
464}
465
466void
467srtp_do_rejection_timing(const srtp_policy_t *policy) {
468 int len;
469
470 /*
471 * note: the output of this function is formatted so that it
472 * can be used in gnuplot. '#' indicates a comment, and "\r\n"
473 * terminates a record
474 */
475
476 printf("# testing srtp rejection throughput:\r\n");
477 printf("# mesg length (octets)\trejections per second\r\n");
478
479 for (len=8; len <= 2048; len *= 2)
480 printf("%d\t\t\t%e\r\n", len, srtp_rejections_per_second(len, policy));
481
482 /* these extra linefeeds let gnuplot know that a dataset is done */
483 printf("\r\n\r\n");
484
485}
486
487
488#define MAX_MSG_LEN 1024
489
490double
491srtp_bits_per_second(int msg_len_octets, const srtp_policy_t *policy) {
492 srtp_t srtp;
493 srtp_hdr_t *mesg;
494 int i;
495 clock_t timer;
496 int num_trials = 100000;
497 int len;
498 uint32_t ssrc;
499 err_status_t status;
500
501 /*
502 * allocate and initialize an srtp session
503 */
504 status = srtp_create(&srtp, policy);
505 if (status) {
506 printf("error: srtp_create() failed with error code %d\n", status);
507 exit(1);
508 }
509
510 /*
511 * if the ssrc is unspecified, use a predetermined one
512 */
513 if (policy->ssrc.type != ssrc_specific) {
514 ssrc = 0xdeadbeef;
515 } else {
516 ssrc = policy->ssrc.value;
517 }
518
519 /*
520 * create a test packet
521 */
522 mesg = srtp_create_test_packet(msg_len_octets, ssrc);
523 if (mesg == NULL)
524 return 0.0; /* indicate failure by returning zero */
525
526 timer = clock();
527 for (i=0; i < num_trials; i++) {
David McGrewd2f8de42006-02-03 19:43:59 +0000528 len = msg_len_octets + 12; /* add in rtp header length */
Cullen Jennings235513a2005-09-21 22:51:36 +0000529
530 /* srtp protect message */
531 status = srtp_protect(srtp, mesg, &len);
532 if (status) {
533 printf("error: srtp_protect() failed with error code %d\n", status);
534 exit(1);
535 }
536
537 /* increment message number */
Jonathan Lennox75b36872010-05-21 00:30:21 +0000538 {
539 /* hack sequence to avoid problems with macros for htons/ntohs on some systems */
540 short new_seq = ntohs(mesg->seq) + 1;
541 mesg->seq = htons(new_seq);
542 }
Cullen Jennings235513a2005-09-21 22:51:36 +0000543 }
544 timer = clock() - timer;
545
546 free(mesg);
Jonathan Lennox80c4c832010-05-17 19:30:28 +0000547
548 status = srtp_dealloc(srtp);
549 if (status) {
550 printf("error: srtp_dealloc() failed with error code %d\n", status);
551 exit(1);
552 }
Cullen Jennings235513a2005-09-21 22:51:36 +0000553
554 return (double) (msg_len_octets) * 8 *
555 num_trials * CLOCKS_PER_SEC / timer;
556}
557
558double
559srtp_rejections_per_second(int msg_len_octets, const srtp_policy_t *policy) {
560 srtp_ctx_t *srtp;
561 srtp_hdr_t *mesg;
562 int i;
563 int len;
564 clock_t timer;
565 int num_trials = 1000000;
566 uint32_t ssrc = policy->ssrc.value;
567 err_status_t status;
568
569 /*
570 * allocate and initialize an srtp session
571 */
572 status = srtp_create(&srtp, policy);
573 if (status) {
574 printf("error: srtp_create() failed with error code %d\n", status);
575 exit(1);
576 }
577
578 mesg = srtp_create_test_packet(msg_len_octets, ssrc);
579 if (mesg == NULL)
580 return 0.0; /* indicate failure by returning zero */
581
582 len = msg_len_octets;
583 srtp_protect(srtp, (srtp_hdr_t *)mesg, &len);
584
585 timer = clock();
586 for (i=0; i < num_trials; i++) {
587 len = msg_len_octets;
588 srtp_unprotect(srtp, (srtp_hdr_t *)mesg, &len);
589 }
590 timer = clock() - timer;
591
592 free(mesg);
Jonathan Lennox80c4c832010-05-17 19:30:28 +0000593
594 status = srtp_dealloc(srtp);
595 if (status) {
596 printf("error: srtp_dealloc() failed with error code %d\n", status);
597 exit(1);
598 }
599
Cullen Jennings235513a2005-09-21 22:51:36 +0000600 return (double) num_trials * CLOCKS_PER_SEC / timer;
601}
602
603
604void
605err_check(err_status_t s) {
606 if (s == err_status_ok)
607 return;
608 else
609 fprintf(stderr, "error: unexpected srtp failure (code %d)\n", s);
610 exit (1);
611}
612
613err_status_t
614srtp_test(const srtp_policy_t *policy) {
615 int i;
616 srtp_t srtp_sender;
617 srtp_t srtp_rcvr;
618 err_status_t status = err_status_ok;
619 srtp_hdr_t *hdr, *hdr2;
Marcus Sundberg5c40da82005-10-08 18:15:00 +0000620 uint8_t hdr_enc[64];
Marcus Sundberg410faaa2005-09-29 12:36:43 +0000621 uint8_t *pkt_end;
Marcus Sundberg5c40da82005-10-08 18:15:00 +0000622 int msg_len_octets, msg_len_enc;
Cullen Jennings235513a2005-09-21 22:51:36 +0000623 int len;
624 int tag_length = policy->rtp.auth_tag_len;
625 uint32_t ssrc;
626 srtp_policy_t *rcvr_policy;
627
628 err_check(srtp_create(&srtp_sender, policy));
629
630 /* print out policy */
631 err_check(srtp_session_print_policy(srtp_sender));
632
633 /*
634 * initialize data buffer, using the ssrc in the policy unless that
635 * value is a wildcard, in which case we'll just use an arbitrary
636 * one
637 */
638 if (policy->ssrc.type != ssrc_specific)
639 ssrc = 0xdecafbad;
640 else
641 ssrc = policy->ssrc.value;
642 msg_len_octets = 28;
643 hdr = srtp_create_test_packet(msg_len_octets, ssrc);
644
645 if (hdr == NULL)
646 return err_status_alloc_fail;
647 hdr2 = srtp_create_test_packet(msg_len_octets, ssrc);
648 if (hdr2 == NULL) {
649 free(hdr);
650 return err_status_alloc_fail;
651 }
652
653 /* set message length */
654 len = msg_len_octets;
655
656 debug_print(mod_driver, "before protection:\n%s",
657 srtp_packet_to_string(hdr, len));
658
659#if PRINT_REFERENCE_PACKET
660 debug_print(mod_driver, "reference packet before protection:\n%s",
Marcus Sundberg410faaa2005-09-29 12:36:43 +0000661 octet_string_hex_string((uint8_t *)hdr, len));
Cullen Jennings235513a2005-09-21 22:51:36 +0000662#endif
663 err_check(srtp_protect(srtp_sender, hdr, &len));
664
665 debug_print(mod_driver, "after protection:\n%s",
666 srtp_packet_to_string(hdr, len));
667#if PRINT_REFERENCE_PACKET
668 debug_print(mod_driver, "after protection:\n%s",
Marcus Sundberg410faaa2005-09-29 12:36:43 +0000669 octet_string_hex_string((uint8_t *)hdr, len));
Cullen Jennings235513a2005-09-21 22:51:36 +0000670#endif
671
Marcus Sundberg5c40da82005-10-08 18:15:00 +0000672 /* save protected message and length */
673 memcpy(hdr_enc, hdr, len);
674 msg_len_enc = len;
675
Cullen Jennings235513a2005-09-21 22:51:36 +0000676 /*
677 * check for overrun of the srtp_protect() function
678 *
679 * The packet is followed by a value of 0xfffff; if the value of the
680 * data following the packet is different, then we know that the
681 * protect function is overwriting the end of the packet.
682 */
Marcus Sundberg410faaa2005-09-29 12:36:43 +0000683 pkt_end = (uint8_t *)hdr + sizeof(srtp_hdr_t)
Cullen Jennings235513a2005-09-21 22:51:36 +0000684 + msg_len_octets + tag_length;
685 for (i = 0; i < 4; i++)
686 if (pkt_end[i] != 0xff) {
687 fprintf(stdout, "overwrite in srtp_protect() function "
688 "(expected %x, found %x in trailing octet %d)\n",
Marcus Sundberg410faaa2005-09-29 12:36:43 +0000689 0xff, ((uint8_t *)hdr)[i], i);
Cullen Jennings235513a2005-09-21 22:51:36 +0000690 free(hdr);
691 free(hdr2);
692 return err_status_algo_fail;
693 }
694
695 /*
696 * if the policy includes confidentiality, check that ciphertext is
697 * different than plaintext
698 *
699 * Note that this check will give false negatives, with some small
700 * probability, especially if the packets are short. For that
701 * reason, we skip this check if the plaintext is less than four
702 * octets long.
703 */
704 if ((policy->rtp.sec_serv & sec_serv_conf) && (msg_len_octets >= 4)) {
705 printf("testing that ciphertext is distinct from plaintext...");
706 status = err_status_algo_fail;
707 for (i=12; i < msg_len_octets+12; i++)
Marcus Sundberg410faaa2005-09-29 12:36:43 +0000708 if (((uint8_t *)hdr)[i] != ((uint8_t *)hdr2)[i]) {
Cullen Jennings235513a2005-09-21 22:51:36 +0000709 status = err_status_ok;
710 }
711 if (status) {
712 printf("failed\n");
713 free(hdr);
714 free(hdr2);
715 return status;
716 }
717 printf("passed\n");
718 }
719
720 /*
721 * if the policy uses a 'wildcard' ssrc, then we need to make a copy
722 * of the policy that changes the direction to inbound
723 *
724 * we always copy the policy into the rcvr_policy, since otherwise
725 * the compiler would fret about the constness of the policy
726 */
Derek MacDonald17127da2006-07-12 22:22:08 +0000727 rcvr_policy = (srtp_policy_t*) malloc(sizeof(srtp_policy_t));
Jonathan Lennox80c4c832010-05-17 19:30:28 +0000728 if (rcvr_policy == NULL) {
729 free(hdr);
730 free(hdr2);
Cullen Jennings235513a2005-09-21 22:51:36 +0000731 return err_status_alloc_fail;
Jonathan Lennox80c4c832010-05-17 19:30:28 +0000732 }
Cullen Jennings235513a2005-09-21 22:51:36 +0000733 memcpy(rcvr_policy, policy, sizeof(srtp_policy_t));
734 if (policy->ssrc.type == ssrc_any_outbound) {
735 rcvr_policy->ssrc.type = ssrc_any_inbound;
736 }
737
738 err_check(srtp_create(&srtp_rcvr, rcvr_policy));
739
740 err_check(srtp_unprotect(srtp_rcvr, hdr, &len));
741
742 debug_print(mod_driver, "after unprotection:\n%s",
743 srtp_packet_to_string(hdr, len));
744
745 /* verify that the unprotected packet matches the origial one */
746 for (i=0; i < msg_len_octets; i++)
Marcus Sundberg410faaa2005-09-29 12:36:43 +0000747 if (((uint8_t *)hdr)[i] != ((uint8_t *)hdr2)[i]) {
Cullen Jennings235513a2005-09-21 22:51:36 +0000748 fprintf(stdout, "mismatch at octet %d\n", i);
749 status = err_status_algo_fail;
750 }
751 if (status) {
752 free(hdr);
753 free(hdr2);
Jonathan Lennox80c4c832010-05-17 19:30:28 +0000754 free(rcvr_policy);
Cullen Jennings235513a2005-09-21 22:51:36 +0000755 return status;
756 }
757
758 /*
759 * if the policy includes authentication, then test for false positives
760 */
761 if (policy->rtp.sec_serv & sec_serv_auth) {
762 char *data = ((char *)hdr) + 12;
763
764 printf("testing for false positives in replay check...");
765
Marcus Sundberg5c40da82005-10-08 18:15:00 +0000766 /* set message length */
767 len = msg_len_enc;
768
Cullen Jennings235513a2005-09-21 22:51:36 +0000769 /* unprotect a second time - should fail with a replay error */
Marcus Sundberg5c40da82005-10-08 18:15:00 +0000770 status = srtp_unprotect(srtp_rcvr, hdr_enc, &len);
Cullen Jennings235513a2005-09-21 22:51:36 +0000771 if (status != err_status_replay_fail) {
772 printf("failed with error code %d\n", status);
773 free(hdr);
774 free(hdr2);
Jonathan Lennox80c4c832010-05-17 19:30:28 +0000775 free(rcvr_policy);
Cullen Jennings235513a2005-09-21 22:51:36 +0000776 return status;
777 } else {
778 printf("passed\n");
779 }
780
781 printf("testing for false positives in auth check...");
782
783 /* increment sequence number in header */
784 hdr->seq++;
785
Marcus Sundberg5c40da82005-10-08 18:15:00 +0000786 /* set message length */
787 len = msg_len_octets;
788
Cullen Jennings235513a2005-09-21 22:51:36 +0000789 /* apply protection */
790 err_check(srtp_protect(srtp_sender, hdr, &len));
791
792 /* flip bits in packet */
793 data[0] ^= 0xff;
794
795 /* unprotect, and check for authentication failure */
796 status = srtp_unprotect(srtp_rcvr, hdr, &len);
797 if (status != err_status_auth_fail) {
798 printf("failed\n");
799 free(hdr);
800 free(hdr2);
Jonathan Lennox80c4c832010-05-17 19:30:28 +0000801 free(rcvr_policy);
Cullen Jennings235513a2005-09-21 22:51:36 +0000802 return status;
803 } else {
804 printf("passed\n");
805 }
806
807 }
808
809 err_check(srtp_dealloc(srtp_sender));
810 err_check(srtp_dealloc(srtp_rcvr));
811
812 free(hdr);
813 free(hdr2);
Jonathan Lennox80c4c832010-05-17 19:30:28 +0000814 free(rcvr_policy);
Cullen Jennings235513a2005-09-21 22:51:36 +0000815 return err_status_ok;
816}
817
818
819err_status_t
David McGrew9c70f292006-05-03 19:38:38 +0000820srtcp_test(const srtp_policy_t *policy) {
821 int i;
822 srtp_t srtcp_sender;
823 srtp_t srtcp_rcvr;
824 err_status_t status = err_status_ok;
825 srtp_hdr_t *hdr, *hdr2;
826 uint8_t hdr_enc[64];
827 uint8_t *pkt_end;
828 int msg_len_octets, msg_len_enc;
829 int len;
830 int tag_length = policy->rtp.auth_tag_len;
831 uint32_t ssrc;
832 srtp_policy_t *rcvr_policy;
833
834 err_check(srtp_create(&srtcp_sender, policy));
835
836 /* print out policy */
837 err_check(srtp_session_print_policy(srtcp_sender));
838
839 /*
840 * initialize data buffer, using the ssrc in the policy unless that
841 * value is a wildcard, in which case we'll just use an arbitrary
842 * one
843 */
844 if (policy->ssrc.type != ssrc_specific)
845 ssrc = 0xdecafbad;
846 else
847 ssrc = policy->ssrc.value;
848 msg_len_octets = 28;
849 hdr = srtp_create_test_packet(msg_len_octets, ssrc);
850
851 if (hdr == NULL)
852 return err_status_alloc_fail;
853 hdr2 = srtp_create_test_packet(msg_len_octets, ssrc);
854 if (hdr2 == NULL) {
855 free(hdr);
856 return err_status_alloc_fail;
857 }
858
859 /* set message length */
860 len = msg_len_octets;
861
862 debug_print(mod_driver, "before protection:\n%s",
863 srtp_packet_to_string(hdr, len));
864
865#if PRINT_REFERENCE_PACKET
866 debug_print(mod_driver, "reference packet before protection:\n%s",
867 octet_string_hex_string((uint8_t *)hdr, len));
868#endif
869 err_check(srtp_protect_rtcp(srtcp_sender, hdr, &len));
870
871 debug_print(mod_driver, "after protection:\n%s",
872 srtp_packet_to_string(hdr, len));
873#if PRINT_REFERENCE_PACKET
874 debug_print(mod_driver, "after protection:\n%s",
875 octet_string_hex_string((uint8_t *)hdr, len));
876#endif
877
878 /* save protected message and length */
879 memcpy(hdr_enc, hdr, len);
880 msg_len_enc = len;
881
882 /*
883 * check for overrun of the srtp_protect() function
884 *
885 * The packet is followed by a value of 0xfffff; if the value of the
886 * data following the packet is different, then we know that the
887 * protect function is overwriting the end of the packet.
888 */
889 pkt_end = (uint8_t *)hdr + sizeof(srtp_hdr_t)
890 + msg_len_octets + tag_length;
891 for (i = 0; i < 4; i++)
892 if (pkt_end[i] != 0xff) {
893 fprintf(stdout, "overwrite in srtp_protect_rtcp() function "
894 "(expected %x, found %x in trailing octet %d)\n",
895 0xff, ((uint8_t *)hdr)[i], i);
896 free(hdr);
897 free(hdr2);
898 return err_status_algo_fail;
899 }
900
901 /*
902 * if the policy includes confidentiality, check that ciphertext is
903 * different than plaintext
904 *
905 * Note that this check will give false negatives, with some small
906 * probability, especially if the packets are short. For that
907 * reason, we skip this check if the plaintext is less than four
908 * octets long.
909 */
910 if ((policy->rtp.sec_serv & sec_serv_conf) && (msg_len_octets >= 4)) {
911 printf("testing that ciphertext is distinct from plaintext...");
912 status = err_status_algo_fail;
913 for (i=12; i < msg_len_octets+12; i++)
914 if (((uint8_t *)hdr)[i] != ((uint8_t *)hdr2)[i]) {
915 status = err_status_ok;
916 }
917 if (status) {
918 printf("failed\n");
919 free(hdr);
920 free(hdr2);
921 return status;
922 }
923 printf("passed\n");
924 }
925
926 /*
927 * if the policy uses a 'wildcard' ssrc, then we need to make a copy
928 * of the policy that changes the direction to inbound
929 *
930 * we always copy the policy into the rcvr_policy, since otherwise
931 * the compiler would fret about the constness of the policy
932 */
Derek MacDonald17127da2006-07-12 22:22:08 +0000933 rcvr_policy = (srtp_policy_t*) malloc(sizeof(srtp_policy_t));
David McGrew9c70f292006-05-03 19:38:38 +0000934 if (rcvr_policy == NULL)
935 return err_status_alloc_fail;
936 memcpy(rcvr_policy, policy, sizeof(srtp_policy_t));
937 if (policy->ssrc.type == ssrc_any_outbound) {
938 rcvr_policy->ssrc.type = ssrc_any_inbound;
939 }
940
941 err_check(srtp_create(&srtcp_rcvr, rcvr_policy));
942
943 err_check(srtp_unprotect_rtcp(srtcp_rcvr, hdr, &len));
944
945 debug_print(mod_driver, "after unprotection:\n%s",
946 srtp_packet_to_string(hdr, len));
947
948 /* verify that the unprotected packet matches the origial one */
949 for (i=0; i < msg_len_octets; i++)
950 if (((uint8_t *)hdr)[i] != ((uint8_t *)hdr2)[i]) {
951 fprintf(stdout, "mismatch at octet %d\n", i);
952 status = err_status_algo_fail;
953 }
954 if (status) {
955 free(hdr);
956 free(hdr2);
Jonathan Lennox80c4c832010-05-17 19:30:28 +0000957 free(rcvr_policy);
David McGrew9c70f292006-05-03 19:38:38 +0000958 return status;
959 }
960
961 /*
962 * if the policy includes authentication, then test for false positives
963 */
964 if (policy->rtp.sec_serv & sec_serv_auth) {
965 char *data = ((char *)hdr) + 12;
966
967 printf("testing for false positives in replay check...");
968
969 /* set message length */
970 len = msg_len_enc;
971
972 /* unprotect a second time - should fail with a replay error */
973 status = srtp_unprotect_rtcp(srtcp_rcvr, hdr_enc, &len);
974 if (status != err_status_replay_fail) {
975 printf("failed with error code %d\n", status);
976 free(hdr);
977 free(hdr2);
Jonathan Lennox80c4c832010-05-17 19:30:28 +0000978 free(rcvr_policy);
David McGrew9c70f292006-05-03 19:38:38 +0000979 return status;
980 } else {
981 printf("passed\n");
982 }
983
984 printf("testing for false positives in auth check...");
985
986 /* increment sequence number in header */
987 hdr->seq++;
988
989 /* set message length */
990 len = msg_len_octets;
991
992 /* apply protection */
993 err_check(srtp_protect_rtcp(srtcp_sender, hdr, &len));
994
995 /* flip bits in packet */
996 data[0] ^= 0xff;
997
998 /* unprotect, and check for authentication failure */
999 status = srtp_unprotect_rtcp(srtcp_rcvr, hdr, &len);
1000 if (status != err_status_auth_fail) {
1001 printf("failed\n");
1002 free(hdr);
1003 free(hdr2);
Jonathan Lennox80c4c832010-05-17 19:30:28 +00001004 free(rcvr_policy);
David McGrew9c70f292006-05-03 19:38:38 +00001005 return status;
1006 } else {
1007 printf("passed\n");
1008 }
1009
1010 }
1011
1012 err_check(srtp_dealloc(srtcp_sender));
1013 err_check(srtp_dealloc(srtcp_rcvr));
1014
1015 free(hdr);
1016 free(hdr2);
Jonathan Lennox80c4c832010-05-17 19:30:28 +00001017 free(rcvr_policy);
David McGrew9c70f292006-05-03 19:38:38 +00001018 return err_status_ok;
1019}
1020
1021
1022err_status_t
Cullen Jennings235513a2005-09-21 22:51:36 +00001023srtp_session_print_policy(srtp_t srtp) {
1024 char *serv_descr[4] = {
1025 "none",
1026 "confidentiality",
1027 "authentication",
1028 "confidentiality and authentication"
1029 };
1030 char *direction[3] = {
1031 "unknown",
1032 "outbound",
1033 "inbound"
1034 };
1035 srtp_stream_t stream;
1036
1037 /* sanity checking */
1038 if (srtp == NULL)
1039 return err_status_fail;
1040
1041 /* if there's a template stream, print it out */
1042 if (srtp->stream_template != NULL) {
1043 stream = srtp->stream_template;
1044 printf("# SSRC: any %s\r\n"
1045 "# rtp cipher: %s\r\n"
1046 "# rtp auth: %s\r\n"
1047 "# rtp services: %s\r\n"
1048 "# rtcp cipher: %s\r\n"
1049 "# rtcp auth: %s\r\n"
Jonathan Lennoxa1242f82010-05-17 21:46:04 +00001050 "# rtcp services: %s\r\n"
Jonathan Lennoxdcee5c62010-05-17 22:08:40 +00001051 "# window size: %lu\r\n"
1052 "# tx rtx allowed:%s\r\n",
Cullen Jennings235513a2005-09-21 22:51:36 +00001053 direction[stream->direction],
1054 stream->rtp_cipher->type->description,
1055 stream->rtp_auth->type->description,
1056 serv_descr[stream->rtp_services],
1057 stream->rtcp_cipher->type->description,
1058 stream->rtcp_auth->type->description,
Jonathan Lennoxa1242f82010-05-17 21:46:04 +00001059 serv_descr[stream->rtcp_services],
Jonathan Lennoxdcee5c62010-05-17 22:08:40 +00001060 rdbx_get_window_size(&stream->rtp_rdbx),
1061 stream->allow_repeat_tx ? "true" : "false");
Cullen Jennings235513a2005-09-21 22:51:36 +00001062 }
1063
1064 /* loop over streams in session, printing the policy of each */
1065 stream = srtp->stream_list;
1066 while (stream != NULL) {
1067 if (stream->rtp_services > sec_serv_conf_and_auth)
1068 return err_status_bad_param;
1069
1070 printf("# SSRC: 0x%08x\r\n"
1071 "# rtp cipher: %s\r\n"
1072 "# rtp auth: %s\r\n"
1073 "# rtp services: %s\r\n"
1074 "# rtcp cipher: %s\r\n"
1075 "# rtcp auth: %s\r\n"
Jonathan Lennoxa1242f82010-05-17 21:46:04 +00001076 "# rtcp services: %s\r\n"
Jonathan Lennoxdcee5c62010-05-17 22:08:40 +00001077 "# window size: %lu\r\n"
1078 "# tx rtx allowed:%s\r\n",
Cullen Jennings235513a2005-09-21 22:51:36 +00001079 stream->ssrc,
1080 stream->rtp_cipher->type->description,
1081 stream->rtp_auth->type->description,
1082 serv_descr[stream->rtp_services],
1083 stream->rtcp_cipher->type->description,
1084 stream->rtcp_auth->type->description,
Jonathan Lennoxa1242f82010-05-17 21:46:04 +00001085 serv_descr[stream->rtcp_services],
Jonathan Lennoxdcee5c62010-05-17 22:08:40 +00001086 rdbx_get_window_size(&stream->rtp_rdbx),
1087 stream->allow_repeat_tx ? "true" : "false");
Cullen Jennings235513a2005-09-21 22:51:36 +00001088
1089 /* advance to next stream in the list */
1090 stream = stream->next;
1091 }
1092 return err_status_ok;
1093}
1094
1095err_status_t
1096srtp_print_policy(const srtp_policy_t *policy) {
1097 err_status_t status;
1098 srtp_t session;
1099
1100 status = srtp_create(&session, policy);
1101 if (status)
1102 return status;
1103 status = srtp_session_print_policy(session);
1104 if (status)
1105 return status;
1106 status = srtp_dealloc(session);
1107 if (status)
1108 return status;
1109 return err_status_ok;
1110}
1111
1112/*
1113 * srtp_print_packet(...) is for debugging only
1114 * it prints an RTP packet to the stdout
1115 *
1116 * note that this function is *not* threadsafe
1117 */
1118
1119#include <stdio.h>
1120
1121#define MTU 2048
1122
1123char packet_string[MTU];
1124
1125char *
1126srtp_packet_to_string(srtp_hdr_t *hdr, int pkt_octet_len) {
1127 int octets_in_rtp_header = 12;
Marcus Sundberg410faaa2005-09-29 12:36:43 +00001128 uint8_t *data = ((uint8_t *)hdr)+octets_in_rtp_header;
Cullen Jennings235513a2005-09-21 22:51:36 +00001129 int hex_len = pkt_octet_len-octets_in_rtp_header;
1130
1131 /* sanity checking */
1132 if ((hdr == NULL) || (pkt_octet_len > MTU))
1133 return NULL;
1134
1135 /* write packet into string */
1136 sprintf(packet_string,
1137 "(s)rtp packet: {\n"
1138 " version:\t%d\n"
1139 " p:\t\t%d\n"
1140 " x:\t\t%d\n"
1141 " cc:\t\t%d\n"
1142 " m:\t\t%d\n"
1143 " pt:\t\t%x\n"
1144 " seq:\t\t%x\n"
1145 " ts:\t\t%x\n"
1146 " ssrc:\t%x\n"
1147 " data:\t%s\n"
1148 "} (%d octets in total)\n",
1149 hdr->version,
1150 hdr->p,
1151 hdr->x,
1152 hdr->cc,
1153 hdr->m,
1154 hdr->pt,
1155 hdr->seq,
1156 hdr->ts,
1157 hdr->ssrc,
1158 octet_string_hex_string(data, hex_len),
1159 pkt_octet_len);
1160
1161 return packet_string;
1162}
1163
1164/*
1165 * mips_estimate() is a simple function to estimate the number of
1166 * instructions per second that the host can perform. note that this
1167 * function can be grossly wrong; you may want to have a manual sanity
1168 * check of its output!
1169 *
1170 * the 'ignore' pointer is there to convince the compiler to not just
1171 * optimize away the function
1172 */
1173
1174double
1175mips_estimate(int num_trials, int *ignore) {
1176 clock_t t;
Jonathan Lennox33554932010-05-15 04:53:10 +00001177 volatile int i, sum;
Cullen Jennings235513a2005-09-21 22:51:36 +00001178
1179 sum = 0;
1180 t = clock();
1181 for (i=0; i<num_trials; i++)
1182 sum += i;
1183 t = clock() - t;
1184
1185/* printf("%d\n", sum); */
1186 *ignore = sum;
1187
1188 return (double) num_trials * CLOCKS_PER_SEC / t;
1189}
1190
1191
1192/*
1193 * srtp_validate() verifies the correctness of libsrtp by comparing
1194 * some computed packets against some pre-computed reference values.
1195 * These packets were made with the default SRTP policy.
1196 */
1197
1198
1199err_status_t
1200srtp_validate() {
Marcus Sundberg410faaa2005-09-29 12:36:43 +00001201 uint8_t srtp_plaintext_ref[28] = {
Cullen Jennings235513a2005-09-21 22:51:36 +00001202 0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
1203 0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab,
1204 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
1205 0xab, 0xab, 0xab, 0xab
1206 };
Marcus Sundberg410faaa2005-09-29 12:36:43 +00001207 uint8_t srtp_plaintext[38] = {
Cullen Jennings235513a2005-09-21 22:51:36 +00001208 0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
1209 0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab,
1210 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
1211 0xab, 0xab, 0xab, 0xab, 0x00, 0x00, 0x00, 0x00,
1212 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1213 };
Marcus Sundberg410faaa2005-09-29 12:36:43 +00001214 uint8_t srtp_ciphertext[38] = {
Cullen Jennings235513a2005-09-21 22:51:36 +00001215 0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
1216 0xca, 0xfe, 0xba, 0xbe, 0x4e, 0x55, 0xdc, 0x4c,
1217 0xe7, 0x99, 0x78, 0xd8, 0x8c, 0xa4, 0xd2, 0x15,
1218 0x94, 0x9d, 0x24, 0x02, 0xb7, 0x8d, 0x6a, 0xcc,
1219 0x99, 0xea, 0x17, 0x9b, 0x8d, 0xbb
1220 };
1221 srtp_t srtp_snd, srtp_recv;
1222 err_status_t status;
1223 int len;
1224 srtp_policy_t policy;
1225
1226 /*
1227 * create a session with a single stream using the default srtp
1228 * policy and with the SSRC value 0xcafebabe
1229 */
1230 crypto_policy_set_rtp_default(&policy.rtp);
1231 crypto_policy_set_rtcp_default(&policy.rtcp);
1232 policy.ssrc.type = ssrc_specific;
1233 policy.ssrc.value = 0xcafebabe;
1234 policy.key = test_key;
Jonathan Lennoxa1242f82010-05-17 21:46:04 +00001235 policy.ekt = NULL;
1236 policy.window_size = 128;
Jonathan Lennoxdcee5c62010-05-17 22:08:40 +00001237 policy.allow_repeat_tx = 0;
Cullen Jennings235513a2005-09-21 22:51:36 +00001238 policy.next = NULL;
1239
1240 status = srtp_create(&srtp_snd, &policy);
1241 if (status)
1242 return status;
1243
1244 /*
1245 * protect plaintext, then compare with ciphertext
1246 */
1247 len = 28;
1248 status = srtp_protect(srtp_snd, srtp_plaintext, &len);
1249 if (status || (len != 38))
1250 return err_status_fail;
1251
1252 debug_print(mod_driver, "ciphertext:\n %s",
1253 octet_string_hex_string(srtp_plaintext, len));
1254 debug_print(mod_driver, "ciphertext reference:\n %s",
1255 octet_string_hex_string(srtp_ciphertext, len));
1256
1257 if (octet_string_is_eq(srtp_plaintext, srtp_ciphertext, len))
1258 return err_status_fail;
1259
1260 /*
1261 * create a receiver session context comparable to the one created
1262 * above - we need to do this so that the replay checking doesn't
1263 * complain
1264 */
1265 status = srtp_create(&srtp_recv, &policy);
1266 if (status)
1267 return status;
1268
1269 /*
1270 * unprotect ciphertext, then compare with plaintext
1271 */
1272 status = srtp_unprotect(srtp_recv, srtp_ciphertext, &len);
1273 if (status || (len != 28))
1274 return status;
1275
1276 if (octet_string_is_eq(srtp_ciphertext, srtp_plaintext_ref, len))
1277 return err_status_fail;
1278
Jonathan Lennox80c4c832010-05-17 19:30:28 +00001279 status = srtp_dealloc(srtp_snd);
1280 if (status)
1281 return status;
1282
1283 status = srtp_dealloc(srtp_recv);
1284 if (status)
1285 return status;
1286
Cullen Jennings235513a2005-09-21 22:51:36 +00001287 return err_status_ok;
1288}
1289
1290
Jonathan Lennox5df951a2010-05-20 20:55:54 +00001291/*
1292 * srtp_validate_aes_256() verifies the correctness of libsrtp by comparing
1293 * some computed packets against some pre-computed reference values.
1294 * These packets were made with the AES-CM-256/HMAC-SHA-1-80 policy.
1295 */
1296
1297
1298err_status_t
1299srtp_validate_aes_256() {
Jonathan Lennox75b36872010-05-21 00:30:21 +00001300 unsigned char aes_256_test_key[46] = {
Jonathan Lennox5df951a2010-05-20 20:55:54 +00001301 0xf0, 0xf0, 0x49, 0x14, 0xb5, 0x13, 0xf2, 0x76,
1302 0x3a, 0x1b, 0x1f, 0xa1, 0x30, 0xf1, 0x0e, 0x29,
1303 0x98, 0xf6, 0xf6, 0xe4, 0x3e, 0x43, 0x09, 0xd1,
1304 0xe6, 0x22, 0xa0, 0xe3, 0x32, 0xb9, 0xf1, 0xb6,
1305
1306 0x3b, 0x04, 0x80, 0x3d, 0xe5, 0x1e, 0xe7, 0xc9,
1307 0x64, 0x23, 0xab, 0x5b, 0x78, 0xd2
1308 };
1309 uint8_t srtp_plaintext_ref[28] = {
1310 0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
1311 0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab,
1312 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
1313 0xab, 0xab, 0xab, 0xab
1314 };
1315 uint8_t srtp_plaintext[38] = {
1316 0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
1317 0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab,
1318 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
1319 0xab, 0xab, 0xab, 0xab, 0x00, 0x00, 0x00, 0x00,
1320 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1321 };
1322 uint8_t srtp_ciphertext[38] = {
1323 0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
1324 0xca, 0xfe, 0xba, 0xbe, 0xf1, 0xd9, 0xde, 0x17,
1325 0xff, 0x25, 0x1f, 0xf1, 0xaa, 0x00, 0x77, 0x74,
1326 0xb0, 0xb4, 0xb4, 0x0d, 0xa0, 0x8d, 0x9d, 0x9a,
1327 0x5b, 0x3a, 0x55, 0xd8, 0x87, 0x3b
1328 };
1329 srtp_t srtp_snd, srtp_recv;
1330 err_status_t status;
1331 int len;
1332 srtp_policy_t policy;
1333
1334 /*
1335 * create a session with a single stream using the default srtp
1336 * policy and with the SSRC value 0xcafebabe
1337 */
1338 crypto_policy_set_aes_cm_256_hmac_sha1_80(&policy.rtp);
1339 crypto_policy_set_aes_cm_256_hmac_sha1_80(&policy.rtcp);
1340 policy.ssrc.type = ssrc_specific;
1341 policy.ssrc.value = 0xcafebabe;
Jonathan Lennox75b36872010-05-21 00:30:21 +00001342 policy.key = aes_256_test_key;
Jonathan Lennox5df951a2010-05-20 20:55:54 +00001343 policy.ekt = NULL;
1344 policy.window_size = 128;
1345 policy.allow_repeat_tx = 0;
1346 policy.next = NULL;
1347
1348 status = srtp_create(&srtp_snd, &policy);
1349 if (status)
1350 return status;
1351
1352 /*
1353 * protect plaintext, then compare with ciphertext
1354 */
1355 len = 28;
1356 status = srtp_protect(srtp_snd, srtp_plaintext, &len);
1357 if (status || (len != 38))
1358 return err_status_fail;
1359
1360 debug_print(mod_driver, "ciphertext:\n %s",
1361 octet_string_hex_string(srtp_plaintext, len));
1362 debug_print(mod_driver, "ciphertext reference:\n %s",
1363 octet_string_hex_string(srtp_ciphertext, len));
1364
1365 if (octet_string_is_eq(srtp_plaintext, srtp_ciphertext, len))
1366 return err_status_fail;
1367
1368 /*
1369 * create a receiver session context comparable to the one created
1370 * above - we need to do this so that the replay checking doesn't
1371 * complain
1372 */
1373 status = srtp_create(&srtp_recv, &policy);
1374 if (status)
1375 return status;
1376
1377 /*
1378 * unprotect ciphertext, then compare with plaintext
1379 */
1380 status = srtp_unprotect(srtp_recv, srtp_ciphertext, &len);
1381 if (status || (len != 28))
1382 return status;
1383
1384 if (octet_string_is_eq(srtp_ciphertext, srtp_plaintext_ref, len))
1385 return err_status_fail;
1386
1387 status = srtp_dealloc(srtp_snd);
1388 if (status)
1389 return status;
1390
1391 status = srtp_dealloc(srtp_recv);
1392 if (status)
1393 return status;
1394
1395 return err_status_ok;
1396}
1397
1398
Cullen Jennings235513a2005-09-21 22:51:36 +00001399err_status_t
1400srtp_create_big_policy(srtp_policy_t **list) {
1401 extern const srtp_policy_t *policy_array[];
1402 srtp_policy_t *p, *tmp;
1403 int i = 0;
1404 uint32_t ssrc = 0;
1405
1406 /* sanity checking */
1407 if ((list == NULL) || (policy_array[0] == NULL))
1408 return err_status_bad_param;
1409
1410 /*
1411 * loop over policy list, mallocing a new list and copying values
1412 * into it (and incrementing the SSRC value as we go along)
1413 */
1414 tmp = NULL;
1415 while (policy_array[i] != NULL) {
Derek MacDonald17127da2006-07-12 22:22:08 +00001416 p = (srtp_policy_t*) malloc(sizeof(srtp_policy_t));
Cullen Jennings235513a2005-09-21 22:51:36 +00001417 if (p == NULL)
1418 return err_status_bad_param;
1419 memcpy(p, policy_array[i], sizeof(srtp_policy_t));
1420 p->ssrc.type = ssrc_specific;
1421 p->ssrc.value = ssrc++;
1422 p->next = tmp;
1423 tmp = p;
1424 i++;
1425 }
1426 *list = p;
1427
1428 return err_status_ok;
1429}
1430
1431err_status_t
Jonathan Lennox80c4c832010-05-17 19:30:28 +00001432srtp_dealloc_big_policy(srtp_policy_t *list) {
1433 srtp_policy_t *p, *next;
1434
1435 for (p = list; p != NULL; p = next) {
1436 next = p->next;
1437 free(p);
1438 }
1439
1440 return err_status_ok;
1441}
1442
1443
1444err_status_t
Cullen Jennings235513a2005-09-21 22:51:36 +00001445srtp_test_remove_stream() {
1446 err_status_t status;
1447 srtp_policy_t *policy_list;
1448 srtp_t session;
1449 srtp_stream_t stream;
1450 /*
1451 * srtp_get_stream() is a libSRTP internal function that we declare
1452 * here so that we can use it to verify the correct operation of the
1453 * library
1454 */
1455 extern srtp_stream_t srtp_get_stream(srtp_t srtp, uint32_t ssrc);
1456
1457
1458 status = srtp_create_big_policy(&policy_list);
1459 if (status)
1460 return status;
1461
1462 status = srtp_create(&session, policy_list);
1463 if (status)
1464 return status;
1465
1466 /*
1467 * check for false positives by trying to remove a stream that's not
1468 * in the session
1469 */
1470 status = srtp_remove_stream(session, htonl(0xaaaaaaaa));
1471 if (status != err_status_no_ctx)
1472 return err_status_fail;
1473
1474 /*
1475 * check for false negatives by removing stream 0x1, then
1476 * searching for streams 0x0 and 0x2
1477 */
1478 status = srtp_remove_stream(session, htonl(0x1));
1479 if (status != err_status_ok)
1480 return err_status_fail;
1481 stream = srtp_get_stream(session, htonl(0x0));
1482 if (stream == NULL)
1483 return err_status_fail;
1484 stream = srtp_get_stream(session, htonl(0x2));
1485 if (stream == NULL)
1486 return err_status_fail;
1487
Jonathan Lennox80c4c832010-05-17 19:30:28 +00001488 status = srtp_dealloc(session);
1489 if (status != err_status_ok)
1490 return status;
1491
1492 status = srtp_dealloc_big_policy(policy_list);
1493 if (status != err_status_ok)
1494 return status;
1495
Cullen Jennings235513a2005-09-21 22:51:36 +00001496 return err_status_ok;
1497}
1498
1499/*
1500 * srtp policy definitions - these definitions are used above
1501 */
1502
1503unsigned char test_key[30] = {
1504 0xe1, 0xf9, 0x7a, 0x0d, 0x3e, 0x01, 0x8b, 0xe0,
1505 0xd6, 0x4f, 0xa3, 0x2c, 0x06, 0xde, 0x41, 0x39,
1506 0x0e, 0xc6, 0x75, 0xad, 0x49, 0x8a, 0xfe, 0xeb,
1507 0xb6, 0x96, 0x0b, 0x3a, 0xab, 0xe6
1508};
1509
1510
1511const srtp_policy_t default_policy = {
1512 { ssrc_any_outbound, 0 }, /* SSRC */
1513 { /* SRTP policy */
1514 AES_128_ICM, /* cipher type */
1515 30, /* cipher key length in octets */
1516 HMAC_SHA1, /* authentication func type */
1517 16, /* auth key length in octets */
1518 10, /* auth tag length in octets */
1519 sec_serv_conf_and_auth /* security services flag */
1520 },
1521 { /* SRTCP policy */
1522 AES_128_ICM, /* cipher type */
1523 30, /* cipher key length in octets */
1524 HMAC_SHA1, /* authentication func type */
1525 16, /* auth key length in octets */
1526 10, /* auth tag length in octets */
1527 sec_serv_conf_and_auth /* security services flag */
1528 },
1529 test_key,
David McGrew79870d62007-06-15 18:17:39 +00001530 NULL, /* indicates that EKT is not in use */
Jonathan Lennoxa1242f82010-05-17 21:46:04 +00001531 128, /* replay window size */
Jonathan Lennoxdcee5c62010-05-17 22:08:40 +00001532 0, /* retransmission not allowed */
Cullen Jennings235513a2005-09-21 22:51:36 +00001533 NULL
1534};
1535
1536const srtp_policy_t aes_tmmh_policy = {
1537 { ssrc_any_outbound, 0 }, /* SSRC */
1538 {
1539 AES_128_ICM, /* cipher type */
1540 30, /* cipher key length in octets */
1541 UST_TMMHv2, /* authentication func type */
1542 94, /* auth key length in octets */
1543 4, /* auth tag length in octets */
1544 sec_serv_conf_and_auth /* security services flag */
1545 },
1546 {
1547 AES_128_ICM, /* cipher type */
1548 30, /* cipher key length in octets */
1549 UST_TMMHv2, /* authentication func type */
1550 94, /* auth key length in octets */
1551 4, /* auth tag length in octets */
1552 sec_serv_conf_and_auth /* security services flag */
1553 },
1554 test_key,
David McGrew79870d62007-06-15 18:17:39 +00001555 NULL, /* indicates that EKT is not in use */
Jonathan Lennoxa1242f82010-05-17 21:46:04 +00001556 128, /* replay window size */
Jonathan Lennoxdcee5c62010-05-17 22:08:40 +00001557 0, /* retransmission not allowed */
Cullen Jennings235513a2005-09-21 22:51:36 +00001558 NULL
1559};
1560
1561const srtp_policy_t tmmh_only_policy = {
1562 { ssrc_any_outbound, 0 }, /* SSRC */
1563 {
1564 AES_128_ICM, /* cipher type */
1565 30, /* cipher key length in octets */
1566 UST_TMMHv2, /* authentication func type */
1567 94, /* auth key length in octets */
1568 4, /* auth tag length in octets */
1569 sec_serv_auth /* security services flag */
1570 },
1571 {
1572 AES_128_ICM, /* cipher type */
1573 30, /* cipher key length in octets */
1574 UST_TMMHv2, /* authentication func type */
1575 94, /* auth key length in octets */
1576 4, /* auth tag length in octets */
1577 sec_serv_auth /* security services flag */
1578 },
1579 test_key,
David McGrew79870d62007-06-15 18:17:39 +00001580 NULL, /* indicates that EKT is not in use */
Jonathan Lennoxa1242f82010-05-17 21:46:04 +00001581 128, /* replay window size */
Jonathan Lennoxdcee5c62010-05-17 22:08:40 +00001582 0, /* retransmission not allowed */
Cullen Jennings235513a2005-09-21 22:51:36 +00001583 NULL
1584};
1585
1586const srtp_policy_t aes_only_policy = {
1587 { ssrc_any_outbound, 0 }, /* SSRC */
1588 {
1589 AES_128_ICM, /* cipher type */
1590 30, /* cipher key length in octets */
1591 NULL_AUTH, /* authentication func type */
1592 0, /* auth key length in octets */
1593 0, /* auth tag length in octets */
1594 sec_serv_conf /* security services flag */
1595 },
1596 {
1597 AES_128_ICM, /* cipher type */
1598 30, /* cipher key length in octets */
1599 NULL_AUTH, /* authentication func type */
1600 0, /* auth key length in octets */
1601 0, /* auth tag length in octets */
1602 sec_serv_conf /* security services flag */
1603 },
1604 test_key,
David McGrew79870d62007-06-15 18:17:39 +00001605 NULL, /* indicates that EKT is not in use */
Jonathan Lennoxa1242f82010-05-17 21:46:04 +00001606 128, /* replay window size */
Jonathan Lennoxdcee5c62010-05-17 22:08:40 +00001607 0, /* retransmission not allowed */
Cullen Jennings235513a2005-09-21 22:51:36 +00001608 NULL
1609};
1610
1611const srtp_policy_t hmac_only_policy = {
1612 { ssrc_any_outbound, 0 }, /* SSRC */
1613 {
1614 NULL_CIPHER, /* cipher type */
1615 0, /* cipher key length in octets */
1616 HMAC_SHA1, /* authentication func type */
1617 20, /* auth key length in octets */
1618 4, /* auth tag length in octets */
1619 sec_serv_auth /* security services flag */
1620 },
1621 {
1622 NULL_CIPHER, /* cipher type */
1623 0, /* cipher key length in octets */
1624 HMAC_SHA1, /* authentication func type */
1625 20, /* auth key length in octets */
1626 4, /* auth tag length in octets */
1627 sec_serv_auth /* security services flag */
1628 },
1629 test_key,
David McGrew79870d62007-06-15 18:17:39 +00001630 NULL, /* indicates that EKT is not in use */
Jonathan Lennoxa1242f82010-05-17 21:46:04 +00001631 128, /* replay window size */
Jonathan Lennoxdcee5c62010-05-17 22:08:40 +00001632 0, /* retransmission not allowed */
Cullen Jennings235513a2005-09-21 22:51:36 +00001633 NULL
1634};
1635
1636const srtp_policy_t null_policy = {
1637 { ssrc_any_outbound, 0 }, /* SSRC */
1638 {
1639 NULL_CIPHER, /* cipher type */
1640 0, /* cipher key length in octets */
1641 NULL_AUTH, /* authentication func type */
1642 0, /* auth key length in octets */
1643 0, /* auth tag length in octets */
1644 sec_serv_none /* security services flag */
1645 },
1646 {
1647 NULL_CIPHER, /* cipher type */
1648 0, /* cipher key length in octets */
1649 NULL_AUTH, /* authentication func type */
1650 0, /* auth key length in octets */
1651 0, /* auth tag length in octets */
1652 sec_serv_none /* security services flag */
1653 },
1654 test_key,
David McGrew79870d62007-06-15 18:17:39 +00001655 NULL, /* indicates that EKT is not in use */
Jonathan Lennoxa1242f82010-05-17 21:46:04 +00001656 128, /* replay window size */
Jonathan Lennoxdcee5c62010-05-17 22:08:40 +00001657 0, /* retransmission not allowed */
David McGrew79870d62007-06-15 18:17:39 +00001658 NULL
1659};
1660
Jonathan Lennox5df951a2010-05-20 20:55:54 +00001661unsigned char test_256_key[46] = {
1662 0xf0, 0xf0, 0x49, 0x14, 0xb5, 0x13, 0xf2, 0x76,
1663 0x3a, 0x1b, 0x1f, 0xa1, 0x30, 0xf1, 0x0e, 0x29,
1664 0x98, 0xf6, 0xf6, 0xe4, 0x3e, 0x43, 0x09, 0xd1,
1665 0xe6, 0x22, 0xa0, 0xe3, 0x32, 0xb9, 0xf1, 0xb6,
1666
1667 0x3b, 0x04, 0x80, 0x3d, 0xe5, 0x1e, 0xe7, 0xc9,
1668 0x64, 0x23, 0xab, 0x5b, 0x78, 0xd2
1669};
1670
1671const srtp_policy_t aes_256_hmac_policy = {
1672 { ssrc_any_outbound, 0 }, /* SSRC */
1673 { /* SRTP policy */
1674 AES_ICM, /* cipher type */
1675 46, /* cipher key length in octets */
1676 HMAC_SHA1, /* authentication func type */
1677 20, /* auth key length in octets */
1678 10, /* auth tag length in octets */
1679 sec_serv_conf_and_auth /* security services flag */
1680 },
1681 { /* SRTCP policy */
1682 AES_ICM, /* cipher type */
1683 46, /* cipher key length in octets */
1684 HMAC_SHA1, /* authentication func type */
1685 20, /* auth key length in octets */
1686 10, /* auth tag length in octets */
1687 sec_serv_conf_and_auth /* security services flag */
1688 },
1689 test_256_key,
1690 NULL, /* indicates that EKT is not in use */
1691 128, /* replay window size */
1692 0, /* retransmission not allowed */
1693 NULL
1694};
1695
David McGrew79870d62007-06-15 18:17:39 +00001696uint8_t ekt_test_key[16] = {
1697 0x77, 0x26, 0x9d, 0xac, 0x16, 0xa3, 0x28, 0xca,
1698 0x8e, 0xc9, 0x68, 0x4b, 0xcc, 0xc4, 0xd2, 0x1b
1699};
1700
1701#include "ekt.h"
1702
1703ekt_policy_ctx_t ekt_test_policy = {
1704 0xa5a5, /* SPI */
1705 EKT_CIPHER_AES_128_ECB,
1706 ekt_test_key,
1707 NULL
1708};
1709
1710const srtp_policy_t hmac_only_with_ekt_policy = {
1711 { ssrc_any_outbound, 0 }, /* SSRC */
1712 {
1713 NULL_CIPHER, /* cipher type */
1714 0, /* cipher key length in octets */
1715 HMAC_SHA1, /* authentication func type */
1716 20, /* auth key length in octets */
1717 4, /* auth tag length in octets */
1718 sec_serv_auth /* security services flag */
1719 },
1720 {
1721 NULL_CIPHER, /* cipher type */
1722 0, /* cipher key length in octets */
1723 HMAC_SHA1, /* authentication func type */
1724 20, /* auth key length in octets */
1725 4, /* auth tag length in octets */
1726 sec_serv_auth /* security services flag */
1727 },
1728 test_key,
1729 &ekt_test_policy, /* indicates that EKT is not in use */
Jonathan Lennoxa1242f82010-05-17 21:46:04 +00001730 128, /* replay window size */
Jonathan Lennoxdcee5c62010-05-17 22:08:40 +00001731 0, /* retransmission not allowed */
Cullen Jennings235513a2005-09-21 22:51:36 +00001732 NULL
1733};
1734
1735
1736/*
1737 * an array of pointers to the policies listed above
1738 *
1739 * This array is used to test various aspects of libSRTP for
1740 * different cryptographic policies. The order of the elements
1741 * matters - the timing test generates output that can be used
1742 * in a plot (see the gnuplot script file 'timing'). If you
1743 * add to this list, you should do it at the end.
1744 */
1745
1746#define USE_TMMH 0
1747
1748const srtp_policy_t *
1749policy_array[] = {
1750 &hmac_only_policy,
1751#if USE_TMMH
1752 &tmmh_only_policy,
1753#endif
1754 &aes_only_policy,
1755#if USE_TMMH
1756 &aes_tmmh_policy,
1757#endif
1758 &default_policy,
1759 &null_policy,
Jonathan Lennox5df951a2010-05-20 20:55:54 +00001760 &aes_256_hmac_policy,
David McGrew79870d62007-06-15 18:17:39 +00001761 &hmac_only_with_ekt_policy,
Cullen Jennings235513a2005-09-21 22:51:36 +00001762 NULL
1763};
1764
1765const srtp_policy_t wildcard_policy = {
1766 { ssrc_any_outbound, 0 }, /* SSRC */
1767 { /* SRTP policy */
1768 AES_128_ICM, /* cipher type */
1769 30, /* cipher key length in octets */
1770 HMAC_SHA1, /* authentication func type */
1771 16, /* auth key length in octets */
1772 10, /* auth tag length in octets */
1773 sec_serv_conf_and_auth /* security services flag */
1774 },
1775 { /* SRTCP policy */
1776 AES_128_ICM, /* cipher type */
1777 30, /* cipher key length in octets */
1778 HMAC_SHA1, /* authentication func type */
1779 16, /* auth key length in octets */
1780 10, /* auth tag length in octets */
1781 sec_serv_conf_and_auth /* security services flag */
1782 },
1783 test_key,
Jonathan Lennox28bd7c12010-05-15 00:23:19 +00001784 NULL,
Jonathan Lennoxa1242f82010-05-17 21:46:04 +00001785 128, /* replay window size */
Jonathan Lennoxdcee5c62010-05-17 22:08:40 +00001786 0, /* retransmission not allowed */
Cullen Jennings235513a2005-09-21 22:51:36 +00001787 NULL
1788};