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