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 "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[NX_WEB_HTTP_SERVER_NONCE_MAX + 1];
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 extern UINT _nx_web_http_client_receive(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option);
73
74 static CHAR nonce_buffer[NX_WEB_HTTP_SERVER_NONCE_SIZE + 1];
75 static CHAR temp_nonce_buffer[NX_WEB_HTTP_SERVER_NONCE_SIZE + 1];
76 static CHAR response_buffer[32 + 1];
77 static NX_MD5 client_md5data;
78
79 static char pkt[] = {
80 0x47, 0x45, 0x54, 0x20, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x20, /* GET /index.htm */
81 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, /* HTTP/1.1.. */
82 };
83
84 #ifdef CTEST
test_application_define(void * first_unused_memory)85 VOID test_application_define(void *first_unused_memory)
86 #else
87 void netx_web_digest_authenticate_timeout_test_application_define(void *first_unused_memory)
88 #endif
89 {
90 CHAR *pointer;
91 UINT status;
92
93
94 error_counter = 0;
95
96 /* Setup the working pointer. */
97 pointer = (CHAR *) first_unused_memory;
98
99 /* Create a helper thread for the server. */
100 tx_thread_create(&server_thread, "HTTP Server thread", thread_server_entry, 0,
101 pointer, DEMO_STACK_SIZE,
102 NX_WEB_HTTP_SERVER_PRIORITY, NX_WEB_HTTP_SERVER_PRIORITY, TX_NO_TIME_SLICE, TX_AUTO_START);
103
104 pointer = pointer + DEMO_STACK_SIZE;
105
106 /* Initialize the NetX system. */
107 nx_system_initialize();
108
109 /* Create the server packet pool. */
110 status = nx_packet_pool_create(&server_pool, "HTTP Server Packet Pool", SERVER_PACKET_SIZE,
111 pointer, SERVER_PACKET_SIZE*8);
112 pointer = pointer + SERVER_PACKET_SIZE * 8;
113 if (status)
114 error_counter++;
115
116 /* Create an IP instance. */
117 status = nx_ip_create(&server_ip, "HTTP Server IP", HTTP_SERVER_ADDRESS,
118 0xFFFFFF00UL, &server_pool, _nx_ram_network_driver_1024,
119 pointer, 4096, 1);
120 pointer = pointer + 4096;
121 if (status)
122 error_counter++;
123
124 /* Enable ARP and supply ARP cache memory for the server IP instance. */
125 status = nx_arp_enable(&server_ip, (void *) pointer, 1024);
126 pointer = pointer + 1024;
127 if (status)
128 error_counter++;
129
130
131 /* Enable TCP traffic. */
132 status = nx_tcp_enable(&server_ip);
133 if (status)
134 error_counter++;
135
136 /* Create the HTTP Client thread. */
137 status = tx_thread_create(&client_thread, "HTTP Client", thread_client_entry, 0,
138 pointer, DEMO_STACK_SIZE,
139 NX_WEB_HTTP_SERVER_PRIORITY + 2, NX_WEB_HTTP_SERVER_PRIORITY + 2, TX_NO_TIME_SLICE, TX_AUTO_START);
140 pointer = pointer + DEMO_STACK_SIZE;
141 if (status)
142 error_counter++;
143
144 /* Create the Client packet pool. */
145 status = nx_packet_pool_create(&client_pool, "HTTP Client Packet Pool", CLIENT_PACKET_SIZE,
146 pointer, CLIENT_PACKET_SIZE*16);
147 pointer = pointer + CLIENT_PACKET_SIZE * 16;
148 if (status)
149 error_counter++;
150
151 /* Create an IP instance. */
152 status = nx_ip_create(&client_ip, "HTTP Client IP", HTTP_CLIENT_ADDRESS,
153 0xFFFFFF00UL, &client_pool, _nx_ram_network_driver_1024,
154 pointer, 2048, 1);
155 pointer = pointer + 2048;
156 if (status)
157 error_counter++;
158
159 status = nx_arp_enable(&client_ip, (void *) pointer, 1024);
160 pointer = pointer + 2048;
161 if (status)
162 error_counter++;
163
164 /* Enable TCP traffic. */
165 status = nx_tcp_enable(&client_ip);
166 if (status)
167 error_counter++;
168
169 tx_semaphore_create(&server_start, "server start", 0);
170 tx_semaphore_create(&client_stop, "client stop", 0);
171 }
172
thread_client_entry(ULONG thread_input)173 void thread_client_entry(ULONG thread_input)
174 {
175 UINT status;
176 NX_PACKET *send_packet[NX_WEB_HTTP_SERVER_NONCE_MAX + 1];
177 NX_PACKET *send_packet_replay;
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_WEB_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 /* Invoke the 'Duo' (supports IPv6/IPv4) connection call. */
217 status = nxd_tcp_client_socket_connect(&client_socket[i], &server_ip_address,
218 NX_WEB_HTTP_SERVER_PORT, NX_WAIT_FOREVER);
219
220 /* Check status. */
221 if (status)
222 error_counter++;
223
224 /* Allocate a packet. */
225 status = nx_packet_allocate(&client_pool, &send_packet[i], NX_TCP_PACKET, NX_WAIT_FOREVER);
226 if (status)
227 error_counter++;
228
229 nx_packet_data_append(send_packet[i], pkt, sizeof(pkt), &client_pool, NX_WAIT_FOREVER);
230 nx_packet_data_append(send_packet[i], "\r\n", 2, &client_pool, NX_WAIT_FOREVER);
231
232 /* Initialize the buffer. */
233 memset(nonce_buffer, 0, sizeof(nonce_buffer));
234 memset(response_buffer, 0, sizeof(response_buffer));
235
236 /* Send the request. */
237 status = nx_tcp_socket_send(&client_socket[i], send_packet[i], NX_WAIT_FOREVER);
238
239 /* Check status. */
240 if (status)
241 error_counter++;
242
243 /* Pickup the response from the Server. */
244 status = nx_tcp_socket_receive(&client_socket[i], &recv_packet, NX_WAIT_FOREVER);
245
246 /* Check status. */
247 if (status)
248 error_counter++;
249 else
250 {
251
252 if (i == NX_WEB_HTTP_SERVER_NONCE_MAX)
253 {
254 buffer_ptr = (CHAR *)recv_packet->nx_packet_prepend_ptr;
255
256 /* Check the status, no nonce entry, it should be 200. */
257 if ((buffer_ptr[9] != '5') || (buffer_ptr[10] != '0') || (buffer_ptr[11] != '0'))
258 error_counter++;
259
260 nx_packet_release(recv_packet);
261
262 /* Discconect. */
263 nx_tcp_socket_disconnect(&client_socket[i], NX_NO_WAIT);
264
265 /* Sleep for the allocated nonce to be timed out. */
266 tx_thread_sleep(NX_WEB_HTTP_SERVER_NONCE_TIMEOUT + NX_IP_PERIODIC_RATE);
267
268 /* Reconnect to HTTP server. */
269 status = nxd_tcp_client_socket_connect(&client_socket[i], &server_ip_address,
270 NX_WEB_HTTP_SERVER_PORT, NX_WAIT_FOREVER);
271
272 /* Check status. */
273 if (status)
274 error_counter++;
275
276 /* Allocate a packet. */
277 status = nx_packet_allocate(&client_pool, &send_packet[i], NX_TCP_PACKET, NX_WAIT_FOREVER);
278 if (status)
279 error_counter++;
280
281 nx_packet_data_append(send_packet[i], pkt, sizeof(pkt), &client_pool, NX_WAIT_FOREVER);
282 nx_packet_data_append(send_packet[i], "\r\n", 2, &client_pool, NX_WAIT_FOREVER);
283
284 /* Initialize the buffer. */
285 memset(nonce_buffer, 0, sizeof(nonce_buffer));
286 memset(response_buffer, 0, sizeof(response_buffer));
287
288 /* Send the request. */
289 status = nx_tcp_socket_send(&client_socket[i], send_packet[i], NX_WAIT_FOREVER);
290
291 /* Check status. */
292 if (status)
293 error_counter++;
294
295 /* Pickup the response from the Server. */
296 status = nx_tcp_socket_receive(&client_socket[i], &recv_packet, NX_WAIT_FOREVER);
297
298 /* Check status. */
299 if (status)
300 error_counter++;
301 }
302
303 /* Retrieve the nonce. */
304 status = http_nonce_retrieve(recv_packet, nonce_buffer);
305 if (status)
306 error_counter++;
307
308 nx_packet_release(recv_packet);
309 }
310
311 /* Calculate the response. */
312 http_digest_response_calculate(&client_md5data, "name", "NetX Duo HTTP demo", "Placeholderpassword", nonce_buffer, "GET",
313 "/index.htm", "00000001", "0a4f113b", response_buffer);
314
315 /* Allocate a packet. */
316 status = nx_packet_allocate(&client_pool, &send_packet[i], NX_TCP_PACKET, NX_WAIT_FOREVER);
317 if (status)
318 error_counter++;
319
320 nx_packet_data_append(send_packet[i], pkt, sizeof(pkt), &client_pool, NX_WAIT_FOREVER);
321
322 /* Build the Authorization header. */
323 nx_packet_data_append(send_packet[i], "Authorization: Digest", 21, &client_pool, NX_WAIT_FOREVER);
324 nx_packet_data_append(send_packet[i], " username=\"name\",", 17, &client_pool, NX_WAIT_FOREVER);
325 nx_packet_data_append(send_packet[i], " realm=\"NetX Duo HTTP demo\",", 28, &client_pool, NX_WAIT_FOREVER);
326 nx_packet_data_append(send_packet[i], " nonce=\"", 8, &client_pool, NX_WAIT_FOREVER);
327 nx_packet_data_append(send_packet[i], nonce_buffer, NX_WEB_HTTP_SERVER_NONCE_SIZE, &client_pool, NX_WAIT_FOREVER);
328 nx_packet_data_append(send_packet[i], "\",", 2, &client_pool, NX_WAIT_FOREVER);
329 nx_packet_data_append(send_packet[i], " uri=\"/index.htm\",", 17, &client_pool, NX_WAIT_FOREVER);
330 nx_packet_data_append(send_packet[i], " qop=auth,", 10, &client_pool, NX_WAIT_FOREVER);
331 nx_packet_data_append(send_packet[i], " nc=00000001,", 13, &client_pool, NX_WAIT_FOREVER);
332 nx_packet_data_append(send_packet[i], " cnonce=\"0a4f113b\",", 19, &client_pool, NX_WAIT_FOREVER);
333 nx_packet_data_append(send_packet[i], " response=\"", 11, &client_pool, NX_WAIT_FOREVER);
334 nx_packet_data_append(send_packet[i], response_buffer, 32, &client_pool, NX_WAIT_FOREVER);
335 nx_packet_data_append(send_packet[i], "\",", 2, &client_pool, NX_WAIT_FOREVER);
336 nx_packet_data_append(send_packet[i], " opaque=\"5ccc069c403ebaf9f0171e9517f40e41\"\r\n", 44, &client_pool, NX_WAIT_FOREVER);
337
338 nx_packet_data_append(send_packet[i], "\r\n", 2, &client_pool, NX_WAIT_FOREVER);
339
340 nx_tcp_socket_disconnect(&client_socket[i], NX_NO_WAIT);
341 }
342
343 /* Copy for replay test. */
344 nx_packet_copy(send_packet[1], &send_packet_replay, &client_pool, NX_WAIT_FOREVER);
345
346 for (i = NX_WEB_HTTP_SERVER_NONCE_MAX; i >= 0; i--)
347 {
348
349 /* Reconnect to the HTTP server. */
350 status = nxd_tcp_client_socket_connect(&client_socket[i], &server_ip_address,
351 NX_WEB_HTTP_SERVER_PORT, NX_WAIT_FOREVER);
352
353 /* Check status. */
354 if (status)
355 error_counter++;
356
357 /* Now send the packet to the HTTP server. */
358 status = nx_tcp_socket_send(&client_socket[i], send_packet[i], NX_WAIT_FOREVER);
359
360 /* Check status. */
361 if (status)
362 error_counter++;
363
364 /* Pickup the response from the Server. */
365 status = nx_tcp_socket_receive(&client_socket[i], &recv_packet, NX_WAIT_FOREVER);
366
367 /* Check status. */
368 if (status)
369 {
370 error_counter++;
371 }
372 else
373 {
374 buffer_ptr = (CHAR *)recv_packet->nx_packet_prepend_ptr;
375
376 if (i == 0)
377 {
378 /* This nonce is timed out, the response should be 401. */
379 if ((buffer_ptr[9] != '4') || (buffer_ptr[10] != '0') || (buffer_ptr[11] != '1'))
380 error_counter++;
381 }
382 else
383 {
384 /* Check the status, If authentication success , it should be 200. */
385 if ((buffer_ptr[9] != '2') || (buffer_ptr[10] != '0') || (buffer_ptr[11] != '0'))
386 error_counter++;
387 }
388
389 nx_packet_release(recv_packet);
390 }
391
392 if (i != 1)
393 {
394
395 /* Disconnect and unbind the socket. */
396 status = nx_tcp_socket_disconnect(&client_socket[i], NX_WEB_HTTP_CLIENT_TIMEOUT);
397 status += nx_tcp_client_socket_unbind(&client_socket[i]);
398 status += nx_tcp_socket_delete(&client_socket[i]);
399 if (status)
400 error_counter++;
401 }
402 }
403
404 /* Use the copied packet for replay test. */
405 /* Create an HTTP client instance. */
406 status = nx_tcp_socket_create(&client_ip, &client_socket[0], "Socket 0",
407 NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, 200,
408 NX_NULL, NX_NULL);
409
410 /* Check status. */
411 if (status)
412 error_counter++;
413
414 /* Bind the client socket. */
415 status = nx_tcp_client_socket_bind(&client_socket[0], NX_ANY_PORT, NX_WAIT_FOREVER);
416
417 /* Check status of the bind. */
418 if (status)
419 error_counter++;
420
421 /* Connect to the HTTP server. */
422 status = nxd_tcp_client_socket_connect(&client_socket[0], &server_ip_address,
423 NX_WEB_HTTP_SERVER_PORT, NX_WAIT_FOREVER);
424
425 /* Check status. */
426 if (status)
427 error_counter++;
428
429 /* Now send the packet to the HTTP server. */
430 status = nx_tcp_socket_send(&client_socket[0], send_packet_replay, NX_WAIT_FOREVER);
431
432 /* Check status. */
433 if (status)
434 error_counter++;
435
436 /* Pickup the response from the Server. */
437 status = nx_tcp_socket_receive(&client_socket[0], &recv_packet, NX_WAIT_FOREVER);
438
439 /* Check status. */
440 if (status)
441 {
442 error_counter++;
443 }
444 else
445 {
446 buffer_ptr = (CHAR *)recv_packet->nx_packet_prepend_ptr;
447
448 /* This is a replay attack, the response should be 401. */
449 if ((buffer_ptr[9] != '4') || (buffer_ptr[10] != '0') || (buffer_ptr[11] != '1'))
450 error_counter++;
451
452 nx_packet_release(recv_packet);
453 }
454
455 for (i = 0; i < 2; i++)
456 {
457
458 /* Disconnect and unbind the socket. */
459 status = nx_tcp_socket_disconnect(&client_socket[i], NX_WEB_HTTP_CLIENT_TIMEOUT);
460 status += nx_tcp_client_socket_unbind(&client_socket[i]);
461 status += nx_tcp_socket_delete(&client_socket[i]);
462 if (status)
463 error_counter++;
464 }
465
466 tx_semaphore_put(&client_stop);
467
468 if(error_counter)
469 {
470 printf("ERROR!\n");
471 test_control_return(1);
472 }
473 else
474 {
475 printf("SUCCESS!\n");
476 test_control_return(0);
477 }
478 }
479
480 /* Define the helper HTTP server thread. */
thread_server_entry(ULONG thread_input)481 void thread_server_entry(ULONG thread_input)
482 {
483 UINT status;
484 FX_FILE my_file;
485
486
487 /* Print out test information banner. */
488 printf("NetX Test: Web Digest Authenticate Timeout Test......................");
489
490 /* Check for earlier error. */
491 if(error_counter)
492 {
493 printf("ERROR!\n");
494 test_control_return(1);
495 }
496
497 fx_media_format(&ram_disk,
498 _fx_ram_driver, // Driver entry
499 ram_disk_memory, // RAM disk memory pointer
500 media_memory, // Media buffer pointer
501 sizeof(media_memory), // Media buffer size
502 "MY_RAM_DISK", // Volume Name
503 1, // Number of FATs
504 32, // Directory Entries
505 0, // Hidden sectors
506 256, // Total sectors
507 512, // Sector size
508 8, // Sectors per cluster
509 1, // Heads
510 1); // Sectors per track
511
512 /* Open the RAM disk. */
513 status = fx_media_open(&ram_disk, "RAM DISK", _fx_ram_driver, ram_disk_memory, media_memory, sizeof(media_memory)) ;
514 if(status)
515 error_counter++;
516
517 /* Give NetX a chance to initialize the system. */
518 tx_thread_sleep(NX_IP_PERIODIC_RATE);
519
520 status = fx_file_create(&ram_disk, "index.htm");
521 status += fx_file_open(&ram_disk, &my_file, "index.htm", FX_OPEN_FOR_WRITE);
522 status += fx_file_write(&my_file, "https server", 12);
523 status += fx_file_close(&my_file);
524 if (status)
525 error_counter++;
526
527 /* Create the HTTP Server. */
528 status = nx_web_http_server_create(&my_server, "My HTTP Server", &server_ip, NX_WEB_HTTP_SERVER_PORT, &ram_disk,
529 &server_stack, sizeof(server_stack), &server_pool,
530 authentication_check, NX_NULL);
531 if (status)
532 error_counter++;
533
534 /* OK to start the HTTP Server. */
535 status = nx_web_http_server_start(&my_server);
536 if (status)
537 error_counter++;
538
539 tx_semaphore_put(&server_start);
540 }
541
542 /* Define the application's authentication check. This is called by
543 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)544 static UINT authentication_check(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type,
545 CHAR *resource, CHAR **name, CHAR **password, CHAR **realm)
546 {
547
548 /* Just use a simple name, password, and realm for all
549 requests and resources. */
550 *name = "name";
551 *password = "Placeholderpassword";
552 *realm = "NetX Duo HTTP demo";
553
554 /* Request digest authentication. */
555 return(NX_WEB_HTTP_DIGEST_AUTHENTICATE);
556 }
557
558 #else
559
560 #ifdef CTEST
test_application_define(void * first_unused_memory)561 VOID test_application_define(void *first_unused_memory)
562 #else
563 void netx_web_digest_authenticate_timeout_test_application_define(void *first_unused_memory)
564 #endif
565 {
566
567 /* Print out test information banner. */
568 printf("NetX Test: Web Digest Authenticate Timeout Test......................N/A\n");
569
570 test_control_return(3);
571 }
572 #endif
573
574