Branch data Line data Source code
1 : : /*
2 : : Copyright (c) 2021 Fraunhofer AISEC. 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 : :
12 : : #include "edhoc/buffer_sizes.h"
13 : : #include "edhoc_internal.h"
14 : :
15 : : #include "common/memcpy_s.h"
16 : : #include "common/print_util.h"
17 : : #include "common/crypto_wrapper.h"
18 : : #include "common/oscore_edhoc_error.h"
19 : :
20 : : #include "edhoc/hkdf_info.h"
21 : : #include "edhoc/messages.h"
22 : : #include "edhoc/okm.h"
23 : : #include "edhoc/plaintext.h"
24 : : #include "edhoc/prk.h"
25 : : #include "edhoc/retrieve_cred.h"
26 : : #include "edhoc/signature_or_mac_msg.h"
27 : : #include "edhoc/suites.h"
28 : : #include "edhoc/th.h"
29 : : #include "edhoc/txrx_wrapper.h"
30 : : #include "edhoc/ciphertext.h"
31 : : #include "edhoc/suites.h"
32 : : #include "edhoc/runtime_context.h"
33 : : #include "edhoc/bstr_encode_decode.h"
34 : : #include "edhoc/int_encode_decode.h"
35 : :
36 : : #include "cbor/edhoc_decode_message_1.h"
37 : : #include "cbor/edhoc_encode_message_2.h"
38 : : #include "cbor/edhoc_decode_message_3.h"
39 : :
40 : : #define CBOR_UINT_SINGLE_BYTE_UINT_MAX_VALUE (0x17)
41 : : #define CBOR_UINT_MULTI_BYTE_UINT_MAX_VALUE (0x17)
42 : : #define CBOR_BSTR_TYPE_MIN_VALUE (0x40)
43 : : #define CBOR_BSTR_TYPE_MAX_VALUE (0x57)
44 : :
45 : : /**
46 : : * @brief Parses message 1.
47 : : * @param[in] msg1 Message 1.
48 : : * @param[out] method EDHOC method.
49 : : * @param[out] suites_i Cipher suites suported by the initiator
50 : : * @param[out] g_x Public ephemeral key of the initiator.
51 : : * @param[out] c_i Connection identifier of the initiator.
52 : : * @param[out] ead1 External authorized data 1.
53 : : * @retval Ok or error code.
54 : : */
55 : : static inline enum err
56 : 3 : msg1_parse(struct byte_array *msg1, enum method_type *method,
57 : : struct byte_array *suites_i, struct byte_array *g_x,
58 : : struct byte_array *c_i, struct byte_array *ead1)
59 : : {
60 : : uint32_t i;
61 : : struct message_1 m;
62 : 3 : size_t decode_len = 0;
63 : :
64 [ - + ]: 3 : TRY_EXPECT(cbor_decode_message_1(msg1->ptr, msg1->len, &m, &decode_len),
65 : : 0);
66 : :
67 : : /*METHOD*/
68 [ + - ]: 3 : if ((m.message_1_METHOD > INITIATOR_SDHK_RESPONDER_SDHK) ||
69 [ - + ]: 3 : (m.message_1_METHOD < INITIATOR_SK_RESPONDER_SK)) {
70 : 0 : return wrong_parameter;
71 : : }
72 : 3 : *method = (enum method_type)m.message_1_METHOD;
73 : 3 : PRINTF("msg1 METHOD: %d\n", (int)*method);
74 : :
75 : : /*SUITES_I*/
76 [ + - ]: 3 : if (m.message_1_SUITES_I_choice == message_1_SUITES_I_int_c) {
77 : : /*the initiator supports only one suite*/
78 : 3 : suites_i->ptr[0] = (uint8_t)m.message_1_SUITES_I_int;
79 : 3 : suites_i->len = 1;
80 : : } else {
81 [ # # ]: 0 : if (0 == m.SUITES_I_suite_l_suite_count) {
82 : 0 : return suites_i_list_empty;
83 : : }
84 : :
85 : : /*the initiator supports more than one suite*/
86 [ # # ]: 0 : if (m.SUITES_I_suite_l_suite_count > suites_i->len) {
87 : 0 : return suites_i_list_to_long;
88 : : }
89 : :
90 [ # # ]: 0 : for (i = 0; i < m.SUITES_I_suite_l_suite_count; i++) {
91 : 0 : suites_i->ptr[i] = (uint8_t)m.SUITES_I_suite_l_suite[i];
92 : : }
93 : 0 : suites_i->len = (uint32_t)m.SUITES_I_suite_l_suite_count;
94 : : }
95 : 3 : PRINT_ARRAY("msg1 SUITES_I", suites_i->ptr, suites_i->len);
96 : :
97 : : /*G_X*/
98 [ - + ]: 3 : TRY(_memcpy_s(g_x->ptr, g_x->len, m.message_1_G_X.value,
99 : : (uint32_t)m.message_1_G_X.len));
100 : 3 : g_x->len = (uint32_t)m.message_1_G_X.len;
101 : 3 : PRINT_ARRAY("msg1 G_X", g_x->ptr, g_x->len);
102 : :
103 : : /*C_I*/
104 [ + - ]: 3 : if (m.message_1_C_I_choice == message_1_C_I_int_c) {
105 : 3 : c_i->ptr[0] = (uint8_t)m.message_1_C_I_int;
106 : 3 : c_i->len = 1;
107 : : } else {
108 [ # # ]: 0 : TRY(_memcpy_s(c_i->ptr, c_i->len, m.message_1_C_I_bstr.value,
109 : : (uint32_t)m.message_1_C_I_bstr.len));
110 : 0 : c_i->len = (uint32_t)m.message_1_C_I_bstr.len;
111 : : }
112 : 3 : PRINT_ARRAY("msg1 C_I_raw", c_i->ptr, c_i->len);
113 : :
114 : : /*ead_1*/
115 [ - + ]: 3 : if (m.message_1_ead_1_present) {
116 [ # # ]: 0 : TRY(_memcpy_s(ead1->ptr, ead1->len, m.message_1_ead_1.value,
117 : : (uint32_t)m.message_1_ead_1.len));
118 : 0 : ead1->len = (uint32_t)m.message_1_ead_1.len;
119 : 0 : PRINT_ARRAY("msg1 ead_1", ead1->ptr, ead1->len);
120 : : }
121 : 3 : return ok;
122 : : }
123 : :
124 : : /**
125 : : * @brief Checks if the selected cipher suite
126 : : * (the first in the list received from the
127 : : * initiator) is supported.
128 : : * @param selected The selected suite.
129 : : * @param[in] suites_r The list of suported cipher suites.
130 : : * @retval True if supported.
131 : : */
132 : 3 : static inline bool selected_suite_is_supported(uint8_t selected,
133 : : struct byte_array *suites_r)
134 : : {
135 [ + - ]: 3 : for (uint32_t i = 0; i < suites_r->len; i++) {
136 [ + - ]: 3 : if (suites_r->ptr[i] == selected)
137 : 3 : PRINTF("Suite %d will be used in this EDHOC run.\n",
138 : : selected);
139 : 3 : return true;
140 : : }
141 : 0 : return false;
142 : : }
143 : :
144 : : /**
145 : : * @brief Encodes message 2.
146 : : * @param[in] g_y Public ephemeral DH key of the responder.
147 : : * @param[in] c_r Connection identifier of the responder.
148 : : * @param[in] ciphertext_2 The ciphertext.
149 : : * @param[out] msg2 The encoded message.
150 : : * @retval Ok or error code.
151 : : */
152 : 3 : static inline enum err msg2_encode(const struct byte_array *g_y,
153 : : struct byte_array *c_r,
154 : : const struct byte_array *ciphertext_2,
155 : : struct byte_array *msg2)
156 : : {
157 [ - + - + ]: 3 : BYTE_ARRAY_NEW(g_y_ciphertext_2, G_Y_CIPHERTEXT_2,
158 : : g_y->len + ciphertext_2->len);
159 : :
160 : 3 : memcpy(g_y_ciphertext_2.ptr, g_y->ptr, g_y->len);
161 : 3 : memcpy(g_y_ciphertext_2.ptr + g_y->len, ciphertext_2->ptr,
162 : 3 : ciphertext_2->len);
163 : :
164 [ - + ]: 3 : TRY(encode_bstr(&g_y_ciphertext_2, msg2));
165 : :
166 : 3 : PRINT_ARRAY("message_2 (CBOR Sequence)", msg2->ptr, msg2->len);
167 : 3 : return ok;
168 : : }
169 : :
170 : 3 : enum err msg2_gen(struct edhoc_responder_context *c, struct runtime_context *rc,
171 : : struct byte_array *c_i)
172 : : {
173 : 3 : PRINT_ARRAY("message_1 (CBOR Sequence)", rc->msg.ptr, rc->msg.len);
174 : :
175 : 3 : enum method_type method = INITIATOR_SK_RESPONDER_SK;
176 [ - + ]: 3 : BYTE_ARRAY_NEW(suites_i, SUITES_I_SIZE, SUITES_I_SIZE);
177 [ - + ]: 3 : BYTE_ARRAY_NEW(g_x, G_X_SIZE, G_X_SIZE);
178 : :
179 [ - + ]: 3 : TRY(msg1_parse(&rc->msg, &method, &suites_i, &g_x, c_i, &rc->ead));
180 : :
181 : : // TODO this may be a vulnerability in case suites_i.len is zero
182 [ - + ]: 3 : if (!(selected_suite_is_supported(suites_i.ptr[suites_i.len - 1],
183 : : &c->suites_r))) {
184 : : // TODO implement here the sending of an error message
185 : 0 : return error_message_sent;
186 : : }
187 : :
188 : : /*get cipher suite*/
189 [ - + ]: 3 : TRY(get_suite((enum suite_label)suites_i.ptr[suites_i.len - 1],
190 : : &rc->suite));
191 : :
192 : : bool static_dh_r;
193 : 3 : authentication_type_get(method, &rc->static_dh_i, &static_dh_r);
194 : :
195 : : /******************* create and send message 2*************************/
196 [ - + - + ]: 3 : BYTE_ARRAY_NEW(th2, HASH_SIZE, get_hash_len(rc->suite.edhoc_hash));
197 [ - + ]: 3 : TRY(hash(rc->suite.edhoc_hash, &rc->msg, &rc->msg1_hash));
198 [ - + ]: 3 : TRY(th2_calculate(rc->suite.edhoc_hash, &rc->msg1_hash, &c->g_y, &th2));
199 : :
200 : : /*calculate the DH shared secret*/
201 [ - + ]: 3 : BYTE_ARRAY_NEW(g_xy, ECDH_SECRET_SIZE, ECDH_SECRET_SIZE);
202 [ - + ]: 3 : TRY(shared_secret_derive(rc->suite.edhoc_ecdh, &c->y, &g_x, g_xy.ptr));
203 : :
204 : 3 : PRINT_ARRAY("G_XY (ECDH shared secret) ", g_xy.ptr, g_xy.len);
205 : :
206 [ - + ]: 3 : BYTE_ARRAY_NEW(PRK_2e, PRK_SIZE, PRK_SIZE);
207 [ - + ]: 3 : TRY(hkdf_extract(rc->suite.edhoc_hash, &th2, &g_xy, PRK_2e.ptr));
208 : 3 : PRINT_ARRAY("PRK_2e", PRK_2e.ptr, PRK_2e.len);
209 : :
210 : : /*derive prk_3e2m*/
211 [ - + ]: 3 : TRY(prk_derive(static_dh_r, rc->suite, SALT_3e2m, &th2, &PRK_2e, &g_x,
212 : : &c->r, rc->prk_3e2m.ptr));
213 : 3 : PRINT_ARRAY("prk_3e2m", rc->prk_3e2m.ptr, rc->prk_3e2m.len);
214 : :
215 : : /*compute signature_or_MAC_2*/
216 [ - + - + ]: 3 : BYTE_ARRAY_NEW(sign_or_mac_2, SIGNATURE_SIZE,
217 : : get_signature_len(rc->suite.edhoc_sign));
218 : :
219 [ - + ]: 3 : TRY(signature_or_mac(GENERATE, static_dh_r, &rc->suite, &c->sk_r,
220 : : &c->pk_r, &rc->prk_3e2m, &c->c_r, &th2,
221 : : &c->id_cred_r, &c->cred_r, &c->ead_2, MAC_2,
222 : : &sign_or_mac_2));
223 : :
224 : : /*compute ciphertext_2*/
225 [ - + - - : 3 : BYTE_ARRAY_NEW(plaintext_2, PLAINTEXT2_SIZE,
- - + - -
+ - - - +
- + - - -
- + - - +
- - - + -
+ - - - -
+ - - + -
- ]
226 : : AS_BSTR_SIZE(c->c_r.len) + c->id_cred_r.len +
227 : : AS_BSTR_SIZE(sign_or_mac_2.len) + c->ead_2.len);
228 [ - + - + ]: 3 : BYTE_ARRAY_NEW(ciphertext_2, CIPHERTEXT2_SIZE, plaintext_2.len);
229 : :
230 [ - + ]: 3 : TRY(ciphertext_gen(CIPHERTEXT2, &rc->suite, &c->c_r, &c->id_cred_r,
231 : : &sign_or_mac_2, &c->ead_2, &PRK_2e, &th2,
232 : : &ciphertext_2, &plaintext_2));
233 : :
234 : : /* Clear the message buffer. */
235 : 3 : memset(rc->msg.ptr, 0, rc->msg.len);
236 : 3 : rc->msg.len = sizeof(rc->msg_buf);
237 : : /*message 2 create*/
238 [ - + ]: 3 : TRY(msg2_encode(&c->g_y, &c->c_r, &ciphertext_2, &rc->msg));
239 : :
240 [ - + ]: 3 : TRY(th34_calculate(rc->suite.edhoc_hash, &th2, &plaintext_2, &c->cred_r,
241 : : &rc->th3));
242 : :
243 : 3 : return ok;
244 : : }
245 : :
246 : 3 : enum err msg3_process(struct edhoc_responder_context *c,
247 : : struct runtime_context *rc,
248 : : struct cred_array *cred_i_array,
249 : : struct byte_array *prk_out,
250 : : struct byte_array *initiator_pk)
251 : 3 : {
252 [ - + - + ]: 3 : BYTE_ARRAY_NEW(ctxt3, CIPHERTEXT3_SIZE, rc->msg.len);
253 [ - + ]: 3 : TRY(decode_bstr(&rc->msg, &ctxt3));
254 : 3 : PRINT_ARRAY("CIPHERTEXT_3", ctxt3.ptr, ctxt3.len);
255 : :
256 [ - + ]: 3 : BYTE_ARRAY_NEW(id_cred_i, ID_CRED_I_SIZE, ID_CRED_I_SIZE);
257 [ - + ]: 3 : BYTE_ARRAY_NEW(sign_or_mac, SIG_OR_MAC_SIZE, SIG_OR_MAC_SIZE);
258 : :
259 : 3 : PRINTF("PLAINTEXT3_SIZE: %d\n", PLAINTEXT3_SIZE);
260 : 3 : PRINTF("ctxt3.len: %d\n", ctxt3.len);
261 : : #if defined(_WIN32)
262 : : BYTE_ARRAY_NEW(ptxt3,
263 : : PLAINTEXT3_SIZE + 16, // 16 is max aead mac length
264 : : ctxt3.len);
265 : : #else
266 [ - + - + ]: 3 : BYTE_ARRAY_NEW(ptxt3,
267 : : PLAINTEXT3_SIZE + get_aead_mac_len(rc->suite.edhoc_aead),
268 : : ctxt3.len);
269 : : #endif
270 : :
271 [ - + ]: 3 : TRY(ciphertext_decrypt_split(CIPHERTEXT3, &rc->suite, NULL, &id_cred_i,
272 : : &sign_or_mac, &rc->ead, &rc->prk_3e2m,
273 : : &rc->th3, &ctxt3, &ptxt3));
274 : :
275 : : /*check the authenticity of the initiator*/
276 [ - + ]: 3 : BYTE_ARRAY_NEW(cred_i, CRED_I_SIZE, CRED_I_SIZE);
277 [ - + ]: 3 : BYTE_ARRAY_NEW(pk, PK_SIZE, PK_SIZE);
278 [ - + ]: 3 : BYTE_ARRAY_NEW(g_i, G_I_SIZE, G_I_SIZE);
279 : :
280 [ - + ]: 3 : TRY(retrieve_cred(rc->static_dh_i, cred_i_array, &id_cred_i, &cred_i,
281 : : &pk, &g_i));
282 : 3 : PRINT_ARRAY("CRED_I", cred_i.ptr, cred_i.len);
283 : 3 : PRINT_ARRAY("pk", pk.ptr, pk.len);
284 : 3 : PRINT_ARRAY("g_i", g_i.ptr, g_i.len);
285 : :
286 : : /* Export public key. */
287 [ + - - + ]: 3 : if ((NULL != initiator_pk) && (NULL != initiator_pk->ptr)) {
288 : 0 : _memcpy_s(initiator_pk->ptr, initiator_pk->len, pk.ptr, pk.len);
289 : 0 : initiator_pk->len = pk.len;
290 : : }
291 : :
292 : : /*derive prk_4e3m*/
293 [ - + ]: 3 : TRY(prk_derive(rc->static_dh_i, rc->suite, SALT_4e3m, &rc->th3,
294 : : &rc->prk_3e2m, &g_i, &c->y, rc->prk_4e3m.ptr));
295 : 3 : PRINT_ARRAY("prk_4e3m", rc->prk_4e3m.ptr, rc->prk_4e3m.len);
296 : :
297 [ - + ]: 3 : TRY(signature_or_mac(VERIFY, rc->static_dh_i, &rc->suite, NULL, &pk,
298 : : &rc->prk_4e3m, &NULL_ARRAY, &rc->th3, &id_cred_i,
299 : : &cred_i, &rc->ead, MAC_3, &sign_or_mac));
300 : :
301 : : /*TH4*/
302 : : // ptxt3.len = ptxt3.len - get_aead_mac_len(rc->suite.edhoc_aead);
303 [ - + ]: 3 : TRY(th34_calculate(rc->suite.edhoc_hash, &rc->th3, &ptxt3, &cred_i,
304 : : &rc->th4));
305 : :
306 : : /*PRK_out*/
307 [ - + ]: 3 : TRY(edhoc_kdf(rc->suite.edhoc_hash, &rc->prk_4e3m, PRK_out, &rc->th4,
308 : : prk_out));
309 : 3 : return ok;
310 : : }
311 : :
312 : : #ifdef MESSAGE_4
313 : : enum err msg4_gen(struct edhoc_responder_context *c, struct runtime_context *rc)
314 : : {
315 : : /*Ciphertext 4 calculate*/
316 : : BYTE_ARRAY_NEW(ctxt4, CIPHERTEXT4_SIZE, CIPHERTEXT4_SIZE);
317 : : #if PLAINTEXT4_SIZE != 0
318 : : BYTE_ARRAY_NEW(ptxt4, PLAINTEXT4_SIZE, PLAINTEXT4_SIZE);
319 : : #else
320 : : struct byte_array ptxt4 = BYTE_ARRAY_INIT(NULL, 0);
321 : : #endif
322 : :
323 : : TRY(ciphertext_gen(CIPHERTEXT4, &rc->suite, &NULL_ARRAY, &NULL_ARRAY,
324 : : &NULL_ARRAY, &c->ead_4, &rc->prk_4e3m, &rc->th4,
325 : : &ctxt4, &ptxt4));
326 : :
327 : : TRY(encode_bstr(&ctxt4, &rc->msg));
328 : :
329 : : PRINT_ARRAY("Message 4 ", rc->msg.ptr, rc->msg.len);
330 : : return ok;
331 : : }
332 : : #endif // MESSAGE_4
333 : :
334 : 3 : enum err edhoc_responder_run_extended(
335 : : struct edhoc_responder_context *c, struct cred_array *cred_i_array,
336 : : struct byte_array *err_msg, struct byte_array *prk_out,
337 : : struct byte_array *initiator_pub_key, struct byte_array *c_i_bytes,
338 : : enum err (*tx)(void *sock, struct byte_array *data),
339 : : enum err (*rx)(void *sock, struct byte_array *data),
340 : : enum err (*ead_process)(void *params, struct byte_array *ead13))
341 : : {
342 : 3 : struct runtime_context rc = { 0 };
343 : 3 : runtime_context_init(&rc);
344 : :
345 : : /*receive message 1*/
346 : 3 : PRINT_MSG("waiting to receive message 1...\n");
347 [ - + ]: 3 : TRY(rx(c->sock, &rc.msg));
348 : :
349 : : /*create and send message 2*/
350 [ - + ]: 3 : TRY(msg2_gen(c, &rc, c_i_bytes));
351 [ - + ]: 3 : TRY(ead_process(c->params_ead_process, &rc.ead));
352 [ - + ]: 3 : TRY(tx(c->sock, &rc.msg));
353 : :
354 : : /*receive message 3*/
355 : 3 : PRINT_MSG("waiting to receive message 3...\n");
356 : 3 : rc.msg.len = sizeof(rc.msg_buf);
357 [ - + ]: 3 : TRY(rx(c->sock, &rc.msg));
358 [ - + ]: 3 : TRY(msg3_process(c, &rc, cred_i_array, prk_out, initiator_pub_key));
359 [ - + ]: 3 : TRY(ead_process(c->params_ead_process, &rc.ead));
360 : :
361 : : /*create and send message 4*/
362 : : #ifdef MESSAGE_4
363 : : TRY(msg4_gen(c, &rc));
364 : : TRY(tx(c->sock, &rc.msg));
365 : : #endif // MESSAGE_4
366 : 3 : return ok;
367 : : }
368 : :
369 : 3 : enum err edhoc_responder_run(
370 : : struct edhoc_responder_context *c, struct cred_array *cred_i_array,
371 : : struct byte_array *err_msg, struct byte_array *prk_out,
372 : : enum err (*tx)(void *sock, struct byte_array *data),
373 : : enum err (*rx)(void *sock, struct byte_array *data),
374 : : enum err (*ead_process)(void *params, struct byte_array *ead13))
375 : : {
376 [ - + ]: 3 : BYTE_ARRAY_NEW(c_i, C_I_SIZE, C_I_SIZE);
377 : 3 : return edhoc_responder_run_extended(c, cred_i_array, err_msg, prk_out,
378 : : &NULL_ARRAY, &c_i, tx, rx,
379 : : ead_process);
380 : : }
|