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