rdbx_driver.c (9967B)
1 /* 2 * rdbx_driver.c 3 * 4 * driver for the rdbx implementation (replay database with extended range) 5 * 6 * David A. McGrew 7 * Cisco Systems, Inc. 8 */ 9 /* 10 * 11 * Copyright (c) 2001-2017, Cisco Systems, Inc. 12 * 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 #ifdef HAVE_CONFIG_H 46 #include <config.h> 47 #endif 48 49 #include <stdio.h> /* for printf() */ 50 #include "getopt_s.h" /* for local getopt() */ 51 52 #include "rdbx.h" 53 #include "cipher_priv.h" 54 55 #ifdef ROC_TEST 56 #error "srtp_rdbx_t won't work with ROC_TEST - bitmask same size as seq_median" 57 #endif 58 59 #include "ut_sim.h" 60 61 srtp_err_status_t test_replay_dbx(int num_trials, unsigned long ws); 62 63 double rdbx_check_adds_per_second(int num_trials, unsigned long ws); 64 65 void usage(char *prog_name) 66 { 67 printf("usage: %s [ -t | -v ]\n", prog_name); 68 exit(255); 69 } 70 71 int main(int argc, char *argv[]) 72 { 73 double rate; 74 srtp_err_status_t status; 75 int q; 76 unsigned do_timing_test = 0; 77 unsigned do_validation = 0; 78 79 /* process input arguments */ 80 while (1) { 81 q = getopt_s(argc, argv, "tv"); 82 if (q == -1) 83 break; 84 switch (q) { 85 case 't': 86 do_timing_test = 1; 87 break; 88 case 'v': 89 do_validation = 1; 90 break; 91 default: 92 usage(argv[0]); 93 } 94 } 95 96 printf("rdbx (replay database w/ extended range) test driver\n" 97 "David A. McGrew\n" 98 "Cisco Systems, Inc.\n"); 99 100 if (!do_validation && !do_timing_test) 101 usage(argv[0]); 102 103 if (do_validation) { 104 printf("testing srtp_rdbx_t (ws=128)...\n"); 105 106 status = test_replay_dbx(1 << 12, 128); 107 if (status) { 108 printf("failed\n"); 109 exit(1); 110 } 111 printf("passed\n"); 112 113 printf("testing srtp_rdbx_t (ws=1024)...\n"); 114 115 status = test_replay_dbx(1 << 12, 1024); 116 if (status) { 117 printf("failed\n"); 118 exit(1); 119 } 120 printf("passed\n"); 121 } 122 123 if (do_timing_test) { 124 rate = rdbx_check_adds_per_second(1 << 18, 128); 125 printf("rdbx_check/replay_adds per second (ws=128): %e\n", rate); 126 rate = rdbx_check_adds_per_second(1 << 18, 1024); 127 printf("rdbx_check/replay_adds per second (ws=1024): %e\n", rate); 128 } 129 130 return 0; 131 } 132 133 /* 134 * rdbx_check_add(rdbx, idx) checks a known-to-be-good idx against 135 * rdbx, then adds it. if a failure is detected (i.e., the check 136 * indicates that the value is already in rdbx) then 137 * srtp_err_status_algo_fail is returned. 138 * 139 */ 140 141 srtp_err_status_t rdbx_check_add(srtp_rdbx_t *rdbx, uint32_t idx) 142 { 143 int delta; 144 srtp_xtd_seq_num_t est; 145 146 delta = srtp_index_guess(&rdbx->index, &est, (srtp_sequence_number_t)idx); 147 148 if (srtp_rdbx_check(rdbx, delta) != srtp_err_status_ok) { 149 printf("replay_check failed at index %u\n", idx); 150 return srtp_err_status_algo_fail; 151 } 152 153 /* 154 * in practice, we'd authenticate the packet containing idx, using 155 * the estimated value est, at this point 156 */ 157 158 if (srtp_rdbx_add_index(rdbx, delta) != srtp_err_status_ok) { 159 printf("rdbx_add_index failed at index %u\n", idx); 160 return srtp_err_status_algo_fail; 161 } 162 163 return srtp_err_status_ok; 164 } 165 166 /* 167 * rdbx_check_expect_failure(srtp_rdbx_t *rdbx, uint32_t idx) 168 * 169 * checks that a sequence number idx is in the replay database 170 * and thus will be rejected 171 */ 172 173 srtp_err_status_t rdbx_check_expect_failure(srtp_rdbx_t *rdbx, uint32_t idx) 174 { 175 int delta; 176 srtp_xtd_seq_num_t est; 177 srtp_err_status_t status; 178 179 delta = srtp_index_guess(&rdbx->index, &est, (srtp_sequence_number_t)idx); 180 181 status = srtp_rdbx_check(rdbx, delta); 182 if (status == srtp_err_status_ok) { 183 printf("delta: %d ", delta); 184 printf("replay_check failed at index %u (false positive)\n", idx); 185 return srtp_err_status_algo_fail; 186 } 187 188 return srtp_err_status_ok; 189 } 190 191 srtp_err_status_t rdbx_check_add_unordered(srtp_rdbx_t *rdbx, uint32_t idx) 192 { 193 int delta; 194 srtp_xtd_seq_num_t est; 195 srtp_err_status_t rstat; 196 197 delta = srtp_index_guess(&rdbx->index, &est, (srtp_sequence_number_t)idx); 198 199 rstat = srtp_rdbx_check(rdbx, delta); 200 if ((rstat != srtp_err_status_ok) && 201 (rstat != srtp_err_status_replay_old)) { 202 printf("replay_check_add_unordered failed at index %u\n", idx); 203 return srtp_err_status_algo_fail; 204 } 205 if (rstat == srtp_err_status_replay_old) { 206 return srtp_err_status_ok; 207 } 208 if (srtp_rdbx_add_index(rdbx, delta) != srtp_err_status_ok) { 209 printf("rdbx_add_index failed at index %u\n", idx); 210 return srtp_err_status_algo_fail; 211 } 212 213 return srtp_err_status_ok; 214 } 215 216 srtp_err_status_t test_replay_dbx(int num_trials, unsigned long ws) 217 { 218 srtp_rdbx_t rdbx; 219 uint32_t idx, ircvd; 220 ut_connection utc; 221 srtp_err_status_t status; 222 int num_fp_trials; 223 224 status = srtp_rdbx_init(&rdbx, ws); 225 if (status) { 226 printf("replay_init failed with error code %d\n", status); 227 exit(1); 228 } 229 230 /* 231 * test sequential insertion 232 */ 233 printf("\ttesting sequential insertion..."); 234 for (idx = 0; (int)idx < num_trials; idx++) { 235 status = rdbx_check_add(&rdbx, idx); 236 if (status) 237 return status; 238 } 239 printf("passed\n"); 240 241 /* 242 * test for false positives by checking all of the index 243 * values which we've just added 244 * 245 * note that we limit the number of trials here, since allowing the 246 * rollover counter to roll over would defeat this test 247 */ 248 num_fp_trials = num_trials % 0x10000; 249 if (num_fp_trials == 0) { 250 printf("warning: no false positive tests performed\n"); 251 } 252 printf("\ttesting for false positives..."); 253 for (idx = 0; (int)idx < num_fp_trials; idx++) { 254 status = rdbx_check_expect_failure(&rdbx, idx); 255 if (status) 256 return status; 257 } 258 printf("passed\n"); 259 260 /* re-initialize */ 261 srtp_rdbx_dealloc(&rdbx); 262 263 if (srtp_rdbx_init(&rdbx, ws) != srtp_err_status_ok) { 264 printf("replay_init failed\n"); 265 return srtp_err_status_init_fail; 266 } 267 268 /* 269 * test non-sequential insertion 270 * 271 * this test covers only fase negatives, since the values returned 272 * by ut_next_index(...) are distinct 273 */ 274 ut_init(&utc); 275 276 printf("\ttesting non-sequential insertion..."); 277 for (idx = 0; (int)idx < num_trials; idx++) { 278 ircvd = ut_next_index(&utc); 279 status = rdbx_check_add_unordered(&rdbx, ircvd); 280 if (status) 281 return status; 282 status = rdbx_check_expect_failure(&rdbx, ircvd); 283 if (status) 284 return status; 285 } 286 printf("passed\n"); 287 288 /* re-initialize */ 289 srtp_rdbx_dealloc(&rdbx); 290 291 if (srtp_rdbx_init(&rdbx, ws) != srtp_err_status_ok) { 292 printf("replay_init failed\n"); 293 return srtp_err_status_init_fail; 294 } 295 296 /* 297 * test insertion with large gaps. 298 * check for false positives for each insertion. 299 */ 300 printf("\ttesting insertion with large gaps..."); 301 for (idx = 0, ircvd = 0; (int)idx < num_trials; 302 idx++, ircvd += (1 << (srtp_cipher_rand_u32_for_tests() % 12))) { 303 status = rdbx_check_add(&rdbx, ircvd); 304 if (status) 305 return status; 306 status = rdbx_check_expect_failure(&rdbx, ircvd); 307 if (status) 308 return status; 309 } 310 printf("passed\n"); 311 312 srtp_rdbx_dealloc(&rdbx); 313 314 return srtp_err_status_ok; 315 } 316 317 #include <time.h> /* for clock() */ 318 319 double rdbx_check_adds_per_second(int num_trials, unsigned long ws) 320 { 321 uint32_t i; 322 int delta; 323 srtp_rdbx_t rdbx; 324 srtp_xtd_seq_num_t est; 325 clock_t timer; 326 int failures; /* count number of failures */ 327 328 if (srtp_rdbx_init(&rdbx, ws) != srtp_err_status_ok) { 329 printf("replay_init failed\n"); 330 exit(1); 331 } 332 333 failures = 0; 334 timer = clock(); 335 for (i = 0; (int)i < num_trials; i++) { 336 delta = srtp_index_guess(&rdbx.index, &est, (srtp_sequence_number_t)i); 337 338 if (srtp_rdbx_check(&rdbx, delta) != srtp_err_status_ok) 339 ++failures; 340 else if (srtp_rdbx_add_index(&rdbx, delta) != srtp_err_status_ok) 341 ++failures; 342 } 343 timer = clock() - timer; 344 if (timer < 1) { 345 timer = 1; 346 } 347 348 printf("number of failures: %d \n", failures); 349 350 srtp_rdbx_dealloc(&rdbx); 351 352 return (double)CLOCKS_PER_SEC * num_trials / timer; 353 }