diff options
Diffstat (limited to '')
-rw-r--r-- | netwerk/srtp/src/test/rdbx_driver.c | 360 |
1 files changed, 360 insertions, 0 deletions
diff --git a/netwerk/srtp/src/test/rdbx_driver.c b/netwerk/srtp/src/test/rdbx_driver.c new file mode 100644 index 0000000000..3da6503719 --- /dev/null +++ b/netwerk/srtp/src/test/rdbx_driver.c @@ -0,0 +1,360 @@ +/* + * rdbx_driver.c + * + * driver for the rdbx implementation (replay database with extended range) + * + * David A. McGrew + * Cisco Systems, Inc. + */ +/* + * + * Copyright (c) 2001-2017, Cisco Systems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * Neither the name of the Cisco Systems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> /* for printf() */ +#include "getopt_s.h" /* for local getopt() */ + +#include "rdbx.h" + +#ifdef ROC_TEST +#error "srtp_rdbx_t won't work with ROC_TEST - bitmask same size as seq_median" +#endif + +#include "ut_sim.h" + +srtp_err_status_t test_replay_dbx(int num_trials, unsigned long ws); + +double rdbx_check_adds_per_second(int num_trials, unsigned long ws); + +void usage(char *prog_name) +{ + printf("usage: %s [ -t | -v ]\n", prog_name); + exit(255); +} + +int main(int argc, char *argv[]) +{ + double rate; + srtp_err_status_t status; + int q; + unsigned do_timing_test = 0; + unsigned do_validation = 0; + + /* process input arguments */ + while (1) { + q = getopt_s(argc, argv, "tv"); + if (q == -1) + break; + switch (q) { + case 't': + do_timing_test = 1; + break; + case 'v': + do_validation = 1; + break; + default: + usage(argv[0]); + } + } + + printf("rdbx (replay database w/ extended range) test driver\n" + "David A. McGrew\n" + "Cisco Systems, Inc.\n"); + + if (!do_validation && !do_timing_test) + usage(argv[0]); + + if (do_validation) { + printf("testing srtp_rdbx_t (ws=128)...\n"); + + status = test_replay_dbx(1 << 12, 128); + if (status) { + printf("failed\n"); + exit(1); + } + printf("passed\n"); + + printf("testing srtp_rdbx_t (ws=1024)...\n"); + + status = test_replay_dbx(1 << 12, 1024); + if (status) { + printf("failed\n"); + exit(1); + } + printf("passed\n"); + } + + if (do_timing_test) { + rate = rdbx_check_adds_per_second(1 << 18, 128); + printf("rdbx_check/replay_adds per second (ws=128): %e\n", rate); + rate = rdbx_check_adds_per_second(1 << 18, 1024); + printf("rdbx_check/replay_adds per second (ws=1024): %e\n", rate); + } + + return 0; +} + +void print_rdbx(srtp_rdbx_t *rdbx) +{ + char buf[2048]; + printf("rdbx: {%llu, %s}\n", (unsigned long long)(rdbx->index), + bitvector_bit_string(&rdbx->bitmask, buf, sizeof(buf))); +} + +/* + * rdbx_check_add(rdbx, idx) checks a known-to-be-good idx against + * rdbx, then adds it. if a failure is detected (i.e., the check + * indicates that the value is already in rdbx) then + * srtp_err_status_algo_fail is returned. + * + */ + +srtp_err_status_t rdbx_check_add(srtp_rdbx_t *rdbx, uint32_t idx) +{ + int delta; + srtp_xtd_seq_num_t est; + + delta = srtp_index_guess(&rdbx->index, &est, idx); + + if (srtp_rdbx_check(rdbx, delta) != srtp_err_status_ok) { + printf("replay_check failed at index %u\n", idx); + return srtp_err_status_algo_fail; + } + + /* + * in practice, we'd authenticate the packet containing idx, using + * the estimated value est, at this point + */ + + if (srtp_rdbx_add_index(rdbx, delta) != srtp_err_status_ok) { + printf("rdbx_add_index failed at index %u\n", idx); + return srtp_err_status_algo_fail; + } + + return srtp_err_status_ok; +} + +/* + * rdbx_check_expect_failure(srtp_rdbx_t *rdbx, uint32_t idx) + * + * checks that a sequence number idx is in the replay database + * and thus will be rejected + */ + +srtp_err_status_t rdbx_check_expect_failure(srtp_rdbx_t *rdbx, uint32_t idx) +{ + int delta; + srtp_xtd_seq_num_t est; + srtp_err_status_t status; + + delta = srtp_index_guess(&rdbx->index, &est, idx); + + status = srtp_rdbx_check(rdbx, delta); + if (status == srtp_err_status_ok) { + printf("delta: %d ", delta); + printf("replay_check failed at index %u (false positive)\n", idx); + return srtp_err_status_algo_fail; + } + + return srtp_err_status_ok; +} + +srtp_err_status_t rdbx_check_add_unordered(srtp_rdbx_t *rdbx, uint32_t idx) +{ + int delta; + srtp_xtd_seq_num_t est; + srtp_err_status_t rstat; + + delta = srtp_index_guess(&rdbx->index, &est, idx); + + rstat = srtp_rdbx_check(rdbx, delta); + if ((rstat != srtp_err_status_ok) && + (rstat != srtp_err_status_replay_old)) { + printf("replay_check_add_unordered failed at index %u\n", idx); + return srtp_err_status_algo_fail; + } + if (rstat == srtp_err_status_replay_old) { + return srtp_err_status_ok; + } + if (srtp_rdbx_add_index(rdbx, delta) != srtp_err_status_ok) { + printf("rdbx_add_index failed at index %u\n", idx); + return srtp_err_status_algo_fail; + } + + return srtp_err_status_ok; +} + +srtp_err_status_t test_replay_dbx(int num_trials, unsigned long ws) +{ + srtp_rdbx_t rdbx; + uint32_t idx, ircvd; + ut_connection utc; + srtp_err_status_t status; + int num_fp_trials; + + status = srtp_rdbx_init(&rdbx, ws); + if (status) { + printf("replay_init failed with error code %d\n", status); + exit(1); + } + + /* + * test sequential insertion + */ + printf("\ttesting sequential insertion..."); + for (idx = 0; (int)idx < num_trials; idx++) { + status = rdbx_check_add(&rdbx, idx); + if (status) + return status; + } + printf("passed\n"); + + /* + * test for false positives by checking all of the index + * values which we've just added + * + * note that we limit the number of trials here, since allowing the + * rollover counter to roll over would defeat this test + */ + num_fp_trials = num_trials % 0x10000; + if (num_fp_trials == 0) { + printf("warning: no false positive tests performed\n"); + } + printf("\ttesting for false positives..."); + for (idx = 0; (int)idx < num_fp_trials; idx++) { + status = rdbx_check_expect_failure(&rdbx, idx); + if (status) + return status; + } + printf("passed\n"); + + /* re-initialize */ + srtp_rdbx_dealloc(&rdbx); + + if (srtp_rdbx_init(&rdbx, ws) != srtp_err_status_ok) { + printf("replay_init failed\n"); + return srtp_err_status_init_fail; + } + + /* + * test non-sequential insertion + * + * this test covers only fase negatives, since the values returned + * by ut_next_index(...) are distinct + */ + ut_init(&utc); + + printf("\ttesting non-sequential insertion..."); + for (idx = 0; (int)idx < num_trials; idx++) { + ircvd = ut_next_index(&utc); + status = rdbx_check_add_unordered(&rdbx, ircvd); + if (status) + return status; + status = rdbx_check_expect_failure(&rdbx, ircvd); + if (status) + return status; + } + printf("passed\n"); + + /* re-initialize */ + srtp_rdbx_dealloc(&rdbx); + + if (srtp_rdbx_init(&rdbx, ws) != srtp_err_status_ok) { + printf("replay_init failed\n"); + return srtp_err_status_init_fail; + } + + /* + * test insertion with large gaps. + * check for false positives for each insertion. + */ + printf("\ttesting insertion with large gaps..."); + for (idx = 0, ircvd = 0; (int)idx < num_trials; + idx++, ircvd += (1 << (rand() % 12))) { + status = rdbx_check_add(&rdbx, ircvd); + if (status) + return status; + status = rdbx_check_expect_failure(&rdbx, ircvd); + if (status) + return status; + } + printf("passed\n"); + + srtp_rdbx_dealloc(&rdbx); + + return srtp_err_status_ok; +} + +#include <time.h> /* for clock() */ +#include <stdlib.h> /* for random() */ + +double rdbx_check_adds_per_second(int num_trials, unsigned long ws) +{ + uint32_t i; + int delta; + srtp_rdbx_t rdbx; + srtp_xtd_seq_num_t est; + clock_t timer; + int failures; /* count number of failures */ + + if (srtp_rdbx_init(&rdbx, ws) != srtp_err_status_ok) { + printf("replay_init failed\n"); + exit(1); + } + + failures = 0; + timer = clock(); + for (i = 0; (int)i < num_trials; i++) { + delta = srtp_index_guess(&rdbx.index, &est, i); + + if (srtp_rdbx_check(&rdbx, delta) != srtp_err_status_ok) + ++failures; + else if (srtp_rdbx_add_index(&rdbx, delta) != srtp_err_status_ok) + ++failures; + } + timer = clock() - timer; + if (timer < 1) { + timer = 1; + } + + printf("number of failures: %d \n", failures); + + srtp_rdbx_dealloc(&rdbx); + + return (double)CLOCKS_PER_SEC * num_trials / timer; +} |