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