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 <stdbool.h>
13 #include "edhoc_internal.h"
14
15 #include "common/crypto_wrapper.h"
16 #include "common/oscore_edhoc_error.h"
17 #include "common/memcpy_s.h"
18 #include "common/print_util.h"
19
20 #include "edhoc/buffer_sizes.h"
21 #include "edhoc/hkdf_info.h"
22 #include "edhoc/messages.h"
23 #include "edhoc/okm.h"
24 #include "edhoc/plaintext.h"
25 #include "edhoc/prk.h"
26 #include "edhoc/retrieve_cred.h"
27 #include "edhoc/signature_or_mac_msg.h"
28 #include "edhoc/suites.h"
29 #include "edhoc/th.h"
30 #include "edhoc/txrx_wrapper.h"
31 #include "edhoc/ciphertext.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_encode_message_1.h"
37 #include "cbor/edhoc_decode_message_2.h"
38 #include "cbor/edhoc_encode_message_3.h"
39
40 /**
41 * @brief Parses message 2.
42 * @param c Initiator context.
43 * @param[in] msg2 Message 2.
44 * @param[out] g_y G_Y ephemeral public key of the responder.
45 * @param[out] c_r C_R connection identifier of the responder.
46 * @param[out] ciphertext2 Ciphertext 2.
47 * @retval Ok or error code.
48 */
msg2_parse(struct byte_array * msg2,struct byte_array * g_y,struct byte_array * c_r,struct byte_array * ciphertext2)49 static inline enum err msg2_parse(struct byte_array *msg2,
50 struct byte_array *g_y,
51 struct byte_array *c_r,
52 struct byte_array *ciphertext2)
53 {
54 size_t decode_len = 0;
55 struct m2 m;
56
57 TRY_EXPECT(cbor_decode_m2(msg2->ptr, msg2->len, &m, &decode_len), 0);
58 TRY(_memcpy_s(g_y->ptr, g_y->len, m.m2_G_Y_CIPHERTEXT_2.value,
59 g_y->len));
60 PRINT_ARRAY("g_y", g_y->ptr, g_y->len);
61
62 TRY(_memcpy_s(ciphertext2->ptr, ciphertext2->len,
63 m.m2_G_Y_CIPHERTEXT_2.value + g_y->len,
64 (uint32_t)(m.m2_G_Y_CIPHERTEXT_2.len - g_y->len)));
65
66 ciphertext2->len = (uint32_t)m.m2_G_Y_CIPHERTEXT_2.len - g_y->len;
67 PRINT_ARRAY("ciphertext2", ciphertext2->ptr, ciphertext2->len);
68
69 if (m.m2_C_R_choice == m2_C_R_int_c) {
70 TRY(encode_int(&m.m2_C_R_int, 1, c_r));
71 } else {
72 TRY(_memcpy_s(c_r->ptr, c_r->len, m.m2_C_R_bstr.value,
73 (uint32_t)m.m2_C_R_bstr.len));
74 c_r->len = (uint32_t)m.m2_C_R_bstr.len;
75 }
76 PRINT_ARRAY("C_R_raw", c_r->ptr, c_r->len);
77
78 return ok;
79 }
80
msg1_gen(const struct edhoc_initiator_context * c,struct runtime_context * rc)81 enum err msg1_gen(const struct edhoc_initiator_context *c,
82 struct runtime_context *rc)
83 {
84 struct message_1 m1;
85
86 /*METHOD_CORR*/
87 m1.message_1_METHOD = (int32_t)c->method;
88
89 /*SUITES_I*/
90 if (c->suites_i.len == 1) {
91 /* only one suite, encode into int */
92 m1.message_1_SUITES_I_choice = message_1_SUITES_I_int_c;
93 m1.message_1_SUITES_I_int = c->suites_i.ptr[0];
94 } else if (c->suites_i.len > 1) {
95 /* more than one suites, encode into array */
96 m1.message_1_SUITES_I_choice = SUITES_I_suite_l_c;
97 m1.SUITES_I_suite_l_suite_count = c->suites_i.len;
98 for (uint32_t i = 0; i < c->suites_i.len; i++) {
99 m1.SUITES_I_suite_l_suite[i] = c->suites_i.ptr[i];
100 }
101 }
102
103 /* G_X ephemeral public key */
104 m1.message_1_G_X.value = c->g_x.ptr;
105 m1.message_1_G_X.len = c->g_x.len;
106
107 /* C_I connection ID of the initiator*/
108 PRINT_ARRAY("C_I", c->c_i.ptr, c->c_i.len);
109 if (c->c_i.len == 1 &&
110 ((0x00 <= c->c_i.ptr[0] && c->c_i.ptr[0] < 0x18) ||
111 (0x1F < c->c_i.ptr[0] && c->c_i.ptr[0] <= 0x37))) {
112 m1.message_1_C_I_choice = message_1_C_I_int_c;
113 TRY(decode_int(&c->c_i, &m1.message_1_C_I_int));
114 } else {
115 m1.message_1_C_I_choice = message_1_C_I_bstr_c;
116 m1.message_1_C_I_bstr.value = c->c_i.ptr;
117 m1.message_1_C_I_bstr.len = c->c_i.len;
118 }
119
120 if (c->ead_1.len != 0) {
121 /* ead_1 unprotected opaque auxiliary data */
122 m1.message_1_ead_1.value = c->ead_1.ptr;
123 m1.message_1_ead_1.len = c->ead_1.len;
124 m1.message_1_ead_1_present = true;
125 } else {
126 m1.message_1_ead_1_present = false;
127 }
128
129 size_t payload_len_out;
130 TRY_EXPECT(cbor_encode_message_1(rc->msg.ptr, rc->msg.len, &m1,
131 &payload_len_out),
132 0);
133 rc->msg.len = (uint32_t)payload_len_out;
134
135 PRINT_ARRAY("message_1 (CBOR Sequence)", rc->msg.ptr, rc->msg.len);
136
137 TRY(get_suite((enum suite_label)c->suites_i.ptr[c->suites_i.len - 1],
138 &rc->suite));
139 /* Calculate hash of msg1 for TH2. */
140 TRY(hash(rc->suite.edhoc_hash, &rc->msg, &rc->msg1_hash));
141 return ok;
142 }
143
msg2_process(const struct edhoc_initiator_context * c,struct runtime_context * rc,struct cred_array * cred_r_array,struct byte_array * c_r,bool static_dh_i,bool static_dh_r,struct byte_array * th3,struct byte_array * PRK_3e2m)144 static enum err msg2_process(const struct edhoc_initiator_context *c,
145 struct runtime_context *rc,
146 struct cred_array *cred_r_array,
147 struct byte_array *c_r, bool static_dh_i,
148 bool static_dh_r, struct byte_array *th3,
149 struct byte_array *PRK_3e2m)
150 {
151 BYTE_ARRAY_NEW(g_y, G_Y_SIZE, get_ecdh_pk_len(rc->suite.edhoc_ecdh));
152 uint32_t ciphertext_len = rc->msg.len - g_y.len - c_r->len;
153 ciphertext_len -= BSTR_ENCODING_OVERHEAD(ciphertext_len);
154 BYTE_ARRAY_NEW(ciphertext, CIPHERTEXT2_SIZE, ciphertext_len);
155 BYTE_ARRAY_NEW(plaintext, PLAINTEXT2_SIZE, ciphertext.len);
156 PRINT_ARRAY("message_2 (CBOR Sequence)", rc->msg.ptr, rc->msg.len);
157
158 /*parse the message*/
159 TRY(msg2_parse(&rc->msg, &g_y, c_r, &ciphertext));
160
161 /*calculate the DH shared secret*/
162 BYTE_ARRAY_NEW(g_xy, ECDH_SECRET_SIZE, ECDH_SECRET_SIZE);
163
164 TRY(shared_secret_derive(rc->suite.edhoc_ecdh, &c->x, &g_y, g_xy.ptr));
165 PRINT_ARRAY("G_XY (ECDH shared secret) ", g_xy.ptr, g_xy.len);
166
167 /*calculate th2*/
168 BYTE_ARRAY_NEW(th2, HASH_SIZE, get_hash_len(rc->suite.edhoc_hash));
169
170 TRY(th2_calculate(rc->suite.edhoc_hash, &rc->msg1_hash, &g_y, c_r,
171 &th2));
172 PRINT_ARRAY("TH_2", th2.ptr, th2.len);
173
174 /*calculate PRK_2e*/
175 BYTE_ARRAY_NEW(PRK_2e, PRK_SIZE, PRK_SIZE);
176 TRY(hkdf_extract(rc->suite.edhoc_hash, &th2, &g_xy, PRK_2e.ptr));
177 PRINT_ARRAY("PRK_2e", PRK_2e.ptr, PRK_2e.len);
178
179 BYTE_ARRAY_NEW(sign_or_mac, SIG_OR_MAC_SIZE, SIG_OR_MAC_SIZE);
180 BYTE_ARRAY_NEW(id_cred_r, ID_CRED_R_SIZE, ID_CRED_R_SIZE);
181
182 plaintext.len = ciphertext.len;
183 TRY(check_buffer_size(PLAINTEXT2_SIZE, plaintext.len));
184
185 TRY(ciphertext_decrypt_split(CIPHERTEXT2, &rc->suite, &id_cred_r,
186 &sign_or_mac, &rc->ead, &PRK_2e, &th2,
187 &ciphertext, &plaintext));
188
189 /*check the authenticity of the responder*/
190 BYTE_ARRAY_NEW(cred_r, CRED_R_SIZE, CRED_R_SIZE);
191 BYTE_ARRAY_NEW(pk, PK_SIZE, PK_SIZE);
192 BYTE_ARRAY_NEW(g_r, G_R_SIZE, G_R_SIZE);
193 TRY(retrieve_cred(static_dh_r, cred_r_array, &id_cred_r, &cred_r, &pk,
194 &g_r));
195 PRINT_ARRAY("CRED_R", cred_r.ptr, cred_r.len);
196 PRINT_ARRAY("pk", pk.ptr, pk.len);
197 PRINT_ARRAY("g_r", g_r.ptr, g_r.len);
198
199 /*derive prk_3e2m*/
200 TRY(prk_derive(static_dh_r, rc->suite, SALT_3e2m, &th2, &PRK_2e, &g_r,
201 &c->x, PRK_3e2m->ptr));
202 PRINT_ARRAY("prk_3e2m", PRK_3e2m->ptr, PRK_3e2m->len);
203
204 TRY(signature_or_mac(VERIFY, static_dh_r, &rc->suite, NULL, &pk,
205 PRK_3e2m, &th2, &id_cred_r, &cred_r, &rc->ead,
206 MAC_2, &sign_or_mac));
207
208 TRY(th34_calculate(rc->suite.edhoc_hash, &th2, &plaintext, &cred_r,
209 th3));
210
211 /*derive prk_4e3m*/
212 TRY(prk_derive(static_dh_i, rc->suite, SALT_4e3m, th3, PRK_3e2m, &g_y,
213 &c->i, rc->prk_4e3m.ptr));
214 PRINT_ARRAY("prk_4e3m", rc->prk_4e3m.ptr, rc->prk_4e3m.len);
215
216 return ok;
217 }
218
msg3_only_gen(const struct edhoc_initiator_context * c,struct runtime_context * rc,bool static_dh_i,struct byte_array * th3,struct byte_array * PRK_3e2m,struct byte_array * prk_out)219 static enum err msg3_only_gen(const struct edhoc_initiator_context *c,
220 struct runtime_context *rc, bool static_dh_i,
221 struct byte_array *th3,
222 struct byte_array *PRK_3e2m,
223 struct byte_array *prk_out)
224 {
225 BYTE_ARRAY_NEW(plaintext, PLAINTEXT3_SIZE,
226 c->id_cred_i.len + (SIG_OR_MAC_SIZE + 2) + c->ead_3.len);
227 BYTE_ARRAY_NEW(ciphertext, CIPHERTEXT3_SIZE,
228 plaintext.len + ENCODING_OVERHEAD);
229 /*calculate Signature_or_MAC_3*/
230 BYTE_ARRAY_NEW(sign_or_mac_3, SIG_OR_MAC_SIZE, SIG_OR_MAC_SIZE);
231 TRY(signature_or_mac(GENERATE, static_dh_i, &rc->suite, &c->sk_i,
232 &c->pk_i, &rc->prk_4e3m, th3, &c->id_cred_i,
233 &c->cred_i, &c->ead_3, MAC_3, &sign_or_mac_3));
234
235 /*create plaintext3 and ciphertext3*/
236 TRY(ciphertext_gen(CIPHERTEXT3, &rc->suite, &c->id_cred_i,
237 &sign_or_mac_3, &c->ead_3, PRK_3e2m, th3,
238 &ciphertext, &plaintext));
239
240 /*massage 3 create and send*/
241 TRY(encode_bstr(&ciphertext, &rc->msg));
242 PRINT_ARRAY("msg3", rc->msg.ptr, rc->msg.len);
243
244 /*TH4*/
245 TRY(th34_calculate(rc->suite.edhoc_hash, th3, &plaintext, &c->cred_i,
246 &rc->th4));
247
248 /*PRK_out*/
249 TRY(edhoc_kdf(rc->suite.edhoc_hash, &rc->prk_4e3m, PRK_out, &rc->th4,
250 prk_out));
251 return ok;
252 }
253
msg3_gen(const struct edhoc_initiator_context * c,struct runtime_context * rc,struct cred_array * cred_r_array,struct byte_array * c_r,struct byte_array * prk_out)254 enum err msg3_gen(const struct edhoc_initiator_context *c,
255 struct runtime_context *rc, struct cred_array *cred_r_array,
256 struct byte_array *c_r, struct byte_array *prk_out)
257 {
258 bool static_dh_i = false, static_dh_r = false;
259 authentication_type_get(c->method, &static_dh_i, &static_dh_r);
260 BYTE_ARRAY_NEW(th3, HASH_SIZE, HASH_SIZE);
261 BYTE_ARRAY_NEW(PRK_3e2m, PRK_SIZE, PRK_SIZE);
262
263 /*process message 2*/
264 TRY(msg2_process(c, rc, cred_r_array, c_r, static_dh_i, static_dh_r,
265 &th3, &PRK_3e2m));
266
267 /*generate message 3*/
268 msg3_only_gen(c, rc, static_dh_i, &th3, &PRK_3e2m, prk_out);
269 return ok;
270 }
271
272 #ifdef MESSAGE_4
msg4_process(struct runtime_context * rc)273 enum err msg4_process(struct runtime_context *rc)
274 {
275 PRINT_ARRAY("message4 (CBOR Sequence)", rc->msg.ptr, rc->msg.len);
276
277 BYTE_ARRAY_NEW(ciphertext4, CIPHERTEXT4_SIZE, CIPHERTEXT4_SIZE);
278 TRY(decode_bstr(&rc->msg, &ciphertext4));
279 PRINT_ARRAY("ciphertext_4", ciphertext4.ptr, ciphertext4.len);
280
281 BYTE_ARRAY_NEW(plaintext4,
282 PLAINTEXT4_SIZE + get_aead_mac_len(rc->suite.edhoc_aead),
283 ciphertext4.len);
284 TRY(ciphertext_decrypt_split(CIPHERTEXT4, &rc->suite, &NULL_ARRAY,
285 &NULL_ARRAY, &rc->ead, &rc->prk_4e3m,
286 &rc->th4, &ciphertext4, &plaintext4));
287 return ok;
288 }
289 #endif // MESSAGE_4
290
edhoc_initiator_run_extended(const struct edhoc_initiator_context * c,struct cred_array * cred_r_array,struct byte_array * err_msg,struct byte_array * c_r_bytes,struct byte_array * prk_out,enum err (* tx)(void * sock,struct byte_array * data),enum err (* rx)(void * sock,struct byte_array * data),enum err (* ead_process)(void * params,struct byte_array * ead24))291 enum err edhoc_initiator_run_extended(
292 const struct edhoc_initiator_context *c,
293 struct cred_array *cred_r_array, struct byte_array *err_msg,
294 struct byte_array *c_r_bytes, struct byte_array *prk_out,
295 enum err (*tx)(void *sock, struct byte_array *data),
296 enum err (*rx)(void *sock, struct byte_array *data),
297 enum err (*ead_process)(void *params, struct byte_array *ead24))
298 {
299 struct runtime_context rc = { 0 };
300 runtime_context_init(&rc);
301
302 /*create and send message 1*/
303 TRY(msg1_gen(c, &rc));
304 TRY(tx(c->sock, &rc.msg));
305
306 /*receive message 2*/
307 PRINT_MSG("waiting to receive message 2...\n");
308 rc.msg.len = sizeof(rc.msg_buf);
309 TRY(rx(c->sock, &rc.msg));
310
311 /*create and send message 3*/
312 TRY(msg3_gen(c, &rc, cred_r_array, c_r_bytes, prk_out));
313 TRY(ead_process(c->params_ead_process, &rc.ead));
314 TRY(tx(c->sock, &rc.msg));
315
316 /*receive message 4*/
317 #ifdef MESSAGE_4
318 PRINT_MSG("waiting to receive message 4...\n");
319 rc.msg.len = sizeof(rc.msg_buf);
320 TRY(rx(c->sock, &rc.msg));
321 TRY(msg4_process(&rc));
322 TRY(ead_process(c->params_ead_process, &rc.ead));
323 #endif // MESSAGE_4
324 return ok;
325 }
326
edhoc_initiator_run(const struct edhoc_initiator_context * c,struct cred_array * cred_r_array,struct byte_array * err_msg,struct byte_array * prk_out,enum err (* tx)(void * sock,struct byte_array * data),enum err (* rx)(void * sock,struct byte_array * data),enum err (* ead_process)(void * params,struct byte_array * ead24))327 enum err edhoc_initiator_run(
328 const struct edhoc_initiator_context *c,
329 struct cred_array *cred_r_array, struct byte_array *err_msg,
330 struct byte_array *prk_out,
331 enum err (*tx)(void *sock, struct byte_array *data),
332 enum err (*rx)(void *sock, struct byte_array *data),
333 enum err (*ead_process)(void *params, struct byte_array *ead24))
334 {
335 BYTE_ARRAY_NEW(c_r, C_R_SIZE, C_R_SIZE);
336
337 return edhoc_initiator_run_extended(c, cred_r_array, err_msg, &c_r,
338 prk_out, tx, rx, ead_process);
339 }
340