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 #include <logging/log.h>
12 #include <stdio.h>
13 LOG_MODULE_REGISTER(net_coap_server_sample, LOG_LEVEL_DBG);
14 
15 #include <edhoc.h>
16 #include <errno.h>
17 #include <net/coap.h>
18 #include <net/coap_link_format.h>
19 #include <net/net_ip.h>
20 #include <net/net_mgmt.h>
21 #include <net/socket.h>
22 #include <net/udp.h>
23 #include <sys/byteorder.h>
24 #include <sys/printk.h>
25 #include <zephyr.h>
26 
27 #include "credentials.h"
28 #include "net_private.h"
29 
30 #define MAX_COAP_MSG_LEN 256
31 
32 #define MY_COAP_PORT 5683
33 
34 #define BLOCK_WISE_TRANSFER_SIZE_GET 2048
35 
36 #if defined(CONFIG_NET_IPV6)
37 #define ALL_NODES_LOCAL_COAP_MCAST                                             \
38 	{                                                                      \
39 		{                                                              \
40 			{                                                      \
41 				0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   \
42 					0, 0, 0xfd                             \
43 			}                                                      \
44 		}                                                              \
45 	}
46 
47 #define MY_IP6ADDR                                                             \
48 	{                                                                      \
49 		{                                                              \
50 			{                                                      \
51 				0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0,   \
52 					0, 0, 0, 0, 0x1                        \
53 			}                                                      \
54 		}                                                              \
55 	}
56 #endif
57 
58 #define NUM_OBSERVERS 3
59 
60 #define NUM_PENDINGS 3
61 
62 /* Uncomment the following line to enable printf output */
63 //#define ENABLE_PRINTK
64 #ifdef ENABLE_PRINTK
65 #define PRINTK(text, ...) printk(text, ##__VA_ARGS__)
66 #else
67 #define PRINTK(text, ...)
68 #endif
69 
70 /* create queues for EDHOC */
71 #define MBOX_MSG_SIZE 300
72 #define MBOX_WAIT_TIME 20
73 K_MBOX_DEFINE(rx_queue);
74 K_MBOX_DEFINE(tx_queue);
75 
76 /**
77  * @brief	Entry function of EDHOC thread. Starts EDHOC responder.
78  * @param
79  * @retval	none
80  */
edhoc_responder_init(void)81 void edhoc_responder_init(void)
82 {
83 	err r;
84 
85 	/* Edhoc internal parameters */
86 	uint8_t PRK_4x3m[PRK_DEFAULT_SIZE];
87 	uint8_t th4[SHA_DEFAULT_SIZE];
88 	uint8_t err_msg[ERR_MSG_DEFAULT_SIZE];
89 	uint32_t err_msg_len = sizeof(err_msg);
90 	struct other_party_cred cred_i = { .id_cred.ptr = ID_CRED_I,
91 					   .id_cred.len = ID_CRED_I_LEN,
92 					   .cred.ptr = CRED_I,
93 					   .cred.len = CRED_I_LEN,
94 					   .pk.ptr = PK_I,
95 					   .pk.len = PK_I_LEN,
96 					   .g.ptr = G_I,
97 					   .g.len = G_I_LEN,
98 					   .ca.ptr = CA,
99 					   .ca.len = CA_LEN,
100 					   .ca_pk.ptr = CA_PK,
101 					   .ca_pk.len = CA_PK_LEN };
102 	struct edhoc_responder_context c_r = { .suites_r.ptr = SUITES_R,
103 					       .suites_r.len = SUITES_R_LEN,
104 					       .g_y.ptr = G_Y,
105 					       .g_y.len = G_Y_LEN,
106 					       .y.ptr = Y,
107 					       .y.len = Y_LEN,
108 					       .c_r.ptr = C_R,
109 					       .c_r.len = C_R_LEN,
110 					       .ad_2.ptr = AD_2,
111 					       .ad_2.len = AD_2_LEN,
112 					       .id_cred_r.ptr = ID_CRED_R,
113 					       .id_cred_r.len = ID_CRED_R_LEN,
114 					       .cred_r.ptr = CRED_R,
115 					       .cred_r.len = CRED_R_LEN,
116 					       .sk_r.ptr = SK_R,
117 					       .sk_r.len = SK_R_LEN,
118 					       .pk_r.ptr = PK_R,
119 					       .pk_r.len = PK_R_LEN,
120 					       .r.ptr = R,
121 					       .r.len = R_LEN,
122 					       .g_r.ptr = G_R,
123 					       .g_r.len = G_R_LEN };
124 	uint8_t ad_1[AD_DEFAULT_SIZE];
125 	uint64_t ad_1_len = sizeof(ad_1);
126 	uint8_t ad_3[AD_DEFAULT_SIZE];
127 	uint64_t ad_3_len = sizeof(ad_3);
128 
129 	while (1) {
130 		r = edhoc_responder_run(&c_r, &cred_i, 1, err_msg, &err_msg_len,
131 					(uint8_t *)&ad_1, &ad_1_len,
132 					(uint8_t *)&ad_3, &ad_3_len, PRK_4x3m,
133 					sizeof(PRK_4x3m), th4, sizeof(th4));
134 		if (r != ok) {
135 			PRINTK("error responder run (Error Code %d)\n", r);
136 		}
137 
138 		PRINTK("PRK_4x3m: (size: %d)\n", sizeof(PRK_4x3m));
139 		for (int i = 0; i < sizeof(PRK_4x3m); i++) {
140 			if (i % 16 == 0)
141 				PRINTK("\n");
142 			else if (i % 8 == 0)
143 				PRINTK("   ");
144 			PRINTK("%02hhX ", PRK_4x3m[i]);
145 		}
146 		PRINTK("\n\n");
147 		PRINTK("th4: (size: %d)\n", sizeof(th4));
148 		for (int i = 0; i < sizeof(th4); i++) {
149 			if (i % 16 == 0)
150 				PRINTK("\n");
151 			else if (i % 8 == 0)
152 				PRINTK("   ");
153 			PRINTK("%02hhX ", th4[i]);
154 		}
155 		PRINTK("\n\n");
156 
157 		/* run edhoc exporter here to extract OSCORE secrets */
158 	}
159 }
160 
161 /* create thread for EDHOC */
162 K_THREAD_DEFINE(edhoc_thread, //name
163 		4608, //stack_size
164 		edhoc_responder_init, //entry_function
165 		NULL, NULL, NULL, //parameter1,parameter2,parameter3
166 		0, //priority
167 		0, //options
168 		0); //delay
169 
170 /* CoAP socket fd */
171 static int sock;
172 
173 static struct coap_observer observers[NUM_OBSERVERS];
174 
175 static struct coap_pending pendings[NUM_PENDINGS];
176 
177 static struct k_delayed_work observer_work;
178 
179 static int obs_counter;
180 
181 static struct coap_resource *resource_to_notify;
182 
183 static struct k_delayed_work retransmit_work;
184 
185 #if defined(CONFIG_NET_IPV6)
join_coap_multicast_group(void)186 static bool join_coap_multicast_group(void)
187 {
188 	static struct in6_addr my_addr = MY_IP6ADDR;
189 	static struct sockaddr_in6 mcast_addr = {
190 		.sin6_family = AF_INET6,
191 		.sin6_addr = ALL_NODES_LOCAL_COAP_MCAST,
192 		.sin6_port = htons(MY_COAP_PORT)
193 	};
194 	struct net_if_mcast_addr *mcast;
195 	struct net_if_addr *ifaddr;
196 	struct net_if *iface;
197 
198 	iface = net_if_get_default();
199 	if (!iface) {
200 		LOG_ERR("Could not get te default interface\n");
201 		return false;
202 	}
203 
204 #if defined(CONFIG_NET_CONFIG_SETTINGS)
205 	if (net_addr_pton(AF_INET6, CONFIG_NET_CONFIG_MY_IPV6_ADDR, &my_addr) <
206 	    0) {
207 		LOG_ERR("Invalid IPv6 address %s",
208 			CONFIG_NET_CONFIG_MY_IPV6_ADDR);
209 	}
210 #endif
211 
212 	ifaddr = net_if_ipv6_addr_add(iface, &my_addr, NET_ADDR_MANUAL, 0);
213 	if (!ifaddr) {
214 		LOG_ERR("Could not add unicast address to interface");
215 		return false;
216 	}
217 
218 	ifaddr->addr_state = NET_ADDR_PREFERRED;
219 
220 	mcast = net_if_ipv6_maddr_add(iface, &mcast_addr.sin6_addr);
221 	if (!mcast) {
222 		LOG_ERR("Could not add multicast address to interface\n");
223 		return false;
224 	}
225 
226 	return true;
227 }
228 #endif
229 
230 #if defined(CONFIG_NET_IPV6)
231 /**
232  * @brief	Initializes sockets for CoAP server (IPv6)
233  * @param
234  * @retval	error code
235  */
start_coap_server(void)236 static int start_coap_server(void)
237 {
238 	struct sockaddr_in6 addr6;
239 	int r;
240 
241 	memset(&addr6, 0, sizeof(addr6));
242 	addr6.sin6_family = AF_INET6;
243 	addr6.sin6_port = htons(MY_COAP_PORT);
244 
245 	sock = socket(addr6.sin6_family, SOCK_DGRAM, IPPROTO_UDP);
246 	if (sock < 0) {
247 		LOG_ERR("Failed to create UDP socket %d", errno);
248 		return -errno;
249 	}
250 
251 	r = bind(sock, (struct sockaddr *)&addr6, sizeof(addr6));
252 	if (r < 0) {
253 		LOG_ERR("Failed to bind UDP socket %d", errno);
254 		return -errno;
255 	}
256 
257 	return 0;
258 }
259 #endif
260 
261 #if defined(CONFIG_NET_IPV4)
262 /**
263  * @brief	Initializes sockets for CoAP server (IPv4)
264  * @param
265  * @retval	error code
266  */
start_coap_server(void)267 static int start_coap_server(void)
268 {
269 	struct sockaddr_in addr;
270 	int r;
271 
272 	memset(&addr, 0, sizeof(addr));
273 	addr.sin_family = AF_INET;
274 	addr.sin_port = htons(MY_COAP_PORT);
275 	addr.sin_addr.s_addr = htonl(INADDR_ANY); //inet_addr("127.0.0.1");
276 
277 	sock = socket(addr.sin_family, SOCK_DGRAM, IPPROTO_UDP);
278 	if (sock < 0) {
279 		LOG_ERR("Failed to create UDP socket %d", errno);
280 		return -errno;
281 	}
282 
283 	r = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
284 	if (r < 0) {
285 		LOG_ERR("Failed to bind UDP socket %d", errno);
286 		return -errno;
287 	}
288 
289 	return 0;
290 }
291 #endif
292 
293 /**
294  * @brief	Receives and replies a UDP message in order to check the connection
295  * 			This function is required since it may happen that the router
296  * 			is not set up at the moment when we want to send a message
297  * @param	sock the socket's fd
298  * @retval	error code
299  */
check_router_connection(int sock)300 static int check_router_connection(int sock)
301 {
302 	uint8_t data[30];
303 	struct sockaddr client_addr;
304 	socklen_t client_addr_len;
305 	client_addr_len = sizeof(client_addr);
306 
307 	int rcvd = recvfrom(sock, data, sizeof(data), 0, &client_addr,
308 			    &client_addr_len);
309 	if (rcvd >= 0) {
310 		PRINTK("%s\n", data);
311 		PRINTK("sending connection confirmation message...\n");
312 		sendto(sock, &data, rcvd, 0, &client_addr, client_addr_len);
313 	} else {
314 		PRINTK("error (%d)\n", errno);
315 		return -errno;
316 	}
317 
318 	return 0;
319 }
320 
321 /**
322  * @brief	Sends CoAP reply packet over network
323  * @param	cpkt CoAP packet to be sent
324  * @param	addr client address (destination)
325  * @param	addr_len length of client address
326  * @retval	error code
327  */
send_coap_reply(struct coap_packet * cpkt,const struct sockaddr * addr,socklen_t addr_len)328 static int send_coap_reply(struct coap_packet *cpkt,
329 			   const struct sockaddr *addr, socklen_t addr_len)
330 {
331 	int r;
332 
333 	net_hexdump("Response", cpkt->data, cpkt->offset);
334 
335 	GPIO_HIGH(LED1);
336 	r = sendto(sock, cpkt->data, cpkt->offset, 0, addr, addr_len);
337 	if (r < 0) {
338 		LOG_ERR("Failed to send %d", errno);
339 		r = -errno;
340 	}
341 	GPIO_LOW(LED1);
342 
343 	return r;
344 }
345 
346 /**
347  * @brief	Reveals available resources to client (see RFC7252 for details)
348  * @param	resource requested resource(s)
349  * @param	request CoAP client request packet
350  * @param	addr client address (destination)
351  * @param	addr_len length of client address
352  * @retval	error code
353  */
well_known_core_get(struct coap_resource * resource,struct coap_packet * request,struct sockaddr * addr,socklen_t addr_len)354 static int well_known_core_get(struct coap_resource *resource,
355 			       struct coap_packet *request,
356 			       struct sockaddr *addr, socklen_t addr_len)
357 {
358 	struct coap_packet response;
359 	uint8_t *data;
360 	int r;
361 
362 	data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN);
363 	if (!data) {
364 		return -ENOMEM;
365 	}
366 
367 	r = coap_well_known_core_get(resource, request, &response, data,
368 				     MAX_COAP_MSG_LEN);
369 	if (r < 0) {
370 		goto end;
371 	}
372 
373 	r = send_coap_reply(&response, addr, addr_len);
374 
375 end:
376 	k_free(data);
377 
378 	return r;
379 }
380 
381 /**
382  * @brief	Callback for EDHOC Post request. Passes request payload to EDHOC thread
383  * 			and waits for EDHOC response message.
384  * @param	resource requested resource
385  * @param	request CoAP client request packet
386  * @param	addr client address (destination)
387  * @param	addr_len length of client address
388  * @retval	error code
389  */
edhoc_post(struct coap_resource * resource,struct coap_packet * request,struct sockaddr * addr,socklen_t addr_len)390 static int edhoc_post(struct coap_resource *resource,
391 		      struct coap_packet *request, struct sockaddr *addr,
392 		      socklen_t addr_len)
393 {
394 	struct coap_packet response;
395 	uint8_t token[8];
396 	const uint8_t *payload;
397 	uint8_t *data;
398 	uint16_t payload_len;
399 	uint8_t code;
400 	uint8_t type;
401 	uint8_t tkl;
402 	uint16_t id;
403 	int r;
404 	struct k_mbox_msg recv_msg; //edhoc post payload
405 	struct k_mbox_msg send_msg; //edhoc response
406 	char buffer[MBOX_MSG_SIZE];
407 	int buffer_bytes_used;
408 	uint8_t finished_indicator[] = { "EDHOC successful" };
409 	static int msg_count = 1;
410 
411 	code = coap_header_get_code(request);
412 	type = coap_header_get_type(request);
413 	id = coap_header_get_id(request);
414 	tkl = coap_header_get_token(request, token);
415 
416 	LOG_INF("*******");
417 	LOG_INF("type: %u code %u id %u", type, code, id);
418 	LOG_INF("*******");
419 
420 	payload = coap_packet_get_payload(request, &payload_len);
421 	if (payload) {
422 		net_hexdump("POST Payload", payload, payload_len);
423 	}
424 
425 	/* prepare message box packet to send to edhoc thread */
426 	buffer_bytes_used = payload_len;
427 	memcpy(buffer, payload, buffer_bytes_used);
428 	recv_msg.info = buffer_bytes_used;
429 	recv_msg.size = buffer_bytes_used;
430 	recv_msg.tx_data = buffer;
431 	recv_msg.tx_block.data = NULL;
432 	recv_msg.tx_target_thread = K_ANY;
433 	k_mbox_put(&rx_queue, &recv_msg, K_FOREVER);
434 	if (recv_msg.size < buffer_bytes_used) {
435 		PRINTK("some message data dropped during transfer!");
436 		PRINTK("receiver only had room for %d bytes", send_msg.info);
437 	}
438 
439 	/* wait for data from edhoc_thread */
440 	send_msg.info = MBOX_MSG_SIZE;
441 	send_msg.size = MBOX_MSG_SIZE;
442 	send_msg.rx_source_thread = K_ANY;
443 	k_mbox_get(&tx_queue, &send_msg, buffer, K_SECONDS(MBOX_WAIT_TIME));
444 	if (send_msg.info != send_msg.size) {
445 		PRINTK("some message data dropped during transfer!");
446 		PRINTK("sender tried to send %d bytes", send_msg.info);
447 	}
448 
449 	if (type == COAP_TYPE_CON) {
450 		type = COAP_TYPE_ACK;
451 	} else {
452 		type = COAP_TYPE_NON_CON;
453 	}
454 
455 	data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN);
456 	if (!data) {
457 		return -ENOMEM;
458 	}
459 
460 	r = coap_packet_init(&response, data, MAX_COAP_MSG_LEN, 1, type, tkl,
461 			     (uint8_t *)token, COAP_RESPONSE_CODE_CHANGED, id);
462 	if (r < 0) {
463 		goto end;
464 	}
465 
466 	/* check if msg2 or edhoc finished */
467 	if (memcmp(buffer, finished_indicator, sizeof(finished_indicator)) !=
468 	    0) {
469 		r = coap_packet_append_payload_marker(&response);
470 		if (r < 0) {
471 			goto end;
472 		}
473 
474 		r = coap_packet_append_payload(&response, buffer,
475 					       send_msg.size);
476 		if (r < 0) {
477 			goto end;
478 		}
479 		msg_count++;
480 	} else {
481 		msg_count = 1;
482 	}
483 
484 	r = send_coap_reply(&response, addr, addr_len);
485 
486 end:
487 	k_free(data);
488 
489 	return r;
490 }
491 
retransmit_request(struct k_work * work)492 static void retransmit_request(struct k_work *work)
493 {
494 	struct coap_pending *pending;
495 
496 	pending = coap_pending_next_to_expire(pendings, NUM_PENDINGS);
497 	if (!pending) {
498 		return;
499 	}
500 
501 	if (!coap_pending_cycle(pending)) {
502 		k_free(pending->data);
503 		coap_pending_clear(pending);
504 		return;
505 	}
506 
507 	k_delayed_work_submit(&retransmit_work, K_MSEC(pending->timeout));
508 }
509 
update_counter(struct k_work * work)510 static void update_counter(struct k_work *work)
511 {
512 	obs_counter++;
513 
514 	if (resource_to_notify) {
515 		coap_resource_notify(resource_to_notify);
516 	}
517 
518 	k_delayed_work_submit(&observer_work, K_SECONDS(5));
519 }
520 
521 static const char *const edhoc_path[] = { ".well-known", "edhoc", NULL };
522 
523 static struct coap_resource resources[] = {
524 	{
525 		.get = well_known_core_get,
526 		.path = COAP_WELL_KNOWN_CORE_PATH,
527 	},
528 	{
529 		.post = edhoc_post,
530 		.path = edhoc_path,
531 	},
532 	{},
533 };
534 
535 static struct coap_resource *
find_resource_by_observer(struct coap_resource * resources,struct coap_observer * o)536 find_resource_by_observer(struct coap_resource *resources,
537 			  struct coap_observer *o)
538 {
539 	struct coap_resource *r;
540 
541 	for (r = resources; r && r->path; r++) {
542 		sys_snode_t *node;
543 
544 		SYS_SLIST_FOR_EACH_NODE (&r->observers, node) {
545 			if (&o->list == node) {
546 				return r;
547 			}
548 		}
549 	}
550 
551 	return NULL;
552 }
553 
554 /**
555  * @brief	Parses CoAP client request and calls handler of requested resource.
556  * @param	data received CoAP client request
557  * @param	data_len length of received CoAP client request
558  * @param	addr client address (destination)
559  * @param	addr_len length of client address
560  * @retval	error code
561  */
process_coap_request(uint8_t * data,uint16_t data_len,struct sockaddr * client_addr,socklen_t client_addr_len)562 static void process_coap_request(uint8_t *data, uint16_t data_len,
563 				 struct sockaddr *client_addr,
564 				 socklen_t client_addr_len)
565 {
566 	struct coap_packet request;
567 	struct coap_pending *pending;
568 	struct coap_option options[16] = { 0 };
569 	uint8_t opt_num = 16U;
570 	uint8_t type;
571 	int r;
572 
573 	r = coap_packet_parse(&request, data, data_len, options, opt_num);
574 	if (r < 0) {
575 		LOG_ERR("Invalid data received (%d)\n", r);
576 	}
577 
578 	type = coap_header_get_type(&request);
579 
580 	pending = coap_pending_received(&request, pendings, NUM_PENDINGS);
581 	if (!pending) {
582 		goto not_found;
583 	}
584 
585 	/* Clear CoAP pending request */
586 	if (type == COAP_TYPE_ACK) {
587 		k_free(pending->data);
588 		coap_pending_clear(pending);
589 	}
590 
591 	return;
592 
593 not_found:
594 
595 	if (type == COAP_TYPE_RESET) {
596 		struct coap_resource *r;
597 		struct coap_observer *o;
598 
599 		o = coap_find_observer_by_addr(observers, NUM_OBSERVERS,
600 					       client_addr);
601 		if (!o) {
602 			LOG_ERR("Observer not found\n");
603 			goto end;
604 		}
605 
606 		r = find_resource_by_observer(resources, o);
607 		if (!r) {
608 			LOG_ERR("Observer found but Resource not found\n");
609 			goto end;
610 		}
611 
612 		coap_remove_observer(r, o);
613 
614 		return;
615 	}
616 
617 end:
618 
619 	r = coap_handle_request(&request, resources, options, opt_num,
620 				client_addr, client_addr_len);
621 	if (r < 0) {
622 		LOG_WRN("No handler for such request (%d)\n", r);
623 	}
624 }
625 
626 /**
627  * @brief	Waits for CoAP client request and passes received data to process_coap_request
628  * @param
629  * @retval	error code
630  */
process_client_request(void)631 static int process_client_request(void)
632 {
633 	int received;
634 	struct sockaddr client_addr;
635 	socklen_t client_addr_len;
636 	uint8_t request[MAX_COAP_MSG_LEN];
637 
638 	do {
639 		client_addr_len = sizeof(client_addr);
640 		GPIO_HIGH(LED1);
641 		received = recvfrom(sock, request, sizeof(request), 0,
642 				    &client_addr, &client_addr_len);
643 		GPIO_LOW(LED1);
644 		if (received < 0) {
645 			LOG_ERR("Connection error %d", errno);
646 			return -errno;
647 		}
648 
649 		process_coap_request(request, received, &client_addr,
650 				     client_addr_len);
651 	} while (true);
652 
653 	return 0;
654 }
655 
main(void)656 void main(void)
657 {
658 	int r;
659 	setbuf(stdout, NULL); //disable printf buffereing
660 
661 	LOG_DBG("Start CoAP-server sample");
662 
663 #ifdef CONFIG_NET_IPV6
664 	bool res;
665 
666 	res = join_coap_multicast_group();
667 	if (!res) {
668 		goto quit;
669 	}
670 #endif
671 
672 	LED_INIT();
673 	GPIO_LOW(LED0);
674 	GPIO_LOW(LED1);
675 
676 	r = start_coap_server();
677 	if (r < 0) {
678 		goto quit;
679 	}
680 
681 	r = check_router_connection(sock);
682 	if (r < 0) {
683 		goto quit;
684 	}
685 
686 	k_delayed_work_init(&retransmit_work, retransmit_request);
687 	k_delayed_work_init(&observer_work, update_counter);
688 
689 	while (1) {
690 		r = process_client_request();
691 		if (r < 0) {
692 			goto quit;
693 		}
694 	}
695 
696 	LOG_DBG("Done");
697 	return;
698 
699 quit:
700 	LOG_ERR("Quit");
701 }
702