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