1 /*
2  * replay_driver.c
3  *
4  * A driver for the replay_database implementation
5  *
6  * David A. McGrew
7  * Cisco Systems, Inc.
8  */
9 
10 /*
11  *
12  * Copyright (c) 2001-2017, Cisco Systems, Inc.
13  * All rights reserved.
14  *
15  * Redistribution and use in source and binary forms, with or without
16  * modification, are permitted provided that the following conditions
17  * are met:
18  *
19  *   Redistributions of source code must retain the above copyright
20  *   notice, this list of conditions and the following disclaimer.
21  *
22  *   Redistributions in binary form must reproduce the above
23  *   copyright notice, this list of conditions and the following
24  *   disclaimer in the documentation and/or other materials provided
25  *   with the distribution.
26  *
27  *   Neither the name of the Cisco Systems, Inc. nor the names of its
28  *   contributors may be used to endorse or promote products derived
29  *   from this software without specific prior written permission.
30  *
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
34  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
35  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
36  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
37  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
38  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
41  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
42  * OF THE POSSIBILITY OF SUCH DAMAGE.
43  *
44  */
45 
46 #ifdef HAVE_CONFIG_H
47 #include <config.h>
48 #endif
49 
50 #include <stdio.h>
51 
52 #include "rdb.h"
53 #include "ut_sim.h"
54 
55 /*
56  * num_trials defines the number of trials that are used in the
57  * validation functions below
58  */
59 
60 unsigned num_trials = 1 << 16;
61 
62 srtp_err_status_t test_rdb_db(void);
63 
64 double rdb_check_adds_per_second(void);
65 
main(void)66 int main(void)
67 {
68     srtp_err_status_t err;
69 
70     printf("testing anti-replay database (srtp_rdb_t)...\n");
71     err = test_rdb_db();
72     if (err) {
73         printf("failed\n");
74         exit(1);
75     }
76     printf("done\n");
77 
78     printf("rdb_check/rdb_adds per second: %e\n", rdb_check_adds_per_second());
79 
80     return 0;
81 }
82 
print_rdb(srtp_rdb_t * rdb)83 void print_rdb(srtp_rdb_t *rdb)
84 {
85     printf("rdb: {%u, %s}\n", rdb->window_start,
86            v128_bit_string(&rdb->bitmask));
87 }
88 
rdb_check_add(srtp_rdb_t * rdb,uint32_t idx)89 srtp_err_status_t rdb_check_add(srtp_rdb_t *rdb, uint32_t idx)
90 {
91     if (srtp_rdb_check(rdb, idx) != srtp_err_status_ok) {
92         printf("rdb_check failed at index %u\n", idx);
93         return srtp_err_status_fail;
94     }
95     if (srtp_rdb_add_index(rdb, idx) != srtp_err_status_ok) {
96         printf("rdb_add_index failed at index %u\n", idx);
97         return srtp_err_status_fail;
98     }
99 
100     return srtp_err_status_ok;
101 }
102 
rdb_check_expect_failure(srtp_rdb_t * rdb,uint32_t idx)103 srtp_err_status_t rdb_check_expect_failure(srtp_rdb_t *rdb, uint32_t idx)
104 {
105     srtp_err_status_t err;
106 
107     err = srtp_rdb_check(rdb, idx);
108     if ((err != srtp_err_status_replay_old) &&
109         (err != srtp_err_status_replay_fail)) {
110         printf("rdb_check failed at index %u (false positive)\n", idx);
111         return srtp_err_status_fail;
112     }
113 
114     return srtp_err_status_ok;
115 }
116 
rdb_check_add_unordered(srtp_rdb_t * rdb,uint32_t idx)117 srtp_err_status_t rdb_check_add_unordered(srtp_rdb_t *rdb, uint32_t idx)
118 {
119     srtp_err_status_t rstat;
120 
121     /* printf("index: %u\n", idx); */
122     rstat = srtp_rdb_check(rdb, idx);
123     if ((rstat != srtp_err_status_ok) &&
124         (rstat != srtp_err_status_replay_old)) {
125         printf("rdb_check_add_unordered failed at index %u\n", idx);
126         return rstat;
127     }
128     if (rstat == srtp_err_status_replay_old) {
129         return srtp_err_status_ok;
130     }
131     if (srtp_rdb_add_index(rdb, idx) != srtp_err_status_ok) {
132         printf("rdb_add_index failed at index %u\n", idx);
133         return srtp_err_status_fail;
134     }
135 
136     return srtp_err_status_ok;
137 }
138 
test_rdb_db()139 srtp_err_status_t test_rdb_db()
140 {
141     srtp_rdb_t rdb;
142     uint32_t idx, ircvd;
143     ut_connection utc;
144     srtp_err_status_t err;
145 
146     if (srtp_rdb_init(&rdb) != srtp_err_status_ok) {
147         printf("rdb_init failed\n");
148         return srtp_err_status_init_fail;
149     }
150 
151     /* test sequential insertion */
152     for (idx = 0; idx < num_trials; idx++) {
153         err = rdb_check_add(&rdb, idx);
154         if (err)
155             return err;
156     }
157 
158     /* test for false positives */
159     for (idx = 0; idx < num_trials; idx++) {
160         err = rdb_check_expect_failure(&rdb, idx);
161         if (err)
162             return err;
163     }
164 
165     /* re-initialize */
166     if (srtp_rdb_init(&rdb) != srtp_err_status_ok) {
167         printf("rdb_init failed\n");
168         return srtp_err_status_fail;
169     }
170 
171     /* test non-sequential insertion */
172     ut_init(&utc);
173 
174     for (idx = 0; idx < num_trials; idx++) {
175         ircvd = ut_next_index(&utc);
176         err = rdb_check_add_unordered(&rdb, ircvd);
177         if (err)
178             return err;
179         err = rdb_check_expect_failure(&rdb, ircvd);
180         if (err)
181             return err;
182     }
183 
184     /* re-initialize */
185     if (srtp_rdb_init(&rdb) != srtp_err_status_ok) {
186         printf("rdb_init failed\n");
187         return srtp_err_status_fail;
188     }
189 
190     /* test insertion with large gaps */
191     for (idx = 0, ircvd = 0; idx < num_trials;
192          idx++, ircvd += (1 << (rand() % 10))) {
193         err = rdb_check_add(&rdb, ircvd);
194         if (err)
195             return err;
196         err = rdb_check_expect_failure(&rdb, ircvd);
197         if (err)
198             return err;
199     }
200 
201     /* re-initialize */
202     if (srtp_rdb_init(&rdb) != srtp_err_status_ok) {
203         printf("rdb_init failed\n");
204         return srtp_err_status_fail;
205     }
206 
207     /* test loss of first 513 packets */
208     for (idx = 0; idx < num_trials; idx++) {
209         err = rdb_check_add(&rdb, idx + 513);
210         if (err)
211             return err;
212     }
213 
214     /* test for false positives */
215     for (idx = 0; idx < num_trials + 513; idx++) {
216         err = rdb_check_expect_failure(&rdb, idx);
217         if (err)
218             return err;
219     }
220 
221     /* test for key expired */
222     if (srtp_rdb_init(&rdb) != srtp_err_status_ok) {
223         printf("rdb_init failed\n");
224         return srtp_err_status_fail;
225     }
226     rdb.window_start = 0x7ffffffe;
227     if (srtp_rdb_increment(&rdb) != srtp_err_status_ok) {
228         printf("srtp_rdb_increment of 0x7ffffffe failed\n");
229         return srtp_err_status_fail;
230     }
231     if (srtp_rdb_get_value(&rdb) != 0x7fffffff) {
232         printf("rdb valiue was not 0x7fffffff\n");
233         return srtp_err_status_fail;
234     }
235     if (srtp_rdb_increment(&rdb) != srtp_err_status_key_expired) {
236         printf("srtp_rdb_increment of 0x7fffffff did not return "
237                "srtp_err_status_key_expired\n");
238         return srtp_err_status_fail;
239     }
240     if (srtp_rdb_get_value(&rdb) != 0x7fffffff) {
241         printf("rdb valiue was not 0x7fffffff\n");
242         return srtp_err_status_fail;
243     }
244 
245     return srtp_err_status_ok;
246 }
247 
248 #include <time.h>   /* for clock()  */
249 #include <stdlib.h> /* for random() */
250 
251 #define REPLAY_NUM_TRIALS 10000000
252 
rdb_check_adds_per_second(void)253 double rdb_check_adds_per_second(void)
254 {
255     uint32_t i;
256     srtp_rdb_t rdb;
257     clock_t timer;
258     int failures = 0; /* count number of failures        */
259 
260     if (srtp_rdb_init(&rdb) != srtp_err_status_ok) {
261         printf("rdb_init failed\n");
262         exit(1);
263     }
264 
265     timer = clock();
266     for (i = 0; i < REPLAY_NUM_TRIALS; i += 3) {
267         if (srtp_rdb_check(&rdb, i + 2) != srtp_err_status_ok)
268             ++failures;
269         if (srtp_rdb_add_index(&rdb, i + 2) != srtp_err_status_ok)
270             ++failures;
271         if (srtp_rdb_check(&rdb, i + 1) != srtp_err_status_ok)
272             ++failures;
273         if (srtp_rdb_add_index(&rdb, i + 1) != srtp_err_status_ok)
274             ++failures;
275         if (srtp_rdb_check(&rdb, i) != srtp_err_status_ok)
276             ++failures;
277         if (srtp_rdb_add_index(&rdb, i) != srtp_err_status_ok)
278             ++failures;
279     }
280     timer = clock() - timer;
281 
282     return (double)CLOCKS_PER_SEC * REPLAY_NUM_TRIALS / timer;
283 }
284