Exemple #1
0
/**
 * We've had some sort of command-line error. Print out the client options.
 */
static void print_client_options(char *option)
{
#ifdef CONFIG_SSL_ENABLE_CLIENT
    int cert_size = ssl_get_config(SSL_MAX_CERT_CFG_OFFSET);
    int ca_cert_size = ssl_get_config(SSL_MAX_CA_CERT_CFG_OFFSET);
#endif

    printf("unknown option %s\n", option);
#ifdef CONFIG_SSL_ENABLE_CLIENT
    printf("usage: s_client [args ...]\n");
    printf(" -connect host:port - who to connect to (default "
           "is localhost:4433)\n");
    printf(" -verify\t- turn on peer certificate verification\n");
    printf(" -cert arg\t- certificate file to use\n");
    printf("\t\t  Can repeat up to %d times\n", cert_size);
    printf(" -key arg\t- Private key file to use\n");
    printf(" -CAfile arg\t- Certificate authority\n");
    printf("\t\t  Can repeat up to %d times\n", ca_cert_size);
    printf(" -quiet\t\t- No client output\n");
    printf(" -reconnect\t- Drop and re-make the connection "
           "with the same Session-ID\n");
    printf(" -pass\t\t- private key file pass phrase source\n");
#ifdef CONFIG_SSL_FULL_MODE
    printf(" -debug\t\t- Print more output\n");
    printf(" -state\t\t- Show state messages\n");
    printf(" -show-rsa\t- Show RSA state\n");
#endif
#else
    printf("Change configuration to allow this feature\n");
#endif
    exit(1);
}
Exemple #2
0
/**
 * We've had some sort of command-line error. Print out the server options.
 */
static void print_server_options(char *option)
{
#ifndef CONFIG_SSL_SKELETON_MODE
    int cert_size = ssl_get_config(SSL_MAX_CERT_CFG_OFFSET);
#endif
#ifdef CONFIG_SSL_CERT_VERIFICATION
    int ca_cert_size = ssl_get_config(SSL_MAX_CA_CERT_CFG_OFFSET);
#endif

    printf("unknown option %s\n", option);
    printf("usage: s_server [args ...]\n");
    printf(" -accept arg\t- port to accept on (default is 4433)\n");
#ifndef CONFIG_SSL_SKELETON_MODE
    printf(" -cert arg\t- certificate file to add (in addition to default)"
           " to chain -\n"
           "\t\t  Can repeat up to %d times\n", cert_size);
    printf(" -key arg\t- Private key file to use\n");
    printf(" -pass\t\t- private key file pass phrase source\n");
#endif
    printf(" -quiet\t\t- No server output\n");
#ifdef CONFIG_SSL_CERT_VERIFICATION
    printf(" -verify\t- turn on peer certificate verification\n");
    printf(" -CAfile arg\t- Certificate authority\n");
    printf("\t\t  Can repeat up to %d times\n", ca_cert_size);
#endif
#ifdef CONFIG_SSL_FULL_MODE
    printf(" -debug\t\t- Print more output\n");
    printf(" -state\t\t- Show state messages\n");
    printf(" -show-rsa\t- Show RSA state\n");
#endif
    exit(1);
}
Exemple #3
0
static SQRESULT sq_axtls_get_config(HSQUIRRELVM v){
    SQ_FUNC_VARS_NO_TOP(v);
    SQ_GET_INTEGER(v, 2, info);
	sq_pushinteger(v, ssl_get_config(info));
	return 1;
}
Exemple #4
0
/******************************************************************************
 * FunctionName : upgrade_task
 * Description  : task to connect with target server and get firmware data 
 * Parameters   : pvParameters--save the server address\port\request frame for
 *              : the upgrade server\call back functions to tell the userapp
 *              : the result of this upgrade task
 * Returns      : none
*******************************************************************************/
void upgrade_ssl_task(void *pvParameters)
{
    int recbytes;
    int sta_socket;
    int retry_count = 0;
    struct ip_info ipconfig;
    
    struct upgrade_server_info *server = pvParameters;

    flash_erased=FALSE;
    precv_buf = (char*)malloc(UPGRADE_DATA_SEG_LEN);//the max data length
    
    while (retry_count++ < UPGRADE_RETRY_TIMES) {
        if (giveup) break;
		
        wifi_get_ip_info(STATION_IF, &ipconfig);

        /* check the ip address or net connection state*/
        while (ipconfig.ip.addr == 0) {
            vTaskDelay(1000 / portTICK_RATE_MS);
            wifi_get_ip_info(STATION_IF, &ipconfig);
        }
        
        sta_socket = socket(PF_INET,SOCK_STREAM,0);
        if (-1 == sta_socket) {
            close(sta_socket);
            vTaskDelay(1000 / portTICK_RATE_MS);
            os_printf("socket fail !\r\n");
            continue;
        }

        /*for upgrade connection debug*/
        //server->sockaddrin.sin_addr.s_addr= inet_addr("192.168.1.170");
        if(0 != connect(sta_socket,(struct sockaddr *)(&server->sockaddrin),sizeof(struct sockaddr))) {
            close(sta_socket);
            vTaskDelay(1000 / portTICK_RATE_MS);
            os_printf("connect fail!\r\n");
            continue;
        }

        uint32_t options = SSL_DISPLAY_CERTS | SSL_NO_DEFAULT_KEY;
        int i=0;
        int quiet = 0;
        int cert_index = 0, ca_cert_index = 0;
        int cert_size, ca_cert_size;
        char **ca_cert, **cert;
        SSL *ssl;
        SSL_CTX *ssl_ctx;
        uint8_t *read_buf = NULL;

        cert_size = ssl_get_config(SSL_MAX_CERT_CFG_OFFSET);
        ca_cert_size = ssl_get_config(SSL_MAX_CA_CERT_CFG_OFFSET);
        ca_cert = (char **)calloc(1, sizeof(char *)*ca_cert_size);
        cert = (char **)calloc(1, sizeof(char *)*cert_size);

        if ((ssl_ctx= ssl_ctx_new(options, SSL_DEFAULT_CLNT_SESS)) == NULL) {
            printf("Error: Client context is invalid\n");
            close(sta_socket);
            continue;
        }

		ssl_obj_memory_load(ssl_ctx, SSL_OBJ_X509_CACERT, default_certificate, default_certificate_len, NULL);

        for (i = 0; i < cert_index; i++) {
            if (ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, cert[i], NULL)){
                printf("Certificate '%s' is undefined.\n", cert[i]);
            }
        }
        
        for (i = 0; i < ca_cert_index; i++) {
            if (ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CACERT, ca_cert[i], NULL)){
                printf("Certificate '%s' is undefined.\n", ca_cert[i]);
            }
        }

        free(cert);
        free(ca_cert);

        ssl= ssl_client_new(ssl_ctx, sta_socket, NULL, 0);
        if (ssl == NULL){
            ssl_ctx_free(ssl_ctx);
            close(sta_socket);
            continue;
        }
        
        if(ssl_handshake_status(ssl) != SSL_OK){
            printf("client handshake fail.\n");
            ssl_free(ssl);
            ssl_ctx_free(ssl_ctx);
            close(sta_socket);
            continue;
        }
        
        //handshake sucesses,show cert and free x509_ctx here
        if (!quiet) {
            const char *common_name = ssl_get_cert_dn(ssl,SSL_X509_CERT_COMMON_NAME);
            if (common_name) {
                printf("Common Name:\t\t\t%s\n", common_name);
            }
            display_session_id(ssl);
            display_cipher(ssl);
            quiet = true;

            x509_free(ssl->x509_ctx);
            ssl->x509_ctx=NULL;
        }

        system_upgrade_init();
        system_upgrade_flag_set(UPGRADE_FLAG_START);

        if(ssl_write(ssl, server->url, strlen(server->url)+1) < 0) {
            ssl_free(ssl);
            ssl_ctx_free(ssl_ctx);
            close(sta_socket);
            vTaskDelay(1000 / portTICK_RATE_MS);
            os_printf("send fail\n");
            continue;
        }
        os_printf("Request send success\n");

        while((recbytes = ssl_read(ssl, &read_buf)) >= 0) {

            if(recbytes == 0){
                vTaskDelay(500 / portTICK_RATE_MS);
                continue;
            }
            
            if(recbytes > UPGRADE_DATA_SEG_LEN) {
                ssl_free(ssl);
                ssl_ctx_free(ssl_ctx);
                close(sta_socket);
                vTaskDelay(2000 / portTICK_RATE_MS);
                printf("bigger than UPGRADE_DATA_SEG_LEN\n");
            }

            if((recbytes)<=1460)
                memcpy(precv_buf,read_buf,recbytes);
            else
                os_printf("ERR2:arr_overflow,%u,%d\n",__LINE__,recbytes);

            if(FALSE==flash_erased){
                ssl_free(ssl);
                ssl_ctx_free(ssl_ctx);
                close(sta_socket);
                os_printf("pre erase flash!\n");
                upgrade_data_load(precv_buf,recbytes);
                break;
            }
            
            if(false == upgrade_data_load(read_buf,recbytes)) {
                os_printf("upgrade data error!\n");
                ssl_free(ssl);
                ssl_ctx_free(ssl_ctx);
                close(sta_socket);
                flash_erased=FALSE;
                vTaskDelay(1000 / portTICK_RATE_MS);
                break;
            }
            /*this two length data should be equal, if totallength is bigger, 
             *maybe data wrong or server send extra info, drop it anyway*/
            if(totallength >= sumlength) {
                os_printf("upgrade data load finish.\n");
                ssl_free(ssl);
                ssl_ctx_free(ssl_ctx);
                close(sta_socket);
                goto finish;
            }
            os_printf("upgrade_task %d word left\n",uxTaskGetStackHighWaterMark(NULL));
            
        }
        
        if(recbytes < 0) {
            os_printf("ERROR:read data fail! recbytes %d\r\n",recbytes);
            ssl_free(ssl);
            ssl_ctx_free(ssl_ctx);
            close(sta_socket);
            flash_erased=FALSE;
            vTaskDelay(1000 / portTICK_RATE_MS);
        }
        
        os_printf("upgrade_task %d word left\n",uxTaskGetStackHighWaterMark(NULL));
        
        totallength =0;
        sumlength = 0;
    }
    
finish:

	if(upgrade_crc_check(system_get_fw_start_sec(),sumlength) != 0)
	{
		printf("upgrade crc check failed !\n");
		server->upgrade_flag = false;
        system_upgrade_flag_set(UPGRADE_FLAG_IDLE);	
	}

    os_timer_disarm(&upgrade_timer);

    totallength = 0;
    sumlength = 0;
    flash_erased=FALSE;
    free(precv_buf);
    
    if(retry_count == UPGRADE_RETRY_TIMES){
        /*retry too many times, fail*/
        server->upgrade_flag = false;
        system_upgrade_flag_set(UPGRADE_FLAG_IDLE);

    }else{
        if (server->upgrade_flag == true)
			system_upgrade_flag_set(UPGRADE_FLAG_FINISH);
    }
    
    upgrade_deinit();
    
    os_printf("\n Exit upgrade task.\n");
    if (server->check_cb != NULL) {
        server->check_cb(server);
    }
    vTaskDelay(100 / portTICK_RATE_MS);
    vTaskDelete(NULL);
}
Exemple #5
0
/**
 * Implement the SSL server logic.
 */
static void do_server(int argc, char *argv[])
{
    int i = 2;
    uint16_t port = 4433;
    uint32_t options = SSL_DISPLAY_CERTS;
    int client_fd;
    SSL_CTX *ssl_ctx;
    int server_fd, res = 0;
    socklen_t client_len;
#ifndef CONFIG_SSL_SKELETON_MODE
    char *private_key_file = NULL;
    const char *password = NULL;
    char **cert;
    int cert_index = 0;
    int cert_size = ssl_get_config(SSL_MAX_CERT_CFG_OFFSET);
#endif
#ifdef WIN32
    char yes = 1;
#else
    int yes = 1;
#endif
    struct sockaddr_in serv_addr;
    struct sockaddr_in client_addr;
    int quiet = 0;
#ifdef CONFIG_SSL_CERT_VERIFICATION
    int ca_cert_index = 0;
    int ca_cert_size = ssl_get_config(SSL_MAX_CA_CERT_CFG_OFFSET);
    char **ca_cert = (char **)calloc(1, sizeof(char *)*ca_cert_size);
#endif
    fd_set read_set;

#ifndef CONFIG_SSL_SKELETON_MODE
    cert = (char **)calloc(1, sizeof(char *)*cert_size);
#endif

    while (i < argc) {
        if (strcmp(argv[i], "-accept") == 0)  {
            if (i >= argc - 1)  {
                print_server_options(argv[i]);
            }

            port = atoi(argv[++i]);
        }
#ifndef CONFIG_SSL_SKELETON_MODE
        else if (strcmp(argv[i], "-cert") == 0) {
            if (i >= argc - 1 || cert_index >= cert_size) {
                print_server_options(argv[i]);
            }

            cert[cert_index++] = argv[++i];
        } else if (strcmp(argv[i], "-key") == 0) {
            if (i >= argc - 1) {
                print_server_options(argv[i]);
            }

            private_key_file = argv[++i];
            options |= SSL_NO_DEFAULT_KEY;
        } else if (strcmp(argv[i], "-pass") == 0) {
            if (i >= argc - 1) {
                print_server_options(argv[i]);
            }

            password = argv[++i];
        }
#endif
        else if (strcmp(argv[i], "-quiet") == 0) {
            quiet = 1;
            options &= ~SSL_DISPLAY_CERTS;
        }
#ifdef CONFIG_SSL_CERT_VERIFICATION
        else if (strcmp(argv[i], "-verify") == 0) {
            options |= SSL_CLIENT_AUTHENTICATION;
        } else if (strcmp(argv[i], "-CAfile") == 0)  {
            if (i >= argc - 1 || ca_cert_index >= ca_cert_size) {
                print_server_options(argv[i]);
            }

            ca_cert[ca_cert_index++] = argv[++i];
        }
#endif
#ifdef CONFIG_SSL_FULL_MODE
        else if (strcmp(argv[i], "-debug") == 0)  {
            options |= SSL_DISPLAY_BYTES;
        } else if (strcmp(argv[i], "-state") == 0) {
            options |= SSL_DISPLAY_STATES;
        } else if (strcmp(argv[i], "-show-rsa") == 0) {
            options |= SSL_DISPLAY_RSA;
        }
#endif
        else  {
            /* don't know what this is */
            print_server_options(argv[i]);
        }

        i++;
    }

    if ((ssl_ctx = ssl_ctx_new(options, SSL_DEFAULT_SVR_SESS)) == NULL)  {
        fprintf(stderr, "Error: Server context is invalid\n");
        exit(1);
    }

#ifndef CONFIG_SSL_SKELETON_MODE
    if (private_key_file)   {
        int obj_type = SSL_OBJ_RSA_KEY;

        /* auto-detect the key type from the file extension */
        if (strstr(private_key_file, ".p8")) {
            obj_type = SSL_OBJ_PKCS8;
        } else if (strstr(private_key_file, ".p12")) {
            obj_type = SSL_OBJ_PKCS12;
        }

        if (ssl_obj_load(ssl_ctx, obj_type, private_key_file, password)) {
            fprintf(stderr, "Error: Private key '%s' is undefined.\n",
                    private_key_file);
            exit(1);
        }
    }

    for (i = 0; i < cert_index; i++)  {
        if (ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, cert[i], NULL)) {
            printf("Certificate '%s' is undefined.\n", cert[i]);
            exit(1);
        }
    }
#endif

#ifdef CONFIG_SSL_CERT_VERIFICATION
    for (i = 0; i < ca_cert_index; i++) {
        if (ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CACERT, ca_cert[i], NULL)) {
            printf("Certificate '%s' is undefined.\n", ca_cert[i]);
            exit(1);
        }
    }

    free(ca_cert);
#endif
#ifndef CONFIG_SSL_SKELETON_MODE
    free(cert);
#endif

    /* Create socket for incoming connections */
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("socket");
        return;
    }

    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));

    /* Construct local address structure */
    memset(&serv_addr, 0, sizeof(serv_addr));      /* Zero out structure */
    serv_addr.sin_family = AF_INET;                /* Internet address family */
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */
    serv_addr.sin_port = htons(port);              /* Local port */

    /* Bind to the local address */
    if (bind(server_fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)    {
        perror("bind");
        exit(1);
    }

    if (listen(server_fd, 5) < 0)    {
        perror("listen");
        exit(1);
    }

    client_len = sizeof(client_addr);

    /*************************************************************************
     * This is where the interesting stuff happens. Up until now we've
     * just been setting up sockets etc. Now we do the SSL handshake.
     *************************************************************************/
    for (;;)    {
        SSL *ssl;
        int reconnected = 0;

        if (!quiet)        {
            printf("ACCEPT\n");
            TTY_FLUSH();
        }

        if ((client_fd = accept(server_fd,
                                (struct sockaddr *)&client_addr, &client_len)) < 0)        {
            break;
        }

        ssl = ssl_server_new(ssl_ctx, client_fd);

        /* now read (and display) whatever the client sends us */
        for (;;)        {
            /* allow parallel reading of client and standard input */
            FD_ZERO(&read_set);
            FD_SET(client_fd, &read_set);

#ifndef WIN32
            /* win32 doesn't like mixing up stdin and sockets */
            if (isatty(STDIN_FILENO)) { /* but only if we are in an active shell */
                FD_SET(STDIN_FILENO, &read_set);
            }

            if ((res = select(client_fd + 1, &read_set, NULL, NULL, NULL)) > 0)  {
                uint8_t buf[1024];

                /* read standard input? */
                if (FD_ISSET(STDIN_FILENO, &read_set))  {
                    if (fgets((char *)buf, sizeof(buf), stdin) == NULL) {
                        res = SSL_ERROR_CONN_LOST;
                    } else {
                        /* small hack to check renegotiation */
                        if (buf[0] == 'r' && (buf[1] == '\n' || buf[1] == '\r')) {
                            res = ssl_renegotiate(ssl);
                        }  else  {
                            /* write our ramblings to the client */
                            res = ssl_write(ssl, buf, strlen((char *)buf) + 1);
                        }
                    }
                } else  /* a socket read */
#endif
                {
                    /* keep reading until we get something interesting */
                    uint8_t *read_buf;

                    if ((res = ssl_read(ssl, &read_buf)) == SSL_OK) {
                        /* are we in the middle of doing a handshake? */
                        if (ssl_handshake_status(ssl) != SSL_OK) {
                            reconnected = 0;
                        } else if (!reconnected) {
                            /* we are connected/reconnected */
                            if (!quiet) {
                                display_session_id(ssl);
                                display_cipher(ssl);
                            }

                            reconnected = 1;
                        }
                    }

                    if (res > SSL_OK) {  /* display our interesting output */
                        int written = 0;
                        while (written < res) {
                            written += write(STDOUT_FILENO, read_buf + written,
                                             res - written);
                        }
                        TTY_FLUSH();
                    } else if (res == SSL_CLOSE_NOTIFY) {
                        printf("shutting down SSL\n");
                        TTY_FLUSH();
                    } else if (res < SSL_OK && !quiet) {
                        ssl_display_error(res);
                    }
                }
#ifndef WIN32
            }
#endif

            if (res < SSL_OK)  {
                if (!quiet)  {
                    printf("CONNECTION CLOSED\n");
                    TTY_FLUSH();
                }

                break;
            }
        }

        /* client was disconnected or the handshake failed. */
        ssl_free(ssl);
        SOCKET_CLOSE(client_fd);
    }

    ssl_ctx_free(ssl_ctx);
}
Exemple #6
0
/**
 * Implement the SSL client logic.
 */
static void do_client(int argc, char *argv[])
{
#ifdef CONFIG_SSL_ENABLE_CLIENT
    int res, i = 2;
    uint16_t port = 4433;
    uint32_t options = SSL_SERVER_VERIFY_LATER | SSL_DISPLAY_CERTS;
    int client_fd;
    char *private_key_file = NULL;
    struct sockaddr_in client_addr;
    struct hostent *hostent;
    int reconnect = 0;
    uint32_t sin_addr;
    SSL_CTX *ssl_ctx;
    SSL *ssl = NULL;
    int quiet = 0;
    int cert_index = 0, ca_cert_index = 0;
    int cert_size, ca_cert_size;
    char **ca_cert, **cert;
    uint8_t session_id[SSL_SESSION_ID_SIZE];
    fd_set read_set;
    const char *password = NULL;

    FD_ZERO(&read_set);
    sin_addr = inet_addr("127.0.0.1");
    cert_size = ssl_get_config(SSL_MAX_CERT_CFG_OFFSET);
    ca_cert_size = ssl_get_config(SSL_MAX_CA_CERT_CFG_OFFSET);
    ca_cert = (char **)calloc(1, sizeof(char *)*ca_cert_size);
    cert = (char **)calloc(1, sizeof(char *)*cert_size);

    while (i < argc) {
        if (strcmp(argv[i], "-connect") == 0)        {
            char *host, *ptr;

            if (i >= argc - 1) {
                print_client_options(argv[i]);
            }

            host = argv[++i];
            if ((ptr = strchr(host, ':')) == NULL) {
                print_client_options(argv[i]);
            }

            *ptr++ = 0;
            port = atoi(ptr);
            hostent = gethostbyname(host);

            if (hostent == NULL) {
                print_client_options(argv[i]);
            }

            sin_addr = *((uint32_t **)hostent->h_addr_list)[0];
        } else if (strcmp(argv[i], "-cert") == 0) {
            if (i >= argc - 1 || cert_index >= cert_size) {
                print_client_options(argv[i]);
            }

            cert[cert_index++] = argv[++i];
        } else if (strcmp(argv[i], "-key") == 0) {
            if (i >= argc - 1) {
                print_client_options(argv[i]);
            }

            private_key_file = argv[++i];
            options |= SSL_NO_DEFAULT_KEY;
        } else if (strcmp(argv[i], "-CAfile") == 0) {
            if (i >= argc - 1 || ca_cert_index >= ca_cert_size) {
                print_client_options(argv[i]);
            }

            ca_cert[ca_cert_index++] = argv[++i];
        } else if (strcmp(argv[i], "-verify") == 0) {
            options &= ~SSL_SERVER_VERIFY_LATER;
        } else if (strcmp(argv[i], "-reconnect") == 0) {
            reconnect = 4;
        } else if (strcmp(argv[i], "-quiet") == 0) {
            quiet = 1;
            options &= ~SSL_DISPLAY_CERTS;
        } else if (strcmp(argv[i], "-pass") == 0) {
            if (i >= argc - 1) {
                print_client_options(argv[i]);
            }

            password = argv[++i];
        }
#ifdef CONFIG_SSL_FULL_MODE
        else if (strcmp(argv[i], "-debug") == 0)  {
            options |= SSL_DISPLAY_BYTES;
        } else if (strcmp(argv[i], "-state") == 0)  {
            options |= SSL_DISPLAY_STATES;
        } else if (strcmp(argv[i], "-show-rsa") == 0) {
            options |= SSL_DISPLAY_RSA;
        }
#endif
        else  {
            /* don't know what this is */
            print_client_options(argv[i]);
        }

        i++;
    }

    if ((ssl_ctx = ssl_ctx_new(options, SSL_DEFAULT_CLNT_SESS)) == NULL) {
        fprintf(stderr, "Error: Client context is invalid\n");
        exit(1);
    }

    if (private_key_file)  {
        int obj_type = SSL_OBJ_RSA_KEY;

        /* auto-detect the key type from the file extension */
        if (strstr(private_key_file, ".p8")) {
            obj_type = SSL_OBJ_PKCS8;
        } else if (strstr(private_key_file, ".p12")) {
            obj_type = SSL_OBJ_PKCS12;
        }

        if (ssl_obj_load(ssl_ctx, obj_type, private_key_file, password))  {
            fprintf(stderr, "Error: Private key '%s' is undefined.\n",
                    private_key_file);
            exit(1);
        }
    }

    for (i = 0; i < cert_index; i++) {
        if (ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, cert[i], NULL)) {
            printf("Certificate '%s' is undefined.\n", cert[i]);
            exit(1);
        }
    }
    for (i = 0; i < ca_cert_index; i++) {
        if (ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CACERT, ca_cert[i], NULL)) {
            printf("Certificate '%s' is undefined.\n", ca_cert[i]);
            exit(1);
        }
    }


    free(cert);
    free(ca_cert);

    /*************************************************************************
     * This is where the interesting stuff happens. Up until now we've
     * just been setting up sockets etc. Now we do the SSL handshake.
     *************************************************************************/
    client_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    memset(&client_addr, 0, sizeof(client_addr));
    client_addr.sin_family = AF_INET;
    client_addr.sin_port = htons(port);
    client_addr.sin_addr.s_addr = sin_addr;

    if (connect(client_fd, (struct sockaddr *)&client_addr,
                sizeof(client_addr)) < 0) {
        perror("connect");
        exit(1);
    }

    if (!quiet) {
        printf("CONNECTED\n");
        TTY_FLUSH();
    }

    /* Try session resumption? */
    if (reconnect) {
        while (reconnect--) {
            ssl = ssl_client_new(ssl_ctx, client_fd, session_id,
                                 sizeof(session_id));
            if ((res = ssl_handshake_status(ssl)) != SSL_OK) {
                if (!quiet) {
                    ssl_display_error(res);
                }

                ssl_free(ssl);
                exit(1);
            }

            display_session_id(ssl);
            memcpy(session_id, ssl_get_session_id(ssl), SSL_SESSION_ID_SIZE);

            if (reconnect) {
                ssl_free(ssl);
                SOCKET_CLOSE(client_fd);

                client_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
                connect(client_fd, (struct sockaddr *)&client_addr,
                        sizeof(client_addr));
            }
        }
    } else {
        ssl = ssl_client_new(ssl_ctx, client_fd, NULL, 0);
    }

    /* check the return status */
    if ((res = ssl_handshake_status(ssl)) != SSL_OK) {
        if (!quiet) {
            ssl_display_error(res);
        }

        exit(1);
    }

    if (!quiet) {
        const char *common_name = ssl_get_cert_dn(ssl,
                                  SSL_X509_CERT_COMMON_NAME);
        if (common_name) {
            printf("Common Name:\t\t\t%s\n", common_name);
        }

        display_session_id(ssl);
        display_cipher(ssl);
    }

    for (;;) {
        uint8_t buf[1024];

        /* allow parallel reading of server and standard input */
        FD_SET(client_fd, &read_set);
#ifndef WIN32
        /* win32 doesn't like mixing up stdin and sockets */
        FD_SET(STDIN_FILENO, &read_set);

        if ((res = select(client_fd + 1, &read_set, NULL, NULL, NULL)) > 0) {
            /* read standard input? */
            if (FD_ISSET(STDIN_FILENO, &read_set))
#endif
            {
                if (fgets((char *)buf, sizeof(buf), stdin) == NULL) {
                    /* bomb out of here */
                    ssl_free(ssl);
                    break;
                } else {
                    /* small hack to check renegotiation */
                    if (buf[0] == 'R' && (buf[1] == '\n' || buf[1] == '\r')) {
                        res = ssl_renegotiate(ssl);
                    } else {
                        res = ssl_write(ssl, buf, strlen((char *)buf));
                    }
                }
            }
#ifndef WIN32
            else {  /* a socket read */
                uint8_t *read_buf;

                res = ssl_read(ssl, &read_buf);

                if (res > 0) {  /* display our interesting output */
                    int written = 0;
                    while (written < res) {
                        written += write(STDOUT_FILENO, read_buf + written,
                                         res - written);
                    }
                    TTY_FLUSH();
                }
            }
        }
#endif

        if (res < 0) {
            if (!quiet) {
                ssl_display_error(res);
            }

            break;      /* get outta here */
        }
    }

    ssl_ctx_free(ssl_ctx);
    SOCKET_CLOSE(client_fd);
#else
    print_client_options(argv[1]);
#endif
}