2
0

rdbx_driver.c 9.8 KB

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