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 }