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