quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

ssl_mail_client.c (25922B)


      1 /*
      2  *  SSL client for SMTP servers
      3  *
      4  *  Copyright The Mbed TLS Contributors
      5  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
      6  */
      7 
      8 /* Enable definition of gethostname() even when compiling with -std=c99. Must
      9  * be set before mbedtls_config.h, which pulls in glibc's features.h indirectly.
     10  * Harmless on other platforms. */
     11 
     12 #define _POSIX_C_SOURCE 200112L
     13 #define _XOPEN_SOURCE 600
     14 
     15 #include "mbedtls/build_info.h"
     16 
     17 #include "mbedtls/platform.h"
     18 
     19 #if !defined(MBEDTLS_BIGNUM_C) || !defined(MBEDTLS_ENTROPY_C) ||  \
     20     !defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_CLI_C) || \
     21     !defined(MBEDTLS_NET_C) || !defined(MBEDTLS_RSA_C) ||         \
     22     !defined(MBEDTLS_CTR_DRBG_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) || \
     23     !defined(MBEDTLS_FS_IO)
     24 int main(void)
     25 {
     26     mbedtls_printf("MBEDTLS_BIGNUM_C and/or MBEDTLS_ENTROPY_C and/or "
     27                    "MBEDTLS_SSL_TLS_C and/or MBEDTLS_SSL_CLI_C and/or "
     28                    "MBEDTLS_NET_C and/or MBEDTLS_RSA_C and/or "
     29                    "MBEDTLS_CTR_DRBG_C and/or MBEDTLS_X509_CRT_PARSE_C "
     30                    "not defined.\n");
     31     mbedtls_exit(0);
     32 }
     33 #else
     34 
     35 #include "mbedtls/base64.h"
     36 #include "mbedtls/error.h"
     37 #include "mbedtls/net_sockets.h"
     38 #include "mbedtls/ssl.h"
     39 #include "mbedtls/entropy.h"
     40 #include "mbedtls/ctr_drbg.h"
     41 #include "test/certs.h"
     42 #include "mbedtls/x509.h"
     43 
     44 #include <stdlib.h>
     45 #include <string.h>
     46 
     47 #if !defined(_MSC_VER) || defined(EFIX64) || defined(EFI32)
     48 #include <unistd.h>
     49 #else
     50 #include <io.h>
     51 #endif
     52 
     53 #if defined(_WIN32) || defined(_WIN32_WCE)
     54 #include <winsock2.h>
     55 #include <windows.h>
     56 
     57 #if defined(_MSC_VER)
     58 #if defined(_WIN32_WCE)
     59 #pragma comment( lib, "ws2.lib" )
     60 #else
     61 #pragma comment( lib, "ws2_32.lib" )
     62 #endif
     63 #endif /* _MSC_VER */
     64 #endif
     65 
     66 #define DFL_SERVER_NAME         "localhost"
     67 #define DFL_SERVER_PORT         "465"
     68 #define DFL_USER_NAME           "user"
     69 #define DFL_USER_PWD            "password"
     70 #define DFL_MAIL_FROM           ""
     71 #define DFL_MAIL_TO             ""
     72 #define DFL_DEBUG_LEVEL         0
     73 #define DFL_CA_FILE             ""
     74 #define DFL_CRT_FILE            ""
     75 #define DFL_KEY_FILE            ""
     76 #define DFL_FORCE_CIPHER        0
     77 #define DFL_MODE                0
     78 #define DFL_AUTHENTICATION      0
     79 
     80 #define MODE_SSL_TLS            0
     81 #define MODE_STARTTLS           0
     82 
     83 #if defined(MBEDTLS_BASE64_C)
     84 #define USAGE_AUTH \
     85     "    authentication=%%d   default: 0 (disabled)\n"          \
     86     "    user_name=%%s        default: \"" DFL_USER_NAME "\"\n" \
     87                                                          "    user_pwd=%%s         default: \"" \
     88     DFL_USER_PWD "\"\n"
     89 #else
     90 #define USAGE_AUTH \
     91     "    authentication options disabled. (Require MBEDTLS_BASE64_C)\n"
     92 #endif /* MBEDTLS_BASE64_C */
     93 
     94 #if defined(MBEDTLS_FS_IO)
     95 #define USAGE_IO \
     96     "    ca_file=%%s          default: \"\" (pre-loaded)\n" \
     97     "    crt_file=%%s         default: \"\" (pre-loaded)\n" \
     98     "    key_file=%%s         default: \"\" (pre-loaded)\n"
     99 #else
    100 #define USAGE_IO \
    101     "    No file operations available (MBEDTLS_FS_IO not defined)\n"
    102 #endif /* MBEDTLS_FS_IO */
    103 
    104 #define USAGE \
    105     "\n usage: ssl_mail_client param=<>...\n"                 \
    106     "\n acceptable parameters:\n"                             \
    107     "    server_name=%%s      default: " DFL_SERVER_NAME "\n" \
    108                                                          "    server_port=%%d      default: " \
    109     DFL_SERVER_PORT "\n" \
    110                     "    debug_level=%%d      default: 0 (disabled)\n"        \
    111                     "    mode=%%d             default: 0 (SSL/TLS) (1 for STARTTLS)\n"  \
    112     USAGE_AUTH                                                \
    113     "    mail_from=%%s        default: \"\"\n"                \
    114     "    mail_to=%%s          default: \"\"\n"                \
    115     USAGE_IO                                                  \
    116     "    force_ciphersuite=<name>    default: all enabled\n"  \
    117     " acceptable ciphersuite names:\n"
    118 
    119 
    120 /*
    121  * global options
    122  */
    123 struct options {
    124     const char *server_name;    /* hostname of the server (client only)     */
    125     const char *server_port;    /* port on which the ssl service runs       */
    126     int debug_level;            /* level of debugging                       */
    127     int authentication;         /* if authentication is required            */
    128     int mode;                   /* SSL/TLS (0) or STARTTLS (1)              */
    129     const char *user_name;      /* username to use for authentication       */
    130     const char *user_pwd;       /* password to use for authentication       */
    131     const char *mail_from;      /* E-Mail address to use as sender          */
    132     const char *mail_to;        /* E-Mail address to use as recipient       */
    133     const char *ca_file;        /* the file with the CA certificate(s)      */
    134     const char *crt_file;       /* the file with the client certificate     */
    135     const char *key_file;       /* the file with the client key             */
    136     int force_ciphersuite[2];   /* protocol/ciphersuite to use, or all      */
    137 } opt;
    138 
    139 static void my_debug(void *ctx, int level,
    140                      const char *file, int line,
    141                      const char *str)
    142 {
    143     ((void) level);
    144 
    145     mbedtls_fprintf((FILE *) ctx, "%s:%04d: %s", file, line, str);
    146     fflush((FILE *) ctx);
    147 }
    148 
    149 static int do_handshake(mbedtls_ssl_context *ssl)
    150 {
    151     int ret;
    152     uint32_t flags;
    153     unsigned char buf[1024];
    154     memset(buf, 0, 1024);
    155 
    156     /*
    157      * 4. Handshake
    158      */
    159     mbedtls_printf("  . Performing the SSL/TLS handshake...");
    160     fflush(stdout);
    161 
    162     while ((ret = mbedtls_ssl_handshake(ssl)) != 0) {
    163         if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
    164 #if defined(MBEDTLS_ERROR_C)
    165             mbedtls_strerror(ret, (char *) buf, 1024);
    166 #endif
    167             mbedtls_printf(" failed\n  ! mbedtls_ssl_handshake returned %d: %s\n\n", ret, buf);
    168             return -1;
    169         }
    170     }
    171 
    172     mbedtls_printf(" ok\n    [ Ciphersuite is %s ]\n",
    173                    mbedtls_ssl_get_ciphersuite(ssl));
    174 
    175     /*
    176      * 5. Verify the server certificate
    177      */
    178     mbedtls_printf("  . Verifying peer X.509 certificate...");
    179 
    180     /* In real life, we probably want to bail out when ret != 0 */
    181     if ((flags = mbedtls_ssl_get_verify_result(ssl)) != 0) {
    182 #if !defined(MBEDTLS_X509_REMOVE_INFO)
    183         char vrfy_buf[512];
    184 #endif
    185 
    186         mbedtls_printf(" failed\n");
    187 
    188 #if !defined(MBEDTLS_X509_REMOVE_INFO)
    189         mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), "  ! ", flags);
    190 
    191         mbedtls_printf("%s\n", vrfy_buf);
    192 #endif
    193     } else {
    194         mbedtls_printf(" ok\n");
    195     }
    196 
    197 #if !defined(MBEDTLS_X509_REMOVE_INFO)
    198     mbedtls_printf("  . Peer certificate information    ...\n");
    199     mbedtls_x509_crt_info((char *) buf, sizeof(buf) - 1, "      ",
    200                           mbedtls_ssl_get_peer_cert(ssl));
    201     mbedtls_printf("%s\n", buf);
    202 #endif
    203 
    204     return 0;
    205 }
    206 
    207 static int write_ssl_data(mbedtls_ssl_context *ssl, unsigned char *buf, size_t len)
    208 {
    209     int ret;
    210 
    211     mbedtls_printf("\n%s", buf);
    212     while (len && (ret = mbedtls_ssl_write(ssl, buf, len)) <= 0) {
    213         if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
    214             mbedtls_printf(" failed\n  ! mbedtls_ssl_write returned %d\n\n", ret);
    215             return -1;
    216         }
    217     }
    218 
    219     return 0;
    220 }
    221 
    222 static int write_ssl_and_get_response(mbedtls_ssl_context *ssl, unsigned char *buf, size_t len)
    223 {
    224     int ret;
    225     unsigned char data[128];
    226     char code[4];
    227     size_t i, idx = 0;
    228 
    229     mbedtls_printf("\n%s", buf);
    230     while (len && (ret = mbedtls_ssl_write(ssl, buf, len)) <= 0) {
    231         if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
    232             mbedtls_printf(" failed\n  ! mbedtls_ssl_write returned %d\n\n", ret);
    233             return -1;
    234         }
    235     }
    236 
    237     do {
    238         len = sizeof(data) - 1;
    239         memset(data, 0, sizeof(data));
    240         ret = mbedtls_ssl_read(ssl, data, len);
    241 
    242         if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
    243             continue;
    244         }
    245 
    246         if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
    247             return -1;
    248         }
    249 
    250         if (ret <= 0) {
    251             mbedtls_printf("failed\n  ! mbedtls_ssl_read returned %d\n\n", ret);
    252             return -1;
    253         }
    254 
    255         mbedtls_printf("\n%s", data);
    256         len = ret;
    257         for (i = 0; i < len; i++) {
    258             if (data[i] != '\n') {
    259                 if (idx < 4) {
    260                     code[idx++] = data[i];
    261                 }
    262                 continue;
    263             }
    264 
    265             if (idx == 4 && code[0] >= '0' && code[0] <= '9' && code[3] == ' ') {
    266                 code[3] = '\0';
    267                 return atoi(code);
    268             }
    269 
    270             idx = 0;
    271         }
    272     } while (1);
    273 }
    274 
    275 static int write_and_get_response(mbedtls_net_context *sock_fd, unsigned char *buf, size_t len)
    276 {
    277     int ret;
    278     unsigned char data[128];
    279     char code[4];
    280     size_t i, idx = 0;
    281 
    282     mbedtls_printf("\n%s", buf);
    283     if (len && (ret = mbedtls_net_send(sock_fd, buf, len)) <= 0) {
    284         mbedtls_printf(" failed\n  ! mbedtls_net_send returned %d\n\n", ret);
    285         return -1;
    286     }
    287 
    288     do {
    289         len = sizeof(data) - 1;
    290         memset(data, 0, sizeof(data));
    291         ret = mbedtls_net_recv(sock_fd, data, len);
    292 
    293         if (ret <= 0) {
    294             mbedtls_printf("failed\n  ! mbedtls_net_recv returned %d\n\n", ret);
    295             return -1;
    296         }
    297 
    298         data[len] = '\0';
    299         mbedtls_printf("\n%s", data);
    300         len = ret;
    301         for (i = 0; i < len; i++) {
    302             if (data[i] != '\n') {
    303                 if (idx < 4) {
    304                     code[idx++] = data[i];
    305                 }
    306                 continue;
    307             }
    308 
    309             if (idx == 4 && code[0] >= '0' && code[0] <= '9' && code[3] == ' ') {
    310                 code[3] = '\0';
    311                 return atoi(code);
    312             }
    313 
    314             idx = 0;
    315         }
    316     } while (1);
    317 }
    318 
    319 int main(int argc, char *argv[])
    320 {
    321     int ret = 1, len;
    322     int exit_code = MBEDTLS_EXIT_FAILURE;
    323     mbedtls_net_context server_fd;
    324 #if defined(MBEDTLS_BASE64_C)
    325     unsigned char base[1024];
    326     /* buf is used as the destination buffer for printing base with the format:
    327      * "%s\r\n". Hence, the size of buf should be at least the size of base
    328      * plus 2 bytes for the \r and \n characters.
    329      */
    330     unsigned char buf[sizeof(base) + 2];
    331 #else
    332     unsigned char buf[1024];
    333 #endif
    334     char hostname[32];
    335     const char *pers = "ssl_mail_client";
    336 
    337     mbedtls_entropy_context entropy;
    338     mbedtls_ctr_drbg_context ctr_drbg;
    339     mbedtls_ssl_context ssl;
    340     mbedtls_ssl_config conf;
    341     mbedtls_x509_crt cacert;
    342     mbedtls_x509_crt clicert;
    343     mbedtls_pk_context pkey;
    344     int i;
    345     size_t n;
    346     char *p, *q;
    347     const int *list;
    348 
    349     /*
    350      * Make sure memory references are valid in case we exit early.
    351      */
    352     mbedtls_net_init(&server_fd);
    353     mbedtls_ssl_init(&ssl);
    354     mbedtls_ssl_config_init(&conf);
    355     memset(&buf, 0, sizeof(buf));
    356     mbedtls_x509_crt_init(&cacert);
    357     mbedtls_x509_crt_init(&clicert);
    358     mbedtls_pk_init(&pkey);
    359     mbedtls_ctr_drbg_init(&ctr_drbg);
    360     mbedtls_entropy_init(&entropy);
    361 
    362 #if defined(MBEDTLS_USE_PSA_CRYPTO)
    363     psa_status_t status = psa_crypto_init();
    364     if (status != PSA_SUCCESS) {
    365         mbedtls_fprintf(stderr, "Failed to initialize PSA Crypto implementation: %d\n",
    366                         (int) status);
    367         goto exit;
    368     }
    369 #endif /* MBEDTLS_USE_PSA_CRYPTO */
    370 
    371     if (argc < 2) {
    372 usage:
    373         mbedtls_printf(USAGE);
    374 
    375         list = mbedtls_ssl_list_ciphersuites();
    376         while (*list) {
    377             mbedtls_printf("    %s\n", mbedtls_ssl_get_ciphersuite_name(*list));
    378             list++;
    379         }
    380         mbedtls_printf("\n");
    381         goto exit;
    382     }
    383 
    384     opt.server_name         = DFL_SERVER_NAME;
    385     opt.server_port         = DFL_SERVER_PORT;
    386     opt.debug_level         = DFL_DEBUG_LEVEL;
    387     opt.authentication      = DFL_AUTHENTICATION;
    388     opt.mode                = DFL_MODE;
    389     opt.user_name           = DFL_USER_NAME;
    390     opt.user_pwd            = DFL_USER_PWD;
    391     opt.mail_from           = DFL_MAIL_FROM;
    392     opt.mail_to             = DFL_MAIL_TO;
    393     opt.ca_file             = DFL_CA_FILE;
    394     opt.crt_file            = DFL_CRT_FILE;
    395     opt.key_file            = DFL_KEY_FILE;
    396     opt.force_ciphersuite[0] = DFL_FORCE_CIPHER;
    397 
    398     for (i = 1; i < argc; i++) {
    399         p = argv[i];
    400         if ((q = strchr(p, '=')) == NULL) {
    401             goto usage;
    402         }
    403         *q++ = '\0';
    404 
    405         if (strcmp(p, "server_name") == 0) {
    406             opt.server_name = q;
    407         } else if (strcmp(p, "server_port") == 0) {
    408             opt.server_port = q;
    409         } else if (strcmp(p, "debug_level") == 0) {
    410             opt.debug_level = atoi(q);
    411             if (opt.debug_level < 0 || opt.debug_level > 65535) {
    412                 goto usage;
    413             }
    414         } else if (strcmp(p, "authentication") == 0) {
    415             opt.authentication = atoi(q);
    416             if (opt.authentication < 0 || opt.authentication > 1) {
    417                 goto usage;
    418             }
    419         } else if (strcmp(p, "mode") == 0) {
    420             opt.mode = atoi(q);
    421             if (opt.mode < 0 || opt.mode > 1) {
    422                 goto usage;
    423             }
    424         } else if (strcmp(p, "user_name") == 0) {
    425             opt.user_name = q;
    426         } else if (strcmp(p, "user_pwd") == 0) {
    427             opt.user_pwd = q;
    428         } else if (strcmp(p, "mail_from") == 0) {
    429             opt.mail_from = q;
    430         } else if (strcmp(p, "mail_to") == 0) {
    431             opt.mail_to = q;
    432         } else if (strcmp(p, "ca_file") == 0) {
    433             opt.ca_file = q;
    434         } else if (strcmp(p, "crt_file") == 0) {
    435             opt.crt_file = q;
    436         } else if (strcmp(p, "key_file") == 0) {
    437             opt.key_file = q;
    438         } else if (strcmp(p, "force_ciphersuite") == 0) {
    439             opt.force_ciphersuite[0] = -1;
    440 
    441             opt.force_ciphersuite[0] = mbedtls_ssl_get_ciphersuite_id(q);
    442 
    443             if (opt.force_ciphersuite[0] <= 0) {
    444                 goto usage;
    445             }
    446 
    447             opt.force_ciphersuite[1] = 0;
    448         } else {
    449             goto usage;
    450         }
    451     }
    452 
    453     /*
    454      * 0. Initialize the RNG and the session data
    455      */
    456     mbedtls_printf("\n  . Seeding the random number generator...");
    457     fflush(stdout);
    458 
    459     if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
    460                                      (const unsigned char *) pers,
    461                                      strlen(pers))) != 0) {
    462         mbedtls_printf(" failed\n  ! mbedtls_ctr_drbg_seed returned %d\n", ret);
    463         goto exit;
    464     }
    465 
    466     mbedtls_printf(" ok\n");
    467 
    468     /*
    469      * 1.1. Load the trusted CA
    470      */
    471     mbedtls_printf("  . Loading the CA root certificate ...");
    472     fflush(stdout);
    473 
    474 #if defined(MBEDTLS_FS_IO)
    475     if (strlen(opt.ca_file)) {
    476         ret = mbedtls_x509_crt_parse_file(&cacert, opt.ca_file);
    477     } else
    478 #endif
    479 #if defined(MBEDTLS_PEM_PARSE_C)
    480     ret = mbedtls_x509_crt_parse(&cacert, (const unsigned char *) mbedtls_test_cas_pem,
    481                                  mbedtls_test_cas_pem_len);
    482 #else
    483     {
    484         mbedtls_printf("MBEDTLS_PEM_PARSE_C not defined.");
    485         goto exit;
    486     }
    487 #endif
    488     if (ret < 0) {
    489         mbedtls_printf(" failed\n  !  mbedtls_x509_crt_parse returned %d\n\n", ret);
    490         goto exit;
    491     }
    492 
    493     mbedtls_printf(" ok (%d skipped)\n", ret);
    494 
    495     /*
    496      * 1.2. Load own certificate and private key
    497      *
    498      * (can be skipped if client authentication is not required)
    499      */
    500     mbedtls_printf("  . Loading the client cert. and key...");
    501     fflush(stdout);
    502 
    503 #if defined(MBEDTLS_FS_IO)
    504     if (strlen(opt.crt_file)) {
    505         ret = mbedtls_x509_crt_parse_file(&clicert, opt.crt_file);
    506     } else
    507 #endif
    508     ret = mbedtls_x509_crt_parse(&clicert, (const unsigned char *) mbedtls_test_cli_crt,
    509                                  mbedtls_test_cli_crt_len);
    510     if (ret != 0) {
    511         mbedtls_printf(" failed\n  !  mbedtls_x509_crt_parse returned %d\n\n", ret);
    512         goto exit;
    513     }
    514 
    515 #if defined(MBEDTLS_FS_IO)
    516     if (strlen(opt.key_file)) {
    517         ret = mbedtls_pk_parse_keyfile(&pkey, opt.key_file, "",
    518                                        mbedtls_ctr_drbg_random, &ctr_drbg);
    519     } else
    520 #endif
    521 #if defined(MBEDTLS_PEM_PARSE_C)
    522     {
    523         ret = mbedtls_pk_parse_key(&pkey,
    524                                    (const unsigned char *) mbedtls_test_cli_key,
    525                                    mbedtls_test_cli_key_len,
    526                                    NULL,
    527                                    0,
    528                                    mbedtls_ctr_drbg_random,
    529                                    &ctr_drbg);
    530     }
    531 #else
    532     {
    533         mbedtls_printf("MBEDTLS_PEM_PARSE_C not defined.");
    534         goto exit;
    535     }
    536 #endif
    537     if (ret != 0) {
    538         mbedtls_printf(" failed\n  !  mbedtls_pk_parse_key returned %d\n\n", ret);
    539         goto exit;
    540     }
    541 
    542     mbedtls_printf(" ok\n");
    543 
    544     /*
    545      * 2. Start the connection
    546      */
    547     mbedtls_printf("  . Connecting to tcp/%s/%s...", opt.server_name,
    548                    opt.server_port);
    549     fflush(stdout);
    550 
    551     if ((ret = mbedtls_net_connect(&server_fd, opt.server_name,
    552                                    opt.server_port, MBEDTLS_NET_PROTO_TCP)) != 0) {
    553         mbedtls_printf(" failed\n  ! mbedtls_net_connect returned %d\n\n", ret);
    554         goto exit;
    555     }
    556 
    557     mbedtls_printf(" ok\n");
    558 
    559     /*
    560      * 3. Setup stuff
    561      */
    562     mbedtls_printf("  . Setting up the SSL/TLS structure...");
    563     fflush(stdout);
    564 
    565     if ((ret = mbedtls_ssl_config_defaults(&conf,
    566                                            MBEDTLS_SSL_IS_CLIENT,
    567                                            MBEDTLS_SSL_TRANSPORT_STREAM,
    568                                            MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
    569         mbedtls_printf(" failed\n  ! mbedtls_ssl_config_defaults returned %d\n\n", ret);
    570         goto exit;
    571     }
    572 
    573     /* OPTIONAL is not optimal for security,
    574      * but makes interop easier in this simplified example */
    575     mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
    576 
    577     mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
    578     mbedtls_ssl_conf_dbg(&conf, my_debug, stdout);
    579 
    580     if (opt.force_ciphersuite[0] != DFL_FORCE_CIPHER) {
    581         mbedtls_ssl_conf_ciphersuites(&conf, opt.force_ciphersuite);
    582     }
    583 
    584     mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);
    585     if ((ret = mbedtls_ssl_conf_own_cert(&conf, &clicert, &pkey)) != 0) {
    586         mbedtls_printf(" failed\n  ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret);
    587         goto exit;
    588     }
    589 
    590     if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) {
    591         mbedtls_printf(" failed\n  ! mbedtls_ssl_setup returned %d\n\n", ret);
    592         goto exit;
    593     }
    594 
    595     if ((ret = mbedtls_ssl_set_hostname(&ssl, opt.server_name)) != 0) {
    596         mbedtls_printf(" failed\n  ! mbedtls_ssl_set_hostname returned %d\n\n", ret);
    597         goto exit;
    598     }
    599 
    600     mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
    601 
    602     mbedtls_printf(" ok\n");
    603 
    604     if (opt.mode == MODE_SSL_TLS) {
    605         if (do_handshake(&ssl) != 0) {
    606             goto exit;
    607         }
    608 
    609         mbedtls_printf("  > Get header from server:");
    610         fflush(stdout);
    611 
    612         ret = write_ssl_and_get_response(&ssl, buf, 0);
    613         if (ret < 200 || ret > 299) {
    614             mbedtls_printf(" failed\n  ! server responded with %d\n\n", ret);
    615             goto exit;
    616         }
    617 
    618         mbedtls_printf(" ok\n");
    619 
    620         mbedtls_printf("  > Write EHLO to server:");
    621         fflush(stdout);
    622 
    623         gethostname(hostname, 32);
    624         len = sprintf((char *) buf, "EHLO %s\r\n", hostname);
    625         ret = write_ssl_and_get_response(&ssl, buf, len);
    626         if (ret < 200 || ret > 299) {
    627             mbedtls_printf(" failed\n  ! server responded with %d\n\n", ret);
    628             goto exit;
    629         }
    630     } else {
    631         mbedtls_printf("  > Get header from server:");
    632         fflush(stdout);
    633 
    634         ret = write_and_get_response(&server_fd, buf, 0);
    635         if (ret < 200 || ret > 299) {
    636             mbedtls_printf(" failed\n  ! server responded with %d\n\n", ret);
    637             goto exit;
    638         }
    639 
    640         mbedtls_printf(" ok\n");
    641 
    642         mbedtls_printf("  > Write EHLO to server:");
    643         fflush(stdout);
    644 
    645         gethostname(hostname, 32);
    646         len = sprintf((char *) buf, "EHLO %s\r\n", hostname);
    647         ret = write_and_get_response(&server_fd, buf, len);
    648         if (ret < 200 || ret > 299) {
    649             mbedtls_printf(" failed\n  ! server responded with %d\n\n", ret);
    650             goto exit;
    651         }
    652 
    653         mbedtls_printf(" ok\n");
    654 
    655         mbedtls_printf("  > Write STARTTLS to server:");
    656         fflush(stdout);
    657 
    658         gethostname(hostname, 32);
    659         len = sprintf((char *) buf, "STARTTLS\r\n");
    660         ret = write_and_get_response(&server_fd, buf, len);
    661         if (ret < 200 || ret > 299) {
    662             mbedtls_printf(" failed\n  ! server responded with %d\n\n", ret);
    663             goto exit;
    664         }
    665 
    666         mbedtls_printf(" ok\n");
    667 
    668         if (do_handshake(&ssl) != 0) {
    669             goto exit;
    670         }
    671     }
    672 
    673 #if defined(MBEDTLS_BASE64_C)
    674     if (opt.authentication) {
    675         mbedtls_printf("  > Write AUTH LOGIN to server:");
    676         fflush(stdout);
    677 
    678         len = sprintf((char *) buf, "AUTH LOGIN\r\n");
    679         ret = write_ssl_and_get_response(&ssl, buf, len);
    680         if (ret < 200 || ret > 399) {
    681             mbedtls_printf(" failed\n  ! server responded with %d\n\n", ret);
    682             goto exit;
    683         }
    684 
    685         mbedtls_printf(" ok\n");
    686 
    687         mbedtls_printf("  > Write username to server: %s", opt.user_name);
    688         fflush(stdout);
    689 
    690         ret = mbedtls_base64_encode(base, sizeof(base), &n, (const unsigned char *) opt.user_name,
    691                                     strlen(opt.user_name));
    692 
    693         if (ret != 0) {
    694             mbedtls_printf(" failed\n  ! mbedtls_base64_encode returned %d\n\n", ret);
    695             goto exit;
    696         }
    697         len = sprintf((char *) buf, "%s\r\n", base);
    698         ret = write_ssl_and_get_response(&ssl, buf, len);
    699         if (ret < 300 || ret > 399) {
    700             mbedtls_printf(" failed\n  ! server responded with %d\n\n", ret);
    701             goto exit;
    702         }
    703 
    704         mbedtls_printf(" ok\n");
    705 
    706         mbedtls_printf("  > Write password to server: %s", opt.user_pwd);
    707         fflush(stdout);
    708 
    709         ret = mbedtls_base64_encode(base, sizeof(base), &n, (const unsigned char *) opt.user_pwd,
    710                                     strlen(opt.user_pwd));
    711 
    712         if (ret != 0) {
    713             mbedtls_printf(" failed\n  ! mbedtls_base64_encode returned %d\n\n", ret);
    714             goto exit;
    715         }
    716         len = sprintf((char *) buf, "%s\r\n", base);
    717         ret = write_ssl_and_get_response(&ssl, buf, len);
    718         if (ret < 200 || ret > 399) {
    719             mbedtls_printf(" failed\n  ! server responded with %d\n\n", ret);
    720             goto exit;
    721         }
    722 
    723         mbedtls_printf(" ok\n");
    724     }
    725 #endif
    726 
    727     mbedtls_printf("  > Write MAIL FROM to server:");
    728     fflush(stdout);
    729 
    730     len = mbedtls_snprintf((char *) buf, sizeof(buf), "MAIL FROM:<%s>\r\n", opt.mail_from);
    731     if (len < 0 || (size_t) len >= sizeof(buf)) {
    732         mbedtls_printf(" failed\n  ! mbedtls_snprintf encountered error or truncated output\n\n");
    733         goto exit;
    734     }
    735     ret = write_ssl_and_get_response(&ssl, buf, len);
    736     if (ret < 200 || ret > 299) {
    737         mbedtls_printf(" failed\n  ! server responded with %d\n\n", ret);
    738         goto exit;
    739     }
    740 
    741     mbedtls_printf(" ok\n");
    742 
    743     mbedtls_printf("  > Write RCPT TO to server:");
    744     fflush(stdout);
    745 
    746     len = mbedtls_snprintf((char *) buf, sizeof(buf), "RCPT TO:<%s>\r\n", opt.mail_to);
    747     if (len < 0 || (size_t) len >= sizeof(buf)) {
    748         mbedtls_printf(" failed\n  ! mbedtls_snprintf encountered error or truncated output\n\n");
    749         goto exit;
    750     }
    751     ret = write_ssl_and_get_response(&ssl, buf, len);
    752     if (ret < 200 || ret > 299) {
    753         mbedtls_printf(" failed\n  ! server responded with %d\n\n", ret);
    754         goto exit;
    755     }
    756 
    757     mbedtls_printf(" ok\n");
    758 
    759     mbedtls_printf("  > Write DATA to server:");
    760     fflush(stdout);
    761 
    762     len = sprintf((char *) buf, "DATA\r\n");
    763     ret = write_ssl_and_get_response(&ssl, buf, len);
    764     if (ret < 300 || ret > 399) {
    765         mbedtls_printf(" failed\n  ! server responded with %d\n\n", ret);
    766         goto exit;
    767     }
    768 
    769     mbedtls_printf(" ok\n");
    770 
    771     mbedtls_printf("  > Write content to server:");
    772     fflush(stdout);
    773 
    774     len = mbedtls_snprintf((char *) buf, sizeof(buf),
    775                            "From: %s\r\nSubject: Mbed TLS Test mail\r\n\r\n"
    776                            "This is a simple test mail from the "
    777                            "Mbed TLS mail client example.\r\n"
    778                            "\r\n"
    779                            "Enjoy!", opt.mail_from);
    780     if (len < 0 || (size_t) len >= sizeof(buf)) {
    781         mbedtls_printf(" failed\n  ! mbedtls_snprintf encountered error or truncated output\n\n");
    782         goto exit;
    783     }
    784     ret = write_ssl_data(&ssl, buf, len);
    785 
    786     len = sprintf((char *) buf, "\r\n.\r\n");
    787     ret = write_ssl_and_get_response(&ssl, buf, len);
    788     if (ret < 200 || ret > 299) {
    789         mbedtls_printf(" failed\n  ! server responded with %d\n\n", ret);
    790         goto exit;
    791     }
    792 
    793     mbedtls_printf(" ok\n");
    794 
    795     mbedtls_ssl_close_notify(&ssl);
    796 
    797     exit_code = MBEDTLS_EXIT_SUCCESS;
    798 
    799 exit:
    800 
    801     mbedtls_net_free(&server_fd);
    802     mbedtls_x509_crt_free(&clicert);
    803     mbedtls_x509_crt_free(&cacert);
    804     mbedtls_pk_free(&pkey);
    805     mbedtls_ssl_free(&ssl);
    806     mbedtls_ssl_config_free(&conf);
    807     mbedtls_ctr_drbg_free(&ctr_drbg);
    808     mbedtls_entropy_free(&entropy);
    809 #if defined(MBEDTLS_USE_PSA_CRYPTO)
    810     mbedtls_psa_crypto_free();
    811 #endif /* MBEDTLS_USE_PSA_CRYPTO */
    812 
    813     mbedtls_exit(exit_code);
    814 }
    815 #endif /* MBEDTLS_BIGNUM_C && MBEDTLS_ENTROPY_C && MBEDTLS_SSL_TLS_C &&
    816           MBEDTLS_SSL_CLI_C && MBEDTLS_NET_C && MBEDTLS_RSA_C **
    817           MBEDTLS_CTR_DRBG_C */