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 <arpa/inet.h>
13 #include <netinet/in.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <sys/socket.h>
18 #include <sys/types.h>
19 #include <unistd.h>
20
21 extern "C" {
22 #include "edhoc.h"
23 #include "sock.h"
24 #include "edhoc_test_vectors_p256_v16.h"
25 }
26 #include "cantcoap.h"
27
28 #define USE_IPV4
29 //#define USE_IPV6
30 /*comment this out to use DH keys from the test vectors*/
31 #define USE_RANDOM_EPHEMERAL_DH_KEY
32
33 /**
34 * @brief Initializes sockets for CoAP client.
35 * @param
36 * @retval error code
37 */
start_coap_client(int * sockfd)38 static int start_coap_client(int *sockfd)
39 {
40 int err;
41 #ifdef USE_IPV4
42 struct sockaddr_in servaddr;
43 const char IPV4_SERVADDR[] = { "127.0.0.1" };
44 //const char IPV4_SERVADDR[] = { "172.31.24.45" };
45 err = sock_init(SOCK_CLIENT, IPV4_SERVADDR, IPv4, &servaddr,
46 sizeof(servaddr), sockfd);
47 if (err < 0) {
48 printf("error during socket initialization (error code: %d)",
49 err);
50 return -1;
51 }
52 #endif
53 #ifdef USE_IPV6
54 struct sockaddr_in6 servaddr;
55 const char IPV6_SERVADDR[] = { "2001:db8::1" };
56 err = sock_init(SOCK_CLIENT, IPV6_SERVADDR, IPv6, &servaddr,
57 sizeof(servaddr), sockfd);
58 if (err < 0) {
59 printf("error during socket initialization (error code: %d)",
60 err);
61 return -1;
62 }
63 #endif
64 return 0;
65 }
66
ead_process(void * params,struct byte_array * ead13)67 enum err ead_process(void *params, struct byte_array *ead13)
68 {
69 /*for this sample we are not using EAD*/
70 /*to save RAM we use FEATURES += -DEAD_SIZE=0*/
71 return ok;
72 }
73
74 /**
75 * @brief Callback function called inside the frontend when data needs to
76 * be send over the network. We use here CoAP as transport
77 * @param data pointer to the data that needs to be send
78 */
tx(void * sock,struct byte_array * data)79 enum err tx(void *sock, struct byte_array *data)
80 {
81 /*construct a CoAP packet*/
82 static uint16_t mid = 0;
83 static uint32_t token = 0;
84 CoapPDU *pdu = new CoapPDU();
85 pdu->reset();
86 pdu->setVersion(1);
87 pdu->setType(CoapPDU::COAP_CONFIRMABLE);
88 pdu->setCode(CoapPDU::COAP_POST);
89 pdu->setToken((uint8_t *)&(++token), sizeof(token));
90 pdu->setMessageID(mid++);
91 pdu->setURI((char *)".well-known/edhoc", 17);
92 pdu->setPayload(data->ptr, data->len);
93
94 send(*((int *)sock), pdu->getPDUPointer(), pdu->getPDULength(), 0);
95
96 delete pdu;
97 return ok;
98 }
99
100 /**
101 * @brief Callback function called inside the frontend when data needs to
102 * be received over the network. We use here CoAP as transport
103 * @param data pointer to the data that needs to be received
104 */
rx(void * sock,struct byte_array * data)105 enum err rx(void *sock, struct byte_array *data)
106 {
107 int n;
108 char buffer[MAXLINE];
109 CoapPDU *recvPDU;
110 /* receive */
111 n = recv(*((int *)sock), (char *)buffer, MAXLINE, MSG_WAITALL);
112 if (n < 0) {
113 printf("recv error");
114 }
115
116 recvPDU = new CoapPDU((uint8_t *)buffer, n);
117
118 if (recvPDU->validate()) {
119 //recvPDU->printHuman();
120 }
121
122 uint32_t payload_len = recvPDU->getPayloadLength();
123 //printf("data_len: %d\n", data->len);
124 //printf("payload_len: %d\n", payload_len);
125
126 if (data->len >= payload_len) {
127 memcpy(data->ptr, recvPDU->getPayloadPointer(), payload_len);
128 data->len = payload_len;
129 } else {
130 printf("insufficient space in buffer");
131 return buffer_to_small;
132 }
133
134 delete recvPDU;
135 return ok;
136 }
137
main()138 int main()
139 {
140 int sockfd;
141 BYTE_ARRAY_NEW(prk_exporter, 32, 32);
142 BYTE_ARRAY_NEW(oscore_master_secret, 16, 16);
143 BYTE_ARRAY_NEW(oscore_master_salt, 8, 8);
144 BYTE_ARRAY_NEW(PRK_out, 32, 32);
145 BYTE_ARRAY_NEW(err_msg, 0, 0);
146
147 /* test vector inputs */
148 struct other_party_cred cred_r;
149 struct edhoc_initiator_context c_i;
150
151 uint8_t TEST_VEC_NUM = 1;
152 uint8_t vec_num_i = TEST_VEC_NUM - 1;
153
154 c_i.sock = &sockfd;
155 c_i.c_i.len = test_vectors[vec_num_i].c_i_len;
156 c_i.c_i.ptr = (uint8_t *)test_vectors[vec_num_i].c_i;
157 c_i.method = (enum method_type) * test_vectors[vec_num_i].method;
158 c_i.suites_i.len = test_vectors[vec_num_i].SUITES_I_len;
159 c_i.suites_i.ptr = (uint8_t *)test_vectors[vec_num_i].SUITES_I;
160 c_i.ead_1.len = test_vectors[vec_num_i].ead_1_len;
161 c_i.ead_1.ptr = (uint8_t *)test_vectors[vec_num_i].ead_1;
162 c_i.ead_3.len = test_vectors[vec_num_i].ead_3_len;
163 c_i.ead_3.ptr = (uint8_t *)test_vectors[vec_num_i].ead_3;
164 c_i.id_cred_i.len = test_vectors[vec_num_i].id_cred_i_len;
165 c_i.id_cred_i.ptr = (uint8_t *)test_vectors[vec_num_i].id_cred_i;
166 c_i.cred_i.len = test_vectors[vec_num_i].cred_i_len;
167 c_i.cred_i.ptr = (uint8_t *)test_vectors[vec_num_i].cred_i;
168 c_i.g_x.len = test_vectors[vec_num_i].g_x_raw_len;
169 c_i.g_x.ptr = (uint8_t *)test_vectors[vec_num_i].g_x_raw;
170 c_i.x.len = test_vectors[vec_num_i].x_raw_len;
171 c_i.x.ptr = (uint8_t *)test_vectors[vec_num_i].x_raw;
172 c_i.g_i.len = test_vectors[vec_num_i].g_i_raw_len;
173 c_i.g_i.ptr = (uint8_t *)test_vectors[vec_num_i].g_i_raw;
174 c_i.i.len = test_vectors[vec_num_i].i_raw_len;
175 c_i.i.ptr = (uint8_t *)test_vectors[vec_num_i].i_raw;
176 c_i.sk_i.len = test_vectors[vec_num_i].sk_i_raw_len;
177 c_i.sk_i.ptr = (uint8_t *)test_vectors[vec_num_i].sk_i_raw;
178 c_i.pk_i.len = test_vectors[vec_num_i].pk_i_raw_len;
179 c_i.pk_i.ptr = (uint8_t *)test_vectors[vec_num_i].pk_i_raw;
180
181 cred_r.id_cred.len = test_vectors[vec_num_i].id_cred_r_len;
182 cred_r.id_cred.ptr = (uint8_t *)test_vectors[vec_num_i].id_cred_r;
183 cred_r.cred.len = test_vectors[vec_num_i].cred_r_len;
184 cred_r.cred.ptr = (uint8_t *)test_vectors[vec_num_i].cred_r;
185 cred_r.g.len = test_vectors[vec_num_i].g_r_raw_len;
186 cred_r.g.ptr = (uint8_t *)test_vectors[vec_num_i].g_r_raw;
187 cred_r.pk.len = test_vectors[vec_num_i].pk_r_raw_len;
188 cred_r.pk.ptr = (uint8_t *)test_vectors[vec_num_i].pk_r_raw;
189 cred_r.ca.len = test_vectors[vec_num_i].ca_r_len;
190 cred_r.ca.ptr = (uint8_t *)test_vectors[vec_num_i].ca_r;
191 cred_r.ca_pk.len = test_vectors[vec_num_i].ca_r_pk_len;
192 cred_r.ca_pk.ptr = (uint8_t *)test_vectors[vec_num_i].ca_r_pk;
193
194 struct cred_array cred_r_array = { .len = 1, .ptr = &cred_r };
195
196 #ifdef USE_RANDOM_EPHEMERAL_DH_KEY
197 uint32_t seed;
198 BYTE_ARRAY_NEW(X_random, 32, 32);
199 BYTE_ARRAY_NEW(G_X_random, 32, 32);
200
201 /*create a random seed*/
202 FILE *fp;
203 fp = fopen("/dev/urandom", "r");
204 uint64_t seed_len = fread((uint8_t *)&seed, 1, sizeof(seed), fp);
205 fclose(fp);
206 PRINT_ARRAY("seed", (uint8_t *)&seed, seed_len);
207
208 /*create ephemeral DH keys from seed*/
209 TRY(ephemeral_dh_key_gen(P256, seed, &X_random, &G_X_random));
210 c_i.g_x.ptr = G_X_random.ptr;
211 c_i.g_x.len = G_X_random.len;
212 c_i.x.ptr = X_random.ptr;
213 c_i.x.len = X_random.len;
214 PRINT_ARRAY("secret ephemeral DH key", c_i.g_x.ptr, c_i.g_x.len);
215 PRINT_ARRAY("public ephemeral DH key", c_i.x.ptr, c_i.x.len);
216
217 #endif
218
219 #ifdef TINYCRYPT
220 /* Register RNG function */
221 uECC_set_rng(default_CSPRNG);
222 #endif
223
224 TRY_EXPECT(start_coap_client(&sockfd), 0);
225 TRY(edhoc_initiator_run(&c_i, &cred_r_array, &err_msg, &PRK_out, tx, rx,
226 ead_process));
227
228 PRINT_ARRAY("PRK_out", PRK_out.ptr, PRK_out.len);
229
230 TRY(prk_out2exporter(SHA_256, &PRK_out, &prk_exporter));
231 PRINT_ARRAY("prk_exporter", prk_exporter.ptr, prk_exporter.len);
232
233 TRY(edhoc_exporter(SHA_256, OSCORE_MASTER_SECRET, &prk_exporter,
234 &oscore_master_secret));
235 PRINT_ARRAY("OSCORE Master Secret", oscore_master_secret.ptr,
236 oscore_master_secret.len);
237
238 TRY(edhoc_exporter(SHA_256, OSCORE_MASTER_SALT, &prk_exporter,
239 &oscore_master_salt));
240 PRINT_ARRAY("OSCORE Master Salt", oscore_master_salt.ptr,
241 oscore_master_salt.len);
242
243 close(sockfd);
244 return 0;
245 }
246