rdbx_driver.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  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. /*
  115. * rdbx_check_add(rdbx, idx) checks a known-to-be-good idx against
  116. * rdbx, then adds it. if a failure is detected (i.e., the check
  117. * indicates that the value is already in rdbx) then
  118. * srtp_err_status_algo_fail is returned.
  119. *
  120. */
  121. srtp_err_status_t rdbx_check_add(srtp_rdbx_t *rdbx, uint32_t idx)
  122. {
  123. int delta;
  124. srtp_xtd_seq_num_t est;
  125. delta = srtp_index_guess(&rdbx->index, &est, idx);
  126. if (srtp_rdbx_check(rdbx, delta) != srtp_err_status_ok) {
  127. printf("replay_check failed at index %u\n", idx);
  128. return srtp_err_status_algo_fail;
  129. }
  130. /*
  131. * in practice, we'd authenticate the packet containing idx, using
  132. * the estimated value est, at this point
  133. */
  134. if (srtp_rdbx_add_index(rdbx, delta) != srtp_err_status_ok) {
  135. printf("rdbx_add_index failed at index %u\n", idx);
  136. return srtp_err_status_algo_fail;
  137. }
  138. return srtp_err_status_ok;
  139. }
  140. /*
  141. * rdbx_check_expect_failure(srtp_rdbx_t *rdbx, uint32_t idx)
  142. *
  143. * checks that a sequence number idx is in the replay database
  144. * and thus will be rejected
  145. */
  146. srtp_err_status_t rdbx_check_expect_failure(srtp_rdbx_t *rdbx, uint32_t idx)
  147. {
  148. int delta;
  149. srtp_xtd_seq_num_t est;
  150. srtp_err_status_t status;
  151. delta = srtp_index_guess(&rdbx->index, &est, idx);
  152. status = srtp_rdbx_check(rdbx, delta);
  153. if (status == srtp_err_status_ok) {
  154. printf("delta: %d ", delta);
  155. printf("replay_check failed at index %u (false positive)\n", idx);
  156. return srtp_err_status_algo_fail;
  157. }
  158. return srtp_err_status_ok;
  159. }
  160. srtp_err_status_t rdbx_check_add_unordered(srtp_rdbx_t *rdbx, uint32_t idx)
  161. {
  162. int delta;
  163. srtp_xtd_seq_num_t est;
  164. srtp_err_status_t rstat;
  165. delta = srtp_index_guess(&rdbx->index, &est, idx);
  166. rstat = srtp_rdbx_check(rdbx, delta);
  167. if ((rstat != srtp_err_status_ok) &&
  168. (rstat != srtp_err_status_replay_old)) {
  169. printf("replay_check_add_unordered failed at index %u\n", idx);
  170. return srtp_err_status_algo_fail;
  171. }
  172. if (rstat == srtp_err_status_replay_old) {
  173. return srtp_err_status_ok;
  174. }
  175. if (srtp_rdbx_add_index(rdbx, delta) != srtp_err_status_ok) {
  176. printf("rdbx_add_index failed at index %u\n", idx);
  177. return srtp_err_status_algo_fail;
  178. }
  179. return srtp_err_status_ok;
  180. }
  181. srtp_err_status_t test_replay_dbx(int num_trials, unsigned long ws)
  182. {
  183. srtp_rdbx_t rdbx;
  184. uint32_t idx, ircvd;
  185. ut_connection utc;
  186. srtp_err_status_t status;
  187. int num_fp_trials;
  188. status = srtp_rdbx_init(&rdbx, ws);
  189. if (status) {
  190. printf("replay_init failed with error code %d\n", status);
  191. exit(1);
  192. }
  193. /*
  194. * test sequential insertion
  195. */
  196. printf("\ttesting sequential insertion...");
  197. for (idx = 0; (int)idx < num_trials; idx++) {
  198. status = rdbx_check_add(&rdbx, idx);
  199. if (status)
  200. return status;
  201. }
  202. printf("passed\n");
  203. /*
  204. * test for false positives by checking all of the index
  205. * values which we've just added
  206. *
  207. * note that we limit the number of trials here, since allowing the
  208. * rollover counter to roll over would defeat this test
  209. */
  210. num_fp_trials = num_trials % 0x10000;
  211. if (num_fp_trials == 0) {
  212. printf("warning: no false positive tests performed\n");
  213. }
  214. printf("\ttesting for false positives...");
  215. for (idx = 0; (int)idx < num_fp_trials; idx++) {
  216. status = rdbx_check_expect_failure(&rdbx, idx);
  217. if (status)
  218. return status;
  219. }
  220. printf("passed\n");
  221. /* re-initialize */
  222. srtp_rdbx_dealloc(&rdbx);
  223. if (srtp_rdbx_init(&rdbx, ws) != srtp_err_status_ok) {
  224. printf("replay_init failed\n");
  225. return srtp_err_status_init_fail;
  226. }
  227. /*
  228. * test non-sequential insertion
  229. *
  230. * this test covers only fase negatives, since the values returned
  231. * by ut_next_index(...) are distinct
  232. */
  233. ut_init(&utc);
  234. printf("\ttesting non-sequential insertion...");
  235. for (idx = 0; (int)idx < num_trials; idx++) {
  236. ircvd = ut_next_index(&utc);
  237. status = rdbx_check_add_unordered(&rdbx, ircvd);
  238. if (status)
  239. return status;
  240. status = rdbx_check_expect_failure(&rdbx, ircvd);
  241. if (status)
  242. return status;
  243. }
  244. printf("passed\n");
  245. /* re-initialize */
  246. srtp_rdbx_dealloc(&rdbx);
  247. if (srtp_rdbx_init(&rdbx, ws) != srtp_err_status_ok) {
  248. printf("replay_init failed\n");
  249. return srtp_err_status_init_fail;
  250. }
  251. /*
  252. * test insertion with large gaps.
  253. * check for false positives for each insertion.
  254. */
  255. printf("\ttesting insertion with large gaps...");
  256. for (idx = 0, ircvd = 0; (int)idx < num_trials;
  257. idx++, ircvd += (1 << (srtp_cipher_rand_u32_for_tests() % 12))) {
  258. status = rdbx_check_add(&rdbx, ircvd);
  259. if (status)
  260. return status;
  261. status = rdbx_check_expect_failure(&rdbx, ircvd);
  262. if (status)
  263. return status;
  264. }
  265. printf("passed\n");
  266. srtp_rdbx_dealloc(&rdbx);
  267. return srtp_err_status_ok;
  268. }
  269. #include <time.h> /* for clock() */
  270. double rdbx_check_adds_per_second(int num_trials, unsigned long ws)
  271. {
  272. uint32_t i;
  273. int delta;
  274. srtp_rdbx_t rdbx;
  275. srtp_xtd_seq_num_t est;
  276. clock_t timer;
  277. int failures; /* count number of failures */
  278. if (srtp_rdbx_init(&rdbx, ws) != srtp_err_status_ok) {
  279. printf("replay_init failed\n");
  280. exit(1);
  281. }
  282. failures = 0;
  283. timer = clock();
  284. for (i = 0; (int)i < num_trials; i++) {
  285. delta = srtp_index_guess(&rdbx.index, &est, i);
  286. if (srtp_rdbx_check(&rdbx, delta) != srtp_err_status_ok)
  287. ++failures;
  288. else if (srtp_rdbx_add_index(&rdbx, delta) != srtp_err_status_ok)
  289. ++failures;
  290. }
  291. timer = clock() - timer;
  292. if (timer < 1) {
  293. timer = 1;
  294. }
  295. printf("number of failures: %d \n", failures);
  296. srtp_rdbx_dealloc(&rdbx);
  297. return (double)CLOCKS_PER_SEC * num_trials / timer;
  298. }