1 #include <stdbool.h>
2 #include <string.h>
3
4 #include "oscore/replay_protection.h"
5 #include "oscore/security_context.h"
6 #include "common/memcpy_s.h"
7 #include "common/byte_array.h"
8
9 #define WINDOW_SIZE OSCORE_SERVER_REPLAY_WINDOW_SIZE
10
11 /**
12 * @brief Insert given sequence number in the specified position of replay window.
13
14 * @param seq_number [in] sequence number to be inserted
15 * @param replay_window [out] replay window array pointer
16 * @param position [in] index to place new number (all older elements will be left-shifted)
17 */
server_replay_window_insert(uint64_t seq_number,struct server_replay_window_t * replay_window,size_t position)18 static void server_replay_window_insert(uint64_t seq_number,
19 struct server_replay_window_t *replay_window,
20 size_t position)
21 {
22 uint64_t *window = replay_window->window;
23
24 /*shift all old values one position to the left*/
25 size_t shift_length = position * sizeof(window[0]);
26 memmove(window, window + 1, shift_length);
27
28 /*insert the new sender sequence number at a given position*/
29 window[position] = seq_number;
30 }
31
server_replay_window_init(struct server_replay_window_t * replay_window)32 enum err server_replay_window_init(struct server_replay_window_t *replay_window)
33 {
34 if (NULL == replay_window) {
35 return wrong_parameter;
36 }
37
38 memset(replay_window->window, 0,
39 WINDOW_SIZE * sizeof(replay_window->window[0]));
40 replay_window->seq_num_zero_received = false;
41 return ok;
42 }
43
server_replay_window_reinit(uint64_t current_sequence_number,struct server_replay_window_t * replay_window)44 enum err server_replay_window_reinit(uint64_t current_sequence_number,
45 struct server_replay_window_t *replay_window)
46 {
47 if (NULL == replay_window) {
48 return wrong_parameter;
49 }
50
51 /*fill the window in a way that only new sequence numbers are accepted*/
52 for (uint8_t j = 0; j < WINDOW_SIZE; j++) {
53 replay_window->window[(WINDOW_SIZE - 1) - j] =
54 current_sequence_number;
55 if (current_sequence_number > 0) {
56 current_sequence_number--;
57 }
58 }
59
60 /* don't accept seqNum=0 anymore */
61 replay_window->seq_num_zero_received = true;
62
63 return ok;
64 }
65
server_is_sequence_number_valid(uint64_t seq_number,struct server_replay_window_t * replay_window)66 bool server_is_sequence_number_valid(uint64_t seq_number,
67 struct server_replay_window_t *replay_window)
68 {
69 if (NULL == replay_window) {
70 return false;
71 }
72
73 /* replay window uses zeros for unused entries, so in case of sequence number is 0, a little logic is needed */
74 if (0 == seq_number) {
75 if ((!replay_window->seq_num_zero_received) &&
76 (0 == replay_window->window[0])) {
77 return true;
78 }
79 return false;
80 }
81
82 if (seq_number > replay_window->window[WINDOW_SIZE - 1]) {
83 return true;
84 }
85
86 if (seq_number < replay_window->window[0]) {
87 return false;
88 }
89
90 for (uint8_t i = 0; i < WINDOW_SIZE; i++) {
91 if (seq_number == replay_window->window[i]) {
92 return false;
93 }
94 }
95
96 return true;
97 }
98
server_replay_window_update(uint64_t seq_number,struct server_replay_window_t * replay_window)99 bool server_replay_window_update(uint64_t seq_number,
100 struct server_replay_window_t *replay_window)
101 {
102 /* Although sequence number should be checked before by the calling function, do it again to prevent possible security issues in case it was not. */
103 bool is_valid =
104 server_is_sequence_number_valid(seq_number, replay_window);
105 if (!is_valid) {
106 return false;
107 }
108
109 if (seq_number == 0) {
110 replay_window->seq_num_zero_received = true;
111 return true;
112 }
113
114 uint16_t index;
115 for (index = 0; index < WINDOW_SIZE - 1; index++) {
116 /* when the loop doesn't find proper index to place the number, it will stop at index = WINDOW_SIZE-1 */
117 if ((replay_window->window[index] < seq_number) &&
118 (replay_window->window[index + 1] > seq_number)) {
119 break;
120 }
121 }
122 server_replay_window_insert(seq_number, replay_window, index);
123 return true;
124 }
125
replay_protection_check_notification(uint64_t notification_num,bool notification_num_initialized,struct byte_array * piv)126 enum err replay_protection_check_notification(uint64_t notification_num,
127 bool notification_num_initialized,
128 struct byte_array *piv)
129 {
130 uint64_t ssn;
131 TRY(piv2ssn(piv, &ssn));
132
133
134 if (notification_num_initialized) {
135 if (notification_num >= ssn) {
136 PRINT_MSG("Replayed notification detected!\n");
137 return oscore_replay_notification_protection_error;
138 }
139 }
140 return ok;
141 }
142
notification_number_update(uint64_t * notification_num,bool * notification_num_initialized,struct byte_array * piv)143 enum err notification_number_update(uint64_t *notification_num,
144 bool *notification_num_initialized,
145 struct byte_array *piv)
146 {
147 TRY(piv2ssn(piv, notification_num));
148 *notification_num_initialized = true;
149 return ok;
150 }