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