1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11 #include <stdio.h>
12 #include <stdarg.h>
13
14 #include "nx_azure_iot.h"
15 #include "azure/core/internal/az_log_internal.h"
16
17 #ifndef NX_AZURE_IOT_WAIT_OPTION
18 #define NX_AZURE_IOT_WAIT_OPTION NX_WAIT_FOREVER
19 #endif /* NX_AZURE_IOT_WAIT_OPTION */
20
21 /* Convert number to upper hex. */
22 #define NX_AZURE_IOT_NUMBER_TO_UPPER_HEX(number) (CHAR)(number + (number < 10 ? '0' : 'A' - 10))
23
24 /* Define the prototypes for Azure RTOS IoT. */
25 NX_AZURE_IOT *_nx_azure_iot_created_ptr;
26
27 /* Define the callback for logging. */
28 static VOID(*_nx_azure_iot_log_callback)(az_log_classification classification, UCHAR *msg, UINT msg_len);
29
30 extern UINT _nxd_mqtt_client_packet_allocate(NXD_MQTT_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option);
31 extern UINT _nxd_mqtt_client_publish_packet_send(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr,
32 USHORT packet_id, UINT QoS, ULONG wait_option);
33
nx_azure_iot_event_process(VOID * nx_azure_iot,ULONG common_events,ULONG module_own_events)34 static VOID nx_azure_iot_event_process(VOID *nx_azure_iot, ULONG common_events, ULONG module_own_events)
35 {
36
37 NX_AZURE_IOT *nx_azure_iot_ptr = (NX_AZURE_IOT *)nx_azure_iot;
38
39 /* Process DPS events. */
40 if (nx_azure_iot_ptr -> nx_azure_iot_provisioning_client_event_process)
41 {
42 nx_azure_iot_ptr -> nx_azure_iot_provisioning_client_event_process(nx_azure_iot_ptr, common_events,
43 module_own_events);
44 }
45 }
46
nx_azure_iot_publish_packet_header_add(NX_PACKET * packet_ptr,UINT topic_len,UINT qos)47 static UINT nx_azure_iot_publish_packet_header_add(NX_PACKET* packet_ptr, UINT topic_len, UINT qos)
48 {
49 UCHAR *buffer_ptr;
50 UINT length;
51
52 /* Check if packet has enough space to write MQTT header. */
53 if (NX_AZURE_IOT_PUBLISH_PACKET_START_OFFSET >
54 (packet_ptr -> nx_packet_prepend_ptr - packet_ptr -> nx_packet_data_start))
55 {
56 return(NX_AZURE_IOT_INVALID_PACKET);
57 }
58
59 /* Start to fill MQTT header. */
60 buffer_ptr = packet_ptr -> nx_packet_prepend_ptr - NX_AZURE_IOT_PUBLISH_PACKET_START_OFFSET;
61
62 /* Set flags. */
63 buffer_ptr[0] = (UCHAR)(MQTT_CONTROL_PACKET_TYPE_PUBLISH << 4);
64 if (qos == NX_AZURE_IOT_MQTT_QOS_1)
65 {
66 buffer_ptr[0] |= MQTT_PUBLISH_QOS_LEVEL_1;
67 }
68
69 /* Set topic length. */
70 buffer_ptr[5] = (UCHAR)(topic_len >> 8);
71 buffer_ptr[6] = (UCHAR)(topic_len & 0xFF);
72
73 /* Set total length.
74 * 2 bytes for topic length.
75 * 2 bytes for packet id.
76 * data_size for payload.
77 *
78 * packet already contains topic length, packet id (optional) and data payload
79 */
80 length = packet_ptr -> nx_packet_length + 2;
81
82 /* Total length is encoded in fixed four bytes format. */
83 buffer_ptr[1] = (UCHAR)((length & 0x7F) | 0x80);
84 length >>= 7;
85 buffer_ptr[2] = (UCHAR)((length & 0x7F) | 0x80);
86 length >>= 7;
87 buffer_ptr[3] = (UCHAR)((length & 0x7F) | 0x80);
88 length >>= 7;
89 buffer_ptr[4] = (UCHAR)(length & 0x7F);
90
91 /* Update packet. */
92 packet_ptr -> nx_packet_prepend_ptr = buffer_ptr;
93 packet_ptr -> nx_packet_length += NX_AZURE_IOT_PUBLISH_PACKET_START_OFFSET;
94
95 return(NX_AZURE_IOT_SUCCESS);
96 }
97
nx_azure_iot_log(UCHAR * type_ptr,UINT type_len,UCHAR * msg_ptr,UINT msg_len,...)98 UINT nx_azure_iot_log(UCHAR *type_ptr, UINT type_len, UCHAR *msg_ptr, UINT msg_len, ...)
99 {
100 va_list ap;
101 UCHAR buffer[10] = { 0 };
102 az_span span;
103 az_span num_span;
104
105 span = az_span_create(type_ptr, (INT)type_len);
106 _az_LOG_WRITE(AZ_LOG_IOT_AZURERTOS, span);
107
108 if (msg_len >= 2 && (msg_ptr[msg_len - 2] == '%') &&
109 ((msg_ptr[msg_len - 1] == 'd') || (msg_ptr[msg_len - 1] == 's')))
110 {
111 span = az_span_create((UCHAR *)msg_ptr, (INT)(msg_len - 2));
112 _az_LOG_WRITE(AZ_LOG_IOT_AZURERTOS, span);
113
114 va_start(ap, msg_len);
115
116 /* Handles %d */
117 if (msg_ptr[msg_len - 1] == 'd')
118 {
119 num_span = az_span_create(buffer, sizeof(buffer));
120 if (!az_result_failed(az_span_u32toa(num_span, va_arg(ap, UINT), &span)))
121 {
122 num_span = az_span_slice(num_span, 0, (INT)sizeof(buffer) - az_span_size(span));
123 _az_LOG_WRITE(AZ_LOG_IOT_AZURERTOS, num_span);
124 }
125 }
126
127 /* Handles %s */
128 if (msg_ptr[msg_len - 1] == 's')
129 {
130 msg_ptr = va_arg(ap, UCHAR*);
131 msg_len = va_arg(ap, UINT);
132 span = az_span_create((UCHAR *)msg_ptr, (INT)msg_len);
133 _az_LOG_WRITE(AZ_LOG_IOT_AZURERTOS, span);
134 }
135
136 va_end(ap);
137 }
138 else
139 {
140 span = az_span_create((UCHAR *)msg_ptr, (INT)msg_len);
141 _az_LOG_WRITE(AZ_LOG_IOT_AZURERTOS, span);
142 }
143
144 _az_LOG_WRITE(AZ_LOG_IOT_AZURERTOS, AZ_SPAN_FROM_STR("\r\n"));
145
146 return(NX_AZURE_IOT_SUCCESS);
147 }
148
nx_azure_iot_log_listener(az_log_classification classification,az_span message)149 static VOID nx_azure_iot_log_listener(az_log_classification classification, az_span message)
150 {
151 NX_PARAMETER_NOT_USED(classification);
152
153 if (_nx_azure_iot_log_callback != NX_NULL)
154 {
155 _nx_azure_iot_log_callback(classification, az_span_ptr(message), (UINT)az_span_size(message));
156 }
157 }
158
nx_azure_iot_log_init(VOID (* log_callback)(az_log_classification classification,UCHAR * msg,UINT msg_len))159 VOID nx_azure_iot_log_init(VOID(*log_callback)(az_log_classification classification, UCHAR *msg, UINT msg_len))
160 {
161 _nx_azure_iot_log_callback = log_callback;
162 az_log_set_message_callback(nx_azure_iot_log_listener);
163 }
164
nx_azure_iot_resource_search(NXD_MQTT_CLIENT * client_ptr)165 NX_AZURE_IOT_RESOURCE *nx_azure_iot_resource_search(NXD_MQTT_CLIENT *client_ptr)
166 {
167 NX_AZURE_IOT_RESOURCE *resource_ptr;
168
169 /* Check if created Azure RTOS IoT. */
170 if ((_nx_azure_iot_created_ptr == NX_NULL) || (client_ptr == NX_NULL))
171 {
172 return(NX_NULL);
173 }
174
175 /* Loop to find the resource associated with current MQTT client. */
176 for (resource_ptr = _nx_azure_iot_created_ptr -> nx_azure_iot_resource_list_header;
177 resource_ptr; resource_ptr = resource_ptr -> resource_next)
178 {
179
180 if (&(resource_ptr -> resource_mqtt) == client_ptr)
181 {
182 return(resource_ptr);
183 }
184 }
185
186 return(NX_NULL);
187 }
188
nx_azure_iot_resource_add(NX_AZURE_IOT * nx_azure_iot_ptr,NX_AZURE_IOT_RESOURCE * resource_ptr)189 UINT nx_azure_iot_resource_add(NX_AZURE_IOT *nx_azure_iot_ptr, NX_AZURE_IOT_RESOURCE *resource_ptr)
190 {
191
192 resource_ptr -> resource_next = nx_azure_iot_ptr -> nx_azure_iot_resource_list_header;
193 nx_azure_iot_ptr -> nx_azure_iot_resource_list_header = resource_ptr;
194
195 return(NX_AZURE_IOT_SUCCESS);
196 }
197
nx_azure_iot_resource_remove(NX_AZURE_IOT * nx_azure_iot_ptr,NX_AZURE_IOT_RESOURCE * resource_ptr)198 UINT nx_azure_iot_resource_remove(NX_AZURE_IOT *nx_azure_iot_ptr, NX_AZURE_IOT_RESOURCE *resource_ptr)
199 {
200
201 NX_AZURE_IOT_RESOURCE *resource_previous;
202
203 if (nx_azure_iot_ptr -> nx_azure_iot_resource_list_header == NX_NULL)
204 {
205 return(NX_AZURE_IOT_NOT_FOUND);
206 }
207
208 if (nx_azure_iot_ptr -> nx_azure_iot_resource_list_header == resource_ptr)
209 {
210 nx_azure_iot_ptr -> nx_azure_iot_resource_list_header = nx_azure_iot_ptr -> nx_azure_iot_resource_list_header -> resource_next;
211 return(NX_AZURE_IOT_SUCCESS);
212 }
213
214 for (resource_previous = nx_azure_iot_ptr -> nx_azure_iot_resource_list_header;
215 resource_previous -> resource_next;
216 resource_previous = resource_previous -> resource_next)
217 {
218 if (resource_previous -> resource_next == resource_ptr)
219 {
220 resource_previous -> resource_next = resource_previous -> resource_next -> resource_next;
221 return(NX_AZURE_IOT_SUCCESS);
222 }
223 }
224
225 return(NX_AZURE_IOT_NOT_FOUND);
226 }
227
nx_azure_iot_create(NX_AZURE_IOT * nx_azure_iot_ptr,const UCHAR * name_ptr,NX_IP * ip_ptr,NX_PACKET_POOL * pool_ptr,NX_DNS * dns_ptr,VOID * stack_memory_ptr,UINT stack_memory_size,UINT priority,UINT (* unix_time_callback)(ULONG * unix_time))228 UINT nx_azure_iot_create(NX_AZURE_IOT *nx_azure_iot_ptr, const UCHAR *name_ptr,
229 NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, NX_DNS *dns_ptr,
230 VOID *stack_memory_ptr, UINT stack_memory_size,
231 UINT priority, UINT (*unix_time_callback)(ULONG *unix_time))
232 {
233 UINT status;
234
235 if ((nx_azure_iot_ptr == NX_NULL) || (ip_ptr == NX_NULL) ||
236 (pool_ptr == NX_NULL) || (dns_ptr == NX_NULL))
237 {
238 LogError(LogLiteralArgs("IoT create fail: INVALID POINTER"));
239 return(NX_AZURE_IOT_INVALID_PARAMETER);
240 }
241
242 nx_azure_iot_ptr -> nx_azure_iot_name = name_ptr;
243 nx_azure_iot_ptr -> nx_azure_iot_ip_ptr = ip_ptr;
244 nx_azure_iot_ptr -> nx_azure_iot_dns_ptr = dns_ptr;
245 nx_azure_iot_ptr -> nx_azure_iot_pool_ptr = pool_ptr;
246 nx_azure_iot_ptr -> nx_azure_iot_unix_time_get = unix_time_callback;
247
248 status = nx_cloud_create(&nx_azure_iot_ptr -> nx_azure_iot_cloud, (CHAR *)name_ptr, stack_memory_ptr,
249 stack_memory_size, priority);
250 if (status)
251 {
252 LogError(LogLiteralArgs("IoT create fail status: %d"), status);
253 return(status);
254 }
255
256 /* Register SDK module on cloud helper. */
257 status = nx_cloud_module_register(&(nx_azure_iot_ptr -> nx_azure_iot_cloud), &(nx_azure_iot_ptr -> nx_azure_iot_cloud_module),
258 "Azure SDK Module", NX_CLOUD_MODULE_AZURE_SDK_EVENT | NX_CLOUD_COMMON_PERIODIC_EVENT,
259 nx_azure_iot_event_process, nx_azure_iot_ptr);
260 if (status)
261 {
262 LogError(LogLiteralArgs("IoT module register fail status: %d"), status);
263 return(status);
264 }
265
266 /* Set the mutex. */
267 nx_azure_iot_ptr -> nx_azure_iot_mutex_ptr = &(nx_azure_iot_ptr -> nx_azure_iot_cloud.nx_cloud_mutex);
268
269 /* Set created IoT pointer. */
270 _nx_azure_iot_created_ptr = nx_azure_iot_ptr;
271
272 return(NX_AZURE_IOT_SUCCESS);
273 }
274
nx_azure_iot_delete(NX_AZURE_IOT * nx_azure_iot_ptr)275 UINT nx_azure_iot_delete(NX_AZURE_IOT *nx_azure_iot_ptr)
276 {
277 UINT status;
278
279 if (nx_azure_iot_ptr == NX_NULL)
280 {
281 LogError(LogLiteralArgs("IoT delete fail: INVALID POINTER"));
282 return(NX_AZURE_IOT_INVALID_PARAMETER);
283 }
284
285 if (nx_azure_iot_ptr -> nx_azure_iot_resource_list_header)
286 {
287 LogError(LogLiteralArgs("IoT delete fail: Resource NOT DELETED"));
288 return(NX_AZURE_IOT_DELETE_ERROR);
289 }
290
291 /* Deregister SDK module on cloud helper. */
292 nx_cloud_module_deregister(&(nx_azure_iot_ptr -> nx_azure_iot_cloud), &(nx_azure_iot_ptr -> nx_azure_iot_cloud_module));
293
294 /* Delete cloud. */
295 status = nx_cloud_delete(&nx_azure_iot_ptr -> nx_azure_iot_cloud);
296 if (status)
297 {
298 LogError(LogLiteralArgs("IoT delete fail status: %d"), status);
299 return(status);
300 }
301
302 _nx_azure_iot_created_ptr = NX_NULL;
303
304 return(NX_AZURE_IOT_SUCCESS);
305 }
306
nx_azure_iot_buffer_allocate(NX_AZURE_IOT * nx_azure_iot_ptr,UCHAR ** buffer_pptr,UINT * buffer_size,VOID ** buffer_context)307 UINT nx_azure_iot_buffer_allocate(NX_AZURE_IOT *nx_azure_iot_ptr, UCHAR **buffer_pptr,
308 UINT *buffer_size, VOID **buffer_context)
309 {
310 NX_PACKET *packet_ptr;
311 UINT status;
312
313 status = nx_packet_allocate(nx_azure_iot_ptr -> nx_azure_iot_pool_ptr,
314 &packet_ptr, 0, NX_AZURE_IOT_WAIT_OPTION);
315 if (status)
316 {
317 return(status);
318 }
319
320 *buffer_pptr = packet_ptr -> nx_packet_data_start;
321 *buffer_size = (UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_data_start);
322 *buffer_context = (VOID *)packet_ptr;
323 return(NX_AZURE_IOT_SUCCESS);
324 }
325
nx_azure_iot_buffer_free(VOID * buffer_context)326 UINT nx_azure_iot_buffer_free(VOID *buffer_context)
327 {
328 NX_PACKET *packet_ptr = (NX_PACKET *)buffer_context;
329
330 return(nx_packet_release(packet_ptr));
331 }
332
nx_azure_iot_publish_packet_get(NX_AZURE_IOT * nx_azure_iot_ptr,NXD_MQTT_CLIENT * client_ptr,NX_PACKET ** packet_pptr,UINT wait_option)333 UINT nx_azure_iot_publish_packet_get(NX_AZURE_IOT *nx_azure_iot_ptr, NXD_MQTT_CLIENT *client_ptr,
334 NX_PACKET **packet_pptr, UINT wait_option)
335 {
336 UINT status;
337
338 NX_PARAMETER_NOT_USED(nx_azure_iot_ptr);
339
340 status = _nxd_mqtt_client_packet_allocate(client_ptr, packet_pptr, wait_option);
341 if (status)
342 {
343 LogError(LogLiteralArgs("Create publish packet failed"));
344 return(status);
345 }
346
347 /* Preserve room for fixed MQTT header. */
348 (*packet_pptr) -> nx_packet_prepend_ptr += NX_AZURE_IOT_PUBLISH_PACKET_START_OFFSET;
349
350 return(NX_AZURE_IOT_SUCCESS);
351 }
352
nx_azure_iot_publish_mqtt_packet(NXD_MQTT_CLIENT * client_ptr,NX_PACKET * packet_ptr,UINT topic_len,UCHAR * packet_id,UINT qos,UINT wait_option)353 UINT nx_azure_iot_publish_mqtt_packet(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr,
354 UINT topic_len, UCHAR *packet_id, UINT qos, UINT wait_option)
355 {
356 UINT status;
357 USHORT id = 0;
358
359 status = nx_azure_iot_publish_packet_header_add(packet_ptr, topic_len, qos);
360 if (status)
361 {
362 LogError(LogLiteralArgs("failed to add mqtt header"));
363 return(status);
364 }
365
366 if (qos != 0)
367 {
368 id = (USHORT)((packet_id[0] << 8) | packet_id[1]);
369 }
370
371 /* Note, mutex will be released by this function. */
372 status = _nxd_mqtt_client_publish_packet_send(client_ptr, packet_ptr,
373 id, qos, wait_option);
374 if (status)
375 {
376 LogError(LogLiteralArgs("Mqtt client send fail: PUBLISH FAIL status: %d"), status);
377 return(status);
378 }
379
380 return(NX_AZURE_IOT_SUCCESS);
381 }
382
nx_azure_iot_mqtt_packet_id_get(NXD_MQTT_CLIENT * client_ptr,UCHAR * packet_id)383 UINT nx_azure_iot_mqtt_packet_id_get(NXD_MQTT_CLIENT *client_ptr, UCHAR *packet_id)
384 {
385 UINT status;
386
387 /* Get packet id under mutex */
388 status = tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, NX_WAIT_FOREVER);
389 if (status)
390 {
391 return(status);
392 }
393
394 /* Do nothing if the client is not connected. */
395 if (client_ptr -> nxd_mqtt_client_state != NXD_MQTT_CLIENT_STATE_CONNECTED)
396 {
397 tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr);
398 LogError(LogLiteralArgs("MQTT NOT CONNECTED"));
399 return(NX_AZURE_IOT_DISCONNECTED);
400 }
401
402 /* Internal API assuming it to be 2 Byte buffer */
403 packet_id[0] = (UCHAR)(client_ptr -> nxd_mqtt_client_packet_identifier >> 8);
404 packet_id[1] = (UCHAR)(client_ptr -> nxd_mqtt_client_packet_identifier & 0xFF);
405
406 /* Update packet id. */
407 client_ptr -> nxd_mqtt_client_packet_identifier = (client_ptr -> nxd_mqtt_client_packet_identifier + 1) & 0xFFFF;
408
409 /* Prevent packet identifier from being zero. MQTT-2.3.1-1. */
410 if(client_ptr -> nxd_mqtt_client_packet_identifier == 0)
411 {
412 client_ptr -> nxd_mqtt_client_packet_identifier = 1;
413 }
414
415 tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr);
416
417 return(NX_AZURE_IOT_SUCCESS);
418 }
419
nx_azure_iot_mqtt_packet_adjust(NX_PACKET * packet_ptr)420 VOID nx_azure_iot_mqtt_packet_adjust(NX_PACKET *packet_ptr)
421 {
422 UINT size;
423 UINT copy_size;
424 NX_PACKET *current_packet_ptr;
425
426 /* Adjust the packet to make sure,
427 * 1. nx_packet_prepend_ptr does not pointer to nx_packet_data_start.
428 * 2. The first packet is full if it is chained with multiple packets. */
429
430 if (packet_ptr -> nx_packet_prepend_ptr != packet_ptr -> nx_packet_data_start)
431 {
432
433 /* Move data to the nx_packet_data_start. */
434 size = (UINT)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr);
435 memmove(packet_ptr -> nx_packet_data_start, packet_ptr -> nx_packet_prepend_ptr, size); /* Use case of memmove is verified. */
436 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_data_start;
437 packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_data_start + size;
438 }
439
440 if (packet_ptr -> nx_packet_next == NX_NULL)
441 {
442
443 /* All data are in the first packet. */
444 return;
445 }
446
447 /* Move data in the chained packet into first one until it is full. */
448 for (current_packet_ptr = packet_ptr -> nx_packet_next;
449 current_packet_ptr;
450 current_packet_ptr = packet_ptr -> nx_packet_next)
451 {
452
453 /* Calculate remaining buffer size in the first packet. */
454 size = (UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_append_ptr);
455
456 /* Calculate copy size from current packet. */
457 copy_size = (UINT)(current_packet_ptr -> nx_packet_append_ptr - current_packet_ptr -> nx_packet_prepend_ptr);
458
459 if (size >= copy_size)
460 {
461
462 /* Copy all data from current packet. */
463 memcpy((VOID *)packet_ptr -> nx_packet_append_ptr, (VOID *)current_packet_ptr -> nx_packet_prepend_ptr, copy_size); /* Use case of memcpy is verified. */
464 packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_append_ptr + copy_size;
465 }
466 else
467 {
468
469 /* Copy partial data from current packet. */
470 memcpy(packet_ptr -> nx_packet_append_ptr, current_packet_ptr -> nx_packet_prepend_ptr, size); /* Use case of memcpy is verified. */
471 packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_data_end;
472
473 /* Move data in current packet to nx_packet_data_start. */
474 memmove((VOID *)current_packet_ptr -> nx_packet_data_start, /* Use case of memmove is verified. */
475 (VOID *)(current_packet_ptr -> nx_packet_prepend_ptr + size),
476 (copy_size - size));
477 current_packet_ptr -> nx_packet_prepend_ptr = current_packet_ptr -> nx_packet_data_start;
478 current_packet_ptr -> nx_packet_append_ptr = current_packet_ptr -> nx_packet_data_start + (copy_size - size);
479
480 /* First packet is full. */
481 break;
482 }
483
484 /* Remove current packet from packet chain. */
485 packet_ptr -> nx_packet_next = current_packet_ptr -> nx_packet_next;
486
487 /* Release current packet. */
488 current_packet_ptr -> nx_packet_next = NX_NULL;
489 nx_packet_release(current_packet_ptr);
490 }
491 }
492
nx_azure_iot_certificate_verify(NX_SECURE_TLS_SESSION * session,NX_SECURE_X509_CERT * certificate)493 static ULONG nx_azure_iot_certificate_verify(NX_SECURE_TLS_SESSION *session, NX_SECURE_X509_CERT* certificate)
494 {
495 NX_AZURE_IOT_RESOURCE *resource_ptr;
496 UINT old_threshold;
497 UINT status = NX_AZURE_IOT_SUCCESS;
498
499 /* Disable preemption. */
500 tx_thread_preemption_change(tx_thread_identify(), 0, &old_threshold);
501
502 /* Check if created Azure RTOS IoT. */
503 if (_nx_azure_iot_created_ptr == NX_NULL)
504 {
505
506 /* Restore preemption. */
507 tx_thread_preemption_change(tx_thread_identify(), old_threshold, &old_threshold);
508 return(NX_AZURE_IOT_NOT_INITIALIZED);
509 }
510
511 /* Get mutex */
512 status = tx_mutex_get(_nx_azure_iot_created_ptr -> nx_azure_iot_mutex_ptr, NX_WAIT_FOREVER);
513
514 /* Restore preemption. */
515 tx_thread_preemption_change(tx_thread_identify(), old_threshold, &old_threshold);
516 if (status)
517 {
518 return(status);
519 }
520
521 /* Loop to find the resource associated with current TLS session. */
522 for (resource_ptr = _nx_azure_iot_created_ptr -> nx_azure_iot_resource_list_header;
523 resource_ptr; resource_ptr = resource_ptr -> resource_next)
524 {
525
526 if (&(resource_ptr -> resource_mqtt.nxd_mqtt_tls_session) == session)
527 {
528 break;
529 }
530 }
531
532 if (resource_ptr)
533 {
534
535 /* Check DNS entry string. */
536 status = nx_secure_x509_common_name_dns_check(certificate,
537 resource_ptr -> resource_hostname,
538 resource_ptr -> resource_hostname_length);
539 if (status)
540 {
541 LogError(LogLiteralArgs("Error in certificate verification: DNS name did not match CN"));
542 }
543 }
544 else
545 {
546
547 /* TLS session not match. */
548 status = NX_AZURE_IOT_NOT_FOUND;
549 }
550
551 /* Release mutex. */
552 tx_mutex_put(_nx_azure_iot_created_ptr -> nx_azure_iot_mutex_ptr);
553
554 return(status);
555 }
556
557 #ifndef NX_AZURE_IOT_DISABLE_CERTIFICATE_DATE
nx_azure_iot_tls_time_function(VOID)558 static ULONG nx_azure_iot_tls_time_function(VOID)
559 {
560 ULONG unix_time = 0;
561 UINT old_threshold;
562
563 /* Disable preemption. */
564 tx_thread_preemption_change(tx_thread_identify(), 0, &old_threshold);
565
566 if (nx_azure_iot_unix_time_get(_nx_azure_iot_created_ptr, &unix_time))
567 {
568
569 /* Unable to get Unix time. */
570 LogError(LogLiteralArgs("Unable to get Unix time"));
571 unix_time = 0;
572 }
573
574 /* Restore preemption. */
575 tx_thread_preemption_change(tx_thread_identify(), old_threshold, &old_threshold);
576 return(unix_time);
577 }
578 #endif /* NX_AZURE_IOT_DISABLE_CERTIFICATE_DATE */
579
nx_azure_iot_mqtt_tls_setup(NXD_MQTT_CLIENT * client_ptr,NX_SECURE_TLS_SESSION * tls_session,NX_SECURE_X509_CERT * certificate,NX_SECURE_X509_CERT * trusted_certificate)580 UINT nx_azure_iot_mqtt_tls_setup(NXD_MQTT_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *tls_session,
581 NX_SECURE_X509_CERT *certificate,
582 NX_SECURE_X509_CERT *trusted_certificate)
583 {
584 UINT status;
585 UINT i;
586 NX_AZURE_IOT_RESOURCE *resource_ptr;
587
588 NX_PARAMETER_NOT_USED(certificate);
589 NX_PARAMETER_NOT_USED(trusted_certificate);
590
591 /* Obtain the mutex. */
592 tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, TX_WAIT_FOREVER);
593
594 resource_ptr = nx_azure_iot_resource_search(client_ptr);
595
596 /* Release the mutex. */
597 tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr);
598
599 if (resource_ptr == NX_NULL)
600 {
601 LogError(LogLiteralArgs("Failed to find associated resource"));
602 return(NX_AZURE_IOT_INVALID_PARAMETER);
603 }
604
605 /* Create TLS session. */
606 status = _nx_secure_tls_session_create_ext(tls_session,
607 resource_ptr -> resource_crypto_array,
608 resource_ptr -> resource_crypto_array_size,
609 resource_ptr -> resource_cipher_map,
610 resource_ptr -> resource_cipher_map_size,
611 resource_ptr -> resource_metadata_ptr,
612 resource_ptr -> resource_metadata_size);
613 if (status)
614 {
615 LogError(LogLiteralArgs("Failed to create TLS session status: %d"), status);
616 return(status);
617 }
618
619 for (i = 0; i < NX_AZURE_IOT_ARRAY_SIZE(resource_ptr -> resource_trusted_certificates); i++)
620 {
621 if (resource_ptr -> resource_trusted_certificates[i])
622 {
623 status = nx_secure_tls_trusted_certificate_add(tls_session, resource_ptr -> resource_trusted_certificates[i]);
624 if (status)
625 {
626 LogError(LogLiteralArgs("Failed to add trusted CA certificate to session status: %d"), status);
627 return(status);
628 }
629 }
630 }
631
632 for (i = 0; i < NX_AZURE_IOT_ARRAY_SIZE(resource_ptr -> resource_device_certificates); i++)
633 {
634 if (resource_ptr -> resource_device_certificates[i])
635 {
636 status = nx_secure_tls_local_certificate_add(tls_session, resource_ptr -> resource_device_certificates[i]);
637 if (status)
638 {
639 LogError(LogLiteralArgs("Failed to add device certificate to session status: %d"), status);
640 return(status);
641 }
642 }
643 }
644
645 status = nx_secure_tls_session_packet_buffer_set(tls_session,
646 resource_ptr -> resource_tls_packet_buffer,
647 sizeof(resource_ptr -> resource_tls_packet_buffer));
648 if (status)
649 {
650 LogError(LogLiteralArgs("Failed to set the session packet buffer: status: %d"), status);
651 return(status);
652 }
653
654 /* Setup the callback invoked when TLS has a certificate it wants to verify so we can
655 do additional checks not done automatically by TLS. */
656 status = nx_secure_tls_session_certificate_callback_set(tls_session,
657 nx_azure_iot_certificate_verify);
658 if (status)
659 {
660 LogError(LogLiteralArgs("Failed to set the session certificate callback: status: %d"), status);
661 return(status);
662 }
663
664 #ifndef NX_AZURE_IOT_DISABLE_CERTIFICATE_DATE
665 /* Setup the callback function used by checking certificate valid date. */
666 nx_secure_tls_session_time_function_set(tls_session, nx_azure_iot_tls_time_function);
667 #endif /* NX_AZURE_IOT_DISABLE_CERTIFICATE_DATE */
668
669 return(NX_AZURE_IOT_SUCCESS);
670 }
671
nx_azure_iot_unix_time_get(NX_AZURE_IOT * nx_azure_iot_ptr,ULONG * unix_time)672 UINT nx_azure_iot_unix_time_get(NX_AZURE_IOT *nx_azure_iot_ptr, ULONG *unix_time)
673 {
674
675 if ((nx_azure_iot_ptr == NX_NULL) ||
676 (nx_azure_iot_ptr -> nx_azure_iot_unix_time_get == NX_NULL) ||
677 (unix_time == NX_NULL))
678 {
679 LogError(LogLiteralArgs("Unix time callback not set"));
680 return(NX_AZURE_IOT_INVALID_PARAMETER);
681 }
682
683 return(nx_azure_iot_ptr -> nx_azure_iot_unix_time_get(unix_time));
684 }
685
686 /* HMAC-SHA256(master key, message ) */
nx_azure_iot_hmac_sha256_calculate(NX_AZURE_IOT_RESOURCE * resource_ptr,UCHAR * key,UINT key_size,const UCHAR * message,UINT message_size,UCHAR * output)687 static UINT nx_azure_iot_hmac_sha256_calculate(NX_AZURE_IOT_RESOURCE *resource_ptr, UCHAR *key, UINT key_size,
688 const UCHAR *message, UINT message_size, UCHAR *output)
689 {
690 UINT i;
691 UINT status;
692 VOID *handler;
693 UCHAR *metadata_ptr = resource_ptr -> resource_metadata_ptr;
694 UINT metadata_size = resource_ptr -> resource_metadata_size;
695 const NX_CRYPTO_METHOD *hmac_sha_256_crypto_method = NX_NULL;
696
697
698 /* Find hmac sha256 crypto method. */
699 for(i = 0; i < resource_ptr -> resource_crypto_array_size; i++)
700 {
701 if(resource_ptr -> resource_crypto_array[i] -> nx_crypto_algorithm == NX_CRYPTO_AUTHENTICATION_HMAC_SHA2_256)
702 {
703 hmac_sha_256_crypto_method = resource_ptr -> resource_crypto_array[i];
704 break;
705 }
706 }
707
708 /* Check if find the crypto method. */
709 if (hmac_sha_256_crypto_method == NX_NULL)
710 {
711 return(NX_AZURE_IOT_NO_AVAILABLE_CIPHER);
712 }
713
714 /* Initialize. */
715 status = hmac_sha_256_crypto_method -> nx_crypto_init((NX_CRYPTO_METHOD *)hmac_sha_256_crypto_method,
716 key, (key_size << 3),
717 &handler,
718 metadata_ptr,
719 metadata_size);
720 if (status)
721 {
722 return(status);
723 }
724
725 /* Authenticate. */
726 status = hmac_sha_256_crypto_method -> nx_crypto_operation(NX_CRYPTO_AUTHENTICATE,
727 handler,
728 (NX_CRYPTO_METHOD *)hmac_sha_256_crypto_method,
729 key,
730 (key_size << 3),
731 (VOID *)message,
732 message_size,
733 NX_CRYPTO_NULL,
734 output,
735 32,
736 metadata_ptr,
737 metadata_size,
738 NX_CRYPTO_NULL,
739 NX_CRYPTO_NULL);
740 if (status)
741 {
742 return(status);
743 }
744
745 /* Cleanup. */
746 status = hmac_sha_256_crypto_method -> nx_crypto_cleanup(metadata_ptr);
747
748 return(status);
749 }
750
nx_azure_iot_base64_hmac_sha256_calculate(NX_AZURE_IOT_RESOURCE * resource_ptr,const UCHAR * key_ptr,UINT key_size,const UCHAR * message_ptr,UINT message_size,UCHAR * buffer_ptr,UINT buffer_len,UCHAR ** output_pptr,UINT * output_len_ptr)751 UINT nx_azure_iot_base64_hmac_sha256_calculate(NX_AZURE_IOT_RESOURCE *resource_ptr,
752 const UCHAR *key_ptr, UINT key_size,
753 const UCHAR *message_ptr, UINT message_size,
754 UCHAR *buffer_ptr, UINT buffer_len,
755 UCHAR **output_pptr, UINT *output_len_ptr)
756 {
757 UINT status;
758 UCHAR *hash_buf;
759 UINT hash_buf_size = 33;
760 UCHAR *encoded_hash_buf;
761 UINT encoded_hash_buf_size = 48;
762 UINT encoded_hash_size;
763 UINT binary_key_buf_size;
764
765 binary_key_buf_size = buffer_len;
766 status = _nx_utility_base64_decode((UCHAR *)key_ptr, key_size,
767 buffer_ptr, binary_key_buf_size, &binary_key_buf_size);
768 if (status)
769 {
770 LogError(LogLiteralArgs("Failed to base64 decode"));
771 return(status);
772 }
773
774 buffer_len -= binary_key_buf_size;
775 if ((hash_buf_size + encoded_hash_buf_size) > buffer_len)
776 {
777 LogError(LogLiteralArgs("Failed to not enough memory"));
778 return(NX_AZURE_IOT_INSUFFICIENT_BUFFER_SPACE);
779 }
780
781 hash_buf = buffer_ptr + binary_key_buf_size;
782 status = nx_azure_iot_hmac_sha256_calculate(resource_ptr, buffer_ptr, binary_key_buf_size,
783 message_ptr, (UINT)message_size, hash_buf);
784 if (status)
785 {
786 LogError(LogLiteralArgs("Failed to get hash256"));
787 return(status);
788 }
789
790 buffer_len -= hash_buf_size;
791 encoded_hash_buf = hash_buf + hash_buf_size;
792
793 /* Additional space is required by encoder. */
794 hash_buf[hash_buf_size - 1] = 0;
795 status = _nx_utility_base64_encode(hash_buf, hash_buf_size - 1,
796 encoded_hash_buf, encoded_hash_buf_size, &encoded_hash_size);
797 if (status)
798 {
799 LogError(LogLiteralArgs("Failed to base64 encode"));
800 return(status);
801 }
802
803 *output_pptr = encoded_hash_buf;
804 *output_len_ptr = encoded_hash_size;
805
806 return(NX_AZURE_IOT_SUCCESS);
807 }
808