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 
13 #include "nx_api.h"
14 #include "nx_azure_iot_hub_client.h"
15 #include "nx_azure_iot_cert.h"
16 #include "nx_azure_iot_ciphersuites.h"
17 
18 
19 #define DEMO_DHCP_DISABLE
20 #define DEMO_IPV4_ADDRESS         IP_ADDRESS(192, 168, 100, 33)
21 #define DEMO_IPV4_MASK            0xFFFFFF00UL
22 #define DEMO_GATEWAY_ADDRESS      IP_ADDRESS(192, 168, 100, 1)
23 #define DEMO_DNS_SERVER_ADDRESS   IP_ADDRESS(192, 168, 100, 1)
24 #define NETWORK_DRIVER            _nx_ram_network_driver
25 
26 /* Include main.c in the test case since we need to disable DHCP in this test. */
27 #include "main.c"
28 
29 
30 #define STRING_UNSIGNED_ARGS(s) (UCHAR *)s, strlen(s)
31 
32 #ifndef DEMO_CLOUD_STACK_SIZE
33 #define DEMO_CLOUD_STACK_SIZE   2048
34 #endif /* DEMO_CLOUD_STACK_SIZE */
35 
36 #ifndef DEMO_CLOUD_THREAD_PRIORITY
37 #define DEMO_CLOUD_THREAD_PRIORITY  (4)
38 #endif /* DEMO_CLOUD_THREAD_PRIORITY */
39 
40 static VOID connection_status_cb(struct NX_AZURE_IOT_HUB_CLIENT_STRUCT *hub_client_ptr, UINT status);
41 
42 static NX_AZURE_IOT iot;
43 static NX_AZURE_IOT_HUB_CLIENT iot_client;
44 static NX_SECURE_X509_CERT root_ca_cert;
45 static UCHAR metadata_buffer[NX_AZURE_IOT_TLS_METADATA_BUFFER_SIZE];
46 static ULONG demo_cloud_thread_stack[DEMO_CLOUD_STACK_SIZE / sizeof(ULONG)];
47 extern int g_argc;
48 extern char **g_argv;
49 
demo_entry(NX_IP * ip_ptr,NX_PACKET_POOL * pool_ptr,NX_DNS * dns_ptr,UINT (* unix_time_callback)(ULONG * unix_time))50 VOID demo_entry(NX_IP* ip_ptr, NX_PACKET_POOL* pool_ptr, NX_DNS* dns_ptr, UINT (*unix_time_callback)(ULONG *unix_time))
51 {
52 CHAR *host_name = "host_name";
53 CHAR *device_id = "device_id";
54 CHAR *module_id = "module_id";
55 CHAR *symmetric_key = "symmetric_key";
56 UINT i;
57 ULONG pool_ptr_available_packet;
58 
59     /* Initialize root certificate.  */
60     assert_int_equal(nx_secure_x509_certificate_initialize(&root_ca_cert, (UCHAR *)_nx_azure_iot_root_cert, (USHORT)_nx_azure_iot_root_cert_size,
61                                                            NX_NULL, 0, NULL, 0, NX_SECURE_X509_KEY_TYPE_NONE),
62                      NX_AZURE_IOT_SUCCESS);
63 
64     assert_int_equal(nx_azure_iot_create(&iot, (UCHAR *)"Azure IoT", ip_ptr, pool_ptr, dns_ptr, (UCHAR *)demo_cloud_thread_stack,
65                                          sizeof(demo_cloud_thread_stack), DEMO_CLOUD_THREAD_PRIORITY, unix_time_callback),
66                      NX_AZURE_IOT_SUCCESS);
67 
68     /* Record number of available packet before test */
69     pool_ptr_available_packet = pool_ptr -> nx_packet_pool_available;
70 
71     assert_int_equal(nx_azure_iot_hub_client_initialize(&iot_client, &iot,
72                                                         STRING_UNSIGNED_ARGS(host_name),
73                                                         STRING_UNSIGNED_ARGS(device_id),
74                                                         NX_NULL, 0,
75                                                         _nx_azure_iot_tls_supported_crypto,
76                                                         _nx_azure_iot_tls_supported_crypto_size,
77                                                         _nx_azure_iot_tls_ciphersuite_map,
78                                                         _nx_azure_iot_tls_ciphersuite_map_size,
79                                                         metadata_buffer, sizeof(metadata_buffer),
80                                                         &root_ca_cert),
81                      NX_AZURE_IOT_SUCCESS);
82 
83     /* Setup callback function. */
84     /* FAIL: NX_AZURE_IOT_HUB_CLIENT pointer is null. */
85     assert_int_not_equal(nx_azure_iot_hub_client_connection_status_callback_set(NX_NULL, connection_status_cb),
86                          NX_AZURE_IOT_SUCCESS);
87 
88     /* SUCCESS: Setup callback function. */
89     assert_int_equal(nx_azure_iot_hub_client_connection_status_callback_set(&iot_client, connection_status_cb),
90                      NX_AZURE_IOT_SUCCESS);
91 
92     /* Setup Setup model Id. */
93     /* FAIL: NX_AZURE_IOT_HUB_CLIENT pointer is null. */
94     assert_int_not_equal(nx_azure_iot_hub_client_model_id_set(NX_NULL, STRING_UNSIGNED_ARGS("test::pnp")),
95                          NX_AZURE_IOT_SUCCESS);
96 
97     /* SUCCESS: Setup model Id. */
98     assert_int_equal(nx_azure_iot_hub_client_model_id_set(&iot_client, STRING_UNSIGNED_ARGS("test::pnp")),
99                      NX_AZURE_IOT_SUCCESS);
100 
101     /* Setup Setup symmetric key. */
102     /* FAIL: NX_AZURE_IOT_HUB_CLIENT pointer is null. */
103     assert_int_not_equal(nx_azure_iot_hub_client_symmetric_key_set(NX_NULL, STRING_UNSIGNED_ARGS("SGVsbG8gdGhpcyBpcyB0ZXN0")),
104                          NX_AZURE_IOT_SUCCESS);
105 
106     /* SUCCESS: Setup Setup symmetric key. */
107     assert_int_equal(nx_azure_iot_hub_client_symmetric_key_set(&iot_client, STRING_UNSIGNED_ARGS("SGVsbG8gdGhpcyBpcyB0ZXN0")),
108                      NX_AZURE_IOT_SUCCESS);
109 
110     /*********** Test nx_azure_iot_hub_client_connect() ***********/
111     /* FAIL: NX_AZURE_IOT_HUB_CLIENT pointer is null. */
112     assert_int_not_equal(nx_azure_iot_hub_client_connect(NX_NULL, NX_FALSE, 20 * NX_IP_PERIODIC_RATE),
113                          NX_AZURE_IOT_SUCCESS);
114 
115     /* FAIL: nx_azure_iot_ptr is null. */
116     iot_client.nx_azure_iot_ptr = NX_NULL;
117     assert_int_not_equal(nx_azure_iot_hub_client_connect(&iot_client, NX_FALSE, 20 * NX_IP_PERIODIC_RATE),
118                          NX_AZURE_IOT_SUCCESS);
119     iot_client.nx_azure_iot_ptr = &iot;
120 
121     /* FAIL: Invalid value of nx_azure_iot_hub_client_state. */
122     iot_client.nx_azure_iot_hub_client_state = NX_AZURE_IOT_HUB_CLIENT_STATUS_CONNECTED;
123     assert_int_equal(nx_azure_iot_hub_client_connect(&iot_client, NX_FALSE, 20 * NX_IP_PERIODIC_RATE),
124                      NX_AZURE_IOT_ALREADY_CONNECTED);
125     iot_client.nx_azure_iot_hub_client_state = NX_AZURE_IOT_HUB_CLIENT_STATUS_CONNECTING;
126     assert_int_equal(nx_azure_iot_hub_client_connect(&iot_client, NX_FALSE, 20 * NX_IP_PERIODIC_RATE),
127                      NX_AZURE_IOT_CONNECTING);
128     iot_client.nx_azure_iot_hub_client_state = NX_AZURE_IOT_HUB_CLIENT_STATUS_NOT_CONNECTED;
129 
130     /* FAIL: nxd_dns_host_by_name_get will fail by hijacked function. */
131     will_return(__wrap__nxde_dns_host_by_name_get, NX_DNS_PARAM_ERROR);
132     assert_int_not_equal(nx_azure_iot_hub_client_connect(&iot_client, NX_FALSE, 20 * NX_IP_PERIODIC_RATE),
133                          NX_AZURE_IOT_SUCCESS);
134     will_return_always(__wrap__nxde_dns_host_by_name_get, NXD_MQTT_SUCCESS);
135 
136     /* TODO: add more test points for packet buffer. */
137 
138     /* FAIL: nxd_mqtt_client_secure_connect will fail by hijacked function. */
139     will_return(__wrap__nxde_mqtt_client_secure_connect, NXD_MQTT_INVALID_PARAMETER);
140     expect_value(connection_status_cb, status, NXD_MQTT_INVALID_PARAMETER);
141     assert_int_not_equal(nx_azure_iot_hub_client_connect(&iot_client, NX_FALSE, 20 * NX_IP_PERIODIC_RATE),
142                          NX_AZURE_IOT_SUCCESS);
143 
144     /* SUCCESS: connected. */
145     will_return_always(__wrap__nxde_mqtt_client_secure_connect, NXD_MQTT_SUCCESS);
146     expect_value(connection_status_cb, status, NX_AZURE_IOT_SUCCESS);
147     assert_int_equal(nx_azure_iot_hub_client_connect(&iot_client, NX_FALSE, 20 * NX_IP_PERIODIC_RATE),
148                      NX_AZURE_IOT_SUCCESS);
149 
150     /*********** Test nx_azure_iot_hub_client_disconnect() ***********/
151     /* FAIL: NX_AZURE_IOT_HUB_CLIENT pointer is null. */
152     assert_int_not_equal(nx_azure_iot_hub_client_disconnect(NX_NULL), NX_AZURE_IOT_SUCCESS);
153 
154     /* FAIL: nxd_mqtt_client_disconnect will fail by hijacked function. */
155     will_return(__wrap__nxde_mqtt_client_disconnect, NXD_MQTT_INVALID_PARAMETER);
156     assert_int_not_equal(nx_azure_iot_hub_client_disconnect(&iot_client), NX_AZURE_IOT_SUCCESS);
157     will_return_always(__wrap__nxde_mqtt_client_disconnect, NXD_MQTT_SUCCESS);
158 
159     /* SUCCESS: disconnected. */
160     assert_int_equal(nx_azure_iot_hub_client_disconnect(&iot_client), NX_AZURE_IOT_SUCCESS);
161 
162     /* Try reconnect. */
163     expect_value(connection_status_cb, status, NX_AZURE_IOT_SUCCESS);
164     assert_int_equal(nx_azure_iot_hub_client_connect(&iot_client, NX_FALSE, 20 * NX_IP_PERIODIC_RATE),
165                      NX_AZURE_IOT_SUCCESS);
166 
167     /* SUCCESS: disconnected. */
168     assert_int_equal(nx_azure_iot_hub_client_disconnect(&iot_client), NX_AZURE_IOT_SUCCESS);
169 
170     /*********** End Test ***********/
171 
172     assert_int_equal(nx_azure_iot_hub_client_deinitialize(&iot_client),
173                      NX_AZURE_IOT_SUCCESS);
174 
175     /* Check if all the packet are released */
176     assert_int_equal(pool_ptr -> nx_packet_pool_available, pool_ptr_available_packet);
177 
178     assert_int_equal(nx_azure_iot_delete(&iot), NX_AZURE_IOT_SUCCESS);
179 }
180 
__wrap__nxde_dns_host_by_name_get(NX_DNS * dns_ptr,UCHAR * host_name,NXD_ADDRESS * host_address_ptr,ULONG wait_option,UINT lookup_type)181 UINT  __wrap__nxde_dns_host_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, NXD_ADDRESS *host_address_ptr,
182                                         ULONG wait_option, UINT lookup_type)
183 {
184 UINT status = (UINT)mock();
185 
186     printf("HIJACKED: %s\n", __func__);
187     if (status)
188     {
189         return(status);
190     }
191 
192     assert_memory_equal(host_name, "host_name", strlen("host_name"));
193     host_address_ptr -> nxd_ip_address.v4 = IP_ADDRESS(127, 0, 0, 1);
194     return(status);
195 }
196 
__wrap__nxde_mqtt_client_secure_connect(NXD_MQTT_CLIENT * client_ptr,NXD_ADDRESS * server_ip,UINT server_port,UINT (* tls_setup)(NXD_MQTT_CLIENT * client_ptr,NX_SECURE_TLS_SESSION *,NX_SECURE_X509_CERT *,NX_SECURE_X509_CERT *),UINT keepalive,UINT clean_session,ULONG wait_option)197 UINT __wrap__nxde_mqtt_client_secure_connect(NXD_MQTT_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port,
198                                              UINT (*tls_setup)(NXD_MQTT_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *,
199                                                                NX_SECURE_X509_CERT *, NX_SECURE_X509_CERT *),
200                                              UINT keepalive, UINT clean_session, ULONG wait_option)
201 {
202 UINT status = (UINT)mock();
203 
204     printf("HIJACKED: %s\n", __func__);
205     if (status)
206     {
207         return(status);
208     }
209 
210     client_ptr -> nxd_mqtt_client_state = NXD_MQTT_CLIENT_STATE_CONNECTED;
211     return(status);
212 }
213 
__wrap__nxde_mqtt_client_disconnect(NXD_MQTT_CLIENT * client_ptr)214 UINT __wrap__nxde_mqtt_client_disconnect(NXD_MQTT_CLIENT *client_ptr)
215 {
216 UINT status = (UINT)mock();
217 
218     printf("HIJACKED: %s\n", __func__);
219     if (status)
220     {
221         return(status);
222     }
223     client_ptr -> nxd_mqtt_client_state = NXD_MQTT_CLIENT_STATE_IDLE;
224     return(status);
225 }
226 
connection_status_cb(struct NX_AZURE_IOT_HUB_CLIENT_STRUCT * hub_client_ptr,UINT status)227 static VOID connection_status_cb(struct NX_AZURE_IOT_HUB_CLIENT_STRUCT *hub_client_ptr, UINT status)
228 {
229     assert_ptr_equal(hub_client_ptr, &iot_client);
230     check_expected(status);
231 }
232 
__wrap_nx_azure_iot_security_module_enable(NX_AZURE_IOT * nx_azure_iot_ptr)233 UINT __wrap_nx_azure_iot_security_module_enable(NX_AZURE_IOT *nx_azure_iot_ptr)
234 {
235     printf("HIJACKED: %s\n", __func__);
236     return(NX_AZURE_IOT_SUCCESS);
237 }
238 
__wrap_nx_azure_iot_security_module_disable(NX_AZURE_IOT * nx_azure_iot_ptr)239 UINT __wrap_nx_azure_iot_security_module_disable(NX_AZURE_IOT *nx_azure_iot_ptr)
240 {
241     printf("HIJACKED: %s\n", __func__);
242     return(NX_AZURE_IOT_SUCCESS);
243 }
244