1 /* This case tests digest authentication.
2  HA1 = MD5("name:NetX Duo HTTP demo:Placeholderpassword")
3      = 01bb2595c9221423951ee86f3573b465
4  HA2 = MD5("GET:/index.htm")
5      = d4b1da8c7955d2e98bc56ffc93003b44
6  Response = MD5("01bb2595c9221423951ee86f3573b465:
7                  nonce:
8                  00000001:0a4f113b:auth:
9                  d4b1da8c7955d2e98bc56ffc93003b44")
10  */
11 #include    "tx_api.h"
12 #include    "nx_api.h"
13 #include    "fx_api.h"
14 #include    "nxd_http_client.h"
15 #include    "nxd_http_server.h"
16 
17 extern void test_control_return(UINT);
18 
19 #if !defined(NX_DISABLE_IPV4) && defined(NX_HTTP_DIGEST_ENABLE)
20 
21 #include "../web_test/http_digest_authentication.c"
22 
23 
24 #define     DEMO_STACK_SIZE         4096
25 
26 /* Set up FileX and file memory resources. */
27 static CHAR             ram_disk_memory[4096];
28 static FX_MEDIA         ram_disk;
29 static UCHAR            media_memory[4096];
30 
31 static UCHAR            server_stack[16000];
32 
33 /* Define device drivers.  */
34 extern void _fx_ram_driver(FX_MEDIA *media_ptr);
35 extern void _nx_ram_network_driver_1024(NX_IP_DRIVER *driver_req_ptr);
36 
37 /* Set up the HTTP client global variables. */
38 
39 #define         CLIENT_PACKET_SIZE  (NX_HTTP_CLIENT_MIN_PACKET_SIZE * 2)
40 
41 static TX_THREAD           client_thread;
42 static NX_PACKET_POOL      client_pool;
43 static NX_HTTP_CLIENT      my_client;
44 static NX_IP               client_ip;
45 static UINT                error_counter;
46 
47 /* Set up the HTTP server global variables */
48 
49 #define         SERVER_PACKET_SIZE  (NX_HTTP_SERVER_MIN_PACKET_SIZE * 2)
50 
51 static NX_HTTP_SERVER      my_server;
52 static NX_PACKET_POOL      server_pool;
53 static TX_THREAD           server_thread;
54 static NX_IP               server_ip;
55 static NX_TCP_SOCKET       client_socket[NX_HTTP_SERVER_NONCE_MAX + 1];
56 #ifdef __PRODUCT_NETXDUO__
57 static NXD_ADDRESS     server_ip_address;
58 #else
59 static ULONG           server_ip_address;
60 #endif
61 
62 static void thread_client_entry(ULONG thread_input);
63 static void thread_server_entry(ULONG thread_input);
64 
65 #define HTTP_SERVER_ADDRESS  IP_ADDRESS(1,2,3,4)
66 #define HTTP_CLIENT_ADDRESS  IP_ADDRESS(1,2,3,5)
67 
68 
69 static TX_SEMAPHORE server_start;
70 static TX_SEMAPHORE client_stop;
71 
72 static UINT  authentication_check(NX_HTTP_SERVER *server_ptr, UINT request_type,
73                                   CHAR *resource, CHAR **name, CHAR **password, CHAR **realm);
74 
75 static CHAR nonce_buffer[NX_HTTP_SERVER_NONCE_SIZE + 1];
76 static CHAR temp_nonce_buffer[NX_HTTP_SERVER_NONCE_SIZE + 1];
77 static CHAR response_buffer[32 + 1];
78 static NX_MD5 client_md5data;
79 
80 static char pkt[] = {
81 0x47, 0x45, 0x54, 0x20, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x20, /* GET /index.htm  */
82 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, /* HTTP/1.1.. */
83 };
84 
85 #ifdef CTEST
test_application_define(void * first_unused_memory)86 VOID test_application_define(void *first_unused_memory)
87 #else
88 void    netx_http_digest_authenticate_timeout_test_application_define(void *first_unused_memory)
89 #endif
90 {
91 CHAR    *pointer;
92 UINT    status;
93 
94 
95     error_counter = 0;
96 
97     /* Setup the working pointer.  */
98     pointer =  (CHAR *) first_unused_memory;
99 
100     /* Create a helper thread for the server. */
101     tx_thread_create(&server_thread, "HTTP Server thread", thread_server_entry, 0,
102                      pointer, DEMO_STACK_SIZE,
103                      4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
104 
105     pointer =  pointer + DEMO_STACK_SIZE;
106 
107     /* Initialize the NetX system.  */
108     nx_system_initialize();
109 
110     /* Create the server packet pool.  */
111     status =  nx_packet_pool_create(&server_pool, "HTTP Server Packet Pool", SERVER_PACKET_SIZE,
112                                     pointer, SERVER_PACKET_SIZE*8);
113     pointer = pointer + SERVER_PACKET_SIZE * 8;
114     if (status)
115         error_counter++;
116 
117     /* Create an IP instance.  */
118     status = nx_ip_create(&server_ip, "HTTP Server IP", HTTP_SERVER_ADDRESS,
119                           0xFFFFFF00UL, &server_pool, _nx_ram_network_driver_1024,
120                           pointer, 4096, 1);
121     pointer =  pointer + 4096;
122     if (status)
123         error_counter++;
124 
125     /* Enable ARP and supply ARP cache memory for the server IP instance.  */
126     status = nx_arp_enable(&server_ip, (void *) pointer, 1024);
127     pointer = pointer + 1024;
128     if (status)
129         error_counter++;
130 
131 
132      /* Enable TCP traffic.  */
133     status = nx_tcp_enable(&server_ip);
134     if (status)
135         error_counter++;
136 
137     /* Create the HTTP Client thread. */
138     status = tx_thread_create(&client_thread, "HTTP Client", thread_client_entry, 0,
139                               pointer, DEMO_STACK_SIZE,
140                               6, 6, TX_NO_TIME_SLICE, TX_AUTO_START);
141     pointer =  pointer + DEMO_STACK_SIZE;
142     if (status)
143         error_counter++;
144 
145     /* Create the Client packet pool.  */
146     status =  nx_packet_pool_create(&client_pool, "HTTP Client Packet Pool", CLIENT_PACKET_SIZE,
147                                     pointer, CLIENT_PACKET_SIZE*16);
148     pointer = pointer + CLIENT_PACKET_SIZE * 16;
149     if (status)
150         error_counter++;
151 
152     /* Create an IP instance.  */
153     status = nx_ip_create(&client_ip, "HTTP Client IP", HTTP_CLIENT_ADDRESS,
154                           0xFFFFFF00UL, &client_pool, _nx_ram_network_driver_1024,
155                           pointer, 2048, 1);
156     pointer =  pointer + 2048;
157     if (status)
158         error_counter++;
159 
160     status  = nx_arp_enable(&client_ip, (void *) pointer, 1024);
161     pointer =  pointer + 2048;
162     if (status)
163         error_counter++;
164 
165      /* Enable TCP traffic.  */
166     status = nx_tcp_enable(&client_ip);
167     if (status)
168         error_counter++;
169 
170     tx_semaphore_create(&server_start, "server start", 0);
171     tx_semaphore_create(&client_stop, "client stop", 0);
172 }
173 
thread_client_entry(ULONG thread_input)174 void thread_client_entry(ULONG thread_input)
175 {
176 UINT            status;
177 NX_PACKET       *send_packet[NX_HTTP_SERVER_NONCE_MAX + 1];
178 NX_PACKET       *recv_packet;
179 CHAR            *buffer_ptr;
180 INT             i;
181 
182 
183     /* Give IP task and driver a chance to initialize the system.  */
184     tx_thread_sleep(NX_IP_PERIODIC_RATE);
185 
186     /* Set server IP address.  */
187 #ifdef __PRODUCT_NETXDUO__
188     server_ip_address.nxd_ip_address.v4 = HTTP_SERVER_ADDRESS;
189     server_ip_address.nxd_ip_version = NX_IP_VERSION_V4;
190 #else
191     server_ip_address = HTTP_SERVER_ADDRESS;
192 #endif
193 
194     tx_semaphore_get(&server_start, NX_WAIT_FOREVER);
195 
196     for (i = 0; i < NX_HTTP_SERVER_NONCE_MAX + 1; i++)
197     {
198 
199         /* Create an HTTP client instance.  */
200         status =  nx_tcp_socket_create(&client_ip, &client_socket[i], "Socket 0",
201                                        NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, 200,
202                                        NX_NULL, NX_NULL);
203 
204         /* Check status.  */
205         if (status)
206             error_counter++;
207 
208         /* Bind the client socket.  */
209         status = nx_tcp_client_socket_bind(&client_socket[i], NX_ANY_PORT, NX_WAIT_FOREVER);
210 
211         /* Check status of the bind.  */
212         if (status)
213             error_counter++;
214 
215         /* Connect to the HTTP server.  */
216 #ifdef __PRODUCT_NETXDUO__
217 
218         /* Invoke the 'Duo' (supports IPv6/IPv4) connection call. */
219         status = nxd_tcp_client_socket_connect(&client_socket[i], &server_ip_address,
220             NX_HTTP_SERVER_PORT, NX_WAIT_FOREVER);
221 #else
222         /* Invoke the NetX (IPv4 only) connection call. */
223         status = nx_tcp_client_socket_connect(&client_socket[i], server_ip_address,
224             NX_HTTP_SERVER_PORT, NX_WAIT_FOREVER);
225 #endif
226 
227         /* Check status.  */
228         if (status)
229             error_counter++;
230 
231         /* Allocate a packet.  */
232         status = nx_packet_allocate(&client_pool, &send_packet[i], NX_TCP_PACKET, NX_WAIT_FOREVER);
233         if (status)
234             error_counter++;
235 
236         nx_packet_data_append(send_packet[i], pkt, sizeof(pkt), &client_pool, NX_WAIT_FOREVER);
237         nx_packet_data_append(send_packet[i], "\r\n", 2, &client_pool, NX_WAIT_FOREVER);
238 
239         /* Initialize the buffer.  */
240         memset(nonce_buffer, 0, sizeof(nonce_buffer));
241         memset(response_buffer, 0, sizeof(response_buffer));
242 
243         /* Send the request.  */
244         status = nx_tcp_socket_send(&client_socket[i], send_packet[i], NX_WAIT_FOREVER);
245 
246         /* Check status.  */
247         if (status)
248             error_counter++;
249 
250         /* Pickup the response from the Server.  */
251         status = nx_tcp_socket_receive(&client_socket[i], &recv_packet, NX_WAIT_FOREVER);
252 
253         /* Check status.  */
254         if (status)
255             error_counter++;
256         else
257         {
258 
259             if (i == NX_HTTP_SERVER_NONCE_MAX)
260             {
261                 buffer_ptr = (CHAR *)recv_packet->nx_packet_prepend_ptr;
262 
263                 /* Check the status, no nonce entry, it should be 200. */
264                 if ((buffer_ptr[9] != '5') || (buffer_ptr[10] != '0') || (buffer_ptr[11] != '0'))
265                     error_counter++;
266 
267                 nx_packet_release(recv_packet);
268 
269                 /* Discconect.  */
270                 nx_tcp_socket_disconnect(&client_socket[i], NX_NO_WAIT);
271 
272                 /* Sleep for the allocated nonce to be timed out.  */
273                 tx_thread_sleep(NX_HTTP_SERVER_NONCE_TIMEOUT + NX_IP_PERIODIC_RATE);
274 
275                 /* Reconnect to HTTP server.  */
276 #ifdef __PRODUCT_NETXDUO__
277 
278                 /* Invoke the 'Duo' (supports IPv6/IPv4) connection call. */
279                 status = nxd_tcp_client_socket_connect(&client_socket[i], &server_ip_address,
280                     NX_HTTP_SERVER_PORT, NX_WAIT_FOREVER);
281 #else
282                 /* Invoke the NetX (IPv4 only) connection call. */
283                 status = nx_tcp_client_socket_connect(&client_socket[i], server_ip_address,
284                     NX_HTTP_SERVER_PORT, NX_WAIT_FOREVER);
285 #endif
286 
287                 /* Check status.  */
288                 if (status)
289                     error_counter++;
290 
291                 /* Allocate a packet.  */
292                 status = nx_packet_allocate(&client_pool, &send_packet[i], NX_TCP_PACKET, NX_WAIT_FOREVER);
293                 if (status)
294                     error_counter++;
295 
296                 nx_packet_data_append(send_packet[i], pkt, sizeof(pkt), &client_pool, NX_WAIT_FOREVER);
297                 nx_packet_data_append(send_packet[i], "\r\n", 2, &client_pool, NX_WAIT_FOREVER);
298 
299                 /* Initialize the buffer.  */
300                 memset(nonce_buffer, 0, sizeof(nonce_buffer));
301                 memset(response_buffer, 0, sizeof(response_buffer));
302 
303                 /* Send the request.  */
304                 status = nx_tcp_socket_send(&client_socket[i], send_packet[i], NX_WAIT_FOREVER);
305 
306                 /* Check status.  */
307                 if (status)
308                     error_counter++;
309 
310                 /* Pickup the response from the Server.  */
311                 status = nx_tcp_socket_receive(&client_socket[i], &recv_packet, NX_WAIT_FOREVER);
312 
313                 /* Check status.  */
314                 if (status)
315                     error_counter++;
316             }
317 
318             /* Retrieve the nonce.  */
319             status = http_nonce_retrieve(recv_packet, nonce_buffer);
320             if (status)
321                 error_counter++;
322 
323             nx_packet_release(recv_packet);
324         }
325 
326         /* Calculate the response.  */
327         http_digest_response_calculate(&client_md5data, "name", "NetX Duo HTTP demo", "Placeholderpassword", nonce_buffer, "GET",
328                                        "/index.htm", "00000001", "0a4f113b", response_buffer);
329 
330         /* Allocate a packet.  */
331         status = nx_packet_allocate(&client_pool, &send_packet[i], NX_TCP_PACKET, NX_WAIT_FOREVER);
332         if (status)
333             error_counter++;
334 
335         nx_packet_data_append(send_packet[i], pkt, sizeof(pkt), &client_pool, NX_WAIT_FOREVER);
336 
337         /* Build the Authorization header.  */
338         nx_packet_data_append(send_packet[i], "Authorization: Digest", 21, &client_pool, NX_WAIT_FOREVER);
339         nx_packet_data_append(send_packet[i], " username=\"name\",", 17, &client_pool, NX_WAIT_FOREVER);
340         nx_packet_data_append(send_packet[i], " realm=\"NetX Duo HTTP demo\",", 28, &client_pool, NX_WAIT_FOREVER);
341         nx_packet_data_append(send_packet[i], " nonce=\"", 8, &client_pool, NX_WAIT_FOREVER);
342         nx_packet_data_append(send_packet[i], nonce_buffer, NX_HTTP_SERVER_NONCE_SIZE, &client_pool, NX_WAIT_FOREVER);
343         nx_packet_data_append(send_packet[i], "\",", 2, &client_pool, NX_WAIT_FOREVER);
344         nx_packet_data_append(send_packet[i], " uri=\"/index.htm\",", 17, &client_pool, NX_WAIT_FOREVER);
345         nx_packet_data_append(send_packet[i], " qop=auth,", 10, &client_pool, NX_WAIT_FOREVER);
346         nx_packet_data_append(send_packet[i], " nc=00000001,", 13, &client_pool, NX_WAIT_FOREVER);
347         nx_packet_data_append(send_packet[i], " cnonce=\"0a4f113b\",", 19, &client_pool, NX_WAIT_FOREVER);
348         nx_packet_data_append(send_packet[i], " response=\"", 11, &client_pool, NX_WAIT_FOREVER);
349         nx_packet_data_append(send_packet[i], response_buffer, 32, &client_pool, NX_WAIT_FOREVER);
350         nx_packet_data_append(send_packet[i], "\",", 2, &client_pool, NX_WAIT_FOREVER);
351         nx_packet_data_append(send_packet[i], " opaque=\"5ccc069c403ebaf9f0171e9517f40e41\"\r\n", 44, &client_pool, NX_WAIT_FOREVER);
352 
353         nx_packet_data_append(send_packet[i], "\r\n", 2, &client_pool, NX_WAIT_FOREVER);
354 
355         nx_tcp_socket_disconnect(&client_socket[i], NX_NO_WAIT);
356     }
357 
358     for (i = NX_HTTP_SERVER_NONCE_MAX; i >= 0; i--)
359     {
360 
361         /* Reconnect to the HTTP server.  */
362 #ifdef __PRODUCT_NETXDUO__
363 
364         /* Invoke the 'Duo' (supports IPv6/IPv4) connection call. */
365         status = nxd_tcp_client_socket_connect(&client_socket[i], &server_ip_address,
366             NX_HTTP_SERVER_PORT, NX_WAIT_FOREVER);
367 #else
368         /* Invoke the NetX (IPv4 only) connection call. */
369         status = nx_tcp_client_socket_connect(&client_socket[i], server_ip_address,
370             NX_HTTP_SERVER_PORT, NX_WAIT_FOREVER);
371 #endif
372 
373         /* Check status.  */
374         if (status)
375             error_counter++;
376 
377         /* Now send the packet to the HTTP server.  */
378         status = nx_tcp_socket_send(&client_socket[i], send_packet[i], NX_WAIT_FOREVER);
379 
380         /* Check status.  */
381         if (status)
382             error_counter++;
383 
384         /* Pickup the response from the Server.  */
385         status = nx_tcp_socket_receive(&client_socket[i], &recv_packet, NX_WAIT_FOREVER);
386 
387         /* Check status.  */
388         if (status)
389         {
390             error_counter++;
391         }
392         else
393         {
394             buffer_ptr = (CHAR *)recv_packet->nx_packet_prepend_ptr;
395 
396             if (i == 0)
397             {
398                 /* This nonce is timed out, the response should be 401. */
399                 if ((buffer_ptr[9] != '4') || (buffer_ptr[10] != '0') || (buffer_ptr[11] != '1'))
400                     error_counter++;
401             }
402             else
403             {
404                 /* Check the status, If authentication success , it should be 200. */
405                 if ((buffer_ptr[9] != '2') || (buffer_ptr[10] != '0') || (buffer_ptr[11] != '0'))
406                     error_counter++;
407             }
408 
409             nx_packet_release(recv_packet);
410         }
411 
412         /* Disconnect and unbind the socket.  */
413         status = nx_tcp_socket_disconnect(&client_socket[i], NX_HTTP_CLIENT_TIMEOUT);
414         status += nx_tcp_client_socket_unbind(&client_socket[i]);
415         status += nx_tcp_socket_delete(&client_socket[i]);
416         if (status)
417             error_counter++;
418     }
419 
420     tx_semaphore_put(&client_stop);
421 
422     if(error_counter)
423     {
424         printf("ERROR!\n");
425         test_control_return(1);
426     }
427     else
428     {
429         printf("SUCCESS!\n");
430         test_control_return(0);
431     }
432 }
433 
434 /* Define the helper HTTP server thread.  */
thread_server_entry(ULONG thread_input)435 void    thread_server_entry(ULONG thread_input)
436 {
437 UINT            status;
438 FX_FILE         my_file;
439 
440 
441     /* Print out test information banner.  */
442     printf("NetX Test:   HTTP Digest Authenticate Timeout Test.....................");
443 
444     /* Check for earlier error.  */
445     if(error_counter)
446     {
447         printf("ERROR!\n");
448         test_control_return(1);
449     }
450 
451     fx_media_format(&ram_disk,
452                     _fx_ram_driver,               // Driver entry
453                     ram_disk_memory,              // RAM disk memory pointer
454                     media_memory,                 // Media buffer pointer
455                     sizeof(media_memory),         // Media buffer size
456                     "MY_RAM_DISK",                // Volume Name
457                     1,                            // Number of FATs
458                     32,                           // Directory Entries
459                     0,                            // Hidden sectors
460                     256,                          // Total sectors
461                     512,                          // Sector size
462                     8,                            // Sectors per cluster
463                     1,                            // Heads
464                     1);                           // Sectors per track
465 
466     /* Open the RAM disk.  */
467     status = fx_media_open(&ram_disk, "RAM DISK", _fx_ram_driver, ram_disk_memory, media_memory, sizeof(media_memory)) ;
468     if(status)
469         error_counter++;
470 
471     /* Give NetX a chance to initialize the system.  */
472     tx_thread_sleep(NX_IP_PERIODIC_RATE);
473 
474     status = fx_file_create(&ram_disk, "index.htm");
475     status += fx_file_open(&ram_disk, &my_file, "index.htm", FX_OPEN_FOR_WRITE);
476     status += fx_file_write(&my_file, "https server", 12);
477     status += fx_file_close(&my_file);
478     if (status)
479         error_counter++;
480 
481     /* Create the HTTP Server.  */
482     status = nx_http_server_create(&my_server, "My HTTP Server", &server_ip, &ram_disk,
483                                    server_stack, sizeof(server_stack), &server_pool, authentication_check, NX_NULL);
484     if (status)
485         error_counter++;
486 
487     /* OK to start the HTTP Server.   */
488     status = nx_http_server_start(&my_server);
489     if (status)
490         error_counter++;
491 
492     tx_semaphore_put(&server_start);
493 }
494 
495 /* Define the application's authentication check.  This is called by
496    the HTTP server whenever a new request is received.  */
authentication_check(NX_HTTP_SERVER * server_ptr,UINT request_type,CHAR * resource,CHAR ** name,CHAR ** password,CHAR ** realm)497 static UINT  authentication_check(NX_HTTP_SERVER *server_ptr, UINT request_type,
498                                   CHAR *resource, CHAR **name, CHAR **password, CHAR **realm)
499 {
500 
501     /* Just use a simple name, password, and realm for all
502        requests and resources.  */
503     *name =     "name";
504     *password = "Placeholderpassword";
505     *realm =    "NetX Duo HTTP demo";
506 
507     /* Request digest authentication.  */
508     return(NX_HTTP_DIGEST_AUTHENTICATE);
509 }
510 
511 #else
512 
513 #ifdef CTEST
test_application_define(void * first_unused_memory)514 VOID test_application_define(void *first_unused_memory)
515 #else
516 void    netx_http_digest_authenticate_timeout_test_application_define(void *first_unused_memory)
517 #endif
518 {
519 
520     /* Print out test information banner.  */
521     printf("NetX Test:   HTTP Digest Authenticate Timeout Test.....................N/A\n");
522 
523     test_control_return(3);
524 }
525 #endif
526 
527