1 /* This is a small demo of the NetX HTTP Client Server API running on a
2    high-performance NetX TCP/IP stack.  */
3 
4 #include   "tx_api.h"
5 #include   "nx_api.h"
6 /* If not using FileX, define this option and define the file writing services
7    declared in filex_stub.h.
8 #define      NX_WEB_HTTP_NO_FILEX
9 */
10 #ifndef      NX_WEB_HTTP_NO_FILEX
11 #include    "fx_api.h"
12 #else
13 #include    "filex_stub.h"
14 #endif
15 
16 #include   "nx_web_http_client.h"
17 #include   "nx_web_http_server.h"
18 
19 
20 #include "tx_api.h"
21 #include "nx_api.h"
22 #include "nx_crypto.h"
23 #include "nx_secure_tls_api.h"
24 #include "nx_secure_dtls_api.h"
25 #include "nx_secure_x509.h"
26 #include "test_utility.h"
27 
28 
29 /* For NetX Duo applications, determine which IP version to use. For IPv6,
30    set IP_TYPE to 6; for IPv4 set to 4. Note that for IPv6, you must enable
31    USE_DUO so the application 'knows' to enabled IPv6 services on the IP task.  */
32 
33 #ifdef NX_DISABLE_IPV4
34 #define     IP_TYPE     6
35 #else
36 #define     IP_TYPE     4
37 #endif /* NX_DISABLE_IPV4 */
38 
39 
40 #define     DEMO_STACK_SIZE         4096
41 
42 /* Replace the 'ram' driver with your Ethernet driver. */
43 VOID        _nx_ram_network_driver(NX_IP_DRIVER *driver_req_ptr);
44 
45 static UINT authentication_check(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type,
46                                  CHAR *resource, CHAR **name, CHAR **password, CHAR **realm);
47 
48 /* Set up the HTTP client global variables. */
49 
50 NX_SECURE_TLS_SESSION client_tls_session;
51 TX_THREAD       client_thread;
52 NX_WEB_HTTPS_CLIENT  my_client;
53 #define         CLIENT_PACKET_SIZE  (NX_WEB_HTTP_SERVER_MIN_PACKET_SIZE * 2)
54 
55 
56 /* Set up the HTTP server global variables */
57 
58 NX_SECURE_TLS_SESSION server_tls_session;
59 NX_WEB_HTTP_SERVER  my_server;
60 NX_PACKET_POOL  server_pool;
61 NX_PACKET_POOL  client_pool;
62 TX_THREAD       server_thread;
63 NX_IP           server_ip;
64 NX_IP           client_ip;
65 
66 NXD_ADDRESS     server_ip_address;
67 #define         SERVER_PACKET_SIZE  (NX_WEB_HTTP_SERVER_MIN_PACKET_SIZE * 2)
68 
69 void https_server_thread_entry(ULONG thread_input);
70 void https_client_thread_entry(ULONG thread_input);
71 
72 /* HTTPS/TLS setup. */
73 
74 #include "test_device_cert.c"
75 
76 #include "test_ca_cert.c"
77 #define ca_cert_der test_ca_cert_der
78 #define ca_cert_der_len test_ca_cert_der_len
79 
80 static CHAR crypto_metadata[8928 * NX_WEB_HTTP_SERVER_SESSION_MAX];
81 static UCHAR tls_packet_buffer[18500];
82 static NX_SECURE_X509_CERT certificate;
83 static NX_SECURE_X509_CERT trusted_certificate;
84 static NX_SECURE_X509_CERT remote_certificate, remote_issuer;
85 static UCHAR remote_cert_buffer[2000];
86 static UCHAR remote_issuer_buffer[2000];
87 
88 /* Define the RAM disk memory.  */
89 static UCHAR media_memory[4096];
90 static CHAR ram_disk_memory[4096];
91 static FX_MEDIA ram_disk;
92 
93 static UCHAR server_stack[16000];
94 
95 extern const NX_SECURE_TLS_CRYPTO nx_crypto_tls_ciphers;
96 
97 /* Gateway IP address - if needed! */
98 //#define GATEWAY_IP_ADDRESS IP_ADDRESS(192, 168, 1, 1)
99 
100 
101 /* Google.com IP address. */
102 //#define HTTP_SERVER_ADDRESS  IP_ADDRESS(172,217,11,174)
103 
104 /* Local IP address. */
105 #define HTTP_SERVER_ADDRESS  IP_ADDRESS(192, 168, 1, 150)
106 #define HTTP_CLIENT_ADDRESS  IP_ADDRESS(192, 168, 1, 151)
107 
108 VOID    _fx_ram_driver(FX_MEDIA *media_ptr) ;
109 VOID    _nx_ram_network_driver(struct NX_IP_DRIVER_STRUCT *driver_req);
110 
111 /* Define the application's authentication check.  This is called by
112    the HTTP server whenever a new request is received.  */
authentication_check(NX_WEB_HTTP_SERVER * server_ptr,UINT request_type,CHAR * resource,CHAR ** name,CHAR ** password,CHAR ** realm)113 static UINT  authentication_check(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type,
114             CHAR *resource, CHAR **name, CHAR **password, CHAR **realm)
115 {
116     NX_PARAMETER_NOT_USED(server_ptr);
117     NX_PARAMETER_NOT_USED(request_type);
118     NX_PARAMETER_NOT_USED(resource);
119 
120     /* Just use a simple name, password, and realm for all
121        requests and resources.  */
122     *name =     "name";
123     *password = "password";
124 
125     *realm =    "NetX Duo HTTP demo";
126 
127     /* Request basic authentication.  */
128     return(NX_WEB_HTTP_BASIC_AUTHENTICATE);
129 }
130 
131 /* Define what the initial system looks like.  */
132 #ifdef CTEST
test_application_define(void * first_unused_memory)133 VOID test_application_define(void *first_unused_memory)
134 #else
135 void    netx_web_https_demo_test_application_define(void *first_unused_memory)
136 #endif
137 {
138 
139 CHAR    *pointer;
140 UINT    status;
141 
142 
143     /* Setup the working pointer.  */
144     pointer =  (CHAR *) first_unused_memory;
145 
146     /* Create a helper thread for the server. */
147     tx_thread_create(&server_thread, "HTTPS Server thread", https_server_thread_entry, 0,
148                      pointer, DEMO_STACK_SIZE,
149                      NX_WEB_HTTP_SERVER_PRIORITY, NX_WEB_HTTP_SERVER_PRIORITY, TX_NO_TIME_SLICE, TX_AUTO_START);
150 
151     pointer =  pointer + DEMO_STACK_SIZE;
152 
153     /* Initialize the NetX system.  */
154     nx_system_initialize();
155 
156     /* Create the server packet pool.  */
157     status =  nx_packet_pool_create(&server_pool, "HTTPS Server Packet Pool", SERVER_PACKET_SIZE,
158                                     pointer, SERVER_PACKET_SIZE * 20);
159     EXPECT_EQ(NX_SUCCESS, status);
160 
161     pointer = pointer + SERVER_PACKET_SIZE * 20;
162 
163     /* Check for pool creation error.  */
164     if (status)
165     {
166 
167         return;
168     }
169 
170     /* Create an IP instance.  */
171     status = nx_ip_create(&server_ip, "HTTP Server IP", HTTP_SERVER_ADDRESS,
172                           0xFFFFFF00UL, &server_pool, _nx_ram_network_driver,
173                           pointer, 4096, 1);
174     EXPECT_EQ(NX_SUCCESS, status);
175 
176     pointer =  pointer + 4096;
177 
178     /* Enable ARP and supply ARP cache memory for the server IP instance.  */
179     status = nx_arp_enable(&server_ip, (void *) pointer, 1024);
180     EXPECT_EQ(NX_SUCCESS, status);
181 
182     pointer = pointer + 1024;
183 
184      /* Enable TCP traffic.  */
185     status = nx_tcp_enable(&server_ip);
186     EXPECT_EQ(NX_SUCCESS, status);
187 
188     /* Set up the server's IPv4 address here. */
189     server_ip_address.nxd_ip_address.v4 = HTTP_SERVER_ADDRESS;
190     server_ip_address.nxd_ip_version = NX_IP_VERSION_V4;
191 
192     pointer =  pointer + 2048;
193 
194     /* Create the HTTP Client thread. */
195     status = tx_thread_create(&client_thread, "HTTPS Client", https_client_thread_entry, 0,
196                      pointer, DEMO_STACK_SIZE,
197                      NX_WEB_HTTP_SERVER_PRIORITY + 2, NX_WEB_HTTP_SERVER_PRIORITY + 2, TX_NO_TIME_SLICE, TX_AUTO_START);
198     EXPECT_EQ(NX_SUCCESS, status);
199 
200     pointer =  pointer + DEMO_STACK_SIZE;
201 
202     /* Create the Client packet pool.  */
203     status =  nx_packet_pool_create(&client_pool, "HTTPS Client Packet Pool", SERVER_PACKET_SIZE,
204                                     pointer, SERVER_PACKET_SIZE * 20);
205     EXPECT_EQ(NX_SUCCESS, status);
206 
207     pointer = pointer + SERVER_PACKET_SIZE * 20;
208 
209     /* Create an IP instance.  */
210     status = nx_ip_create(&client_ip, "HTTPS Client IP", HTTP_CLIENT_ADDRESS,
211                           0xFFFFFF00UL, &client_pool, _nx_ram_network_driver,
212                           pointer, 2048, 1);
213     EXPECT_EQ(NX_SUCCESS, status);
214 
215     pointer =  pointer + 2048;
216 
217     nx_arp_enable(&client_ip, (void *) pointer, 1024);
218 
219     pointer =  pointer + 2048;
220 
221      /* Enable TCP traffic.  */
222     nx_tcp_enable(&client_ip);
223 
224     return;
225 }
226 
https_client_thread_entry(ULONG thread_input)227 VOID https_client_thread_entry(ULONG thread_input)
228 {
229 
230 UINT            status;
231 NX_PACKET       *my_packet;
232 NX_PACKET *receive_packet;
233 UCHAR receive_buffer[1000];
234 ULONG bytes;
235 NXD_ADDRESS    server_ip_address;
236 
237     NX_PARAMETER_NOT_USED(thread_input);
238 
239     printf("NetX Test:   Web HTTPS Demo Test.......................................");
240 
241     /* Give IP task and driver a chance to initialize the system. */
242     tx_thread_sleep(7 * NX_IP_PERIODIC_RATE);
243 
244     status = nx_secure_tls_session_create(&client_tls_session, &nx_crypto_tls_ciphers, crypto_metadata, sizeof(crypto_metadata));
245     EXPECT_EQ(NX_SUCCESS, status);
246 
247     /* Create an HTTPS client instance.  */
248     status = _nx_web_https_client_create(&my_client, "HTTP Client", &client_ip, &client_pool, 65535, &client_tls_session);
249     EXPECT_EQ(NX_SUCCESS, status);
250 
251     /* Allocate space for packet reassembly. */
252     status = nx_secure_tls_session_packet_buffer_set(my_client.nx_web_http_client_tls_session, tls_packet_buffer, sizeof(tls_packet_buffer));
253     EXPECT_EQ(NX_SUCCESS, status);
254 
255     /* Add a CA Certificate to our trusted store for verifying incoming server certificates. */
256     nx_secure_x509_certificate_initialize(&trusted_certificate, ca_cert_der, ca_cert_der_len, NX_NULL, 0, NULL, 0, NX_SECURE_X509_KEY_TYPE_NONE);
257     nx_secure_tls_trusted_certificate_add(&client_tls_session, &trusted_certificate);
258 
259     /* Need to allocate space for the certificate coming in from the remote host. */
260     nx_secure_tls_remote_certificate_allocate(&client_tls_session, &remote_certificate, remote_cert_buffer, sizeof(remote_cert_buffer));
261     nx_secure_tls_remote_certificate_allocate(&client_tls_session, &remote_issuer, remote_issuer_buffer, sizeof(remote_issuer_buffer));
262 
263     /* Allocate a packet.  */
264     //status =  nx_packet_allocate(&pool_0, &my_packet, NX_TCP_PACKET, NX_WAIT_FOREVER);
265     status =  nx_packet_allocate(&client_pool, &my_packet, NX_TCP_PACKET, NX_WAIT_FOREVER);
266     EXPECT_EQ(NX_SUCCESS, status);
267 
268     /* GET the test page */
269     /* Use the 'NetX' service to send a GET request to the server (can only use IPv4 addresses). */
270     server_ip_address.nxd_ip_address.v4 = HTTP_SERVER_ADDRESS;
271     server_ip_address.nxd_ip_version = NX_IP_VERSION_V4;
272     status =  nx_web_http_client_get_start(&my_client, &server_ip_address, "/https_server.sh",
273                                        NX_NULL, 0, "name", "password", NX_WAIT_FOREVER);
274     EXPECT_EQ(NX_SUCCESS, status);
275 
276     status = nx_web_http_client_get_packet(&my_client, &receive_packet, NX_WAIT_FOREVER);
277     EXPECT_EQ(NX_SUCCESS, status);
278 
279     status = nx_packet_data_extract_offset(receive_packet, 0, receive_buffer, 1000, &bytes);
280     EXPECT_EQ(NX_SUCCESS, status);
281 
282     receive_buffer[bytes] = 0;
283     //printf("Received: %s\n", receive_buffer);
284     EXPECT_EQ((UINT)bytes, 12);
285     EXPECT_EQ(receive_buffer[0], 'h');
286     EXPECT_EQ(receive_buffer[1], 't');
287     EXPECT_EQ(receive_buffer[2], 't');
288     EXPECT_EQ(receive_buffer[3], 'p');
289     EXPECT_EQ(receive_buffer[4], 's');
290     EXPECT_EQ(receive_buffer[5], ' ');
291     EXPECT_EQ(receive_buffer[6], 's');
292     EXPECT_EQ(receive_buffer[7], 'e');
293     EXPECT_EQ(receive_buffer[8], 'r');
294     EXPECT_EQ(receive_buffer[9], 'v');
295     EXPECT_EQ(receive_buffer[10], 'e');
296     EXPECT_EQ(receive_buffer[11], 'r');
297 
298     status = nx_web_http_client_delete(&my_client);
299     EXPECT_EQ(NX_SUCCESS, status);
300 
301     printf("SUCCESS!\n");
302     test_control_return(0);
303 }
304 
305 /************* HTTP(S) Server *************************/
306 
307 
308 /* TLS setup callback, used to configure the TLS sessions for an HTTPS server. */
server_tls_setup(NX_WEB_HTTP_SERVER * http_server_ptr,NX_TCPSERVER * socket_server)309 UINT server_tls_setup(NX_WEB_HTTP_SERVER *http_server_ptr, NX_TCPSERVER *socket_server)
310 {
311 UINT status;
312 
313     /* Initialize device certificate (used for all sessions in HTTPS server). */
314     memset(&certificate, 0, sizeof(certificate));
315     nx_secure_x509_certificate_initialize(&certificate, test_device_cert_der, test_device_cert_der_len, NX_NULL, 0, test_device_cert_key_der, test_device_cert_key_der_len, NX_SECURE_X509_KEY_TYPE_RSA_PKCS1_DER);
316 
317     /* Setup TLS session data for the TCP server. */
318     status = nx_tcpserver_tls_setup(&http_server_ptr -> nx_web_http_server_tcpserver, &nx_crypto_tls_ciphers,
319                                     crypto_metadata, sizeof(crypto_metadata), tls_packet_buffer, sizeof(tls_packet_buffer),
320                                     &certificate, NX_NULL, 0, NX_NULL, 0);
321     return(status);
322 }
323 
server_request_callback(NX_WEB_HTTP_SERVER * server_ptr,UINT request_type,CHAR * resource,NX_PACKET * packet_ptr)324 UINT server_request_callback(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, NX_PACKET *packet_ptr)
325 {
326 ULONG        offset, length;
327 NX_PACKET   *response_pkt;
328 UCHAR       buffer[1440];
329 UINT i;
330 UINT status;
331 
332     /* Process multipart data. */
333     if(request_type == NX_WEB_HTTP_SERVER_POST_REQUEST)
334     {
335         /* Get the content header. */
336         while(nx_web_http_server_get_entity_header(server_ptr, &packet_ptr, buffer,
337                                                sizeof(buffer)) == NX_SUCCESS)
338         {
339 
340             /* Header obtained successfully. Get the content data location. */
341             while(nx_web_http_server_get_entity_content(server_ptr, &packet_ptr, &offset,
342                                                     &length) == NX_SUCCESS)
343             {
344                 /* Write content data to buffer. */
345                 nx_packet_data_extract_offset(packet_ptr, offset, buffer, length,
346                                               &length);
347                 buffer[length] = 0;
348             }
349 
350             printf("Receive buffer of size %d:\n", (UINT)length);
351             for(i = 0; i < length; ++i)
352             {
353                 printf("%c", buffer[i]);
354             }
355         }
356 
357         /* Generate HTTP header. */
358         status = nx_web_http_server_callback_generate_response_header(server_ptr,
359         &response_pkt, NX_WEB_HTTP_STATUS_OK, 800, "text/html",
360         "Server: NetX HTTPS Experimental\r\n");
361 
362         if(status == NX_SUCCESS)
363         {
364             if(nx_web_http_server_callback_packet_send(server_ptr, response_pkt) !=
365                                                    NX_SUCCESS)
366             {
367                 nx_packet_release(response_pkt);
368             }
369         }
370     }
371     else
372     {
373         /* Indicate we have not processed the response to client yet.*/
374         return(NX_SUCCESS);
375     }
376 
377 
378     /* Release the received client packet. */
379     nx_packet_release(packet_ptr);
380 
381     /* Indicate the response to client is transmitted. */
382     return(NX_WEB_HTTP_CALLBACK_COMPLETED);
383 
384 }
385 
386 /* Define the helper HTTP server thread.  */
https_server_thread_entry(ULONG thread_input)387 void    https_server_thread_entry(ULONG thread_input)
388 {
389 
390 UINT    status;
391 FX_FILE my_file;
392 
393     NX_PARAMETER_NOT_USED(thread_input);
394     status = fx_media_format(&ram_disk,
395                     _fx_ram_driver,               // Driver entry
396                     ram_disk_memory,              // RAM disk memory pointer
397                     media_memory,              // Media buffer pointer
398                     sizeof(media_memory),      // Media buffer size
399                     "MY_RAM_DISK",                // Volume Name
400                     1,                            // Number of FATs
401                     32,                           // Directory Entries
402                     0,                            // Hidden sectors
403                     256,                          // Total sectors
404                     512,                          // Sector size
405                     8,                            // Sectors per cluster
406                     1,                            // Heads
407                     1);                           // Sectors per track
408     EXPECT_EQ(NX_SUCCESS, status);
409 
410     /* Open the RAM disk.  */
411     status = fx_media_open(&ram_disk, "RAM DISK", _fx_ram_driver, ram_disk_memory, media_memory, sizeof(media_memory)) ;
412     status += fx_file_create(&ram_disk, "/https_server.sh");
413     status += fx_file_open(&ram_disk, &my_file, "https_server.sh", FX_OPEN_FOR_WRITE);
414     status += fx_file_write(&my_file, "https server", 12);
415     status += fx_file_close(&my_file);
416     EXPECT_EQ(NX_SUCCESS, status);
417 
418     /* Give NetX a chance to initialize the system. */
419     tx_thread_sleep(NX_IP_PERIODIC_RATE * 7);
420 
421     /* Create the HTTPS Server. */
422     status = nx_web_http_server_create(&my_server, "My HTTP Server", &server_ip, &ram_disk, &server_stack, sizeof(server_stack), &server_pool, authentication_check, server_request_callback);
423     EXPECT_EQ(NX_SUCCESS, status);
424 
425     /* Start an HTTPS Server with TLS.  */
426     status = nx_web_http_server_secure_start(&my_server, server_tls_setup, NX_NULL);
427     EXPECT_EQ(NX_SUCCESS, status);
428 
429     /* HTTP server ready to take requests! */
430     /* Let the IP thread execute.    */
431     tx_thread_sleep(NX_IP_PERIODIC_RATE);
432 
433     while(1)
434     {
435         tx_thread_sleep(NX_IP_PERIODIC_RATE);
436     }
437     //return;
438 }
439 
440 
441 
442