LCOV - code coverage report
Current view: top level - test/oscore_unit_tests - unit_test_replay_protection.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 124 124 100.0 %
Date: 2024-09-16 20:15:30 Functions: 11 11 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 14 14 100.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :    Copyright (c) 2022 Assa Abloy. See the COPYRIGHT
       3                 :            :    file at the top-level directory of this distribution.
       4                 :            : 
       5                 :            :    Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
       6                 :            :    http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
       7                 :            :    <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
       8                 :            :    option. This file may not be copied, modified, or distributed
       9                 :            :    except according to those terms.
      10                 :            : */
      11                 :            : #include <stdio.h>
      12                 :            : #include <string.h>
      13                 :            : #include <zephyr/ztest.h>
      14                 :            : 
      15                 :            : #include "oscore/replay_protection.h"
      16                 :            : 
      17                 :            : #define WINDOW_SIZE OSCORE_SERVER_REPLAY_WINDOW_SIZE
      18                 :            : #define DUMMY_BYTE 10
      19                 :            : #define WINDOW_SIZE_BYTES (WINDOW_SIZE * sizeof(uint64_t))
      20                 :            : 
      21                 :            : static struct server_replay_window_t replay_window;
      22                 :            : 
      23                 :          3 : static void _copy_window(struct server_replay_window_t *dest,
      24                 :            :                          const struct server_replay_window_t *src)
      25                 :            : {
      26                 :          3 :         memcpy(dest, src, sizeof(struct server_replay_window_t));
      27                 :          3 : }
      28                 :            : 
      29                 :         14 : static void _compare_windows(struct server_replay_window_t *current,
      30                 :            :                              const struct server_replay_window_t *expected)
      31                 :            : {
      32                 :         14 :         zassert_mem_equal(current->window, expected->window, WINDOW_SIZE_BYTES,
      33                 :            :                           "");
      34                 :         14 :         zassert_equal(current->seq_num_zero_received,
      35                 :            :                       expected->seq_num_zero_received, "");
      36                 :         14 : }
      37                 :            : 
      38                 :            : static void
      39                 :        198 : _update_window_and_check_result(uint64_t seq_num,
      40                 :            :                                 struct server_replay_window_t *replay_window,
      41                 :            :                                 bool expected_result)
      42                 :            : {
      43                 :        198 :         bool result = server_replay_window_update(seq_num, replay_window);
      44                 :        198 :         zassert_equal(expected_result, result, "");
      45                 :        198 : }
      46                 :            : 
      47                 :            : static void
      48                 :         65 : _validate_window_and_check_result(uint64_t seq_num,
      49                 :            :                                   struct server_replay_window_t *replay_window,
      50                 :            :                                   bool expected_result)
      51                 :            : {
      52                 :         65 :         bool result = server_is_sequence_number_valid(seq_num, replay_window);
      53                 :         65 :         zassert_equal(expected_result, result, "");
      54                 :         65 : }
      55                 :            : 
      56                 :            : /**
      57                 :            :  * @brief Test replay window initialization.
      58                 :            :  */
      59                 :          1 : void t600_server_replay_init_test(void)
      60                 :            : {
      61                 :          1 :         static struct server_replay_window_t compare_window = { 0 };
      62                 :            : 
      63                 :            :         /* set random data to all fields */
      64                 :          1 :         memset(replay_window.window, DUMMY_BYTE, WINDOW_SIZE_BYTES);
      65                 :          1 :         replay_window.seq_num_zero_received = true;
      66                 :            : 
      67                 :          1 :         enum err result;
      68                 :          1 :         result = server_replay_window_init(NULL);
      69                 :          1 :         zassert_equal(wrong_parameter, result, "");
      70                 :            : 
      71                 :          1 :         result = server_replay_window_init(&replay_window);
      72                 :          1 :         zassert_equal(ok, result, "");
      73                 :          1 :         _compare_windows(&replay_window, &compare_window);
      74                 :            : 
      75                 :            :         /* extra check of helper function */
      76                 :          1 :         zassert_equal(false, server_is_sequence_number_valid(0, NULL), "");
      77                 :          1 : }
      78                 :            : 
      79                 :            : /**
      80                 :            :  * @brief Test replay window re-initialization.
      81                 :            :  */
      82                 :          1 : void t601_server_replay_reinit_test(void)
      83                 :            : {
      84                 :          1 :         static const struct server_replay_window_t compare_window_1 = {
      85                 :            :                 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      86                 :            :                   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6 },
      87                 :            :                 true
      88                 :            :         };
      89                 :            : 
      90                 :          1 :         static const struct server_replay_window_t compare_window_2 = {
      91                 :            :                 { 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
      92                 :            :                   111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121,
      93                 :            :                   122, 123, 124, 125, 126, 127, 128, 129, 130, 131 },
      94                 :            :                 true
      95                 :            :         };
      96                 :            : 
      97                 :          1 :         enum err result;
      98                 :          1 :         result = server_replay_window_reinit(6, NULL);
      99                 :          1 :         zassert_equal(wrong_parameter, result, "");
     100                 :            : 
     101                 :          1 :         result = server_replay_window_reinit(6, &replay_window);
     102                 :          1 :         zassert_equal(ok, result, "");
     103                 :          1 :         _compare_windows(&replay_window, &compare_window_1);
     104                 :            : 
     105                 :          1 :         result = server_replay_window_reinit(131, &replay_window);
     106                 :          1 :         zassert_equal(ok, result, "");
     107                 :          1 :         _compare_windows(&replay_window, &compare_window_2);
     108                 :          1 : }
     109                 :            : 
     110                 :            : /**
     111                 :            :  * @brief Test replay window check for various sequence numbers - this case represents beginning of the communication.
     112                 :            :  */
     113                 :          1 : void t602_server_replay_check_at_start_test(void)
     114                 :            : {
     115                 :            :         // missing Sequence Numbers in starting_point: 9, 5, 3, 2, 1, 0
     116                 :            :         // SN 11 is ahead of current window = OK
     117                 :            :         // SN 12 might be received before SN 11 = also OK
     118                 :            :         // SN 10 is received in the last message = NOT OK
     119                 :            :         // SN 9 is delayed and not received yet = OK
     120                 :            :         // SN 8 is already received = NOT OK
     121                 :            :         // SN 5 is delayed = OK
     122                 :            :         // SN 0 is delayed and still in the window range = OK
     123                 :            : 
     124                 :          1 :         static const struct server_replay_window_t starting_point = {
     125                 :            :                 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     126                 :            :                   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 6, 7, 8, 10 },
     127                 :            :                 false
     128                 :            :         };
     129                 :            : 
     130                 :          1 :         static const uint64_t numbers_to_check[] = { 11, 12, 10, 9, 8, 5, 0 };
     131                 :          1 :         static const bool numbers_results[] = { true,  true, false, true,
     132                 :            :                                                 false, true, true };
     133                 :          1 :         const uint16_t check_count =
     134                 :            :                 sizeof(numbers_to_check) / sizeof(numbers_to_check[0]);
     135                 :            : 
     136                 :          1 :         _copy_window(&replay_window, &starting_point);
     137                 :            : 
     138         [ +  + ]:          8 :         for (uint16_t index = 0; index < check_count; index++) {
     139                 :          7 :                 bool result_valid = numbers_results[index];
     140                 :          7 :                 uint64_t seq_num = numbers_to_check[index];
     141                 :          7 :                 _validate_window_and_check_result(seq_num, &replay_window,
     142                 :            :                                                   result_valid);
     143                 :            :         }
     144                 :          1 : }
     145                 :            : 
     146                 :            : /**
     147                 :            :  * @brief Test replay window check for various sequence numbers - this case represents communication in progress.
     148                 :            :  */
     149                 :          1 : void t603_server_replay_check_in_progress_test(void)
     150                 :            : {
     151                 :            :         // missing Sequence Numbers in starting_point: 126, 127, 133
     152                 :            :         // SN 99 and below are behind the window = NOT OK
     153                 :            : 
     154                 :          1 :         static const struct server_replay_window_t starting_point = {
     155                 :            :                 { 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
     156                 :            :                   111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121,
     157                 :            :                   122, 123, 124, 125, 128, 129, 130, 131, 132, 134 },
     158                 :            :                 true
     159                 :            :         };
     160                 :            : 
     161                 :          1 :         static const uint64_t numbers_to_check[] = { 135, 134, 133, 132,
     162                 :            :                                                      127, 126, 99,  80 };
     163                 :          1 :         static const bool numbers_results[] = { true, false, true,  false,
     164                 :            :                                                 true, true,  false, false };
     165                 :          1 :         const uint16_t check_count =
     166                 :            :                 sizeof(numbers_to_check) / sizeof(numbers_to_check[0]);
     167                 :            : 
     168                 :          1 :         _copy_window(&replay_window, &starting_point);
     169                 :            : 
     170         [ +  + ]:          9 :         for (uint16_t index = 0; index < check_count; index++) {
     171                 :          8 :                 bool result_valid = numbers_results[index];
     172                 :          8 :                 uint64_t seq_num = numbers_to_check[index];
     173                 :          8 :                 _validate_window_and_check_result(seq_num, &replay_window,
     174                 :            :                                                   result_valid);
     175                 :            :         }
     176                 :          1 : }
     177                 :            : 
     178                 :            : /**
     179                 :            :  * @brief Test inserting zero into replay window at different moments of the session.
     180                 :            :  */
     181                 :          1 : void t604_server_replay_insert_zero_test(void)
     182                 :            : {
     183                 :          1 :         static const struct server_replay_window_t compare_window_1 = { { 0 }, true };
     184                 :            : 
     185                 :          1 :         static const struct server_replay_window_t compare_window_2 = {
     186                 :            :                 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     187                 :            :                   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
     188                 :            :                 true
     189                 :            :         };
     190                 :            : 
     191                 :          1 :         server_replay_window_init(&replay_window);
     192                 :            : 
     193                 :            :         /* First, check if sequence number 0 at the beginning of the session doesn't break anything. */
     194                 :            :         /* After inserting 0, window should still be empty, but zero received flag should be true. */
     195                 :          1 :         _update_window_and_check_result(0, &replay_window, true);
     196                 :          1 :         _compare_windows(&replay_window, &compare_window_1);
     197                 :            : 
     198                 :            :         /* Inserting 0 for the second time should result in error. */
     199                 :          1 :         _update_window_and_check_result(0, &replay_window, false);
     200                 :            : 
     201                 :            :         /* Inserting valid number should be ok. */
     202                 :          1 :         _update_window_and_check_result(1, &replay_window, true);
     203                 :          1 :         _compare_windows(&replay_window, &compare_window_2);
     204                 :            : 
     205                 :            :         /* Reset replay window and insert SeqNum=1. Later, inserting delayed SeqNum=0 should still be ok. */
     206                 :          1 :         server_replay_window_init(&replay_window);
     207                 :          1 :         _update_window_and_check_result(1, &replay_window, true);
     208                 :          1 :         _update_window_and_check_result(0, &replay_window, true);
     209                 :          1 :         _compare_windows(&replay_window, &compare_window_2);
     210                 :            : 
     211                 :            :         /* Reset replay window and test immunity to simple replay attack using SeqNum=0. */
     212                 :          1 :         server_replay_window_init(&replay_window);
     213                 :          1 :         _update_window_and_check_result(0, &replay_window, true);
     214                 :          1 :         _update_window_and_check_result(1, &replay_window, true);
     215                 :          1 :         _update_window_and_check_result(0, &replay_window, false);
     216                 :          1 :         _compare_windows(&replay_window, &compare_window_2);
     217                 :            : 
     218                 :            :         /* Reset replay window and insert multiple values that will roll the window. Later, inserting delayed SeqNum=0 should fail. */
     219                 :          1 :         server_replay_window_init(&replay_window);
     220         [ +  + ]:         51 :         for (uint64_t seq_num = 1; seq_num <= 50; seq_num++) {
     221                 :         50 :                 _update_window_and_check_result(seq_num, &replay_window, true);
     222                 :            :         }
     223                 :          1 :         _update_window_and_check_result(0, &replay_window, false);
     224                 :          1 : }
     225                 :            : 
     226                 :            : /**
     227                 :            :  * @brief Test inserting values into replay window at different moments of the session.
     228                 :            :  */
     229                 :          1 : void t605_server_replay_insert_test(void)
     230                 :            : {
     231                 :          1 :         static const struct server_replay_window_t starting_point = {
     232                 :            :                 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     233                 :            :                   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 6, 7, 8, 10 },
     234                 :            :                 false
     235                 :            :         };
     236                 :          1 :         static const struct server_replay_window_t compare_window_1 = {
     237                 :            :                 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     238                 :            :                   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 6, 7, 8, 10 },
     239                 :            :                 false
     240                 :            :         };
     241                 :          1 :         static const struct server_replay_window_t compare_window_2 = {
     242                 :            :                 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     243                 :            :                   0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 5, 6, 7, 8, 10 },
     244                 :            :                 false
     245                 :            :         };
     246                 :          1 :         static const struct server_replay_window_t compare_window_3 = {
     247                 :            :                 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     248                 :            :                   0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 5, 6, 7, 8, 9, 10 },
     249                 :            :                 false
     250                 :            :         };
     251                 :          1 :         static const struct server_replay_window_t compare_window_4 = {
     252                 :            :                 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,
     253                 :            :                   0, 0, 0, 0, 0, 0, 0, 1, 4, 5, 6, 7, 8, 9, 10, 12 },
     254                 :            :                 false
     255                 :            :         };
     256                 :          1 :         static const struct server_replay_window_t compare_window_5 = {
     257                 :            :                 { 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
     258                 :            :                   80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
     259                 :            :                   91, 92, 93, 94, 95, 96, 97, 98, 99, 100 },
     260                 :            :                 false
     261                 :            :         };
     262                 :            : 
     263                 :          1 :         _copy_window(&replay_window, &starting_point);
     264                 :            : 
     265                 :          1 :         _update_window_and_check_result(1, &replay_window, true);
     266                 :          1 :         _compare_windows(&replay_window, &compare_window_1);
     267                 :            : 
     268                 :          1 :         _update_window_and_check_result(5, &replay_window, true);
     269                 :          1 :         _compare_windows(&replay_window, &compare_window_2);
     270                 :            : 
     271                 :          1 :         _update_window_and_check_result(9, &replay_window, true);
     272                 :          1 :         _compare_windows(&replay_window, &compare_window_3);
     273                 :            : 
     274                 :          1 :         _update_window_and_check_result(12, &replay_window, true);
     275                 :          1 :         _compare_windows(&replay_window, &compare_window_4);
     276                 :            : 
     277         [ +  + ]:         89 :         for (uint64_t seq_num = 13; seq_num <= 100; seq_num++) {
     278                 :         88 :                 _update_window_and_check_result(seq_num, &replay_window, true);
     279                 :            :         }
     280                 :          1 :         _compare_windows(&replay_window, &compare_window_5);
     281                 :          1 : }
     282                 :            : 
     283                 :            : /**
     284                 :            :  * @brief Standard scenario test - checks and updates
     285                 :            :  */
     286                 :          1 : void t606_server_replay_standard_scenario_test(void)
     287                 :            : {
     288                 :          1 :         static const struct server_replay_window_t compare_window_1 = {
     289                 :            :                 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     290                 :            :                   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5 },
     291                 :            :                 true
     292                 :            :         };
     293                 :            : 
     294                 :          1 :         static const struct server_replay_window_t compare_window_2 = {
     295                 :            :                 { 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
     296                 :            :                   30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
     297                 :            :                   41, 42, 43, 44, 45, 46, 47, 48, 49, 50 },
     298                 :            :                 true
     299                 :            :         };
     300                 :            : 
     301                 :          1 :         static const uint64_t incoming_numbers[] = { 1, 0, 4, 4, 2, 3, 5, 1, 0 };
     302                 :          1 :         static const enum err check_results[] = { true,  true,  true,
     303                 :            :                                                   false, true,  true,
     304                 :            :                                                   true,  false, false };
     305                 :          1 :         uint16_t const check_count =
     306                 :            :                 sizeof(incoming_numbers) / sizeof(incoming_numbers[0]);
     307                 :            : 
     308                 :          1 :         server_replay_window_init(&replay_window);
     309                 :            : 
     310                 :            :         //several messages are out of order or repeated
     311         [ +  + ]:         10 :         for (uint16_t index = 0; index < check_count; index++) {
     312                 :          9 :                 bool result_valid = check_results[index];
     313                 :          9 :                 uint64_t seq_num = incoming_numbers[index];
     314                 :          9 :                 _validate_window_and_check_result(seq_num, &replay_window,
     315                 :            :                                                   result_valid);
     316                 :            : 
     317         [ +  + ]:          9 :                 if (result_valid) {
     318                 :            :                         //replay check OK - after MAC verification, window can be updated
     319                 :          6 :                         _update_window_and_check_result(seq_num, &replay_window,
     320                 :            :                                                         true);
     321                 :            :                 }
     322                 :            :         }
     323                 :          1 :         _compare_windows(&replay_window, &compare_window_1);
     324                 :            : 
     325                 :            :         //proper reception of multiple messages, to make sure that in real scenario window can do its job
     326         [ +  + ]:         42 :         for (uint64_t seq_num = 10; seq_num <= 50; seq_num++) {
     327                 :         41 :                 _validate_window_and_check_result(seq_num, &replay_window,
     328                 :            :                                                   true);
     329                 :         41 :                 _update_window_and_check_result(seq_num, &replay_window, true);
     330                 :            :         }
     331                 :          1 :         _compare_windows(&replay_window, &compare_window_2);
     332                 :          1 : }

Generated by: LCOV version 1.14