blob: 2cad32edcc6ebf27513d495e08b813b9b36d5671 [file] [log] [blame]
Paul Bakker1496d382011-05-23 12:07:29 +00001/*
2 * SSL client for SMTP servers
3 *
Manuel Pégourié-Gonnarda658a402015-01-23 09:45:19 +00004 * Copyright (C) 2006-2012, ARM Limited, All Rights Reserved
Paul Bakker1496d382011-05-23 12:07:29 +00005 *
Manuel Pégourié-Gonnard967a2a52015-01-22 14:28:16 +00006 * This file is part of mbed TLS (http://www.polarssl.org)
Paul Bakker1496d382011-05-23 12:07:29 +00007 * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
8 *
Paul Bakker1496d382011-05-23 12:07:29 +00009 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 */
23
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020024#if !defined(POLARSSL_CONFIG_FILE)
Manuel Pégourié-Gonnardabd6e022013-09-20 13:30:43 +020025#include "polarssl/config.h"
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020026#else
27#include POLARSSL_CONFIG_FILE
28#endif
Paul Bakker1496d382011-05-23 12:07:29 +000029
30#include <string.h>
31#include <stdlib.h>
32#include <stdio.h>
Paul Bakkerfdda7852013-11-30 15:15:31 +010033
34#if !defined(_MSC_VER) || defined(EFIX64) || defined(EFI32)
Paul Bakker1496d382011-05-23 12:07:29 +000035#include <unistd.h>
Paul Bakkerfdda7852013-11-30 15:15:31 +010036#else
37#include <io.h>
38#define read _read
39#define write _write
40#endif
Paul Bakker1496d382011-05-23 12:07:29 +000041
Paul Bakker5a835222011-10-12 09:19:31 +000042#if defined(_WIN32) || defined(_WIN32_WCE)
43
44#include <winsock2.h>
45#include <windows.h>
46
Paul Bakkerf0fc2a22013-12-30 15:42:43 +010047#if defined(_MSC_VER)
Paul Bakker5a835222011-10-12 09:19:31 +000048#if defined(_WIN32_WCE)
49#pragma comment( lib, "ws2.lib" )
50#else
51#pragma comment( lib, "ws2_32.lib" )
52#endif
Paul Bakkerf0fc2a22013-12-30 15:42:43 +010053#endif /* _MSC_VER */
Paul Bakker5a835222011-10-12 09:19:31 +000054#endif
55
Paul Bakker1496d382011-05-23 12:07:29 +000056#include "polarssl/base64.h"
57#include "polarssl/error.h"
58#include "polarssl/net.h"
59#include "polarssl/ssl.h"
Paul Bakker508ad5a2011-12-04 17:09:26 +000060#include "polarssl/entropy.h"
61#include "polarssl/ctr_drbg.h"
Paul Bakker1496d382011-05-23 12:07:29 +000062#include "polarssl/certs.h"
63#include "polarssl/x509.h"
64
Paul Bakker9a97c5d2013-09-15 17:07:33 +020065#if !defined(POLARSSL_BIGNUM_C) || !defined(POLARSSL_ENTROPY_C) || \
66 !defined(POLARSSL_SSL_TLS_C) || !defined(POLARSSL_SSL_CLI_C) || \
67 !defined(POLARSSL_NET_C) || !defined(POLARSSL_RSA_C) || \
Paul Bakker36713e82013-09-17 13:25:29 +020068 !defined(POLARSSL_CTR_DRBG_C) || !defined(POLARSSL_X509_CRT_PARSE_C)
Paul Bakker9a97c5d2013-09-15 17:07:33 +020069int main( int argc, char *argv[] )
70{
71 ((void) argc);
72 ((void) argv);
73
74 printf("POLARSSL_BIGNUM_C and/or POLARSSL_ENTROPY_C and/or "
75 "POLARSSL_SSL_TLS_C and/or POLARSSL_SSL_CLI_C and/or "
76 "POLARSSL_NET_C and/or POLARSSL_RSA_C and/or "
Paul Bakker36713e82013-09-17 13:25:29 +020077 "POLARSSL_CTR_DRBG_C and/or POLARSSL_X509_CRT_PARSE_C "
Paul Bakker9a97c5d2013-09-15 17:07:33 +020078 "not defined.\n");
79 return( 0 );
80}
81#else
82
Paul Bakker1496d382011-05-23 12:07:29 +000083#define DFL_SERVER_NAME "localhost"
84#define DFL_SERVER_PORT 465
85#define DFL_USER_NAME "user"
86#define DFL_USER_PWD "password"
87#define DFL_MAIL_FROM ""
88#define DFL_MAIL_TO ""
89#define DFL_DEBUG_LEVEL 0
Paul Bakker5690efc2011-05-26 13:16:06 +000090#define DFL_CA_FILE ""
Paul Bakker1496d382011-05-23 12:07:29 +000091#define DFL_CRT_FILE ""
92#define DFL_KEY_FILE ""
93#define DFL_FORCE_CIPHER 0
94#define DFL_MODE 0
95#define DFL_AUTHENTICATION 0
96
97#define MODE_SSL_TLS 0
98#define MODE_STARTTLS 0
99
100/*
101 * global options
102 */
103struct options
104{
Paul Bakkeref3f8c72013-06-24 13:01:08 +0200105 const char *server_name; /* hostname of the server (client only) */
Paul Bakker1496d382011-05-23 12:07:29 +0000106 int server_port; /* port on which the ssl service runs */
107 int debug_level; /* level of debugging */
108 int authentication; /* if authentication is required */
109 int mode; /* SSL/TLS (0) or STARTTLS (1) */
Paul Bakkeref3f8c72013-06-24 13:01:08 +0200110 const char *user_name; /* username to use for authentication */
111 const char *user_pwd; /* password to use for authentication */
112 const char *mail_from; /* E-Mail address to use as sender */
113 const char *mail_to; /* E-Mail address to use as recipient */
114 const char *ca_file; /* the file with the CA certificate(s) */
115 const char *crt_file; /* the file with the client certificate */
116 const char *key_file; /* the file with the client key */
Paul Bakker1496d382011-05-23 12:07:29 +0000117 int force_ciphersuite[2]; /* protocol/ciphersuite to use, or all */
118} opt;
119
Paul Bakker3c5ef712013-06-25 16:37:45 +0200120static void my_debug( void *ctx, int level, const char *str )
Paul Bakker1496d382011-05-23 12:07:29 +0000121{
122 if( level < opt.debug_level )
123 {
124 fprintf( (FILE *) ctx, "%s", str );
125 fflush( (FILE *) ctx );
126 }
127}
128
Paul Bakker3c5ef712013-06-25 16:37:45 +0200129static int do_handshake( ssl_context *ssl, struct options *opt )
Paul Bakker1496d382011-05-23 12:07:29 +0000130{
131 int ret;
132 unsigned char buf[1024];
Paul Bakker5690efc2011-05-26 13:16:06 +0000133 memset(buf, 0, 1024);
Paul Bakker1496d382011-05-23 12:07:29 +0000134
135 /*
136 * 4. Handshake
137 */
138 printf( " . Performing the SSL/TLS handshake..." );
139 fflush( stdout );
140
141 while( ( ret = ssl_handshake( ssl ) ) != 0 )
142 {
143 if( ret != POLARSSL_ERR_NET_WANT_READ && ret != POLARSSL_ERR_NET_WANT_WRITE )
144 {
Paul Bakker5690efc2011-05-26 13:16:06 +0000145#if defined(POLARSSL_ERROR_C)
Paul Bakker03a8a792013-06-30 12:18:08 +0200146 polarssl_strerror( ret, (char *) buf, 1024 );
Paul Bakker5690efc2011-05-26 13:16:06 +0000147#endif
Paul Bakker1496d382011-05-23 12:07:29 +0000148 printf( " failed\n ! ssl_handshake returned %d: %s\n\n", ret, buf );
149 return( -1 );
150 }
151 }
152
153 printf( " ok\n [ Ciphersuite is %s ]\n",
154 ssl_get_ciphersuite( ssl ) );
155
156 /*
157 * 5. Verify the server certificate
158 */
159 printf( " . Verifying peer X.509 certificate..." );
160
Manuel Pégourié-Gonnardfcf2fc22014-03-11 11:10:27 +0100161 /* In real life, we may want to bail out when ret != 0 */
Paul Bakker1496d382011-05-23 12:07:29 +0000162 if( ( ret = ssl_get_verify_result( ssl ) ) != 0 )
163 {
164 printf( " failed\n" );
165
166 if( ( ret & BADCERT_EXPIRED ) != 0 )
167 printf( " ! server certificate has expired\n" );
168
169 if( ( ret & BADCERT_REVOKED ) != 0 )
170 printf( " ! server certificate has been revoked\n" );
171
172 if( ( ret & BADCERT_CN_MISMATCH ) != 0 )
173 printf( " ! CN mismatch (expected CN=%s)\n", opt->server_name );
174
175 if( ( ret & BADCERT_NOT_TRUSTED ) != 0 )
176 printf( " ! self-signed or not signed by a trusted CA\n" );
177
178 printf( "\n" );
179 }
180 else
181 printf( " ok\n" );
182
183 printf( " . Peer certificate information ...\n" );
Paul Bakkerddf26b42013-09-18 13:46:23 +0200184 x509_crt_info( (char *) buf, sizeof( buf ) - 1, " ",
185 ssl_get_peer_cert( ssl ) );
Paul Bakker1496d382011-05-23 12:07:29 +0000186 printf( "%s\n", buf );
187
188 return( 0 );
189}
190
Paul Bakker3c5ef712013-06-25 16:37:45 +0200191static int write_ssl_data( ssl_context *ssl, unsigned char *buf, size_t len )
Paul Bakker1496d382011-05-23 12:07:29 +0000192{
193 int ret;
194
195 printf("\n%s", buf);
196 while( len && ( ret = ssl_write( ssl, buf, len ) ) <= 0 )
197 {
198 if( ret != POLARSSL_ERR_NET_WANT_READ && ret != POLARSSL_ERR_NET_WANT_WRITE )
199 {
200 printf( " failed\n ! ssl_write returned %d\n\n", ret );
201 return -1;
202 }
203 }
204
205 return( 0 );
206}
207
Paul Bakker3c5ef712013-06-25 16:37:45 +0200208static int write_ssl_and_get_response( ssl_context *ssl, unsigned char *buf, size_t len )
Paul Bakker1496d382011-05-23 12:07:29 +0000209{
210 int ret;
211 unsigned char data[128];
212 char code[4];
213 size_t i, idx = 0;
214
215 printf("\n%s", buf);
216 while( len && ( ret = ssl_write( ssl, buf, len ) ) <= 0 )
217 {
218 if( ret != POLARSSL_ERR_NET_WANT_READ && ret != POLARSSL_ERR_NET_WANT_WRITE )
219 {
220 printf( " failed\n ! ssl_write returned %d\n\n", ret );
221 return -1;
222 }
223 }
224
225 do
226 {
227 len = sizeof( data ) - 1;
228 memset( data, 0, sizeof( data ) );
229 ret = ssl_read( ssl, data, len );
230
231 if( ret == POLARSSL_ERR_NET_WANT_READ || ret == POLARSSL_ERR_NET_WANT_WRITE )
232 continue;
233
234 if( ret == POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY )
235 return -1;
236
237 if( ret <= 0 )
238 {
239 printf( "failed\n ! ssl_read returned %d\n\n", ret );
240 return -1;
241 }
242
243 printf("\n%s", data);
244 len = ret;
245 for( i = 0; i < len; i++ )
246 {
247 if( data[i] != '\n' )
248 {
249 if( idx < 4 )
250 code[ idx++ ] = data[i];
251 continue;
252 }
253
254 if( idx == 4 && code[0] >= '0' && code[0] <= '9' && code[3] == ' ' )
255 {
256 code[3] = '\0';
257 return atoi( code );
258 }
Paul Bakker3c5ef712013-06-25 16:37:45 +0200259
Paul Bakker1496d382011-05-23 12:07:29 +0000260 idx = 0;
261 }
262 }
263 while( 1 );
264}
265
Paul Bakker3c5ef712013-06-25 16:37:45 +0200266static int write_and_get_response( int sock_fd, unsigned char *buf, size_t len )
Paul Bakker1496d382011-05-23 12:07:29 +0000267{
268 int ret;
269 unsigned char data[128];
270 char code[4];
271 size_t i, idx = 0;
272
273 printf("\n%s", buf);
274 if( len && ( ret = write( sock_fd, buf, len ) ) <= 0 )
275 {
276 printf( " failed\n ! ssl_write returned %d\n\n", ret );
277 return -1;
278 }
279
280 do
281 {
282 len = sizeof( data ) - 1;
283 memset( data, 0, sizeof( data ) );
284 ret = read( sock_fd, data, len );
285
286 if( ret <= 0 )
287 {
288 printf( "failed\n ! read returned %d\n\n", ret );
289 return -1;
290 }
291
Paul Bakkerdf71dd12014-04-17 16:03:48 +0200292 data[len] = '\0';
Paul Bakker1496d382011-05-23 12:07:29 +0000293 printf("\n%s", data);
294 len = ret;
295 for( i = 0; i < len; i++ )
296 {
297 if( data[i] != '\n' )
298 {
299 if( idx < 4 )
300 code[ idx++ ] = data[i];
301 continue;
302 }
303
304 if( idx == 4 && code[0] >= '0' && code[0] <= '9' && code[3] == ' ' )
305 {
306 code[3] = '\0';
307 return atoi( code );
308 }
309
310 idx = 0;
311 }
312 }
313 while( 1 );
314}
315
Paul Bakker5690efc2011-05-26 13:16:06 +0000316#if defined(POLARSSL_BASE64_C)
317#define USAGE_AUTH \
318 " authentication=%%d default: 0 (disabled)\n" \
319 " user_name=%%s default: \"user\"\n" \
320 " user_pwd=%%s default: \"password\"\n"
321#else
322#define USAGE_AUTH \
323 " authentication options disabled. (Require POLARSSL_BASE64_C)\n"
324#endif /* POLARSSL_BASE64_C */
325
326#if defined(POLARSSL_FS_IO)
327#define USAGE_IO \
328 " ca_file=%%s default: \"\" (pre-loaded)\n" \
329 " crt_file=%%s default: \"\" (pre-loaded)\n" \
330 " key_file=%%s default: \"\" (pre-loaded)\n"
331#else
332#define USAGE_IO \
333 " No file operations available (POLARSSL_FS_IO not defined)\n"
334#endif /* POLARSSL_FS_IO */
335
Paul Bakker1496d382011-05-23 12:07:29 +0000336#define USAGE \
337 "\n usage: ssl_mail_client param=<>...\n" \
338 "\n acceptable parameters:\n" \
339 " server_name=%%s default: localhost\n" \
340 " server_port=%%d default: 4433\n" \
341 " debug_level=%%d default: 0 (disabled)\n" \
Paul Bakker1496d382011-05-23 12:07:29 +0000342 " mode=%%d default: 0 (SSL/TLS) (1 for STARTTLS)\n" \
Paul Bakker5690efc2011-05-26 13:16:06 +0000343 USAGE_AUTH \
Paul Bakker1496d382011-05-23 12:07:29 +0000344 " mail_from=%%s default: \"\"\n" \
345 " mail_to=%%s default: \"\"\n" \
Paul Bakker5690efc2011-05-26 13:16:06 +0000346 USAGE_IO \
Paul Bakker1496d382011-05-23 12:07:29 +0000347 " force_ciphersuite=<name> default: all enabled\n"\
348 " acceptable ciphersuite names:\n"
349
350int main( int argc, char *argv[] )
351{
352 int ret = 0, len, server_fd;
Paul Bakker09c9dd82014-08-18 11:06:56 +0200353 unsigned char buf[1024];
Paul Bakker5690efc2011-05-26 13:16:06 +0000354#if defined(POLARSSL_BASE64_C)
Paul Bakker1496d382011-05-23 12:07:29 +0000355 unsigned char base[1024];
Paul Bakker5690efc2011-05-26 13:16:06 +0000356#endif
Paul Bakker1496d382011-05-23 12:07:29 +0000357 char hostname[32];
Paul Bakkeref3f8c72013-06-24 13:01:08 +0200358 const char *pers = "ssl_mail_client";
Paul Bakker508ad5a2011-12-04 17:09:26 +0000359
360 entropy_context entropy;
361 ctr_drbg_context ctr_drbg;
Paul Bakker1496d382011-05-23 12:07:29 +0000362 ssl_context ssl;
Paul Bakkerc559c7a2013-09-18 14:13:26 +0200363 x509_crt cacert;
364 x509_crt clicert;
Manuel Pégourié-Gonnardac755232013-08-19 14:10:16 +0200365 pk_context pkey;
Paul Bakker1496d382011-05-23 12:07:29 +0000366 int i;
Paul Bakker819370c2012-09-28 07:04:41 +0000367 size_t n;
Paul Bakker1496d382011-05-23 12:07:29 +0000368 char *p, *q;
369 const int *list;
370
371 /*
Manuel Pégourié-Gonnard3bd2aae2013-09-20 13:10:13 +0200372 * Make sure memory references are valid in case we exit early.
Paul Bakker1496d382011-05-23 12:07:29 +0000373 */
374 server_fd = 0;
Manuel Pégourié-Gonnard3bd2aae2013-09-20 13:10:13 +0200375 memset( &ssl, 0, sizeof( ssl_context ) );
Paul Bakker333fdec2014-08-04 12:12:09 +0200376 memset( &buf, 0, sizeof( buf ) );
Paul Bakker369d2eb2013-09-18 11:58:25 +0200377 x509_crt_init( &cacert );
378 x509_crt_init( &clicert );
Manuel Pégourié-Gonnardac755232013-08-19 14:10:16 +0200379 pk_init( &pkey );
Paul Bakker1496d382011-05-23 12:07:29 +0000380
381 if( argc == 0 )
382 {
383 usage:
384 printf( USAGE );
385
386 list = ssl_list_ciphersuites();
387 while( *list )
388 {
389 printf(" %s\n", ssl_get_ciphersuite_name( *list ) );
390 list++;
391 }
392 printf("\n");
393 goto exit;
394 }
395
396 opt.server_name = DFL_SERVER_NAME;
397 opt.server_port = DFL_SERVER_PORT;
398 opt.debug_level = DFL_DEBUG_LEVEL;
399 opt.authentication = DFL_AUTHENTICATION;
400 opt.mode = DFL_MODE;
401 opt.user_name = DFL_USER_NAME;
402 opt.user_pwd = DFL_USER_PWD;
403 opt.mail_from = DFL_MAIL_FROM;
404 opt.mail_to = DFL_MAIL_TO;
Paul Bakker5690efc2011-05-26 13:16:06 +0000405 opt.ca_file = DFL_CA_FILE;
Paul Bakker1496d382011-05-23 12:07:29 +0000406 opt.crt_file = DFL_CRT_FILE;
407 opt.key_file = DFL_KEY_FILE;
408 opt.force_ciphersuite[0]= DFL_FORCE_CIPHER;
409
410 for( i = 1; i < argc; i++ )
411 {
Paul Bakker1496d382011-05-23 12:07:29 +0000412 p = argv[i];
413 if( ( q = strchr( p, '=' ) ) == NULL )
414 goto usage;
415 *q++ = '\0';
416
417 if( strcmp( p, "server_name" ) == 0 )
418 opt.server_name = q;
419 else if( strcmp( p, "server_port" ) == 0 )
420 {
421 opt.server_port = atoi( q );
422 if( opt.server_port < 1 || opt.server_port > 65535 )
423 goto usage;
424 }
425 else if( strcmp( p, "debug_level" ) == 0 )
426 {
427 opt.debug_level = atoi( q );
428 if( opt.debug_level < 0 || opt.debug_level > 65535 )
429 goto usage;
430 }
431 else if( strcmp( p, "authentication" ) == 0 )
432 {
433 opt.authentication = atoi( q );
434 if( opt.authentication < 0 || opt.authentication > 1 )
435 goto usage;
436 }
437 else if( strcmp( p, "mode" ) == 0 )
438 {
439 opt.mode = atoi( q );
440 if( opt.mode < 0 || opt.mode > 1 )
441 goto usage;
442 }
443 else if( strcmp( p, "user_name" ) == 0 )
444 opt.user_name = q;
445 else if( strcmp( p, "user_pwd" ) == 0 )
446 opt.user_pwd = q;
447 else if( strcmp( p, "mail_from" ) == 0 )
448 opt.mail_from = q;
449 else if( strcmp( p, "mail_to" ) == 0 )
450 opt.mail_to = q;
Paul Bakker5690efc2011-05-26 13:16:06 +0000451 else if( strcmp( p, "ca_file" ) == 0 )
452 opt.ca_file = q;
Paul Bakker1496d382011-05-23 12:07:29 +0000453 else if( strcmp( p, "crt_file" ) == 0 )
454 opt.crt_file = q;
455 else if( strcmp( p, "key_file" ) == 0 )
456 opt.key_file = q;
457 else if( strcmp( p, "force_ciphersuite" ) == 0 )
458 {
459 opt.force_ciphersuite[0] = -1;
460
461 opt.force_ciphersuite[0] = ssl_get_ciphersuite_id( q );
462
463 if( opt.force_ciphersuite[0] <= 0 )
464 goto usage;
465
466 opt.force_ciphersuite[1] = 0;
467 }
468 else
469 goto usage;
470 }
471
472 /*
473 * 0. Initialize the RNG and the session data
474 */
Paul Bakker508ad5a2011-12-04 17:09:26 +0000475 printf( "\n . Seeding the random number generator..." );
476 fflush( stdout );
477
478 entropy_init( &entropy );
479 if( ( ret = ctr_drbg_init( &ctr_drbg, entropy_func, &entropy,
Paul Bakkeref3f8c72013-06-24 13:01:08 +0200480 (const unsigned char *) pers,
481 strlen( pers ) ) ) != 0 )
Paul Bakker508ad5a2011-12-04 17:09:26 +0000482 {
483 printf( " failed\n ! ctr_drbg_init returned %d\n", ret );
484 goto exit;
485 }
486
487 printf( " ok\n" );
Paul Bakker1496d382011-05-23 12:07:29 +0000488
489 /*
490 * 1.1. Load the trusted CA
491 */
Paul Bakker508ad5a2011-12-04 17:09:26 +0000492 printf( " . Loading the CA root certificate ..." );
Paul Bakker1496d382011-05-23 12:07:29 +0000493 fflush( stdout );
494
Paul Bakker5690efc2011-05-26 13:16:06 +0000495#if defined(POLARSSL_FS_IO)
496 if( strlen( opt.ca_file ) )
Paul Bakkerddf26b42013-09-18 13:46:23 +0200497 ret = x509_crt_parse_file( &cacert, opt.ca_file );
Paul Bakker5690efc2011-05-26 13:16:06 +0000498 else
499#endif
500#if defined(POLARSSL_CERTS_C)
Manuel Pégourié-Gonnard641de712013-09-25 13:23:33 +0200501 ret = x509_crt_parse( &cacert, (const unsigned char *) test_ca_list,
502 strlen( test_ca_list ) );
Paul Bakker5690efc2011-05-26 13:16:06 +0000503#else
504 {
505 ret = 1;
506 printf("POLARSSL_CERTS_C not defined.");
507 }
508#endif
Paul Bakker42488232012-05-16 08:21:05 +0000509 if( ret < 0 )
Paul Bakker1496d382011-05-23 12:07:29 +0000510 {
Paul Bakkerddf26b42013-09-18 13:46:23 +0200511 printf( " failed\n ! x509_crt_parse returned %d\n\n", ret );
Paul Bakker1496d382011-05-23 12:07:29 +0000512 goto exit;
513 }
514
Paul Bakker42488232012-05-16 08:21:05 +0000515 printf( " ok (%d skipped)\n", ret );
Paul Bakker1496d382011-05-23 12:07:29 +0000516
517 /*
518 * 1.2. Load own certificate and private key
519 *
520 * (can be skipped if client authentication is not required)
521 */
522 printf( " . Loading the client cert. and key..." );
523 fflush( stdout );
524
Paul Bakker5690efc2011-05-26 13:16:06 +0000525#if defined(POLARSSL_FS_IO)
Paul Bakker1496d382011-05-23 12:07:29 +0000526 if( strlen( opt.crt_file ) )
Paul Bakkerddf26b42013-09-18 13:46:23 +0200527 ret = x509_crt_parse_file( &clicert, opt.crt_file );
528 else
Paul Bakker5690efc2011-05-26 13:16:06 +0000529#endif
530#if defined(POLARSSL_CERTS_C)
Paul Bakkerddf26b42013-09-18 13:46:23 +0200531 ret = x509_crt_parse( &clicert, (const unsigned char *) test_cli_crt,
532 strlen( test_cli_crt ) );
Paul Bakker5690efc2011-05-26 13:16:06 +0000533#else
534 {
Paul Bakker69e095c2011-12-10 21:55:01 +0000535 ret = -1;
Paul Bakker5690efc2011-05-26 13:16:06 +0000536 printf("POLARSSL_CERTS_C not defined.");
537 }
538#endif
Paul Bakker1496d382011-05-23 12:07:29 +0000539 if( ret != 0 )
540 {
Paul Bakkerddf26b42013-09-18 13:46:23 +0200541 printf( " failed\n ! x509_crt_parse returned %d\n\n", ret );
Paul Bakker1496d382011-05-23 12:07:29 +0000542 goto exit;
543 }
544
Paul Bakker5690efc2011-05-26 13:16:06 +0000545#if defined(POLARSSL_FS_IO)
Paul Bakker1496d382011-05-23 12:07:29 +0000546 if( strlen( opt.key_file ) )
Paul Bakker1a7550a2013-09-15 13:01:22 +0200547 ret = pk_parse_keyfile( &pkey, opt.key_file, "" );
Paul Bakker1496d382011-05-23 12:07:29 +0000548 else
Paul Bakker5690efc2011-05-26 13:16:06 +0000549#endif
550#if defined(POLARSSL_CERTS_C)
Paul Bakker1a7550a2013-09-15 13:01:22 +0200551 ret = pk_parse_key( &pkey, (const unsigned char *) test_cli_key,
Paul Bakker1496d382011-05-23 12:07:29 +0000552 strlen( test_cli_key ), NULL, 0 );
Paul Bakker5690efc2011-05-26 13:16:06 +0000553#else
554 {
Paul Bakker69e095c2011-12-10 21:55:01 +0000555 ret = -1;
Paul Bakker5690efc2011-05-26 13:16:06 +0000556 printf("POLARSSL_CERTS_C not defined.");
557 }
558#endif
Paul Bakker1496d382011-05-23 12:07:29 +0000559 if( ret != 0 )
560 {
Paul Bakker1a7550a2013-09-15 13:01:22 +0200561 printf( " failed\n ! pk_parse_key returned %d\n\n", ret );
Paul Bakker1496d382011-05-23 12:07:29 +0000562 goto exit;
563 }
564
565 printf( " ok\n" );
566
567 /*
568 * 2. Start the connection
569 */
570 printf( " . Connecting to tcp/%s/%-4d...", opt.server_name,
571 opt.server_port );
572 fflush( stdout );
573
574 if( ( ret = net_connect( &server_fd, opt.server_name,
575 opt.server_port ) ) != 0 )
576 {
577 printf( " failed\n ! net_connect returned %d\n\n", ret );
578 goto exit;
579 }
580
581 printf( " ok\n" );
582
583 /*
584 * 3. Setup stuff
585 */
586 printf( " . Setting up the SSL/TLS structure..." );
587 fflush( stdout );
588
Paul Bakker1496d382011-05-23 12:07:29 +0000589 if( ( ret = ssl_init( &ssl ) ) != 0 )
590 {
591 printf( " failed\n ! ssl_init returned %d\n\n", ret );
592 goto exit;
593 }
594
595 printf( " ok\n" );
596
597 ssl_set_endpoint( &ssl, SSL_IS_CLIENT );
Manuel Pégourié-Gonnardfcf2fc22014-03-11 11:10:27 +0100598 /* OPTIONAL is not optimal for security,
599 * but makes interop easier in this simplified example */
Paul Bakker1496d382011-05-23 12:07:29 +0000600 ssl_set_authmode( &ssl, SSL_VERIFY_OPTIONAL );
601
Manuel Pégourié-Gonnard448ea502015-01-12 11:40:14 +0100602 /* SSLv3 is deprecated, set minimum to TLS 1.0 */
603 ssl_set_min_version( &ssl, SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_1 );
Manuel Pégourié-Gonnardfa065812015-01-12 14:05:33 +0100604 /* RC4 is deprecated, disable it */
605 ssl_set_arc4_support( &ssl, SSL_ARC4_DISABLED );
Manuel Pégourié-Gonnard448ea502015-01-12 11:40:14 +0100606
Paul Bakker508ad5a2011-12-04 17:09:26 +0000607 ssl_set_rng( &ssl, ctr_drbg_random, &ctr_drbg );
Paul Bakker1496d382011-05-23 12:07:29 +0000608 ssl_set_dbg( &ssl, my_debug, stdout );
609 ssl_set_bio( &ssl, net_recv, &server_fd,
610 net_send, &server_fd );
611
Paul Bakker645ce3a2012-10-31 12:32:41 +0000612 if( opt.force_ciphersuite[0] != DFL_FORCE_CIPHER )
Paul Bakker1496d382011-05-23 12:07:29 +0000613 ssl_set_ciphersuites( &ssl, opt.force_ciphersuite );
614
Paul Bakker1496d382011-05-23 12:07:29 +0000615 ssl_set_ca_chain( &ssl, &cacert, NULL, opt.server_name );
Manuel Pégourié-Gonnardc5fd3912014-07-08 14:05:52 +0200616 if( ( ret = ssl_set_own_cert( &ssl, &clicert, &pkey ) ) != 0 )
617 {
618 printf( " failed\n ! ssl_set_own_cert returned %d\n\n", ret );
619 goto exit;
620 }
Paul Bakker1496d382011-05-23 12:07:29 +0000621
Paul Bakker0be444a2013-08-27 21:55:01 +0200622#if defined(POLARSSL_SSL_SERVER_NAME_INDICATION)
Manuel Pégourié-Gonnardc5fd3912014-07-08 14:05:52 +0200623 if( ( ret = ssl_set_hostname( &ssl, opt.server_name ) ) != 0 )
624 {
625 printf( " failed\n ! ssl_set_hostname returned %d\n\n", ret );
626 goto exit;
627 }
Paul Bakker0be444a2013-08-27 21:55:01 +0200628#endif
Paul Bakker1496d382011-05-23 12:07:29 +0000629
630 if( opt.mode == MODE_SSL_TLS )
631 {
632 if( do_handshake( &ssl, &opt ) != 0 )
633 goto exit;
634
635 printf( " > Get header from server:" );
636 fflush( stdout );
637
638 ret = write_ssl_and_get_response( &ssl, buf, 0 );
639 if( ret < 200 || ret > 299 )
640 {
641 printf( " failed\n ! server responded with %d\n\n", ret );
642 goto exit;
643 }
644
645 printf(" ok\n" );
646
647 printf( " > Write EHLO to server:" );
648 fflush( stdout );
649
650 gethostname( hostname, 32 );
Paul Bakkerd75ba402014-01-24 16:11:17 +0100651 len = sprintf( (char *) buf, "EHLO %s\r\n", hostname );
Paul Bakker1496d382011-05-23 12:07:29 +0000652 ret = write_ssl_and_get_response( &ssl, buf, len );
653 if( ret < 200 || ret > 299 )
654 {
655 printf( " failed\n ! server responded with %d\n\n", ret );
656 goto exit;
657 }
658 }
659 else
660 {
661 printf( " > Get header from server:" );
662 fflush( stdout );
663
664 ret = write_and_get_response( server_fd, buf, 0 );
665 if( ret < 200 || ret > 299 )
666 {
667 printf( " failed\n ! server responded with %d\n\n", ret );
668 goto exit;
669 }
670
671 printf(" ok\n" );
672
673 printf( " > Write EHLO to server:" );
674 fflush( stdout );
675
676 gethostname( hostname, 32 );
Paul Bakkerd75ba402014-01-24 16:11:17 +0100677 len = sprintf( (char *) buf, "EHLO %s\r\n", hostname );
Paul Bakker1496d382011-05-23 12:07:29 +0000678 ret = write_and_get_response( server_fd, buf, len );
679 if( ret < 200 || ret > 299 )
680 {
681 printf( " failed\n ! server responded with %d\n\n", ret );
682 goto exit;
683 }
684
685 printf(" ok\n" );
686
687 printf( " > Write STARTTLS to server:" );
688 fflush( stdout );
689
690 gethostname( hostname, 32 );
Paul Bakkerd75ba402014-01-24 16:11:17 +0100691 len = sprintf( (char *) buf, "STARTTLS\r\n" );
Paul Bakker1496d382011-05-23 12:07:29 +0000692 ret = write_and_get_response( server_fd, buf, len );
693 if( ret < 200 || ret > 299 )
694 {
695 printf( " failed\n ! server responded with %d\n\n", ret );
696 goto exit;
697 }
698
699 printf(" ok\n" );
700
701 if( do_handshake( &ssl, &opt ) != 0 )
702 goto exit;
703 }
704
Paul Bakker5690efc2011-05-26 13:16:06 +0000705#if defined(POLARSSL_BASE64_C)
Paul Bakker1496d382011-05-23 12:07:29 +0000706 if( opt.authentication )
707 {
708 printf( " > Write AUTH LOGIN to server:" );
709 fflush( stdout );
710
Paul Bakkerd75ba402014-01-24 16:11:17 +0100711 len = sprintf( (char *) buf, "AUTH LOGIN\r\n" );
Paul Bakker1496d382011-05-23 12:07:29 +0000712 ret = write_ssl_and_get_response( &ssl, buf, len );
713 if( ret < 200 || ret > 399 )
714 {
715 printf( " failed\n ! server responded with %d\n\n", ret );
716 goto exit;
717 }
718
719 printf(" ok\n" );
720
721 printf( " > Write username to server: %s", opt.user_name );
722 fflush( stdout );
723
724 n = sizeof( buf );
Alfred Klomp7c034242014-07-14 22:11:13 +0200725 ret = base64_encode( base, &n, (const unsigned char *) opt.user_name,
Paul Bakkeref3f8c72013-06-24 13:01:08 +0200726 strlen( opt.user_name ) );
Alfred Klomp7c034242014-07-14 22:11:13 +0200727
728 if( ret != 0 ) {
729 printf( " failed\n ! base64_encode returned %d\n\n", ret );
730 goto exit;
731 }
Paul Bakkerd75ba402014-01-24 16:11:17 +0100732 len = sprintf( (char *) buf, "%s\r\n", base );
Paul Bakker1496d382011-05-23 12:07:29 +0000733 ret = write_ssl_and_get_response( &ssl, buf, len );
734 if( ret < 300 || ret > 399 )
735 {
736 printf( " failed\n ! server responded with %d\n\n", ret );
737 goto exit;
738 }
739
740 printf(" ok\n" );
741
742 printf( " > Write password to server: %s", opt.user_pwd );
743 fflush( stdout );
744
Alfred Klomp7c034242014-07-14 22:11:13 +0200745 ret = base64_encode( base, &n, (const unsigned char *) opt.user_pwd,
Paul Bakkeref3f8c72013-06-24 13:01:08 +0200746 strlen( opt.user_pwd ) );
Alfred Klomp7c034242014-07-14 22:11:13 +0200747
748 if( ret != 0 ) {
749 printf( " failed\n ! base64_encode returned %d\n\n", ret );
750 goto exit;
751 }
Paul Bakkerd75ba402014-01-24 16:11:17 +0100752 len = sprintf( (char *) buf, "%s\r\n", base );
Paul Bakker1496d382011-05-23 12:07:29 +0000753 ret = write_ssl_and_get_response( &ssl, buf, len );
754 if( ret < 200 || ret > 399 )
755 {
756 printf( " failed\n ! server responded with %d\n\n", ret );
757 goto exit;
758 }
759
760 printf(" ok\n" );
761 }
Paul Bakker5690efc2011-05-26 13:16:06 +0000762#endif
Paul Bakker1496d382011-05-23 12:07:29 +0000763
764 printf( " > Write MAIL FROM to server:" );
765 fflush( stdout );
766
Paul Bakkerd75ba402014-01-24 16:11:17 +0100767 len = sprintf( (char *) buf, "MAIL FROM:<%s>\r\n", opt.mail_from );
Paul Bakker1496d382011-05-23 12:07:29 +0000768 ret = write_ssl_and_get_response( &ssl, buf, len );
769 if( ret < 200 || ret > 299 )
770 {
771 printf( " failed\n ! server responded with %d\n\n", ret );
772 goto exit;
773 }
774
775 printf(" ok\n" );
776
777 printf( " > Write RCPT TO to server:" );
778 fflush( stdout );
779
Paul Bakkerd75ba402014-01-24 16:11:17 +0100780 len = sprintf( (char *) buf, "RCPT TO:<%s>\r\n", opt.mail_to );
Paul Bakker1496d382011-05-23 12:07:29 +0000781 ret = write_ssl_and_get_response( &ssl, buf, len );
782 if( ret < 200 || ret > 299 )
783 {
784 printf( " failed\n ! server responded with %d\n\n", ret );
785 goto exit;
786 }
787
788 printf(" ok\n" );
789
790 printf( " > Write DATA to server:" );
791 fflush( stdout );
792
Paul Bakkerd75ba402014-01-24 16:11:17 +0100793 len = sprintf( (char *) buf, "DATA\r\n" );
Paul Bakker1496d382011-05-23 12:07:29 +0000794 ret = write_ssl_and_get_response( &ssl, buf, len );
795 if( ret < 300 || ret > 399 )
796 {
797 printf( " failed\n ! server responded with %d\n\n", ret );
798 goto exit;
799 }
800
801 printf(" ok\n" );
802
803 printf( " > Write content to server:" );
804 fflush( stdout );
805
Manuel Pégourié-Gonnard91699212015-01-22 16:26:39 +0000806 len = sprintf( (char *) buf, "From: %s\r\nSubject: mbed TLS Test mail\r\n\r\n"
Paul Bakker1496d382011-05-23 12:07:29 +0000807 "This is a simple test mail from the "
Manuel Pégourié-Gonnard91699212015-01-22 16:26:39 +0000808 "mbed TLS mail client example.\r\n"
Paul Bakkerd75ba402014-01-24 16:11:17 +0100809 "\r\n"
Paul Bakker1496d382011-05-23 12:07:29 +0000810 "Enjoy!", opt.mail_from );
811 ret = write_ssl_data( &ssl, buf, len );
812
813 len = sprintf( (char *) buf, "\r\n.\r\n");
814 ret = write_ssl_and_get_response( &ssl, buf, len );
815 if( ret < 200 || ret > 299 )
816 {
817 printf( " failed\n ! server responded with %d\n\n", ret );
818 goto exit;
819 }
820
821 printf(" ok\n" );
822
823 ssl_close_notify( &ssl );
824
825exit:
826
827 if( server_fd )
828 net_close( server_fd );
Paul Bakker36713e82013-09-17 13:25:29 +0200829 x509_crt_free( &clicert );
830 x509_crt_free( &cacert );
Manuel Pégourié-Gonnardac755232013-08-19 14:10:16 +0200831 pk_free( &pkey );
Paul Bakker1496d382011-05-23 12:07:29 +0000832 ssl_free( &ssl );
Paul Bakkera317a982014-06-18 16:44:11 +0200833 ctr_drbg_free( &ctr_drbg );
Paul Bakker1ffefac2013-09-28 15:23:03 +0200834 entropy_free( &entropy );
Paul Bakker1496d382011-05-23 12:07:29 +0000835
Paul Bakkercce9d772011-11-18 14:26:47 +0000836#if defined(_WIN32)
Paul Bakker1496d382011-05-23 12:07:29 +0000837 printf( " + Press Enter to exit this program.\n" );
838 fflush( stdout ); getchar();
839#endif
840
841 return( ret );
842}
Paul Bakker508ad5a2011-12-04 17:09:26 +0000843#endif /* POLARSSL_BIGNUM_C && POLARSSL_ENTROPY_C && POLARSSL_SSL_TLS_C &&
844 POLARSSL_SSL_CLI_C && POLARSSL_NET_C && POLARSSL_RSA_C **
845 POLARSSL_CTR_DRBG_C */