blob: 4e85f72bfad3820b0d612679765a0731089e12d2 [file] [log] [blame]
Paul Bakkerb60b95f2012-09-25 09:05:17 +00001/*
2 * SSL client with options
3 *
4 * Copyright (C) 2006-2012, Brainspark B.V.
5 *
6 * This file is part of PolarSSL (http://www.polarssl.org)
7 * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
8 *
9 * All rights reserved.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 */
25
26#ifndef _CRT_SECURE_NO_DEPRECATE
27#define _CRT_SECURE_NO_DEPRECATE 1
28#endif
29
30#if defined(_WIN32)
31#include <windows.h>
32#endif
33
34#include <string.h>
35#include <stdlib.h>
36#include <stdio.h>
37
38#include "polarssl/config.h"
39
40#include "polarssl/net.h"
41#include "polarssl/ssl.h"
42#include "polarssl/entropy.h"
43#include "polarssl/ctr_drbg.h"
44#include "polarssl/certs.h"
45#include "polarssl/x509.h"
46#include "polarssl/error.h"
47
48#define DFL_SERVER_PORT 4433
49#define DFL_REQUEST_PAGE "/"
50#define DFL_DEBUG_LEVEL 0
51#define DFL_CA_FILE ""
52#define DFL_CA_PATH ""
53#define DFL_CRT_FILE ""
54#define DFL_KEY_FILE ""
55#define DFL_FORCE_CIPHER 0
56#define DFL_RENEGOTIATION SSL_RENEGOTIATION_ENABLED
57#define DFL_ALLOW_LEGACY SSL_LEGACY_NO_RENEGOTIATION
58
59#define HTTP_RESPONSE \
60 "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n" \
61 "<h2>PolarSSL Test Server</h2>\r\n" \
62 "<p>Successful connection using: %s</p>\r\n"
63
64/*
65 * Computing a "safe" DH-1024 prime can take a very
66 * long time, so a precomputed value is provided below.
67 * You may run dh_genprime to generate a new value.
68 */
69char *my_dhm_P =
70 "E4004C1F94182000103D883A448B3F80" \
71 "2CE4B44A83301270002C20D0321CFD00" \
72 "11CCEF784C26A400F43DFB901BCA7538" \
73 "F2C6B176001CF5A0FD16D2C48B1D0C1C" \
74 "F6AC8E1DA6BCC3B4E1F96B0564965300" \
75 "FFA1D0B601EB2800F489AA512C4B248C" \
76 "01F76949A60BB7F00A40B1EAB64BDD48" \
77 "E8A700D60B7F1200FA8E77B0A979DABF";
78
79char *my_dhm_G = "4";
80
81/*
82 * global options
83 */
84struct options
85{
86 int server_port; /* port on which the ssl service runs */
87 int debug_level; /* level of debugging */
88 char *ca_file; /* the file with the CA certificate(s) */
89 char *ca_path; /* the path with the CA certificate(s) reside */
90 char *crt_file; /* the file with the client certificate */
91 char *key_file; /* the file with the client key */
92 int force_ciphersuite[2]; /* protocol/ciphersuite to use, or all */
93 int renegotiation; /* enable / disable renegotiation */
94 int allow_legacy; /* allow legacy renegotiation */
95} opt;
96
97void my_debug( void *ctx, int level, const char *str )
98{
99 if( level < opt.debug_level )
100 {
101 fprintf( (FILE *) ctx, "%s", str );
102 fflush( (FILE *) ctx );
103 }
104}
105
106/*
107 * These session callbacks use a simple chained list
108 * to store and retrieve the session information.
109 */
110ssl_session *s_list_1st = NULL;
111ssl_session *cur, *prv;
112
113static int my_get_session( ssl_context *ssl )
114{
115 time_t t = time( NULL );
116
117 if( ssl->resume == 0 )
118 return( 1 );
119
120 cur = s_list_1st;
121 prv = NULL;
122
123 while( cur != NULL )
124 {
125 prv = cur;
126 cur = cur->next;
127
128 if( ssl->timeout != 0 && (int) ( t - prv->start ) > ssl->timeout )
129 continue;
130
131 if( ssl->session->ciphersuite != prv->ciphersuite ||
132 ssl->session->length != prv->length )
133 continue;
134
135 if( memcmp( ssl->session->id, prv->id, prv->length ) != 0 )
136 continue;
137
138 memcpy( ssl->session->master, prv->master, 48 );
139 return( 0 );
140 }
141
142 return( 1 );
143}
144
145static int my_set_session( ssl_context *ssl )
146{
147 time_t t = time( NULL );
148
149 cur = s_list_1st;
150 prv = NULL;
151
152 while( cur != NULL )
153 {
154 if( ssl->timeout != 0 && (int) ( t - cur->start ) > ssl->timeout )
155 break; /* expired, reuse this slot */
156
157 if( memcmp( ssl->session->id, cur->id, cur->length ) == 0 )
158 break; /* client reconnected */
159
160 prv = cur;
161 cur = cur->next;
162 }
163
164 if( cur == NULL )
165 {
166 cur = (ssl_session *) malloc( sizeof( ssl_session ) );
167 if( cur == NULL )
168 return( 1 );
169
170 if( prv == NULL )
171 s_list_1st = cur;
172 else prv->next = cur;
173 }
174
175 memcpy( cur, ssl->session, sizeof( ssl_session ) );
176
177 return( 0 );
178}
179
180#if defined(POLARSSL_FS_IO)
181#define USAGE_IO \
182 " ca_file=%%s default: \"\" (pre-loaded)\n" \
183 " ca_path=%%s default: \"\" (pre-loaded) (overrides ca_file)\n" \
184 " crt_file=%%s default: \"\" (pre-loaded)\n" \
185 " key_file=%%s default: \"\" (pre-loaded)\n"
186#else
187#define USAGE_IO \
188 " No file operations available (POLARSSL_FS_IO not defined)\n"
189#endif /* POLARSSL_FS_IO */
190
191#define USAGE \
192 "\n usage: ssl_server2 param=<>...\n" \
193 "\n acceptable parameters:\n" \
194 " server_port=%%d default: 4433\n" \
195 " debug_level=%%d default: 0 (disabled)\n" \
196 USAGE_IO \
197 " request_page=%%s default: \".\"\n" \
198 " renegotiation=%%d default: 1 (enabled)\n" \
199 " allow_legacy=%%d default: 0 (disabled)\n" \
200 " force_ciphersuite=<name> default: all enabled\n"\
201 " acceptable ciphersuite names:\n"
202
203#if !defined(POLARSSL_BIGNUM_C) || !defined(POLARSSL_ENTROPY_C) || \
204 !defined(POLARSSL_SSL_TLS_C) || !defined(POLARSSL_SSL_SRV_C) || \
205 !defined(POLARSSL_NET_C) || !defined(POLARSSL_RSA_C) || \
206 !defined(POLARSSL_CTR_DRBG_C)
207int main( int argc, char *argv[] )
208{
209 ((void) argc);
210 ((void) argv);
211
212 printf("POLARSSL_BIGNUM_C and/or POLARSSL_ENTROPY_C and/or "
213 "POLARSSL_SSL_TLS_C and/or POLARSSL_SSL_SRV_C and/or "
214 "POLARSSL_NET_C and/or POLARSSL_RSA_C and/or "
215 "POLARSSL_CTR_DRBG_C not defined.\n");
216 return( 0 );
217}
218#else
219int main( int argc, char *argv[] )
220{
221 int ret = 0, len;
222 int listen_fd;
223 int client_fd = -1;
224 unsigned char buf[1024];
225 char *pers = "ssl_server2";
226
227 entropy_context entropy;
228 ctr_drbg_context ctr_drbg;
229 ssl_context ssl;
230 ssl_session ssn;
231 x509_cert cacert;
232 x509_cert srvcert;
233 rsa_context rsa;
234
235 int i;
236 size_t j, n;
237 char *p, *q;
238 const int *list;
239
240 /*
241 * Make sure memory references are valid.
242 */
243 listen_fd = 0;
244 memset( &ssn, 0, sizeof( ssl_session ) );
245 memset( &ssl, 0, sizeof( ssl_context ) );
246 memset( &cacert, 0, sizeof( x509_cert ) );
247 memset( &srvcert, 0, sizeof( x509_cert ) );
248 memset( &rsa, 0, sizeof( rsa_context ) );
249
250 if( argc == 0 )
251 {
252 usage:
253 if( ret == 0 )
254 ret = 1;
255
256 printf( USAGE );
257
258 list = ssl_list_ciphersuites();
259 while( *list )
260 {
261 printf(" %s\n", ssl_get_ciphersuite_name( *list ) );
262 list++;
263 }
264 printf("\n");
265 goto exit;
266 }
267
268 opt.server_port = DFL_SERVER_PORT;
269 opt.debug_level = DFL_DEBUG_LEVEL;
270 opt.ca_file = DFL_CA_FILE;
271 opt.ca_path = DFL_CA_PATH;
272 opt.crt_file = DFL_CRT_FILE;
273 opt.key_file = DFL_KEY_FILE;
274 opt.force_ciphersuite[0]= DFL_FORCE_CIPHER;
275 opt.renegotiation = DFL_RENEGOTIATION;
276 opt.allow_legacy = DFL_ALLOW_LEGACY;
277
278 for( i = 1; i < argc; i++ )
279 {
280 n = strlen( argv[i] );
281
282 for( j = 0; j < n; j++ )
283 {
284 if( argv[i][j] >= 'A' && argv[i][j] <= 'Z' )
285 argv[i][j] |= 0x20;
286 }
287
288 p = argv[i];
289 if( ( q = strchr( p, '=' ) ) == NULL )
290 goto usage;
291 *q++ = '\0';
292
293 if( strcmp( p, "server_port" ) == 0 )
294 {
295 opt.server_port = atoi( q );
296 if( opt.server_port < 1 || opt.server_port > 65535 )
297 goto usage;
298 }
299 else if( strcmp( p, "debug_level" ) == 0 )
300 {
301 opt.debug_level = atoi( q );
302 if( opt.debug_level < 0 || opt.debug_level > 65535 )
303 goto usage;
304 }
305 else if( strcmp( p, "ca_file" ) == 0 )
306 opt.ca_file = q;
307 else if( strcmp( p, "ca_path" ) == 0 )
308 opt.ca_path = q;
309 else if( strcmp( p, "crt_file" ) == 0 )
310 opt.crt_file = q;
311 else if( strcmp( p, "key_file" ) == 0 )
312 opt.key_file = q;
313 else if( strcmp( p, "force_ciphersuite" ) == 0 )
314 {
315 opt.force_ciphersuite[0] = -1;
316
317 opt.force_ciphersuite[0] = ssl_get_ciphersuite_id( q );
318
319 if( opt.force_ciphersuite[0] <= 0 )
320 {
321 ret = 2;
322 goto usage;
323 }
324 opt.force_ciphersuite[1] = 0;
325 }
326 else if( strcmp( p, "renegotiation" ) == 0 )
327 {
328 opt.renegotiation = (atoi( q )) ? SSL_RENEGOTIATION_ENABLED :
329 SSL_RENEGOTIATION_DISABLED;
330 }
331 else if( strcmp( p, "allow_legacy" ) == 0 )
332 {
333 opt.allow_legacy = atoi( q );
334 if( opt.allow_legacy < 0 || opt.allow_legacy > 1 )
335 goto usage;
336 }
337 else
338 goto usage;
339 }
340
341 /*
342 * 0. Initialize the RNG and the session data
343 */
344 printf( "\n . Seeding the random number generator..." );
345 fflush( stdout );
346
347 entropy_init( &entropy );
348 if( ( ret = ctr_drbg_init( &ctr_drbg, entropy_func, &entropy,
349 (unsigned char *) pers, strlen( pers ) ) ) != 0 )
350 {
351 printf( " failed\n ! ctr_drbg_init returned -0x%x\n", -ret );
352 goto exit;
353 }
354
355 printf( " ok\n" );
356
357 /*
358 * 1.1. Load the trusted CA
359 */
360 printf( " . Loading the CA root certificate ..." );
361 fflush( stdout );
362
363#if defined(POLARSSL_FS_IO)
364 if( strlen( opt.ca_path ) )
365 ret = x509parse_crtpath( &cacert, opt.ca_path );
366 else if( strlen( opt.ca_file ) )
367 ret = x509parse_crtfile( &cacert, opt.ca_file );
368 else
369#endif
370#if defined(POLARSSL_CERTS_C)
371 ret = x509parse_crt( &cacert, (unsigned char *) test_ca_crt,
372 strlen( test_ca_crt ) );
373#else
374 {
375 ret = 1;
376 printf("POLARSSL_CERTS_C not defined.");
377 }
378#endif
379 if( ret < 0 )
380 {
381 printf( " failed\n ! x509parse_crt returned -0x%x\n\n", -ret );
382 goto exit;
383 }
384
385 printf( " ok (%d skipped)\n", ret );
386
387 /*
388 * 1.2. Load own certificate and private key
389 */
390 printf( " . Loading the server cert. and key..." );
391 fflush( stdout );
392
393#if defined(POLARSSL_FS_IO)
394 if( strlen( opt.crt_file ) )
395 ret = x509parse_crtfile( &srvcert, opt.crt_file );
396 else
397#endif
398#if defined(POLARSSL_CERTS_C)
399 ret = x509parse_crt( &srvcert, (unsigned char *) test_srv_crt,
400 strlen( test_srv_crt ) );
401#else
402 {
403 ret = 1;
404 printf("POLARSSL_CERTS_C not defined.");
405 }
406#endif
407 if( ret != 0 )
408 {
409 printf( " failed\n ! x509parse_crt returned -0x%x\n\n", -ret );
410 goto exit;
411 }
412
413#if defined(POLARSSL_FS_IO)
414 if( strlen( opt.key_file ) )
415 ret = x509parse_keyfile( &rsa, opt.key_file, "" );
416 else
417#endif
418#if defined(POLARSSL_CERTS_C)
419 ret = x509parse_key( &rsa, (unsigned char *) test_srv_key,
420 strlen( test_srv_key ), NULL, 0 );
421#else
422 {
423 ret = 1;
424 printf("POLARSSL_CERTS_C not defined.");
425 }
426#endif
427 if( ret != 0 )
428 {
429 printf( " failed\n ! x509parse_key returned -0x%x\n\n", -ret );
430 goto exit;
431 }
432
433 printf( " ok\n" );
434
435 /*
436 * 2. Setup the listening TCP socket
437 */
438 printf( " . Bind on tcp://localhost:%-4d/ ...", opt.server_port );
439 fflush( stdout );
440
441 if( ( ret = net_bind( &listen_fd, NULL, opt.server_port ) ) != 0 )
442 {
443 printf( " failed\n ! net_bind returned -0x%x\n\n", -ret );
444 goto exit;
445 }
446
447 printf( " ok\n" );
448
449 /*
450 * 3. Setup stuff
451 */
452 printf( " . Setting up the SSL/TLS structure..." );
453 fflush( stdout );
454
455 if( ( ret = ssl_init( &ssl ) ) != 0 )
456 {
457 printf( " failed\n ! ssl_init returned -0x%x\n\n", -ret );
458 goto exit;
459 }
460
461 ssl_set_endpoint( &ssl, SSL_IS_SERVER );
462 ssl_set_authmode( &ssl, SSL_VERIFY_NONE );
463
464 ssl_set_rng( &ssl, ctr_drbg_random, &ctr_drbg );
465 ssl_set_dbg( &ssl, my_debug, stdout );
466
467 ssl_set_scb( &ssl, my_get_session,
468 my_set_session );
469
470 if( opt.force_ciphersuite[0] == DFL_FORCE_CIPHER )
471 ssl_set_ciphersuites( &ssl, ssl_default_ciphersuites );
472 else
473 ssl_set_ciphersuites( &ssl, opt.force_ciphersuite );
474
475 ssl_set_renegotiation( &ssl, opt.renegotiation );
476 ssl_legacy_renegotiation( &ssl, opt.allow_legacy );
477
478 ssl_set_session( &ssl, 1, 0, &ssn );
479
480 ssl_set_ca_chain( &ssl, &cacert, NULL, NULL );
481 ssl_set_own_cert( &ssl, &srvcert, &rsa );
482
483#if defined(POLARSSL_DHM_C)
484 ssl_set_dh_param( &ssl, my_dhm_P, my_dhm_G );
485#endif
486
487 printf( " ok\n" );
488
489reset:
490#ifdef POLARSSL_ERROR_C
491 if( ret != 0 )
492 {
493 char error_buf[100];
494 error_strerror( ret, error_buf, 100 );
495 printf("Last error was: %d - %s\n\n", ret, error_buf );
496 }
497#endif
498
499 if( client_fd != -1 )
500 net_close( client_fd );
501
502 ssl_session_reset( &ssl );
503
504 /*
505 * 3. Wait until a client connects
506 */
507#if defined(_WIN32_WCE)
508 {
509 SHELLEXECUTEINFO sei;
510
511 ZeroMemory( &sei, sizeof( SHELLEXECUTEINFO ) );
512
513 sei.cbSize = sizeof( SHELLEXECUTEINFO );
514 sei.fMask = 0;
515 sei.hwnd = 0;
516 sei.lpVerb = _T( "open" );
517 sei.lpFile = _T( "https://localhost:4433/" );
518 sei.lpParameters = NULL;
519 sei.lpDirectory = NULL;
520 sei.nShow = SW_SHOWNORMAL;
521
522 ShellExecuteEx( &sei );
523 }
524#elif defined(_WIN32)
525 ShellExecute( NULL, "open", "https://localhost:4433/",
526 NULL, NULL, SW_SHOWNORMAL );
527#endif
528
529 client_fd = -1;
530
531 printf( " . Waiting for a remote connection ..." );
532 fflush( stdout );
533
534 if( ( ret = net_accept( listen_fd, &client_fd, NULL ) ) != 0 )
535 {
536 printf( " failed\n ! net_accept returned -0x%x\n\n", -ret );
537 goto exit;
538 }
539
540 ssl_set_bio( &ssl, net_recv, &client_fd,
541 net_send, &client_fd );
542
543 printf( " ok\n" );
544
545 /*
546 * 4. Handshake
547 */
548 printf( " . Performing the SSL/TLS handshake..." );
549 fflush( stdout );
550
551 while( ( ret = ssl_handshake( &ssl ) ) != 0 )
552 {
553 if( ret != POLARSSL_ERR_NET_WANT_READ && ret != POLARSSL_ERR_NET_WANT_WRITE )
554 {
555 printf( " failed\n ! ssl_handshake returned -0x%x\n\n", -ret );
556 goto exit;
557 }
558 }
559
560 printf( " ok\n [ Ciphersuite is %s ]\n",
561 ssl_get_ciphersuite( &ssl ) );
562
563 /*
564 * 5. Verify the server certificate
565 */
566 printf( " . Verifying peer X.509 certificate..." );
567
568 if( ( ret = ssl_get_verify_result( &ssl ) ) != 0 )
569 {
570 printf( " failed\n" );
571
572 if( !ssl.session->peer_cert )
573 printf( " ! no client certificate sent\n" );
574
575 if( ( ret & BADCERT_EXPIRED ) != 0 )
576 printf( " ! client certificate has expired\n" );
577
578 if( ( ret & BADCERT_REVOKED ) != 0 )
579 printf( " ! client certificate has been revoked\n" );
580
581 if( ( ret & BADCERT_NOT_TRUSTED ) != 0 )
582 printf( " ! self-signed or not signed by a trusted CA\n" );
583
584 printf( "\n" );
585 }
586 else
587 printf( " ok\n" );
588
589 if( ssl.session->peer_cert )
590 {
591 printf( " . Peer certificate information ...\n" );
592 x509parse_cert_info( (char *) buf, sizeof( buf ) - 1, " ",
593 ssl.session->peer_cert );
594 printf( "%s\n", buf );
595 }
596
597 /*
598 * 6. Read the HTTP Request
599 */
600 printf( " < Read from client:" );
601 fflush( stdout );
602
603 do
604 {
605 len = sizeof( buf ) - 1;
606 memset( buf, 0, sizeof( buf ) );
607 ret = ssl_read( &ssl, buf, len );
608
609 if( ret == POLARSSL_ERR_NET_WANT_READ || ret == POLARSSL_ERR_NET_WANT_WRITE )
610 continue;
611
612 if( ret <= 0 )
613 {
614 switch( ret )
615 {
616 case POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY:
617 printf( " connection was closed gracefully\n" );
618 break;
619
620 case POLARSSL_ERR_NET_CONN_RESET:
621 printf( " connection was reset by peer\n" );
622 break;
623
624 default:
625 printf( " ssl_read returned -0x%x\n", -ret );
626 break;
627 }
628
629 break;
630 }
631
632 len = ret;
633 printf( " %d bytes read\n\n%s", len, (char *) buf );
634
635 if( ret > 0 )
636 break;
637 }
638 while( 1 );
639
640 /*
641 * 7. Write the 200 Response
642 */
643 printf( " > Write to client:" );
644 fflush( stdout );
645
646 len = sprintf( (char *) buf, HTTP_RESPONSE,
647 ssl_get_ciphersuite( &ssl ) );
648
649 while( ( ret = ssl_write( &ssl, buf, len ) ) <= 0 )
650 {
651 if( ret == POLARSSL_ERR_NET_CONN_RESET )
652 {
653 printf( " failed\n ! peer closed the connection\n\n" );
654 goto reset;
655 }
656
657 if( ret != POLARSSL_ERR_NET_WANT_READ && ret != POLARSSL_ERR_NET_WANT_WRITE )
658 {
659 printf( " failed\n ! ssl_write returned %d\n\n", ret );
660 goto exit;
661 }
662 }
663
664 len = ret;
665 printf( " %d bytes written\n\n%s\n", len, (char *) buf );
666
667 ret = 0;
668 goto reset;
669
670exit:
671
672#ifdef POLARSSL_ERROR_C
673 if( ret != 0 )
674 {
675 char error_buf[100];
676 error_strerror( ret, error_buf, 100 );
677 printf("Last error was: -0x%X - %s\n\n", -ret, error_buf );
678 }
679#endif
680
681 net_close( client_fd );
682 x509_free( &srvcert );
683 x509_free( &cacert );
684 rsa_free( &rsa );
685 ssl_session_free( &ssn );
686 ssl_session_free( s_list_1st );
687 ssl_free( &ssl );
688
689#if defined(_WIN32)
690 printf( " + Press Enter to exit this program.\n" );
691 fflush( stdout ); getchar();
692#endif
693
694 return( ret );
695}
696#endif /* POLARSSL_BIGNUM_C && POLARSSL_ENTROPY_C && POLARSSL_SSL_TLS_C &&
697 POLARSSL_SSL_SRV_C && POLARSSL_NET_C && POLARSSL_RSA_C &&
698 POLARSSL_CTR_DRBG_C */