1 /*
2  * Copyright (c) 2018-2023 O.S.Systems
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_REGISTER(updatehub, CONFIG_UPDATEHUB_LOG_LEVEL);
9 
10 #include <zephyr/logging/log_ctrl.h>
11 #include <zephyr/net/socket.h>
12 #include <zephyr/net/net_mgmt.h>
13 #include <zephyr/net/net_ip.h>
14 #include <zephyr/net/udp.h>
15 #include <zephyr/net/coap.h>
16 #include <zephyr/net/dns_resolve.h>
17 #include <zephyr/sys/reboot.h>
18 #include <zephyr/data/json.h>
19 #include <zephyr/mgmt/updatehub.h>
20 
21 #include "updatehub_priv.h"
22 #include "updatehub_firmware.h"
23 #include "updatehub_device.h"
24 #include "updatehub_timer.h"
25 #include "updatehub_integrity.h"
26 #include "updatehub_storage.h"
27 
28 #if defined(CONFIG_UPDATEHUB_DTLS)
29 #define CA_CERTIFICATE_TAG 1
30 #include <zephyr/net/tls_credentials.h>
31 #endif
32 
33 #define NETWORK_TIMEOUT (2 * MSEC_PER_SEC)
34 #define UPDATEHUB_POLL_INTERVAL K_MINUTES(CONFIG_UPDATEHUB_POLL_INTERVAL)
35 #define MAX_PATH_SIZE 255
36 /* MAX_PAYLOAD_SIZE must reflect size COAP_BLOCK_x option */
37 #define MAX_PAYLOAD_SIZE 1024
38 /* MAX_DOWNLOAD_DATA must be equal or bigger than:
39  * MAX_PAYLOAD_SIZE + (len + header + options)
40  * otherwise download size will be less than real size.
41  */
42 #define MAX_DOWNLOAD_DATA (MAX_PAYLOAD_SIZE + 32)
43 #define MAX_IP_SIZE 30
44 
45 #if defined(CONFIG_UPDATEHUB_CE)
46 #define UPDATEHUB_SERVER CONFIG_UPDATEHUB_SERVER
47 #else
48 #define UPDATEHUB_SERVER "coap.updatehub.io"
49 #endif
50 
51 #ifdef CONFIG_UPDATEHUB_DOWNLOAD_SHA256_VERIFICATION
52 #define _DOWNLOAD_SHA256_VERIFICATION
53 #elif defined(CONFIG_UPDATEHUB_DOWNLOAD_STORAGE_SHA256_VERIFICATION)
54 #define _DOWNLOAD_SHA256_VERIFICATION
55 #define _STORAGE_SHA256_VERIFICATION
56 #elif defined(CONFIG_UPDATEHUB_STORAGE_SHA256_VERIFICATION)
57 #define _STORAGE_SHA256_VERIFICATION
58 #endif
59 
60 static struct updatehub_context {
61 	struct coap_block_context block;
62 	struct k_sem semaphore;
63 	struct updatehub_storage_context storage_ctx;
64 	struct updatehub_crypto_context crypto_ctx;
65 	enum updatehub_response code_status;
66 	uint8_t hash[SHA256_BIN_DIGEST_SIZE];
67 	uint8_t uri_path[MAX_PATH_SIZE];
68 	uint8_t payload[MAX_PAYLOAD_SIZE];
69 	int downloaded_size;
70 	struct pollfd fds[1];
71 	int sock;
72 	int nfds;
73 } ctx;
74 
75 static struct update_info {
76 	char package_uid[SHA256_HEX_DIGEST_SIZE];
77 	char sha256sum_image[SHA256_HEX_DIGEST_SIZE];
78 	int image_size;
79 } update_info;
80 
81 static struct k_work_delayable updatehub_work_handle;
82 
bin2hex_str(uint8_t * bin,size_t bin_len,char * str,size_t str_buf_len)83 static int bin2hex_str(uint8_t *bin, size_t bin_len, char *str, size_t str_buf_len)
84 {
85 	if (bin == NULL || str == NULL) {
86 		return -1;
87 	}
88 
89 	/* ensures at least an empty string */
90 	if (str_buf_len < 1) {
91 		return -2;
92 	}
93 
94 	memset(str, 0, str_buf_len);
95 	bin2hex(bin, bin_len, str, str_buf_len);
96 
97 	return 0;
98 }
99 
wait_fds(void)100 static void wait_fds(void)
101 {
102 	if (poll(ctx.fds, ctx.nfds, NETWORK_TIMEOUT) < 0) {
103 		LOG_ERR("Error in poll");
104 	}
105 }
106 
prepare_fds(void)107 static void prepare_fds(void)
108 {
109 	ctx.fds[ctx.nfds].fd = ctx.sock;
110 	ctx.fds[ctx.nfds].events = POLLIN;
111 	ctx.nfds++;
112 }
113 
metadata_hash_get(char * metadata)114 static int metadata_hash_get(char *metadata)
115 {
116 	struct updatehub_crypto_context local_crypto_ctx;
117 
118 	if (updatehub_integrity_init(&local_crypto_ctx)) {
119 		return -1;
120 	}
121 
122 	if (updatehub_integrity_update(&local_crypto_ctx, metadata, strlen(metadata))) {
123 		return -1;
124 	}
125 
126 	if (updatehub_integrity_finish(&local_crypto_ctx, ctx.hash, sizeof(ctx.hash))) {
127 		return -1;
128 	}
129 
130 	if (bin2hex_str(ctx.hash, SHA256_BIN_DIGEST_SIZE,
131 		update_info.package_uid, SHA256_HEX_DIGEST_SIZE)) {
132 		return -1;
133 	}
134 
135 	return 0;
136 }
137 
138 static bool
is_compatible_hardware(struct resp_probe_some_boards * metadata_some_boards)139 is_compatible_hardware(struct resp_probe_some_boards *metadata_some_boards)
140 {
141 	int i;
142 
143 	for (i = 0; i < metadata_some_boards->supported_hardware_len; i++) {
144 		if (strncmp(metadata_some_boards->supported_hardware[i],
145 			    CONFIG_BOARD, strlen(CONFIG_BOARD)) == 0) {
146 			return true;
147 		}
148 	}
149 	return false;
150 }
151 
cleanup_connection(void)152 static void cleanup_connection(void)
153 {
154 	int i;
155 
156 	if (close(ctx.sock) < 0) {
157 		LOG_ERR("Could not close the socket");
158 	}
159 
160 	for (i = 0; i < ctx.nfds; i++) {
161 		memset(&ctx.fds[i], 0, sizeof(ctx.fds[i]));
162 	}
163 
164 	ctx.nfds = 0;
165 	ctx.sock = 0;
166 }
167 
start_coap_client(void)168 static bool start_coap_client(void)
169 {
170 	struct addrinfo *addr;
171 	struct addrinfo hints;
172 	int resolve_attempts = 10;
173 	int ret = -1;
174 
175 	memset(&hints, 0, sizeof(hints));
176 
177 	if (IS_ENABLED(CONFIG_NET_IPV6)) {
178 		hints.ai_family = AF_INET6;
179 		hints.ai_socktype = SOCK_STREAM;
180 	} else if (IS_ENABLED(CONFIG_NET_IPV4)) {
181 		hints.ai_family = AF_INET;
182 		hints.ai_socktype = SOCK_STREAM;
183 	}
184 
185 #if defined(CONFIG_UPDATEHUB_DTLS)
186 	int verify = TLS_PEER_VERIFY_REQUIRED;
187 	sec_tag_t sec_list[] = { CA_CERTIFICATE_TAG };
188 	int protocol = IPPROTO_DTLS_1_2;
189 	char port[] = "5684";
190 #else
191 	int protocol = IPPROTO_UDP;
192 	char port[] = "5683";
193 #endif
194 
195 	while (resolve_attempts--) {
196 		ret = getaddrinfo(UPDATEHUB_SERVER, port, &hints, &addr);
197 		if (ret == 0) {
198 			break;
199 		}
200 		k_sleep(K_SECONDS(1));
201 	}
202 	if (ret < 0) {
203 		LOG_ERR("Could not resolve dns");
204 		return false;
205 	}
206 
207 	ret = 1;
208 
209 	ctx.sock = socket(addr->ai_family, SOCK_DGRAM, protocol);
210 	if (ctx.sock < 0) {
211 		LOG_ERR("Failed to create UDP socket");
212 		goto error;
213 	}
214 
215 	ret = -1;
216 
217 #if defined(CONFIG_UPDATEHUB_DTLS)
218 	if (setsockopt(ctx.sock, SOL_TLS, TLS_SEC_TAG_LIST,
219 		       sec_list, sizeof(sec_list)) < 0) {
220 		LOG_ERR("Failed to set TLS_TAG option");
221 		goto error;
222 	}
223 
224 	if (setsockopt(ctx.sock, SOL_TLS, TLS_PEER_VERIFY, &verify, sizeof(int)) < 0) {
225 		LOG_ERR("Failed to set TLS_PEER_VERIFY option");
226 		goto error;
227 	}
228 #endif
229 
230 	if (connect(ctx.sock, addr->ai_addr, addr->ai_addrlen) < 0) {
231 		LOG_ERR("Cannot connect to UDP remote");
232 		goto error;
233 	}
234 
235 	prepare_fds();
236 
237 	ret = 0;
238 error:
239 	freeaddrinfo(addr);
240 
241 	if (ret > 0) {
242 		cleanup_connection();
243 	}
244 
245 	return (ret == 0) ? true : false;
246 }
247 
send_request(enum coap_msgtype msgtype,enum coap_method method,enum updatehub_uri_path type)248 static int send_request(enum coap_msgtype msgtype, enum coap_method method,
249 			enum updatehub_uri_path type)
250 {
251 	struct coap_packet request_packet;
252 	int ret = -1;
253 	uint8_t *data = k_malloc(MAX_PAYLOAD_SIZE);
254 
255 	if (data == NULL) {
256 		LOG_ERR("Could not alloc data memory");
257 		goto error;
258 	}
259 
260 	ret = coap_packet_init(&request_packet, data, MAX_PAYLOAD_SIZE,
261 			       COAP_VERSION_1, COAP_TYPE_CON,
262 			       COAP_TOKEN_MAX_LEN, coap_next_token(), method,
263 			       coap_next_id());
264 	if (ret < 0) {
265 		LOG_ERR("Could not init packet");
266 		goto error;
267 	}
268 
269 	switch (method) {
270 	case COAP_METHOD_GET:
271 		snprintk(ctx.uri_path, MAX_PATH_SIZE,
272 			 "%s/%s/packages/%s/objects/%s", uri_path(type),
273 			 CONFIG_UPDATEHUB_PRODUCT_UID, update_info.package_uid,
274 			 update_info.sha256sum_image);
275 
276 		ret = coap_packet_append_option(&request_packet,
277 						COAP_OPTION_URI_PATH,
278 						ctx.uri_path,
279 						strlen(ctx.uri_path));
280 		if (ret < 0) {
281 			LOG_ERR("Unable add option to request path");
282 			goto error;
283 		}
284 
285 		ret = coap_append_block2_option(&request_packet,
286 						&ctx.block);
287 		if (ret < 0) {
288 			LOG_ERR("Unable coap append block 2");
289 			goto error;
290 		}
291 
292 		ret = coap_packet_append_option(&request_packet, 2048,
293 						UPDATEHUB_API_HEADER, strlen(UPDATEHUB_API_HEADER));
294 		if (ret < 0) {
295 			LOG_ERR("Unable add option to add updatehub header");
296 			goto error;
297 		}
298 
299 		break;
300 
301 	case COAP_METHOD_POST:
302 		ret = coap_packet_append_option(&request_packet,
303 						COAP_OPTION_URI_PATH,
304 						uri_path(type),
305 						strlen(uri_path(type)));
306 		if (ret < 0) {
307 			LOG_ERR("Unable add option to request path");
308 			goto error;
309 		}
310 
311 		ret = coap_append_option_int(&request_packet,
312 					     COAP_OPTION_CONTENT_FORMAT,
313 					     COAP_CONTENT_FORMAT_APP_JSON);
314 		if (ret < 0) {
315 			LOG_ERR("Unable add option to request format");
316 			goto error;
317 		}
318 
319 		ret = coap_packet_append_option(&request_packet, 2048,
320 						UPDATEHUB_API_HEADER, strlen(UPDATEHUB_API_HEADER));
321 		if (ret < 0) {
322 			LOG_ERR("Unable add option to add updatehub header");
323 			goto error;
324 		}
325 
326 		ret = coap_packet_append_payload_marker(&request_packet);
327 		if (ret < 0) {
328 			LOG_ERR("Unable to append payload marker");
329 			goto error;
330 		}
331 
332 		ret = coap_packet_append_payload(&request_packet,
333 						 ctx.payload,
334 						 strlen(ctx.payload));
335 		if (ret < 0) {
336 			LOG_ERR("Not able to append payload");
337 			goto error;
338 		}
339 
340 		break;
341 
342 	default:
343 		LOG_ERR("Invalid method");
344 		ret = -1;
345 		goto error;
346 	}
347 
348 	ret = send(ctx.sock, request_packet.data, request_packet.offset, 0);
349 	if (ret < 0) {
350 		LOG_ERR("Could not send request");
351 		goto error;
352 	}
353 
354 error:
355 	k_free(data);
356 
357 	return ret;
358 }
359 
360 #ifdef _DOWNLOAD_SHA256_VERIFICATION
install_update_cb_sha256(void)361 static bool install_update_cb_sha256(void)
362 {
363 	char sha256[SHA256_HEX_DIGEST_SIZE];
364 
365 	if (updatehub_integrity_finish(&ctx.crypto_ctx, ctx.hash, sizeof(ctx.hash))) {
366 		LOG_ERR("Could not finish sha256sum");
367 		return false;
368 	}
369 
370 	if (bin2hex_str(ctx.hash, SHA256_BIN_DIGEST_SIZE,
371 		sha256, SHA256_HEX_DIGEST_SIZE)) {
372 		LOG_ERR("Could not create sha256sum hex representation");
373 		return false;
374 	}
375 
376 	if (strncmp(sha256, update_info.sha256sum_image,
377 		    SHA256_HEX_DIGEST_SIZE) != 0) {
378 		LOG_ERR("SHA256SUM of image are not the same");
379 		ctx.code_status = UPDATEHUB_DOWNLOAD_ERROR;
380 		return false;
381 	}
382 
383 	return true;
384 }
385 #endif
386 
install_update_cb_check_blk_num(const struct coap_packet * resp)387 static int install_update_cb_check_blk_num(const struct coap_packet *resp)
388 {
389 	int blk_num;
390 	int blk2_opt;
391 	uint16_t payload_len;
392 
393 	blk2_opt = coap_get_option_int(resp, COAP_OPTION_BLOCK2);
394 	(void)coap_packet_get_payload(resp, &payload_len);
395 
396 	if ((payload_len == 0) || (blk2_opt < 0)) {
397 		LOG_DBG("Invalid data received or block number is < 0");
398 		return -ENOENT;
399 	}
400 
401 	blk_num = GET_BLOCK_NUM(blk2_opt);
402 
403 	if (blk_num == updatehub_blk_get(UPDATEHUB_BLK_INDEX)) {
404 		updatehub_blk_inc(UPDATEHUB_BLK_INDEX);
405 
406 		return 0;
407 	}
408 
409 	return -EAGAIN;
410 }
411 
install_update_cb(void)412 static void install_update_cb(void)
413 {
414 	struct coap_packet response_packet;
415 	uint8_t *data = k_malloc(MAX_DOWNLOAD_DATA);
416 	const uint8_t *payload_start;
417 	uint16_t payload_len;
418 	int rcvd = -1;
419 
420 	if (data == NULL) {
421 		LOG_ERR("Could not alloc data memory");
422 		ctx.code_status = UPDATEHUB_DOWNLOAD_ERROR;
423 		goto cleanup;
424 	}
425 
426 	wait_fds();
427 
428 	rcvd = recv(ctx.sock, data, MAX_DOWNLOAD_DATA, MSG_DONTWAIT);
429 	if (rcvd <= 0) {
430 		ctx.code_status = UPDATEHUB_NETWORKING_ERROR;
431 		LOG_ERR("Could not receive data");
432 		goto cleanup;
433 	}
434 
435 	if (coap_packet_parse(&response_packet, data, rcvd, NULL, 0) < 0) {
436 		LOG_ERR("Invalid data received");
437 		ctx.code_status = UPDATEHUB_DOWNLOAD_ERROR;
438 		goto cleanup;
439 	}
440 
441 	if (install_update_cb_check_blk_num(&response_packet) < 0) {
442 		ctx.code_status = UPDATEHUB_DOWNLOAD_ERROR;
443 		goto cleanup;
444 	}
445 
446 	/* payload_len is > 0, checked at install_update_cb_check_blk_num */
447 	payload_start = coap_packet_get_payload(&response_packet, &payload_len);
448 
449 	updatehub_tmr_stop();
450 	updatehub_blk_set(UPDATEHUB_BLK_ATTEMPT, 0);
451 	updatehub_blk_set(UPDATEHUB_BLK_TX_AVAILABLE, 1);
452 
453 	ctx.downloaded_size = ctx.downloaded_size + payload_len;
454 
455 #ifdef _DOWNLOAD_SHA256_VERIFICATION
456 	if (updatehub_integrity_update(&ctx.crypto_ctx,
457 			     payload_start,
458 			     payload_len)) {
459 		LOG_ERR("Could not update sha256sum");
460 		ctx.code_status = UPDATEHUB_DOWNLOAD_ERROR;
461 		goto cleanup;
462 	}
463 #endif
464 
465 	if (updatehub_storage_write(&ctx.storage_ctx, payload_start, payload_len,
466 				    ctx.downloaded_size == ctx.block.total_size)) {
467 		LOG_ERR("Error to write on the flash");
468 		ctx.code_status = UPDATEHUB_INSTALL_ERROR;
469 		goto cleanup;
470 	}
471 
472 	if (coap_update_from_block(&response_packet, &ctx.block) < 0) {
473 		ctx.code_status = UPDATEHUB_DOWNLOAD_ERROR;
474 		goto cleanup;
475 	}
476 
477 	if (coap_next_block(&response_packet, &ctx.block) == 0) {
478 		if (ctx.downloaded_size != ctx.block.total_size) {
479 			LOG_ERR("Could not get the next coap block");
480 			ctx.code_status = UPDATEHUB_DOWNLOAD_ERROR;
481 			goto cleanup;
482 		}
483 
484 		LOG_INF("Firmware download complete");
485 
486 #ifdef _DOWNLOAD_SHA256_VERIFICATION
487 		if (!install_update_cb_sha256()) {
488 			LOG_ERR("Firmware - download validation has failed");
489 			ctx.code_status = UPDATEHUB_DOWNLOAD_ERROR;
490 			goto cleanup;
491 		}
492 #else
493 		if (hex2bin(update_info.sha256sum_image,
494 			    SHA256_HEX_DIGEST_SIZE - 1, ctx.hash,
495 			    SHA256_BIN_DIGEST_SIZE) != SHA256_BIN_DIGEST_SIZE) {
496 			LOG_ERR("Firmware - metadata validation has failed");
497 			ctx.code_status = UPDATEHUB_DOWNLOAD_ERROR;
498 			goto cleanup;
499 		}
500 #endif
501 
502 #ifdef _STORAGE_SHA256_VERIFICATION
503 		if (updatehub_storage_check(&ctx.storage_ctx,
504 					    UPDATEHUB_SLOT_PARTITION_1,
505 					    ctx.hash, ctx.downloaded_size)) {
506 			LOG_ERR("Firmware - flash validation has failed");
507 			ctx.code_status = UPDATEHUB_INSTALL_ERROR;
508 			goto cleanup;
509 		}
510 #endif
511 	}
512 
513 	ctx.code_status = UPDATEHUB_OK;
514 
515 cleanup:
516 	k_free(data);
517 }
518 
install_update(void)519 static enum updatehub_response install_update(void)
520 {
521 #ifdef _DOWNLOAD_SHA256_VERIFICATION
522 	if (updatehub_integrity_init(&ctx.crypto_ctx)) {
523 		LOG_ERR("Could not start sha256sum");
524 		ctx.code_status = UPDATEHUB_DOWNLOAD_ERROR;
525 		goto error;
526 	}
527 #endif
528 
529 	if (!start_coap_client()) {
530 		ctx.code_status = UPDATEHUB_NETWORKING_ERROR;
531 		goto error;
532 	}
533 
534 	if (coap_block_transfer_init(&ctx.block,
535 				     CONFIG_UPDATEHUB_COAP_BLOCK_SIZE_EXP,
536 				     update_info.image_size) < 0) {
537 		LOG_ERR("Unable init block transfer");
538 		ctx.code_status = UPDATEHUB_NETWORKING_ERROR;
539 		goto cleanup;
540 	}
541 
542 	if (updatehub_storage_init(&ctx.storage_ctx,
543 				   UPDATEHUB_SLOT_PARTITION_1)) {
544 		LOG_ERR("Unable init flash");
545 		ctx.code_status = UPDATEHUB_FLASH_INIT_ERROR;
546 		goto cleanup;
547 	}
548 
549 	ctx.downloaded_size = 0;
550 	updatehub_blk_set(UPDATEHUB_BLK_ATTEMPT, 0);
551 	updatehub_blk_set(UPDATEHUB_BLK_INDEX, 0);
552 	updatehub_blk_set(UPDATEHUB_BLK_TX_AVAILABLE, 1);
553 
554 	while (ctx.downloaded_size != ctx.block.total_size) {
555 		if (updatehub_blk_get(UPDATEHUB_BLK_TX_AVAILABLE)) {
556 			if (send_request(COAP_TYPE_CON, COAP_METHOD_GET,
557 					 UPDATEHUB_DOWNLOAD) < 0) {
558 				ctx.code_status = UPDATEHUB_NETWORKING_ERROR;
559 				goto cleanup;
560 			}
561 
562 			updatehub_blk_set(UPDATEHUB_BLK_TX_AVAILABLE, 0);
563 			updatehub_blk_inc(UPDATEHUB_BLK_ATTEMPT);
564 			updatehub_tmr_start();
565 		}
566 
567 		install_update_cb();
568 
569 		if (ctx.code_status == UPDATEHUB_OK) {
570 			continue;
571 		}
572 
573 		if (ctx.code_status != UPDATEHUB_DOWNLOAD_ERROR &&
574 		    ctx.code_status != UPDATEHUB_NETWORKING_ERROR) {
575 			LOG_DBG("status: %d", ctx.code_status);
576 			goto cleanup;
577 		}
578 
579 		if (updatehub_blk_get(UPDATEHUB_BLK_ATTEMPT) ==
580 		    CONFIG_UPDATEHUB_COAP_MAX_RETRY) {
581 			updatehub_tmr_stop();
582 
583 			LOG_ERR("Could not get the packet");
584 			ctx.code_status = UPDATEHUB_DOWNLOAD_ERROR;
585 			goto cleanup;
586 		}
587 	}
588 
589 cleanup:
590 	cleanup_connection();
591 
592 error:
593 	ctx.downloaded_size = 0;
594 
595 	return ctx.code_status;
596 }
597 
report(enum updatehub_state state)598 static int report(enum updatehub_state state)
599 {
600 	struct report report;
601 	int ret = -1;
602 	const char *exec = state_name(state);
603 	char *device_id = k_malloc(DEVICE_ID_HEX_MAX_SIZE);
604 	char *firmware_version = k_malloc(FIRMWARE_IMG_VER_STRLEN_MAX);
605 
606 	if (device_id == NULL || firmware_version == NULL) {
607 		LOG_ERR("Could not alloc device_id or firmware_version memory");
608 		goto error;
609 	}
610 
611 	if (!updatehub_get_device_identity(device_id, DEVICE_ID_HEX_MAX_SIZE)) {
612 		goto error;
613 	}
614 
615 	if (!updatehub_get_firmware_version(UPDATEHUB_SLOT_PARTITION_0,
616 					    firmware_version,
617 					    FIRMWARE_IMG_VER_STRLEN_MAX)) {
618 		goto error;
619 	}
620 
621 	memset(&report, 0, sizeof(report));
622 	report.product_uid = CONFIG_UPDATEHUB_PRODUCT_UID;
623 	report.device_identity.id = device_id;
624 	report.version = firmware_version;
625 	report.hardware = CONFIG_BOARD;
626 	report.status = exec;
627 	report.package_uid = update_info.package_uid;
628 
629 	switch (ctx.code_status) {
630 	case UPDATEHUB_INSTALL_ERROR:
631 		report.previous_state =
632 			state_name(UPDATEHUB_STATE_INSTALLING);
633 		break;
634 	case UPDATEHUB_DOWNLOAD_ERROR:
635 		report.previous_state =
636 			state_name(UPDATEHUB_STATE_DOWNLOADING);
637 		break;
638 	case UPDATEHUB_FLASH_INIT_ERROR:
639 		report.previous_state =
640 			state_name(UPDATEHUB_FLASH_INIT_ERROR);
641 		break;
642 	default:
643 		report.previous_state = "";
644 		break;
645 	}
646 
647 	if (strncmp(report.previous_state, "", sizeof("") - 1) != 0) {
648 		report.error_message = updatehub_response(ctx.code_status);
649 	} else {
650 		report.error_message = "";
651 	}
652 
653 	memset(&ctx.payload, 0, MAX_PAYLOAD_SIZE);
654 	ret = json_obj_encode_buf(send_report_descr,
655 				  ARRAY_SIZE(send_report_descr),
656 				  &report, ctx.payload,
657 				  MAX_PAYLOAD_SIZE - 1);
658 	if (ret < 0) {
659 		LOG_ERR("Could not encode metadata");
660 		goto error;
661 	}
662 
663 	if (!start_coap_client()) {
664 		goto error;
665 	}
666 
667 	ret = send_request(COAP_TYPE_NON_CON, COAP_METHOD_POST,
668 			   UPDATEHUB_REPORT);
669 	if (ret < 0) {
670 		goto cleanup;
671 	}
672 
673 	wait_fds();
674 
675 cleanup:
676 	cleanup_connection();
677 
678 error:
679 	k_free(firmware_version);
680 	k_free(device_id);
681 
682 	return ret;
683 }
684 
probe_cb(char * metadata,size_t metadata_size)685 static void probe_cb(char *metadata, size_t metadata_size)
686 {
687 	struct coap_packet reply;
688 	char tmp[MAX_DOWNLOAD_DATA];
689 	const uint8_t *payload_start;
690 	uint16_t payload_len;
691 	size_t tmp_len;
692 	int rcvd = -1;
693 
694 	wait_fds();
695 
696 	rcvd = recv(ctx.sock, tmp, MAX_DOWNLOAD_DATA, MSG_DONTWAIT);
697 	if (rcvd <= 0) {
698 		LOG_ERR("Could not receive data");
699 		ctx.code_status = UPDATEHUB_NETWORKING_ERROR;
700 		return;
701 	}
702 
703 	if (coap_packet_parse(&reply, tmp, rcvd, NULL, 0) < 0) {
704 		LOG_ERR("Invalid data received");
705 		ctx.code_status = UPDATEHUB_DOWNLOAD_ERROR;
706 		return;
707 	}
708 
709 	if (coap_header_get_code(&reply) == COAP_RESPONSE_CODE_NOT_FOUND) {
710 		LOG_INF("No update available");
711 		ctx.code_status = UPDATEHUB_NO_UPDATE;
712 		return;
713 	}
714 
715 	payload_start = coap_packet_get_payload(&reply, &payload_len);
716 	if (payload_len == 0) {
717 		LOG_ERR("Invalid payload received");
718 		ctx.code_status = UPDATEHUB_DOWNLOAD_ERROR;
719 		return;
720 	}
721 
722 	if (metadata_size < payload_len) {
723 		LOG_ERR("There is no buffer available");
724 		ctx.code_status = UPDATEHUB_METADATA_ERROR;
725 		return;
726 	}
727 
728 	memset(metadata, 0, metadata_size);
729 	memcpy(metadata, payload_start, payload_len);
730 
731 	/* ensures payload have a valid string with size lower
732 	 * than metadata_size
733 	 */
734 	tmp_len = strlen(metadata);
735 	if (tmp_len >= metadata_size) {
736 		LOG_ERR("Invalid metadata data received");
737 		ctx.code_status = UPDATEHUB_METADATA_ERROR;
738 		return;
739 	}
740 
741 	ctx.code_status = UPDATEHUB_OK;
742 
743 	LOG_INF("Probe metadata received");
744 }
745 
z_impl_updatehub_confirm(void)746 int z_impl_updatehub_confirm(void)
747 {
748 	return updatehub_storage_mark_partition_as_confirmed(UPDATEHUB_SLOT_PARTITION_0);
749 }
750 
z_impl_updatehub_reboot(void)751 int z_impl_updatehub_reboot(void)
752 {
753 	sys_reboot(SYS_REBOOT_WARM);
754 
755 	return 0;
756 }
757 
z_impl_updatehub_probe(void)758 enum updatehub_response z_impl_updatehub_probe(void)
759 {
760 	struct probe request;
761 	struct resp_probe_some_boards metadata_some_boards = { 0 };
762 	struct resp_probe_any_boards metadata_any_boards = { 0 };
763 
764 	char *metadata = k_malloc(MAX_DOWNLOAD_DATA);
765 	char *metadata_copy = k_malloc(MAX_DOWNLOAD_DATA);
766 	char *device_id = k_malloc(DEVICE_ID_HEX_MAX_SIZE);
767 	char *firmware_version = k_malloc(FIRMWARE_IMG_VER_STRLEN_MAX);
768 
769 	size_t sha256size;
770 
771 	if (device_id == NULL || firmware_version == NULL ||
772 	    metadata == NULL || metadata_copy == NULL) {
773 		LOG_ERR("Could not alloc probe memory");
774 		ctx.code_status = UPDATEHUB_METADATA_ERROR;
775 		goto error;
776 	}
777 
778 	if (!updatehub_storage_is_partition_good(&ctx.storage_ctx)) {
779 		LOG_ERR("The current image is not confirmed");
780 		ctx.code_status = UPDATEHUB_UNCONFIRMED_IMAGE;
781 		goto error;
782 	}
783 
784 	if (!updatehub_get_firmware_version(UPDATEHUB_SLOT_PARTITION_0,
785 					    firmware_version,
786 					    FIRMWARE_IMG_VER_STRLEN_MAX)) {
787 		ctx.code_status = UPDATEHUB_METADATA_ERROR;
788 		goto error;
789 	}
790 
791 	if (!updatehub_get_device_identity(device_id, DEVICE_ID_HEX_MAX_SIZE)) {
792 		ctx.code_status = UPDATEHUB_METADATA_ERROR;
793 		goto error;
794 	}
795 
796 	memset(&request, 0, sizeof(request));
797 	request.product_uid = CONFIG_UPDATEHUB_PRODUCT_UID;
798 	request.device_identity.id = device_id;
799 	request.version = firmware_version;
800 	request.hardware = CONFIG_BOARD;
801 
802 	memset(&ctx.payload, 0, MAX_PAYLOAD_SIZE);
803 	if (json_obj_encode_buf(send_probe_descr,
804 				ARRAY_SIZE(send_probe_descr),
805 				&request, ctx.payload,
806 				MAX_PAYLOAD_SIZE - 1) < 0) {
807 		LOG_ERR("Could not encode metadata");
808 		ctx.code_status = UPDATEHUB_METADATA_ERROR;
809 		goto error;
810 	}
811 
812 	ctx.nfds = 0;
813 
814 	if (!start_coap_client()) {
815 		ctx.code_status = UPDATEHUB_NETWORKING_ERROR;
816 		goto error;
817 	}
818 
819 	if (send_request(COAP_TYPE_CON, COAP_METHOD_POST, UPDATEHUB_PROBE) < 0) {
820 		ctx.code_status = UPDATEHUB_NETWORKING_ERROR;
821 		goto cleanup;
822 	}
823 
824 	probe_cb(metadata, MAX_DOWNLOAD_DATA);
825 
826 	if (ctx.code_status != UPDATEHUB_OK) {
827 		goto cleanup;
828 	}
829 
830 	memset(&update_info, 0, sizeof(update_info));
831 	if (metadata_hash_get(metadata) < 0) {
832 		LOG_ERR("Could not get metadata hash");
833 		ctx.code_status = UPDATEHUB_METADATA_ERROR;
834 		goto cleanup;
835 	}
836 
837 	LOG_DBG("metadata size: %d", strlen(metadata));
838 	LOG_HEXDUMP_DBG(metadata, MAX_DOWNLOAD_DATA, "metadata");
839 
840 	memcpy(metadata_copy, metadata, strlen(metadata));
841 	if (json_obj_parse(metadata, strlen(metadata),
842 			   recv_probe_sh_array_descr,
843 			   ARRAY_SIZE(recv_probe_sh_array_descr),
844 			   &metadata_some_boards) < 0) {
845 
846 		if (json_obj_parse(metadata_copy, strlen(metadata_copy),
847 				   recv_probe_sh_string_descr,
848 				   ARRAY_SIZE(recv_probe_sh_string_descr),
849 				   &metadata_any_boards) < 0) {
850 			LOG_ERR("Could not parse json");
851 			ctx.code_status = UPDATEHUB_METADATA_ERROR;
852 			goto cleanup;
853 		}
854 
855 		if (metadata_any_boards.objects_len != 2) {
856 			LOG_ERR("Could not parse json");
857 			ctx.code_status = UPDATEHUB_METADATA_ERROR;
858 			goto cleanup;
859 		}
860 
861 		sha256size = strlen(
862 			metadata_any_boards.objects[1].objects.sha256sum) + 1;
863 
864 		if (sha256size != SHA256_HEX_DIGEST_SIZE) {
865 			LOG_ERR("SHA256 size is invalid");
866 			ctx.code_status = UPDATEHUB_METADATA_ERROR;
867 			goto cleanup;
868 		}
869 
870 		memcpy(update_info.sha256sum_image,
871 		       metadata_any_boards.objects[1].objects.sha256sum,
872 		       SHA256_HEX_DIGEST_SIZE);
873 		update_info.image_size = metadata_any_boards.objects[1].objects.size;
874 		LOG_DBG("metadata_any: %s",
875 			update_info.sha256sum_image);
876 	} else {
877 		if (metadata_some_boards.objects_len != 2) {
878 			LOG_ERR("Could not parse json");
879 			ctx.code_status = UPDATEHUB_METADATA_ERROR;
880 			goto cleanup;
881 		}
882 
883 		if (!is_compatible_hardware(&metadata_some_boards)) {
884 			LOG_ERR("Incompatible hardware");
885 			ctx.code_status =
886 				UPDATEHUB_INCOMPATIBLE_HARDWARE;
887 			goto cleanup;
888 		}
889 
890 		sha256size = strlen(
891 			metadata_some_boards.objects[1].objects.sha256sum) + 1;
892 
893 		if (sha256size != SHA256_HEX_DIGEST_SIZE) {
894 			LOG_ERR("SHA256 size is invalid");
895 			ctx.code_status = UPDATEHUB_METADATA_ERROR;
896 			goto cleanup;
897 		}
898 
899 		memcpy(update_info.sha256sum_image,
900 		       metadata_some_boards.objects[1].objects.sha256sum,
901 		       SHA256_HEX_DIGEST_SIZE);
902 		update_info.image_size =
903 			metadata_some_boards.objects[1].objects.size;
904 		LOG_DBG("metadata_some: %s",
905 			update_info.sha256sum_image);
906 	}
907 
908 	ctx.code_status = UPDATEHUB_HAS_UPDATE;
909 
910 cleanup:
911 	cleanup_connection();
912 
913 error:
914 	k_free(metadata);
915 	k_free(metadata_copy);
916 	k_free(firmware_version);
917 	k_free(device_id);
918 
919 	return ctx.code_status;
920 }
921 
z_impl_updatehub_update(void)922 enum updatehub_response z_impl_updatehub_update(void)
923 {
924 	if (report(UPDATEHUB_STATE_DOWNLOADING) < 0) {
925 		LOG_ERR("Could not reporting downloading state");
926 		goto error;
927 	}
928 
929 	if (report(UPDATEHUB_STATE_INSTALLING) < 0) {
930 		LOG_ERR("Could not reporting installing state");
931 		goto error;
932 	}
933 
934 	if (install_update() != UPDATEHUB_OK) {
935 		goto error;
936 	}
937 
938 	if (report(UPDATEHUB_STATE_DOWNLOADED) < 0) {
939 		LOG_ERR("Could not reporting downloaded state");
940 		goto error;
941 	}
942 
943 	if (updatehub_storage_mark_partition_to_upgrade(&ctx.storage_ctx,
944 							UPDATEHUB_SLOT_PARTITION_1)) {
945 		LOG_ERR("Could not reporting downloaded state");
946 		ctx.code_status = UPDATEHUB_INSTALL_ERROR;
947 		goto error;
948 	}
949 
950 	if (report(UPDATEHUB_STATE_INSTALLED) < 0) {
951 		LOG_ERR("Could not reporting installed state");
952 		goto error;
953 	}
954 
955 	if (report(UPDATEHUB_STATE_REBOOTING) < 0) {
956 		LOG_ERR("Could not reporting rebooting state");
957 		goto error;
958 	}
959 
960 	LOG_INF("Image flashed successfully, you can reboot now");
961 
962 	return ctx.code_status;
963 
964 error:
965 	if (ctx.code_status != UPDATEHUB_NETWORKING_ERROR) {
966 		if (report(UPDATEHUB_STATE_ERROR) < 0) {
967 			LOG_ERR("Could not reporting error state");
968 		}
969 	}
970 
971 	return ctx.code_status;
972 }
973 
autohandler(struct k_work * work)974 static void autohandler(struct k_work *work)
975 {
976 	switch (updatehub_probe()) {
977 	case UPDATEHUB_UNCONFIRMED_IMAGE:
978 		LOG_ERR("Image is unconfirmed. Rebooting to revert back to previous"
979 			"confirmed image.");
980 
981 		LOG_PANIC();
982 		updatehub_reboot();
983 		break;
984 
985 	case UPDATEHUB_HAS_UPDATE:
986 		switch (updatehub_update()) {
987 		case UPDATEHUB_OK:
988 			LOG_PANIC();
989 			updatehub_reboot();
990 			break;
991 
992 		default:
993 			break;
994 		}
995 
996 		break;
997 
998 	case UPDATEHUB_NO_UPDATE:
999 		break;
1000 
1001 	default:
1002 		break;
1003 	}
1004 
1005 	k_work_reschedule(&updatehub_work_handle, UPDATEHUB_POLL_INTERVAL);
1006 }
1007 
z_impl_updatehub_autohandler(void)1008 void z_impl_updatehub_autohandler(void)
1009 {
1010 #if defined(CONFIG_UPDATEHUB_DOWNLOAD_SHA256_VERIFICATION)
1011 	LOG_INF("SHA-256 verification on download only");
1012 #endif
1013 #if defined(CONFIG_UPDATEHUB_STORAGE_SHA256_VERIFICATION)
1014 	LOG_INF("SHA-256 verification from flash only");
1015 #endif
1016 #if defined(CONFIG_UPDATEHUB_DOWNLOAD_STORAGE_SHA256_VERIFICATION)
1017 	LOG_INF("SHA-256 verification on download and from flash");
1018 #endif
1019 
1020 	k_work_init_delayable(&updatehub_work_handle, autohandler);
1021 	k_work_reschedule(&updatehub_work_handle, K_NO_WAIT);
1022 }
1023