blob: 51b33f52870e499991f19d46523ad28363b1894a [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++) {
528 err_status_t status;
David McGrewd2f8de42006-02-03 19:43:59 +0000529 len = msg_len_octets + 12; /* add in rtp header length */
Cullen Jennings235513a2005-09-21 22:51:36 +0000530
531 /* srtp protect message */
532 status = srtp_protect(srtp, mesg, &len);
533 if (status) {
534 printf("error: srtp_protect() failed with error code %d\n", status);
535 exit(1);
536 }
537
538 /* increment message number */
539 mesg->seq = htons(ntohs(mesg->seq) + 1);
540
541 }
542 timer = clock() - timer;
543
544 free(mesg);
Jonathan Lennox80c4c832010-05-17 19:30:28 +0000545
546 status = srtp_dealloc(srtp);
547 if (status) {
548 printf("error: srtp_dealloc() failed with error code %d\n", status);
549 exit(1);
550 }
Cullen Jennings235513a2005-09-21 22:51:36 +0000551
552 return (double) (msg_len_octets) * 8 *
553 num_trials * CLOCKS_PER_SEC / timer;
554}
555
556double
557srtp_rejections_per_second(int msg_len_octets, const srtp_policy_t *policy) {
558 srtp_ctx_t *srtp;
559 srtp_hdr_t *mesg;
560 int i;
561 int len;
562 clock_t timer;
563 int num_trials = 1000000;
564 uint32_t ssrc = policy->ssrc.value;
565 err_status_t status;
566
567 /*
568 * allocate and initialize an srtp session
569 */
570 status = srtp_create(&srtp, policy);
571 if (status) {
572 printf("error: srtp_create() failed with error code %d\n", status);
573 exit(1);
574 }
575
576 mesg = srtp_create_test_packet(msg_len_octets, ssrc);
577 if (mesg == NULL)
578 return 0.0; /* indicate failure by returning zero */
579
580 len = msg_len_octets;
581 srtp_protect(srtp, (srtp_hdr_t *)mesg, &len);
582
583 timer = clock();
584 for (i=0; i < num_trials; i++) {
585 len = msg_len_octets;
586 srtp_unprotect(srtp, (srtp_hdr_t *)mesg, &len);
587 }
588 timer = clock() - timer;
589
590 free(mesg);
Jonathan Lennox80c4c832010-05-17 19:30:28 +0000591
592 status = srtp_dealloc(srtp);
593 if (status) {
594 printf("error: srtp_dealloc() failed with error code %d\n", status);
595 exit(1);
596 }
597
Cullen Jennings235513a2005-09-21 22:51:36 +0000598 return (double) num_trials * CLOCKS_PER_SEC / timer;
599}
600
601
602void
603err_check(err_status_t s) {
604 if (s == err_status_ok)
605 return;
606 else
607 fprintf(stderr, "error: unexpected srtp failure (code %d)\n", s);
608 exit (1);
609}
610
611err_status_t
612srtp_test(const srtp_policy_t *policy) {
613 int i;
614 srtp_t srtp_sender;
615 srtp_t srtp_rcvr;
616 err_status_t status = err_status_ok;
617 srtp_hdr_t *hdr, *hdr2;
Marcus Sundberg5c40da82005-10-08 18:15:00 +0000618 uint8_t hdr_enc[64];
Marcus Sundberg410faaa2005-09-29 12:36:43 +0000619 uint8_t *pkt_end;
Marcus Sundberg5c40da82005-10-08 18:15:00 +0000620 int msg_len_octets, msg_len_enc;
Cullen Jennings235513a2005-09-21 22:51:36 +0000621 int len;
622 int tag_length = policy->rtp.auth_tag_len;
623 uint32_t ssrc;
624 srtp_policy_t *rcvr_policy;
625
626 err_check(srtp_create(&srtp_sender, policy));
627
628 /* print out policy */
629 err_check(srtp_session_print_policy(srtp_sender));
630
631 /*
632 * initialize data buffer, using the ssrc in the policy unless that
633 * value is a wildcard, in which case we'll just use an arbitrary
634 * one
635 */
636 if (policy->ssrc.type != ssrc_specific)
637 ssrc = 0xdecafbad;
638 else
639 ssrc = policy->ssrc.value;
640 msg_len_octets = 28;
641 hdr = srtp_create_test_packet(msg_len_octets, ssrc);
642
643 if (hdr == NULL)
644 return err_status_alloc_fail;
645 hdr2 = srtp_create_test_packet(msg_len_octets, ssrc);
646 if (hdr2 == NULL) {
647 free(hdr);
648 return err_status_alloc_fail;
649 }
650
651 /* set message length */
652 len = msg_len_octets;
653
654 debug_print(mod_driver, "before protection:\n%s",
655 srtp_packet_to_string(hdr, len));
656
657#if PRINT_REFERENCE_PACKET
658 debug_print(mod_driver, "reference packet before protection:\n%s",
Marcus Sundberg410faaa2005-09-29 12:36:43 +0000659 octet_string_hex_string((uint8_t *)hdr, len));
Cullen Jennings235513a2005-09-21 22:51:36 +0000660#endif
661 err_check(srtp_protect(srtp_sender, hdr, &len));
662
663 debug_print(mod_driver, "after protection:\n%s",
664 srtp_packet_to_string(hdr, len));
665#if PRINT_REFERENCE_PACKET
666 debug_print(mod_driver, "after protection:\n%s",
Marcus Sundberg410faaa2005-09-29 12:36:43 +0000667 octet_string_hex_string((uint8_t *)hdr, len));
Cullen Jennings235513a2005-09-21 22:51:36 +0000668#endif
669
Marcus Sundberg5c40da82005-10-08 18:15:00 +0000670 /* save protected message and length */
671 memcpy(hdr_enc, hdr, len);
672 msg_len_enc = len;
673
Cullen Jennings235513a2005-09-21 22:51:36 +0000674 /*
675 * check for overrun of the srtp_protect() function
676 *
677 * The packet is followed by a value of 0xfffff; if the value of the
678 * data following the packet is different, then we know that the
679 * protect function is overwriting the end of the packet.
680 */
Marcus Sundberg410faaa2005-09-29 12:36:43 +0000681 pkt_end = (uint8_t *)hdr + sizeof(srtp_hdr_t)
Cullen Jennings235513a2005-09-21 22:51:36 +0000682 + msg_len_octets + tag_length;
683 for (i = 0; i < 4; i++)
684 if (pkt_end[i] != 0xff) {
685 fprintf(stdout, "overwrite in srtp_protect() function "
686 "(expected %x, found %x in trailing octet %d)\n",
Marcus Sundberg410faaa2005-09-29 12:36:43 +0000687 0xff, ((uint8_t *)hdr)[i], i);
Cullen Jennings235513a2005-09-21 22:51:36 +0000688 free(hdr);
689 free(hdr2);
690 return err_status_algo_fail;
691 }
692
693 /*
694 * if the policy includes confidentiality, check that ciphertext is
695 * different than plaintext
696 *
697 * Note that this check will give false negatives, with some small
698 * probability, especially if the packets are short. For that
699 * reason, we skip this check if the plaintext is less than four
700 * octets long.
701 */
702 if ((policy->rtp.sec_serv & sec_serv_conf) && (msg_len_octets >= 4)) {
703 printf("testing that ciphertext is distinct from plaintext...");
704 status = err_status_algo_fail;
705 for (i=12; i < msg_len_octets+12; i++)
Marcus Sundberg410faaa2005-09-29 12:36:43 +0000706 if (((uint8_t *)hdr)[i] != ((uint8_t *)hdr2)[i]) {
Cullen Jennings235513a2005-09-21 22:51:36 +0000707 status = err_status_ok;
708 }
709 if (status) {
710 printf("failed\n");
711 free(hdr);
712 free(hdr2);
713 return status;
714 }
715 printf("passed\n");
716 }
717
718 /*
719 * if the policy uses a 'wildcard' ssrc, then we need to make a copy
720 * of the policy that changes the direction to inbound
721 *
722 * we always copy the policy into the rcvr_policy, since otherwise
723 * the compiler would fret about the constness of the policy
724 */
Derek MacDonald17127da2006-07-12 22:22:08 +0000725 rcvr_policy = (srtp_policy_t*) malloc(sizeof(srtp_policy_t));
Jonathan Lennox80c4c832010-05-17 19:30:28 +0000726 if (rcvr_policy == NULL) {
727 free(hdr);
728 free(hdr2);
Cullen Jennings235513a2005-09-21 22:51:36 +0000729 return err_status_alloc_fail;
Jonathan Lennox80c4c832010-05-17 19:30:28 +0000730 }
Cullen Jennings235513a2005-09-21 22:51:36 +0000731 memcpy(rcvr_policy, policy, sizeof(srtp_policy_t));
732 if (policy->ssrc.type == ssrc_any_outbound) {
733 rcvr_policy->ssrc.type = ssrc_any_inbound;
734 }
735
736 err_check(srtp_create(&srtp_rcvr, rcvr_policy));
737
738 err_check(srtp_unprotect(srtp_rcvr, hdr, &len));
739
740 debug_print(mod_driver, "after unprotection:\n%s",
741 srtp_packet_to_string(hdr, len));
742
743 /* verify that the unprotected packet matches the origial one */
744 for (i=0; i < msg_len_octets; i++)
Marcus Sundberg410faaa2005-09-29 12:36:43 +0000745 if (((uint8_t *)hdr)[i] != ((uint8_t *)hdr2)[i]) {
Cullen Jennings235513a2005-09-21 22:51:36 +0000746 fprintf(stdout, "mismatch at octet %d\n", i);
747 status = err_status_algo_fail;
748 }
749 if (status) {
750 free(hdr);
751 free(hdr2);
Jonathan Lennox80c4c832010-05-17 19:30:28 +0000752 free(rcvr_policy);
Cullen Jennings235513a2005-09-21 22:51:36 +0000753 return status;
754 }
755
756 /*
757 * if the policy includes authentication, then test for false positives
758 */
759 if (policy->rtp.sec_serv & sec_serv_auth) {
760 char *data = ((char *)hdr) + 12;
761
762 printf("testing for false positives in replay check...");
763
Marcus Sundberg5c40da82005-10-08 18:15:00 +0000764 /* set message length */
765 len = msg_len_enc;
766
Cullen Jennings235513a2005-09-21 22:51:36 +0000767 /* unprotect a second time - should fail with a replay error */
Marcus Sundberg5c40da82005-10-08 18:15:00 +0000768 status = srtp_unprotect(srtp_rcvr, hdr_enc, &len);
Cullen Jennings235513a2005-09-21 22:51:36 +0000769 if (status != err_status_replay_fail) {
770 printf("failed with error code %d\n", status);
771 free(hdr);
772 free(hdr2);
Jonathan Lennox80c4c832010-05-17 19:30:28 +0000773 free(rcvr_policy);
Cullen Jennings235513a2005-09-21 22:51:36 +0000774 return status;
775 } else {
776 printf("passed\n");
777 }
778
779 printf("testing for false positives in auth check...");
780
781 /* increment sequence number in header */
782 hdr->seq++;
783
Marcus Sundberg5c40da82005-10-08 18:15:00 +0000784 /* set message length */
785 len = msg_len_octets;
786
Cullen Jennings235513a2005-09-21 22:51:36 +0000787 /* apply protection */
788 err_check(srtp_protect(srtp_sender, hdr, &len));
789
790 /* flip bits in packet */
791 data[0] ^= 0xff;
792
793 /* unprotect, and check for authentication failure */
794 status = srtp_unprotect(srtp_rcvr, hdr, &len);
795 if (status != err_status_auth_fail) {
796 printf("failed\n");
797 free(hdr);
798 free(hdr2);
Jonathan Lennox80c4c832010-05-17 19:30:28 +0000799 free(rcvr_policy);
Cullen Jennings235513a2005-09-21 22:51:36 +0000800 return status;
801 } else {
802 printf("passed\n");
803 }
804
805 }
806
807 err_check(srtp_dealloc(srtp_sender));
808 err_check(srtp_dealloc(srtp_rcvr));
809
810 free(hdr);
811 free(hdr2);
Jonathan Lennox80c4c832010-05-17 19:30:28 +0000812 free(rcvr_policy);
Cullen Jennings235513a2005-09-21 22:51:36 +0000813 return err_status_ok;
814}
815
816
817err_status_t
David McGrew9c70f292006-05-03 19:38:38 +0000818srtcp_test(const srtp_policy_t *policy) {
819 int i;
820 srtp_t srtcp_sender;
821 srtp_t srtcp_rcvr;
822 err_status_t status = err_status_ok;
823 srtp_hdr_t *hdr, *hdr2;
824 uint8_t hdr_enc[64];
825 uint8_t *pkt_end;
826 int msg_len_octets, msg_len_enc;
827 int len;
828 int tag_length = policy->rtp.auth_tag_len;
829 uint32_t ssrc;
830 srtp_policy_t *rcvr_policy;
831
832 err_check(srtp_create(&srtcp_sender, policy));
833
834 /* print out policy */
835 err_check(srtp_session_print_policy(srtcp_sender));
836
837 /*
838 * initialize data buffer, using the ssrc in the policy unless that
839 * value is a wildcard, in which case we'll just use an arbitrary
840 * one
841 */
842 if (policy->ssrc.type != ssrc_specific)
843 ssrc = 0xdecafbad;
844 else
845 ssrc = policy->ssrc.value;
846 msg_len_octets = 28;
847 hdr = srtp_create_test_packet(msg_len_octets, ssrc);
848
849 if (hdr == NULL)
850 return err_status_alloc_fail;
851 hdr2 = srtp_create_test_packet(msg_len_octets, ssrc);
852 if (hdr2 == NULL) {
853 free(hdr);
854 return err_status_alloc_fail;
855 }
856
857 /* set message length */
858 len = msg_len_octets;
859
860 debug_print(mod_driver, "before protection:\n%s",
861 srtp_packet_to_string(hdr, len));
862
863#if PRINT_REFERENCE_PACKET
864 debug_print(mod_driver, "reference packet before protection:\n%s",
865 octet_string_hex_string((uint8_t *)hdr, len));
866#endif
867 err_check(srtp_protect_rtcp(srtcp_sender, hdr, &len));
868
869 debug_print(mod_driver, "after protection:\n%s",
870 srtp_packet_to_string(hdr, len));
871#if PRINT_REFERENCE_PACKET
872 debug_print(mod_driver, "after protection:\n%s",
873 octet_string_hex_string((uint8_t *)hdr, len));
874#endif
875
876 /* save protected message and length */
877 memcpy(hdr_enc, hdr, len);
878 msg_len_enc = len;
879
880 /*
881 * check for overrun of the srtp_protect() function
882 *
883 * The packet is followed by a value of 0xfffff; if the value of the
884 * data following the packet is different, then we know that the
885 * protect function is overwriting the end of the packet.
886 */
887 pkt_end = (uint8_t *)hdr + sizeof(srtp_hdr_t)
888 + msg_len_octets + tag_length;
889 for (i = 0; i < 4; i++)
890 if (pkt_end[i] != 0xff) {
891 fprintf(stdout, "overwrite in srtp_protect_rtcp() function "
892 "(expected %x, found %x in trailing octet %d)\n",
893 0xff, ((uint8_t *)hdr)[i], i);
894 free(hdr);
895 free(hdr2);
896 return err_status_algo_fail;
897 }
898
899 /*
900 * if the policy includes confidentiality, check that ciphertext is
901 * different than plaintext
902 *
903 * Note that this check will give false negatives, with some small
904 * probability, especially if the packets are short. For that
905 * reason, we skip this check if the plaintext is less than four
906 * octets long.
907 */
908 if ((policy->rtp.sec_serv & sec_serv_conf) && (msg_len_octets >= 4)) {
909 printf("testing that ciphertext is distinct from plaintext...");
910 status = err_status_algo_fail;
911 for (i=12; i < msg_len_octets+12; i++)
912 if (((uint8_t *)hdr)[i] != ((uint8_t *)hdr2)[i]) {
913 status = err_status_ok;
914 }
915 if (status) {
916 printf("failed\n");
917 free(hdr);
918 free(hdr2);
919 return status;
920 }
921 printf("passed\n");
922 }
923
924 /*
925 * if the policy uses a 'wildcard' ssrc, then we need to make a copy
926 * of the policy that changes the direction to inbound
927 *
928 * we always copy the policy into the rcvr_policy, since otherwise
929 * the compiler would fret about the constness of the policy
930 */
Derek MacDonald17127da2006-07-12 22:22:08 +0000931 rcvr_policy = (srtp_policy_t*) malloc(sizeof(srtp_policy_t));
David McGrew9c70f292006-05-03 19:38:38 +0000932 if (rcvr_policy == NULL)
933 return err_status_alloc_fail;
934 memcpy(rcvr_policy, policy, sizeof(srtp_policy_t));
935 if (policy->ssrc.type == ssrc_any_outbound) {
936 rcvr_policy->ssrc.type = ssrc_any_inbound;
937 }
938
939 err_check(srtp_create(&srtcp_rcvr, rcvr_policy));
940
941 err_check(srtp_unprotect_rtcp(srtcp_rcvr, hdr, &len));
942
943 debug_print(mod_driver, "after unprotection:\n%s",
944 srtp_packet_to_string(hdr, len));
945
946 /* verify that the unprotected packet matches the origial one */
947 for (i=0; i < msg_len_octets; i++)
948 if (((uint8_t *)hdr)[i] != ((uint8_t *)hdr2)[i]) {
949 fprintf(stdout, "mismatch at octet %d\n", i);
950 status = err_status_algo_fail;
951 }
952 if (status) {
953 free(hdr);
954 free(hdr2);
Jonathan Lennox80c4c832010-05-17 19:30:28 +0000955 free(rcvr_policy);
David McGrew9c70f292006-05-03 19:38:38 +0000956 return status;
957 }
958
959 /*
960 * if the policy includes authentication, then test for false positives
961 */
962 if (policy->rtp.sec_serv & sec_serv_auth) {
963 char *data = ((char *)hdr) + 12;
964
965 printf("testing for false positives in replay check...");
966
967 /* set message length */
968 len = msg_len_enc;
969
970 /* unprotect a second time - should fail with a replay error */
971 status = srtp_unprotect_rtcp(srtcp_rcvr, hdr_enc, &len);
972 if (status != err_status_replay_fail) {
973 printf("failed with error code %d\n", status);
974 free(hdr);
975 free(hdr2);
Jonathan Lennox80c4c832010-05-17 19:30:28 +0000976 free(rcvr_policy);
David McGrew9c70f292006-05-03 19:38:38 +0000977 return status;
978 } else {
979 printf("passed\n");
980 }
981
982 printf("testing for false positives in auth check...");
983
984 /* increment sequence number in header */
985 hdr->seq++;
986
987 /* set message length */
988 len = msg_len_octets;
989
990 /* apply protection */
991 err_check(srtp_protect_rtcp(srtcp_sender, hdr, &len));
992
993 /* flip bits in packet */
994 data[0] ^= 0xff;
995
996 /* unprotect, and check for authentication failure */
997 status = srtp_unprotect_rtcp(srtcp_rcvr, hdr, &len);
998 if (status != err_status_auth_fail) {
999 printf("failed\n");
1000 free(hdr);
1001 free(hdr2);
Jonathan Lennox80c4c832010-05-17 19:30:28 +00001002 free(rcvr_policy);
David McGrew9c70f292006-05-03 19:38:38 +00001003 return status;
1004 } else {
1005 printf("passed\n");
1006 }
1007
1008 }
1009
1010 err_check(srtp_dealloc(srtcp_sender));
1011 err_check(srtp_dealloc(srtcp_rcvr));
1012
1013 free(hdr);
1014 free(hdr2);
Jonathan Lennox80c4c832010-05-17 19:30:28 +00001015 free(rcvr_policy);
David McGrew9c70f292006-05-03 19:38:38 +00001016 return err_status_ok;
1017}
1018
1019
1020err_status_t
Cullen Jennings235513a2005-09-21 22:51:36 +00001021srtp_session_print_policy(srtp_t srtp) {
1022 char *serv_descr[4] = {
1023 "none",
1024 "confidentiality",
1025 "authentication",
1026 "confidentiality and authentication"
1027 };
1028 char *direction[3] = {
1029 "unknown",
1030 "outbound",
1031 "inbound"
1032 };
1033 srtp_stream_t stream;
1034
1035 /* sanity checking */
1036 if (srtp == NULL)
1037 return err_status_fail;
1038
1039 /* if there's a template stream, print it out */
1040 if (srtp->stream_template != NULL) {
1041 stream = srtp->stream_template;
1042 printf("# SSRC: any %s\r\n"
1043 "# rtp cipher: %s\r\n"
1044 "# rtp auth: %s\r\n"
1045 "# rtp services: %s\r\n"
1046 "# rtcp cipher: %s\r\n"
1047 "# rtcp auth: %s\r\n"
Jonathan Lennoxa1242f82010-05-17 21:46:04 +00001048 "# rtcp services: %s\r\n"
Jonathan Lennoxdcee5c62010-05-17 22:08:40 +00001049 "# window size: %lu\r\n"
1050 "# tx rtx allowed:%s\r\n",
Cullen Jennings235513a2005-09-21 22:51:36 +00001051 direction[stream->direction],
1052 stream->rtp_cipher->type->description,
1053 stream->rtp_auth->type->description,
1054 serv_descr[stream->rtp_services],
1055 stream->rtcp_cipher->type->description,
1056 stream->rtcp_auth->type->description,
Jonathan Lennoxa1242f82010-05-17 21:46:04 +00001057 serv_descr[stream->rtcp_services],
Jonathan Lennoxdcee5c62010-05-17 22:08:40 +00001058 rdbx_get_window_size(&stream->rtp_rdbx),
1059 stream->allow_repeat_tx ? "true" : "false");
Cullen Jennings235513a2005-09-21 22:51:36 +00001060 }
1061
1062 /* loop over streams in session, printing the policy of each */
1063 stream = srtp->stream_list;
1064 while (stream != NULL) {
1065 if (stream->rtp_services > sec_serv_conf_and_auth)
1066 return err_status_bad_param;
1067
1068 printf("# SSRC: 0x%08x\r\n"
1069 "# rtp cipher: %s\r\n"
1070 "# rtp auth: %s\r\n"
1071 "# rtp services: %s\r\n"
1072 "# rtcp cipher: %s\r\n"
1073 "# rtcp auth: %s\r\n"
Jonathan Lennoxa1242f82010-05-17 21:46:04 +00001074 "# rtcp services: %s\r\n"
Jonathan Lennoxdcee5c62010-05-17 22:08:40 +00001075 "# window size: %lu\r\n"
1076 "# tx rtx allowed:%s\r\n",
Cullen Jennings235513a2005-09-21 22:51:36 +00001077 stream->ssrc,
1078 stream->rtp_cipher->type->description,
1079 stream->rtp_auth->type->description,
1080 serv_descr[stream->rtp_services],
1081 stream->rtcp_cipher->type->description,
1082 stream->rtcp_auth->type->description,
Jonathan Lennoxa1242f82010-05-17 21:46:04 +00001083 serv_descr[stream->rtcp_services],
Jonathan Lennoxdcee5c62010-05-17 22:08:40 +00001084 rdbx_get_window_size(&stream->rtp_rdbx),
1085 stream->allow_repeat_tx ? "true" : "false");
Cullen Jennings235513a2005-09-21 22:51:36 +00001086
1087 /* advance to next stream in the list */
1088 stream = stream->next;
1089 }
1090 return err_status_ok;
1091}
1092
1093err_status_t
1094srtp_print_policy(const srtp_policy_t *policy) {
1095 err_status_t status;
1096 srtp_t session;
1097
1098 status = srtp_create(&session, policy);
1099 if (status)
1100 return status;
1101 status = srtp_session_print_policy(session);
1102 if (status)
1103 return status;
1104 status = srtp_dealloc(session);
1105 if (status)
1106 return status;
1107 return err_status_ok;
1108}
1109
1110/*
1111 * srtp_print_packet(...) is for debugging only
1112 * it prints an RTP packet to the stdout
1113 *
1114 * note that this function is *not* threadsafe
1115 */
1116
1117#include <stdio.h>
1118
1119#define MTU 2048
1120
1121char packet_string[MTU];
1122
1123char *
1124srtp_packet_to_string(srtp_hdr_t *hdr, int pkt_octet_len) {
1125 int octets_in_rtp_header = 12;
Marcus Sundberg410faaa2005-09-29 12:36:43 +00001126 uint8_t *data = ((uint8_t *)hdr)+octets_in_rtp_header;
Cullen Jennings235513a2005-09-21 22:51:36 +00001127 int hex_len = pkt_octet_len-octets_in_rtp_header;
1128
1129 /* sanity checking */
1130 if ((hdr == NULL) || (pkt_octet_len > MTU))
1131 return NULL;
1132
1133 /* write packet into string */
1134 sprintf(packet_string,
1135 "(s)rtp packet: {\n"
1136 " version:\t%d\n"
1137 " p:\t\t%d\n"
1138 " x:\t\t%d\n"
1139 " cc:\t\t%d\n"
1140 " m:\t\t%d\n"
1141 " pt:\t\t%x\n"
1142 " seq:\t\t%x\n"
1143 " ts:\t\t%x\n"
1144 " ssrc:\t%x\n"
1145 " data:\t%s\n"
1146 "} (%d octets in total)\n",
1147 hdr->version,
1148 hdr->p,
1149 hdr->x,
1150 hdr->cc,
1151 hdr->m,
1152 hdr->pt,
1153 hdr->seq,
1154 hdr->ts,
1155 hdr->ssrc,
1156 octet_string_hex_string(data, hex_len),
1157 pkt_octet_len);
1158
1159 return packet_string;
1160}
1161
1162/*
1163 * mips_estimate() is a simple function to estimate the number of
1164 * instructions per second that the host can perform. note that this
1165 * function can be grossly wrong; you may want to have a manual sanity
1166 * check of its output!
1167 *
1168 * the 'ignore' pointer is there to convince the compiler to not just
1169 * optimize away the function
1170 */
1171
1172double
1173mips_estimate(int num_trials, int *ignore) {
1174 clock_t t;
Jonathan Lennox33554932010-05-15 04:53:10 +00001175 volatile int i, sum;
Cullen Jennings235513a2005-09-21 22:51:36 +00001176
1177 sum = 0;
1178 t = clock();
1179 for (i=0; i<num_trials; i++)
1180 sum += i;
1181 t = clock() - t;
1182
1183/* printf("%d\n", sum); */
1184 *ignore = sum;
1185
1186 return (double) num_trials * CLOCKS_PER_SEC / t;
1187}
1188
1189
1190/*
1191 * srtp_validate() verifies the correctness of libsrtp by comparing
1192 * some computed packets against some pre-computed reference values.
1193 * These packets were made with the default SRTP policy.
1194 */
1195
1196
1197err_status_t
1198srtp_validate() {
1199 unsigned char test_key[30] = {
1200 0xe1, 0xf9, 0x7a, 0x0d, 0x3e, 0x01, 0x8b, 0xe0,
1201 0xd6, 0x4f, 0xa3, 0x2c, 0x06, 0xde, 0x41, 0x39,
1202 0x0e, 0xc6, 0x75, 0xad, 0x49, 0x8a, 0xfe, 0xeb,
1203 0xb6, 0x96, 0x0b, 0x3a, 0xab, 0xe6
1204 };
Marcus Sundberg410faaa2005-09-29 12:36:43 +00001205 uint8_t srtp_plaintext_ref[28] = {
Cullen Jennings235513a2005-09-21 22:51:36 +00001206 0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
1207 0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab,
1208 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
1209 0xab, 0xab, 0xab, 0xab
1210 };
Marcus Sundberg410faaa2005-09-29 12:36:43 +00001211 uint8_t srtp_plaintext[38] = {
Cullen Jennings235513a2005-09-21 22:51:36 +00001212 0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
1213 0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab,
1214 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
1215 0xab, 0xab, 0xab, 0xab, 0x00, 0x00, 0x00, 0x00,
1216 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1217 };
Marcus Sundberg410faaa2005-09-29 12:36:43 +00001218 uint8_t srtp_ciphertext[38] = {
Cullen Jennings235513a2005-09-21 22:51:36 +00001219 0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
1220 0xca, 0xfe, 0xba, 0xbe, 0x4e, 0x55, 0xdc, 0x4c,
1221 0xe7, 0x99, 0x78, 0xd8, 0x8c, 0xa4, 0xd2, 0x15,
1222 0x94, 0x9d, 0x24, 0x02, 0xb7, 0x8d, 0x6a, 0xcc,
1223 0x99, 0xea, 0x17, 0x9b, 0x8d, 0xbb
1224 };
1225 srtp_t srtp_snd, srtp_recv;
1226 err_status_t status;
1227 int len;
1228 srtp_policy_t policy;
1229
1230 /*
1231 * create a session with a single stream using the default srtp
1232 * policy and with the SSRC value 0xcafebabe
1233 */
1234 crypto_policy_set_rtp_default(&policy.rtp);
1235 crypto_policy_set_rtcp_default(&policy.rtcp);
1236 policy.ssrc.type = ssrc_specific;
1237 policy.ssrc.value = 0xcafebabe;
1238 policy.key = test_key;
Jonathan Lennoxa1242f82010-05-17 21:46:04 +00001239 policy.ekt = NULL;
1240 policy.window_size = 128;
Jonathan Lennoxdcee5c62010-05-17 22:08:40 +00001241 policy.allow_repeat_tx = 0;
Cullen Jennings235513a2005-09-21 22:51:36 +00001242 policy.next = NULL;
1243
1244 status = srtp_create(&srtp_snd, &policy);
1245 if (status)
1246 return status;
1247
1248 /*
1249 * protect plaintext, then compare with ciphertext
1250 */
1251 len = 28;
1252 status = srtp_protect(srtp_snd, srtp_plaintext, &len);
1253 if (status || (len != 38))
1254 return err_status_fail;
1255
1256 debug_print(mod_driver, "ciphertext:\n %s",
1257 octet_string_hex_string(srtp_plaintext, len));
1258 debug_print(mod_driver, "ciphertext reference:\n %s",
1259 octet_string_hex_string(srtp_ciphertext, len));
1260
1261 if (octet_string_is_eq(srtp_plaintext, srtp_ciphertext, len))
1262 return err_status_fail;
1263
1264 /*
1265 * create a receiver session context comparable to the one created
1266 * above - we need to do this so that the replay checking doesn't
1267 * complain
1268 */
1269 status = srtp_create(&srtp_recv, &policy);
1270 if (status)
1271 return status;
1272
1273 /*
1274 * unprotect ciphertext, then compare with plaintext
1275 */
1276 status = srtp_unprotect(srtp_recv, srtp_ciphertext, &len);
1277 if (status || (len != 28))
1278 return status;
1279
1280 if (octet_string_is_eq(srtp_ciphertext, srtp_plaintext_ref, len))
1281 return err_status_fail;
1282
Jonathan Lennox80c4c832010-05-17 19:30:28 +00001283 status = srtp_dealloc(srtp_snd);
1284 if (status)
1285 return status;
1286
1287 status = srtp_dealloc(srtp_recv);
1288 if (status)
1289 return status;
1290
Cullen Jennings235513a2005-09-21 22:51:36 +00001291 return err_status_ok;
1292}
1293
1294
Jonathan Lennox5df951a2010-05-20 20:55:54 +00001295/*
1296 * srtp_validate_aes_256() verifies the correctness of libsrtp by comparing
1297 * some computed packets against some pre-computed reference values.
1298 * These packets were made with the AES-CM-256/HMAC-SHA-1-80 policy.
1299 */
1300
1301
1302err_status_t
1303srtp_validate_aes_256() {
1304 unsigned char test_key[46] = {
1305 0xf0, 0xf0, 0x49, 0x14, 0xb5, 0x13, 0xf2, 0x76,
1306 0x3a, 0x1b, 0x1f, 0xa1, 0x30, 0xf1, 0x0e, 0x29,
1307 0x98, 0xf6, 0xf6, 0xe4, 0x3e, 0x43, 0x09, 0xd1,
1308 0xe6, 0x22, 0xa0, 0xe3, 0x32, 0xb9, 0xf1, 0xb6,
1309
1310 0x3b, 0x04, 0x80, 0x3d, 0xe5, 0x1e, 0xe7, 0xc9,
1311 0x64, 0x23, 0xab, 0x5b, 0x78, 0xd2
1312 };
1313 uint8_t srtp_plaintext_ref[28] = {
1314 0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
1315 0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab,
1316 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
1317 0xab, 0xab, 0xab, 0xab
1318 };
1319 uint8_t srtp_plaintext[38] = {
1320 0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
1321 0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab,
1322 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
1323 0xab, 0xab, 0xab, 0xab, 0x00, 0x00, 0x00, 0x00,
1324 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1325 };
1326 uint8_t srtp_ciphertext[38] = {
1327 0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
1328 0xca, 0xfe, 0xba, 0xbe, 0xf1, 0xd9, 0xde, 0x17,
1329 0xff, 0x25, 0x1f, 0xf1, 0xaa, 0x00, 0x77, 0x74,
1330 0xb0, 0xb4, 0xb4, 0x0d, 0xa0, 0x8d, 0x9d, 0x9a,
1331 0x5b, 0x3a, 0x55, 0xd8, 0x87, 0x3b
1332 };
1333 srtp_t srtp_snd, srtp_recv;
1334 err_status_t status;
1335 int len;
1336 srtp_policy_t policy;
1337
1338 /*
1339 * create a session with a single stream using the default srtp
1340 * policy and with the SSRC value 0xcafebabe
1341 */
1342 crypto_policy_set_aes_cm_256_hmac_sha1_80(&policy.rtp);
1343 crypto_policy_set_aes_cm_256_hmac_sha1_80(&policy.rtcp);
1344 policy.ssrc.type = ssrc_specific;
1345 policy.ssrc.value = 0xcafebabe;
1346 policy.key = test_key;
1347 policy.ekt = NULL;
1348 policy.window_size = 128;
1349 policy.allow_repeat_tx = 0;
1350 policy.next = NULL;
1351
1352 status = srtp_create(&srtp_snd, &policy);
1353 if (status)
1354 return status;
1355
1356 /*
1357 * protect plaintext, then compare with ciphertext
1358 */
1359 len = 28;
1360 status = srtp_protect(srtp_snd, srtp_plaintext, &len);
1361 if (status || (len != 38))
1362 return err_status_fail;
1363
1364 debug_print(mod_driver, "ciphertext:\n %s",
1365 octet_string_hex_string(srtp_plaintext, len));
1366 debug_print(mod_driver, "ciphertext reference:\n %s",
1367 octet_string_hex_string(srtp_ciphertext, len));
1368
1369 if (octet_string_is_eq(srtp_plaintext, srtp_ciphertext, len))
1370 return err_status_fail;
1371
1372 /*
1373 * create a receiver session context comparable to the one created
1374 * above - we need to do this so that the replay checking doesn't
1375 * complain
1376 */
1377 status = srtp_create(&srtp_recv, &policy);
1378 if (status)
1379 return status;
1380
1381 /*
1382 * unprotect ciphertext, then compare with plaintext
1383 */
1384 status = srtp_unprotect(srtp_recv, srtp_ciphertext, &len);
1385 if (status || (len != 28))
1386 return status;
1387
1388 if (octet_string_is_eq(srtp_ciphertext, srtp_plaintext_ref, len))
1389 return err_status_fail;
1390
1391 status = srtp_dealloc(srtp_snd);
1392 if (status)
1393 return status;
1394
1395 status = srtp_dealloc(srtp_recv);
1396 if (status)
1397 return status;
1398
1399 return err_status_ok;
1400}
1401
1402
Cullen Jennings235513a2005-09-21 22:51:36 +00001403err_status_t
1404srtp_create_big_policy(srtp_policy_t **list) {
1405 extern const srtp_policy_t *policy_array[];
1406 srtp_policy_t *p, *tmp;
1407 int i = 0;
1408 uint32_t ssrc = 0;
1409
1410 /* sanity checking */
1411 if ((list == NULL) || (policy_array[0] == NULL))
1412 return err_status_bad_param;
1413
1414 /*
1415 * loop over policy list, mallocing a new list and copying values
1416 * into it (and incrementing the SSRC value as we go along)
1417 */
1418 tmp = NULL;
1419 while (policy_array[i] != NULL) {
Derek MacDonald17127da2006-07-12 22:22:08 +00001420 p = (srtp_policy_t*) malloc(sizeof(srtp_policy_t));
Cullen Jennings235513a2005-09-21 22:51:36 +00001421 if (p == NULL)
1422 return err_status_bad_param;
1423 memcpy(p, policy_array[i], sizeof(srtp_policy_t));
1424 p->ssrc.type = ssrc_specific;
1425 p->ssrc.value = ssrc++;
1426 p->next = tmp;
1427 tmp = p;
1428 i++;
1429 }
1430 *list = p;
1431
1432 return err_status_ok;
1433}
1434
1435err_status_t
Jonathan Lennox80c4c832010-05-17 19:30:28 +00001436srtp_dealloc_big_policy(srtp_policy_t *list) {
1437 srtp_policy_t *p, *next;
1438
1439 for (p = list; p != NULL; p = next) {
1440 next = p->next;
1441 free(p);
1442 }
1443
1444 return err_status_ok;
1445}
1446
1447
1448err_status_t
Cullen Jennings235513a2005-09-21 22:51:36 +00001449srtp_test_remove_stream() {
1450 err_status_t status;
1451 srtp_policy_t *policy_list;
1452 srtp_t session;
1453 srtp_stream_t stream;
1454 /*
1455 * srtp_get_stream() is a libSRTP internal function that we declare
1456 * here so that we can use it to verify the correct operation of the
1457 * library
1458 */
1459 extern srtp_stream_t srtp_get_stream(srtp_t srtp, uint32_t ssrc);
1460
1461
1462 status = srtp_create_big_policy(&policy_list);
1463 if (status)
1464 return status;
1465
1466 status = srtp_create(&session, policy_list);
1467 if (status)
1468 return status;
1469
1470 /*
1471 * check for false positives by trying to remove a stream that's not
1472 * in the session
1473 */
1474 status = srtp_remove_stream(session, htonl(0xaaaaaaaa));
1475 if (status != err_status_no_ctx)
1476 return err_status_fail;
1477
1478 /*
1479 * check for false negatives by removing stream 0x1, then
1480 * searching for streams 0x0 and 0x2
1481 */
1482 status = srtp_remove_stream(session, htonl(0x1));
1483 if (status != err_status_ok)
1484 return err_status_fail;
1485 stream = srtp_get_stream(session, htonl(0x0));
1486 if (stream == NULL)
1487 return err_status_fail;
1488 stream = srtp_get_stream(session, htonl(0x2));
1489 if (stream == NULL)
1490 return err_status_fail;
1491
Jonathan Lennox80c4c832010-05-17 19:30:28 +00001492 status = srtp_dealloc(session);
1493 if (status != err_status_ok)
1494 return status;
1495
1496 status = srtp_dealloc_big_policy(policy_list);
1497 if (status != err_status_ok)
1498 return status;
1499
Cullen Jennings235513a2005-09-21 22:51:36 +00001500 return err_status_ok;
1501}
1502
1503/*
1504 * srtp policy definitions - these definitions are used above
1505 */
1506
1507unsigned char test_key[30] = {
1508 0xe1, 0xf9, 0x7a, 0x0d, 0x3e, 0x01, 0x8b, 0xe0,
1509 0xd6, 0x4f, 0xa3, 0x2c, 0x06, 0xde, 0x41, 0x39,
1510 0x0e, 0xc6, 0x75, 0xad, 0x49, 0x8a, 0xfe, 0xeb,
1511 0xb6, 0x96, 0x0b, 0x3a, 0xab, 0xe6
1512};
1513
1514
1515const srtp_policy_t default_policy = {
1516 { ssrc_any_outbound, 0 }, /* SSRC */
1517 { /* SRTP policy */
1518 AES_128_ICM, /* cipher type */
1519 30, /* cipher key length in octets */
1520 HMAC_SHA1, /* authentication func type */
1521 16, /* auth key length in octets */
1522 10, /* auth tag length in octets */
1523 sec_serv_conf_and_auth /* security services flag */
1524 },
1525 { /* SRTCP policy */
1526 AES_128_ICM, /* cipher type */
1527 30, /* cipher key length in octets */
1528 HMAC_SHA1, /* authentication func type */
1529 16, /* auth key length in octets */
1530 10, /* auth tag length in octets */
1531 sec_serv_conf_and_auth /* security services flag */
1532 },
1533 test_key,
David McGrew79870d62007-06-15 18:17:39 +00001534 NULL, /* indicates that EKT is not in use */
Jonathan Lennoxa1242f82010-05-17 21:46:04 +00001535 128, /* replay window size */
Jonathan Lennoxdcee5c62010-05-17 22:08:40 +00001536 0, /* retransmission not allowed */
Cullen Jennings235513a2005-09-21 22:51:36 +00001537 NULL
1538};
1539
1540const srtp_policy_t aes_tmmh_policy = {
1541 { ssrc_any_outbound, 0 }, /* SSRC */
1542 {
1543 AES_128_ICM, /* cipher type */
1544 30, /* cipher key length in octets */
1545 UST_TMMHv2, /* authentication func type */
1546 94, /* auth key length in octets */
1547 4, /* auth tag length in octets */
1548 sec_serv_conf_and_auth /* security services flag */
1549 },
1550 {
1551 AES_128_ICM, /* cipher type */
1552 30, /* cipher key length in octets */
1553 UST_TMMHv2, /* authentication func type */
1554 94, /* auth key length in octets */
1555 4, /* auth tag length in octets */
1556 sec_serv_conf_and_auth /* security services flag */
1557 },
1558 test_key,
David McGrew79870d62007-06-15 18:17:39 +00001559 NULL, /* indicates that EKT is not in use */
Jonathan Lennoxa1242f82010-05-17 21:46:04 +00001560 128, /* replay window size */
Jonathan Lennoxdcee5c62010-05-17 22:08:40 +00001561 0, /* retransmission not allowed */
Cullen Jennings235513a2005-09-21 22:51:36 +00001562 NULL
1563};
1564
1565const srtp_policy_t tmmh_only_policy = {
1566 { ssrc_any_outbound, 0 }, /* SSRC */
1567 {
1568 AES_128_ICM, /* cipher type */
1569 30, /* cipher key length in octets */
1570 UST_TMMHv2, /* authentication func type */
1571 94, /* auth key length in octets */
1572 4, /* auth tag length in octets */
1573 sec_serv_auth /* security services flag */
1574 },
1575 {
1576 AES_128_ICM, /* cipher type */
1577 30, /* cipher key length in octets */
1578 UST_TMMHv2, /* authentication func type */
1579 94, /* auth key length in octets */
1580 4, /* auth tag length in octets */
1581 sec_serv_auth /* security services flag */
1582 },
1583 test_key,
David McGrew79870d62007-06-15 18:17:39 +00001584 NULL, /* indicates that EKT is not in use */
Jonathan Lennoxa1242f82010-05-17 21:46:04 +00001585 128, /* replay window size */
Jonathan Lennoxdcee5c62010-05-17 22:08:40 +00001586 0, /* retransmission not allowed */
Cullen Jennings235513a2005-09-21 22:51:36 +00001587 NULL
1588};
1589
1590const srtp_policy_t aes_only_policy = {
1591 { ssrc_any_outbound, 0 }, /* SSRC */
1592 {
1593 AES_128_ICM, /* cipher type */
1594 30, /* cipher key length in octets */
1595 NULL_AUTH, /* authentication func type */
1596 0, /* auth key length in octets */
1597 0, /* auth tag length in octets */
1598 sec_serv_conf /* security services flag */
1599 },
1600 {
1601 AES_128_ICM, /* cipher type */
1602 30, /* cipher key length in octets */
1603 NULL_AUTH, /* authentication func type */
1604 0, /* auth key length in octets */
1605 0, /* auth tag length in octets */
1606 sec_serv_conf /* security services flag */
1607 },
1608 test_key,
David McGrew79870d62007-06-15 18:17:39 +00001609 NULL, /* indicates that EKT is not in use */
Jonathan Lennoxa1242f82010-05-17 21:46:04 +00001610 128, /* replay window size */
Jonathan Lennoxdcee5c62010-05-17 22:08:40 +00001611 0, /* retransmission not allowed */
Cullen Jennings235513a2005-09-21 22:51:36 +00001612 NULL
1613};
1614
1615const srtp_policy_t hmac_only_policy = {
1616 { ssrc_any_outbound, 0 }, /* SSRC */
1617 {
1618 NULL_CIPHER, /* cipher type */
1619 0, /* cipher key length in octets */
1620 HMAC_SHA1, /* authentication func type */
1621 20, /* auth key length in octets */
1622 4, /* auth tag length in octets */
1623 sec_serv_auth /* security services flag */
1624 },
1625 {
1626 NULL_CIPHER, /* cipher type */
1627 0, /* cipher key length in octets */
1628 HMAC_SHA1, /* authentication func type */
1629 20, /* auth key length in octets */
1630 4, /* auth tag length in octets */
1631 sec_serv_auth /* security services flag */
1632 },
1633 test_key,
David McGrew79870d62007-06-15 18:17:39 +00001634 NULL, /* indicates that EKT is not in use */
Jonathan Lennoxa1242f82010-05-17 21:46:04 +00001635 128, /* replay window size */
Jonathan Lennoxdcee5c62010-05-17 22:08:40 +00001636 0, /* retransmission not allowed */
Cullen Jennings235513a2005-09-21 22:51:36 +00001637 NULL
1638};
1639
1640const srtp_policy_t null_policy = {
1641 { ssrc_any_outbound, 0 }, /* SSRC */
1642 {
1643 NULL_CIPHER, /* cipher type */
1644 0, /* cipher key length in octets */
1645 NULL_AUTH, /* authentication func type */
1646 0, /* auth key length in octets */
1647 0, /* auth tag length in octets */
1648 sec_serv_none /* security services flag */
1649 },
1650 {
1651 NULL_CIPHER, /* cipher type */
1652 0, /* cipher key length in octets */
1653 NULL_AUTH, /* authentication func type */
1654 0, /* auth key length in octets */
1655 0, /* auth tag length in octets */
1656 sec_serv_none /* security services flag */
1657 },
1658 test_key,
David McGrew79870d62007-06-15 18:17:39 +00001659 NULL, /* indicates that EKT is not in use */
Jonathan Lennoxa1242f82010-05-17 21:46:04 +00001660 128, /* replay window size */
Jonathan Lennoxdcee5c62010-05-17 22:08:40 +00001661 0, /* retransmission not allowed */
David McGrew79870d62007-06-15 18:17:39 +00001662 NULL
1663};
1664
Jonathan Lennox5df951a2010-05-20 20:55:54 +00001665unsigned char test_256_key[46] = {
1666 0xf0, 0xf0, 0x49, 0x14, 0xb5, 0x13, 0xf2, 0x76,
1667 0x3a, 0x1b, 0x1f, 0xa1, 0x30, 0xf1, 0x0e, 0x29,
1668 0x98, 0xf6, 0xf6, 0xe4, 0x3e, 0x43, 0x09, 0xd1,
1669 0xe6, 0x22, 0xa0, 0xe3, 0x32, 0xb9, 0xf1, 0xb6,
1670
1671 0x3b, 0x04, 0x80, 0x3d, 0xe5, 0x1e, 0xe7, 0xc9,
1672 0x64, 0x23, 0xab, 0x5b, 0x78, 0xd2
1673};
1674
1675const srtp_policy_t aes_256_hmac_policy = {
1676 { ssrc_any_outbound, 0 }, /* SSRC */
1677 { /* SRTP policy */
1678 AES_ICM, /* cipher type */
1679 46, /* cipher key length in octets */
1680 HMAC_SHA1, /* authentication func type */
1681 20, /* auth key length in octets */
1682 10, /* auth tag length in octets */
1683 sec_serv_conf_and_auth /* security services flag */
1684 },
1685 { /* SRTCP policy */
1686 AES_ICM, /* cipher type */
1687 46, /* cipher key length in octets */
1688 HMAC_SHA1, /* authentication func type */
1689 20, /* auth key length in octets */
1690 10, /* auth tag length in octets */
1691 sec_serv_conf_and_auth /* security services flag */
1692 },
1693 test_256_key,
1694 NULL, /* indicates that EKT is not in use */
1695 128, /* replay window size */
1696 0, /* retransmission not allowed */
1697 NULL
1698};
1699
David McGrew79870d62007-06-15 18:17:39 +00001700uint8_t ekt_test_key[16] = {
1701 0x77, 0x26, 0x9d, 0xac, 0x16, 0xa3, 0x28, 0xca,
1702 0x8e, 0xc9, 0x68, 0x4b, 0xcc, 0xc4, 0xd2, 0x1b
1703};
1704
1705#include "ekt.h"
1706
1707ekt_policy_ctx_t ekt_test_policy = {
1708 0xa5a5, /* SPI */
1709 EKT_CIPHER_AES_128_ECB,
1710 ekt_test_key,
1711 NULL
1712};
1713
1714const srtp_policy_t hmac_only_with_ekt_policy = {
1715 { ssrc_any_outbound, 0 }, /* SSRC */
1716 {
1717 NULL_CIPHER, /* cipher type */
1718 0, /* cipher key length in octets */
1719 HMAC_SHA1, /* authentication func type */
1720 20, /* auth key length in octets */
1721 4, /* auth tag length in octets */
1722 sec_serv_auth /* security services flag */
1723 },
1724 {
1725 NULL_CIPHER, /* cipher type */
1726 0, /* cipher key length in octets */
1727 HMAC_SHA1, /* authentication func type */
1728 20, /* auth key length in octets */
1729 4, /* auth tag length in octets */
1730 sec_serv_auth /* security services flag */
1731 },
1732 test_key,
1733 &ekt_test_policy, /* indicates that EKT is not in use */
Jonathan Lennoxa1242f82010-05-17 21:46:04 +00001734 128, /* replay window size */
Jonathan Lennoxdcee5c62010-05-17 22:08:40 +00001735 0, /* retransmission not allowed */
Cullen Jennings235513a2005-09-21 22:51:36 +00001736 NULL
1737};
1738
1739
1740/*
1741 * an array of pointers to the policies listed above
1742 *
1743 * This array is used to test various aspects of libSRTP for
1744 * different cryptographic policies. The order of the elements
1745 * matters - the timing test generates output that can be used
1746 * in a plot (see the gnuplot script file 'timing'). If you
1747 * add to this list, you should do it at the end.
1748 */
1749
1750#define USE_TMMH 0
1751
1752const srtp_policy_t *
1753policy_array[] = {
1754 &hmac_only_policy,
1755#if USE_TMMH
1756 &tmmh_only_policy,
1757#endif
1758 &aes_only_policy,
1759#if USE_TMMH
1760 &aes_tmmh_policy,
1761#endif
1762 &default_policy,
1763 &null_policy,
Jonathan Lennox5df951a2010-05-20 20:55:54 +00001764 &aes_256_hmac_policy,
David McGrew79870d62007-06-15 18:17:39 +00001765 &hmac_only_with_ekt_policy,
Cullen Jennings235513a2005-09-21 22:51:36 +00001766 NULL
1767};
1768
1769const srtp_policy_t wildcard_policy = {
1770 { ssrc_any_outbound, 0 }, /* SSRC */
1771 { /* SRTP policy */
1772 AES_128_ICM, /* cipher type */
1773 30, /* cipher key length in octets */
1774 HMAC_SHA1, /* authentication func type */
1775 16, /* auth key length in octets */
1776 10, /* auth tag length in octets */
1777 sec_serv_conf_and_auth /* security services flag */
1778 },
1779 { /* SRTCP policy */
1780 AES_128_ICM, /* cipher type */
1781 30, /* cipher key length in octets */
1782 HMAC_SHA1, /* authentication func type */
1783 16, /* auth key length in octets */
1784 10, /* auth tag length in octets */
1785 sec_serv_conf_and_auth /* security services flag */
1786 },
1787 test_key,
Jonathan Lennox28bd7c12010-05-15 00:23:19 +00001788 NULL,
Jonathan Lennoxa1242f82010-05-17 21:46:04 +00001789 128, /* replay window size */
Jonathan Lennoxdcee5c62010-05-17 22:08:40 +00001790 0, /* retransmission not allowed */
Cullen Jennings235513a2005-09-21 22:51:36 +00001791 NULL
1792};