Ejemplo n.º 1
0
Archivo: x509.c Proyecto: ftes/opensgx
/*
 * Store the serial in printable form into buf; no more
 * than size characters will be written
 */
int x509_serial_gets( char *buf, size_t size, const x509_buf *serial )
{
    int ret;
    size_t i, n, nr;
    char *p;

    p = buf;
    n = size;

    nr = ( serial->len <= 32 )
         ? serial->len  : 28;

    for( i = 0; i < nr; i++ )
    {
        if( i == 0 && nr > 1 && serial->p[i] == 0x0 )
            continue;

        ret = polarssl_snprintf( p, n, "%02X%s",
                                 serial->p[i], ( i < nr - 1 ) ? ":" : "" );
        SAFE_SNPRINTF();
    }

    if( nr != serial->len )
    {
        ret = polarssl_snprintf( p, n, "...." );
        SAFE_SNPRINTF();
    }

    return( (int) ( size - n ) );
}
Ejemplo n.º 2
0
Archivo: x509.c Proyecto: ftes/opensgx
/*
 * Store the name in printable form into buf; no more
 * than size characters will be written
 */
int x509_dn_gets( char *buf, size_t size, const x509_name *dn )
{
    int ret;
    size_t i, n;
    unsigned char c, merge = 0;
    const x509_name *name;
    const char *short_name = NULL;
    char s[X509_MAX_DN_NAME_SIZE], *p;

    memset( s, 0, sizeof( s ) );

    name = dn;
    p = buf;
    n = size;

    while( name != NULL )
    {
        if( !name->oid.p )
        {
            name = name->next;
            continue;
        }

        if( name != dn )
        {
            ret = polarssl_snprintf( p, n, merge ? " + " : ", " );
            SAFE_SNPRINTF();
        }

        ret = oid_get_attr_short_name( &name->oid, &short_name );

        if( ret == 0 )
            ret = polarssl_snprintf( p, n, "%s=", short_name );
        else
            ret = polarssl_snprintf( p, n, "\?\?=" );
        SAFE_SNPRINTF();

        for( i = 0; i < name->val.len; i++ )
        {
            if( i >= sizeof( s ) - 1 )
                break;

            c = name->val.p[i];
            if( c < 32 || c == 127 || ( c > 128 && c < 160 ) )
                s[i] = '?';
            else s[i] = c;
        }
        s[i] = '\0';
        ret = polarssl_snprintf( p, n, "%s", s );
        SAFE_SNPRINTF();

        merge = name->next_merged;
        name = name->next;
    }

    return( (int) ( size - n ) );
}
Ejemplo n.º 3
0
void debug_print_buf( const ssl_context *ssl, int level,
                      const char *file, int line, const char *text,
                      unsigned char *buf, size_t len )
{
    char str[512];
    char txt[17];
    size_t i, maxlen = sizeof( str ) - 1, idx = 0;

    if( ssl->f_dbg == NULL || level > debug_threshold )
        return;

    if( debug_log_mode == POLARSSL_DEBUG_LOG_FULL )
        idx = polarssl_snprintf( str, maxlen, "%s(%04d): ", file, line );

    polarssl_snprintf( str + idx, maxlen - idx, "dumping '%s' (%u bytes)\n",
              text, (unsigned int) len );

    str[maxlen] = '\0';
    ssl->f_dbg( ssl->p_dbg, level, str );

    idx = 0;
    memset( txt, 0, sizeof( txt ) );
    for( i = 0; i < len; i++ )
    {
        if( i >= 4096 )
            break;

        if( i % 16 == 0 )
        {
            if( i > 0 )
            {
                polarssl_snprintf( str + idx, maxlen - idx, "  %s\n", txt );
                ssl->f_dbg( ssl->p_dbg, level, str );

                idx = 0;
                memset( txt, 0, sizeof( txt ) );
            }

            if( debug_log_mode == POLARSSL_DEBUG_LOG_FULL )
                idx = polarssl_snprintf( str, maxlen, "%s(%04d): ", file, line );

            idx += polarssl_snprintf( str + idx, maxlen - idx, "%04x: ",
                             (unsigned int) i );

        }

        idx += polarssl_snprintf( str + idx, maxlen - idx, " %02x",
                         (unsigned int) buf[i] );
        txt[i % 16] = ( buf[i] > 31 && buf[i] < 127 ) ? buf[i] : '.' ;
    }

    if( len > 0 )
    {
        for( /* i = i */; i % 16 != 0; i++ )
            idx += polarssl_snprintf( str + idx, maxlen - idx, "   " );

        polarssl_snprintf( str + idx, maxlen - idx, "  %s\n", txt );
        ssl->f_dbg( ssl->p_dbg, level, str );
    }
}
Ejemplo n.º 4
0
void debug_print_ecp( const ssl_context *ssl, int level,
                      const char *file, int line,
                      const char *text, const ecp_point *X )
{
    char str[512];
    int maxlen = sizeof( str ) - 1;

    /*if( ssl->f_dbg == NULL || level > debug_threshold )
        return;*/

    polarssl_snprintf( str, maxlen, "%s(X)", text );
    str[maxlen] = '\0';
    debug_print_mpi( ssl, level, file, line, str, &X->X );

    polarssl_snprintf( str, maxlen, "%s(Y)", text );
    str[maxlen] = '\0';
    debug_print_mpi( ssl, level, file, line, str, &X->Y );
}
Ejemplo n.º 5
0
void debug_print_ret( const ssl_context *ssl, int level,
                      const char *file, int line,
                      const char *text, int ret )
{
    char str[512];
    int maxlen = sizeof( str ) - 1;
    size_t idx = 0;

    if( ssl->f_dbg == NULL || level > debug_threshold )
        return;

    if( debug_log_mode == POLARSSL_DEBUG_LOG_FULL )
        idx = polarssl_snprintf( str, maxlen, "%s(%04d): ", file, line );

    polarssl_snprintf( str + idx, maxlen - idx, "%s() returned %d (-0x%04x)\n",
              text, ret, -ret );

    str[maxlen] = '\0';
    ssl->f_dbg( ssl->p_dbg, level, str );
}
Ejemplo n.º 6
0
Archivo: x509.c Proyecto: ftes/opensgx
/*
 * Helper for writing signature algorithms
 */
int x509_sig_alg_gets( char *buf, size_t size, const x509_buf *sig_oid,
                       pk_type_t pk_alg, md_type_t md_alg,
                       const void *sig_opts )
{
    int ret;
    char *p = buf;
    size_t n = size;
    const char *desc = NULL;

    ret = oid_get_sig_alg_desc( sig_oid, &desc );
    if( ret != 0 )
        ret = polarssl_snprintf( p, n, "???"  );
    else
        ret = polarssl_snprintf( p, n, "%s", desc );
    SAFE_SNPRINTF();

#if defined(POLARSSL_X509_RSASSA_PSS_SUPPORT)
    if( pk_alg == POLARSSL_PK_RSASSA_PSS )
    {
        const pk_rsassa_pss_options *pss_opts;
        const md_info_t *md_info, *mgf_md_info;

        pss_opts = (const pk_rsassa_pss_options *) sig_opts;

        md_info = md_info_from_type( md_alg );
        mgf_md_info = md_info_from_type( pss_opts->mgf1_hash_id );

        ret = polarssl_snprintf( p, n, " (%s, MGF1-%s, 0x%02X)",
                                 md_info ? md_info->name : "???",
                                 mgf_md_info ? mgf_md_info->name : "???",
                                 pss_opts->expected_salt_len );
        SAFE_SNPRINTF();
    }
#else
    ((void) pk_alg);
    ((void) md_alg);
    ((void) sig_opts);
#endif /* POLARSSL_X509_RSASSA_PSS_SUPPORT */

    return( (int)( size - n ) );
}
Ejemplo n.º 7
0
/*
 * Return an informational string about the CSR.
 */
int x509_csr_info( char *buf, size_t size, const char *prefix,
                   const x509_csr *csr )
{
    int ret;
    size_t n;
    char *p;
    char key_size_str[BEFORE_COLON];

    p = buf;
    n = size;

    ret = polarssl_snprintf( p, n, "%sCSR version   : %d",
                               prefix, csr->version );
    SAFE_SNPRINTF();

    ret = polarssl_snprintf( p, n, "\n%ssubject name  : ", prefix );
    SAFE_SNPRINTF();
    ret = x509_dn_gets( p, n, &csr->subject );
    SAFE_SNPRINTF();

    ret = polarssl_snprintf( p, n, "\n%ssigned using  : ", prefix );
    SAFE_SNPRINTF();

    ret = x509_sig_alg_gets( p, n, &csr->sig_oid, csr->sig_pk, csr->sig_md,
                             csr->sig_opts );
    SAFE_SNPRINTF();

    if( ( ret = x509_key_size_helper( key_size_str, BEFORE_COLON,
                                      pk_get_name( &csr->pk ) ) ) != 0 )
    {
        return( ret );
    }

    ret = polarssl_snprintf( p, n, "\n%s%-" BC "s: %d bits\n", prefix, key_size_str,
                          (int) pk_get_size( &csr->pk ) );
    SAFE_SNPRINTF();

    return( (int) ( size - n ) );
}
Ejemplo n.º 8
0
Archivo: x509.c Proyecto: ftes/opensgx
/*
 * Helper for writing "RSA key size", "EC key size", etc
 */
int x509_key_size_helper( char *buf, size_t size, const char *name )
{
    char *p = buf;
    size_t n = size;
    int ret;

    if( strlen( name ) + sizeof( " key size" ) > size )
        return( POLARSSL_ERR_DEBUG_BUF_TOO_SMALL );

    ret = polarssl_snprintf( p, n, "%s key size", name );
    SAFE_SNPRINTF();

    return( 0 );
}
Ejemplo n.º 9
0
void debug_print_msg( const ssl_context *ssl, int level,
                      const char *file, int line, const char *text )
{
    char str[512];
    int maxlen = sizeof( str ) - 1;

    if( ssl->f_dbg == NULL || level > debug_threshold )
        return;

    if( debug_log_mode == POLARSSL_DEBUG_LOG_RAW )
    {
        ssl->f_dbg( ssl->p_dbg, level, text );
        return;
    }

    polarssl_snprintf( str, maxlen, "%s(%04d): %s\n", file, line, text );
    str[maxlen] = '\0';
    ssl->f_dbg( ssl->p_dbg, level, str );
}
Ejemplo n.º 10
0
/*
 * Return an informational string about the CRL.
 */
int x509_crl_info( char *buf, size_t size, const char *prefix,
                   const x509_crl *crl )
{
    int ret;
    size_t n;
    char *p;
    const x509_crl_entry *entry;

    p = buf;
    n = size;

    ret = polarssl_snprintf( p, n, "%sCRL version   : %d",
                               prefix, crl->version );
    SAFE_SNPRINTF();

    ret = polarssl_snprintf( p, n, "\n%sissuer name   : ", prefix );
    SAFE_SNPRINTF();
    ret = x509_dn_gets( p, n, &crl->issuer );
    SAFE_SNPRINTF();

    ret = polarssl_snprintf( p, n, "\n%sthis update   : " \
                   "%04d-%02d-%02d %02d:%02d:%02d", prefix,
                   crl->this_update.year, crl->this_update.mon,
                   crl->this_update.day,  crl->this_update.hour,
                   crl->this_update.min,  crl->this_update.sec );
    SAFE_SNPRINTF();

    ret = polarssl_snprintf( p, n, "\n%snext update   : " \
                   "%04d-%02d-%02d %02d:%02d:%02d", prefix,
                   crl->next_update.year, crl->next_update.mon,
                   crl->next_update.day,  crl->next_update.hour,
                   crl->next_update.min,  crl->next_update.sec );
    SAFE_SNPRINTF();

    entry = &crl->entry;

    ret = polarssl_snprintf( p, n, "\n%sRevoked certificates:",
                               prefix );
    SAFE_SNPRINTF();

    while( entry != NULL && entry->raw.len != 0 )
    {
        ret = polarssl_snprintf( p, n, "\n%sserial number: ",
                               prefix );
        SAFE_SNPRINTF();

        ret = x509_serial_gets( p, n, &entry->serial );
        SAFE_SNPRINTF();

        ret = polarssl_snprintf( p, n, " revocation date: " \
                   "%04d-%02d-%02d %02d:%02d:%02d",
                   entry->revocation_date.year, entry->revocation_date.mon,
                   entry->revocation_date.day,  entry->revocation_date.hour,
                   entry->revocation_date.min,  entry->revocation_date.sec );
        SAFE_SNPRINTF();

        entry = entry->next;
    }

    ret = polarssl_snprintf( p, n, "\n%ssigned using  : ", prefix );
    SAFE_SNPRINTF();

    ret = x509_sig_alg_gets( p, n, &crl->sig_oid1, crl->sig_pk, crl->sig_md,
                             crl->sig_opts );
    SAFE_SNPRINTF();

    ret = polarssl_snprintf( p, n, "\n" );
    SAFE_SNPRINTF();

    return( (int) ( size - n ) );
}
Ejemplo n.º 11
0
void debug_print_mpi( const ssl_context *ssl, int level,
                      const char *file, int line,
                      const char *text, const mpi *X )
{
    char str[512];
    int j, k, maxlen = sizeof( str ) - 1, zeros = 1;
    size_t i, n, idx = 0;

    /*if( ssl->f_dbg == NULL || X == NULL || level > debug_threshold )
        return;*/

    for( n = X->n - 1; n > 0; n-- )
        if( X->p[n] != 0 )
            break;

    for( j = ( sizeof(t_uint) << 3 ) - 1; j >= 0; j-- )
        if( ( ( X->p[n] >> j ) & 1 ) != 0 )
            break;

    if( debug_log_mode == POLARSSL_DEBUG_LOG_FULL )
        idx = polarssl_snprintf( str, maxlen, "%s(%04d): ", file, line );

    polarssl_snprintf( str + idx, maxlen - idx, "value of '%s' (%d bits) is:\n",
              text, (int) ( ( n * ( sizeof(t_uint) << 3 ) ) + j + 1 ) );

    str[maxlen] = '\0';
    //ssl->f_dbg( ssl->p_dbg, level, str );
    printf("%s", str);

    idx = 0;
    for( i = n + 1, j = 0; i > 0; i-- )
    {
        if( zeros && X->p[i - 1] == 0 )
            continue;

        for( k = sizeof( t_uint ) - 1; k >= 0; k-- )
        {
            if( zeros && ( ( X->p[i - 1] >> ( k << 3 ) ) & 0xFF ) == 0 )
                continue;
            else
                zeros = 0;

            if( j % 16 == 0 )
            {
                if( j > 0 )
                {
                    polarssl_snprintf( str + idx, maxlen - idx, "\n" );
                    //ssl->f_dbg( ssl->p_dbg, level, str );
                    printf("%s", str);
                    idx = 0;
                }

                if( debug_log_mode == POLARSSL_DEBUG_LOG_FULL )
                    idx = polarssl_snprintf( str, maxlen, "%s(%04d): ", file, line );
            }

            idx += polarssl_snprintf( str + idx, maxlen - idx, " %02x", (unsigned int)
                             ( X->p[i - 1] >> ( k << 3 ) ) & 0xFF );

            j++;
        }

    }
Ejemplo n.º 12
0
void polarssl_strerror( int ret, char *buf, size_t buflen )
{
    size_t len;
    int use_ret;

    if( buflen == 0 )
        return;

    memset( buf, 0x00, buflen );
    /* Reduce buflen to make sure MSVC _snprintf() ends with \0 as well */
    buflen -= 1;

    if( ret < 0 )
        ret = -ret;

    if( ret & 0xFF80 )
    {
        use_ret = ret & 0xFF80;

        // High level error codes
        //
        // BEGIN generated code
#if defined(POLARSSL_CIPHER_C)
        if( use_ret == -(POLARSSL_ERR_CIPHER_FEATURE_UNAVAILABLE) )
            polarssl_snprintf( buf, buflen, "CIPHER - The selected feature is not available" );
        if( use_ret == -(POLARSSL_ERR_CIPHER_BAD_INPUT_DATA) )
            polarssl_snprintf( buf, buflen, "CIPHER - Bad input parameters to function" );
        if( use_ret == -(POLARSSL_ERR_CIPHER_ALLOC_FAILED) )
            polarssl_snprintf( buf, buflen, "CIPHER - Failed to allocate memory" );
        if( use_ret == -(POLARSSL_ERR_CIPHER_INVALID_PADDING) )
            polarssl_snprintf( buf, buflen, "CIPHER - Input data contains invalid padding and is rejected" );
        if( use_ret == -(POLARSSL_ERR_CIPHER_FULL_BLOCK_EXPECTED) )
            polarssl_snprintf( buf, buflen, "CIPHER - Decryption of block requires a full block" );
        if( use_ret == -(POLARSSL_ERR_CIPHER_AUTH_FAILED) )
            polarssl_snprintf( buf, buflen, "CIPHER - Authentication failed (for AEAD modes)" );
#endif /* POLARSSL_CIPHER_C */

#if defined(POLARSSL_DHM_C)
        if( use_ret == -(POLARSSL_ERR_DHM_BAD_INPUT_DATA) )
            polarssl_snprintf( buf, buflen, "DHM - Bad input parameters to function" );
        if( use_ret == -(POLARSSL_ERR_DHM_READ_PARAMS_FAILED) )
            polarssl_snprintf( buf, buflen, "DHM - Reading of the DHM parameters failed" );
        if( use_ret == -(POLARSSL_ERR_DHM_MAKE_PARAMS_FAILED) )
            polarssl_snprintf( buf, buflen, "DHM - Making of the DHM parameters failed" );
        if( use_ret == -(POLARSSL_ERR_DHM_READ_PUBLIC_FAILED) )
            polarssl_snprintf( buf, buflen, "DHM - Reading of the public values failed" );
        if( use_ret == -(POLARSSL_ERR_DHM_MAKE_PUBLIC_FAILED) )
            polarssl_snprintf( buf, buflen, "DHM - Making of the public value failed" );
        if( use_ret == -(POLARSSL_ERR_DHM_CALC_SECRET_FAILED) )
            polarssl_snprintf( buf, buflen, "DHM - Calculation of the DHM secret failed" );
        if( use_ret == -(POLARSSL_ERR_DHM_INVALID_FORMAT) )
            polarssl_snprintf( buf, buflen, "DHM - The ASN.1 data is not formatted correctly" );
        if( use_ret == -(POLARSSL_ERR_DHM_MALLOC_FAILED) )
            polarssl_snprintf( buf, buflen, "DHM - Allocation of memory failed" );
        if( use_ret == -(POLARSSL_ERR_DHM_FILE_IO_ERROR) )
            polarssl_snprintf( buf, buflen, "DHM - Read/write of file failed" );
#endif /* POLARSSL_DHM_C */

#if defined(POLARSSL_ECP_C)
        if( use_ret == -(POLARSSL_ERR_ECP_BAD_INPUT_DATA) )
            polarssl_snprintf( buf, buflen, "ECP - Bad input parameters to function" );
        if( use_ret == -(POLARSSL_ERR_ECP_BUFFER_TOO_SMALL) )
            polarssl_snprintf( buf, buflen, "ECP - The buffer is too small to write to" );
        if( use_ret == -(POLARSSL_ERR_ECP_FEATURE_UNAVAILABLE) )
            polarssl_snprintf( buf, buflen, "ECP - Requested curve not available" );
        if( use_ret == -(POLARSSL_ERR_ECP_VERIFY_FAILED) )
            polarssl_snprintf( buf, buflen, "ECP - The signature is not valid" );
        if( use_ret == -(POLARSSL_ERR_ECP_MALLOC_FAILED) )
            polarssl_snprintf( buf, buflen, "ECP - Memory allocation failed" );
        if( use_ret == -(POLARSSL_ERR_ECP_RANDOM_FAILED) )
            polarssl_snprintf( buf, buflen, "ECP - Generation of random value, such as (ephemeral) key, failed" );
        if( use_ret == -(POLARSSL_ERR_ECP_INVALID_KEY) )
            polarssl_snprintf( buf, buflen, "ECP - Invalid private or public key" );
        if( use_ret == -(POLARSSL_ERR_ECP_SIG_LEN_MISMATCH) )
            polarssl_snprintf( buf, buflen, "ECP - Signature is valid but shorter than the user-supplied length" );
#endif /* POLARSSL_ECP_C */

#if defined(POLARSSL_MD_C)
        if( use_ret == -(POLARSSL_ERR_MD_FEATURE_UNAVAILABLE) )
            polarssl_snprintf( buf, buflen, "MD - The selected feature is not available" );
        if( use_ret == -(POLARSSL_ERR_MD_BAD_INPUT_DATA) )
            polarssl_snprintf( buf, buflen, "MD - Bad input parameters to function" );
        if( use_ret == -(POLARSSL_ERR_MD_ALLOC_FAILED) )
            polarssl_snprintf( buf, buflen, "MD - Failed to allocate memory" );
        if( use_ret == -(POLARSSL_ERR_MD_FILE_IO_ERROR) )
            polarssl_snprintf( buf, buflen, "MD - Opening or reading of file failed" );
#endif /* POLARSSL_MD_C */

#if defined(POLARSSL_PEM_PARSE_C) || defined(POLARSSL_PEM_WRITE_C)
        if( use_ret == -(POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT) )
            polarssl_snprintf( buf, buflen, "PEM - No PEM header or footer found" );
        if( use_ret == -(POLARSSL_ERR_PEM_INVALID_DATA) )
            polarssl_snprintf( buf, buflen, "PEM - PEM string is not as expected" );
        if( use_ret == -(POLARSSL_ERR_PEM_MALLOC_FAILED) )
            polarssl_snprintf( buf, buflen, "PEM - Failed to allocate memory" );
        if( use_ret == -(POLARSSL_ERR_PEM_INVALID_ENC_IV) )
            polarssl_snprintf( buf, buflen, "PEM - RSA IV is not in hex-format" );
        if( use_ret == -(POLARSSL_ERR_PEM_UNKNOWN_ENC_ALG) )
            polarssl_snprintf( buf, buflen, "PEM - Unsupported key encryption algorithm" );
        if( use_ret == -(POLARSSL_ERR_PEM_PASSWORD_REQUIRED) )
            polarssl_snprintf( buf, buflen, "PEM - Private key password can't be empty" );
        if( use_ret == -(POLARSSL_ERR_PEM_PASSWORD_MISMATCH) )
            polarssl_snprintf( buf, buflen, "PEM - Given private key password does not allow for correct decryption" );
        if( use_ret == -(POLARSSL_ERR_PEM_FEATURE_UNAVAILABLE) )
            polarssl_snprintf( buf, buflen, "PEM - Unavailable feature, e.g. hashing/encryption combination" );
        if( use_ret == -(POLARSSL_ERR_PEM_BAD_INPUT_DATA) )
            polarssl_snprintf( buf, buflen, "PEM - Bad input parameters to function" );
#endif /* POLARSSL_PEM_PARSE_C || POLARSSL_PEM_WRITE_C */

#if defined(POLARSSL_PK_C)
        if( use_ret == -(POLARSSL_ERR_PK_MALLOC_FAILED) )
            polarssl_snprintf( buf, buflen, "PK - Memory alloation failed" );
        if( use_ret == -(POLARSSL_ERR_PK_TYPE_MISMATCH) )
            polarssl_snprintf( buf, buflen, "PK - Type mismatch, eg attempt to encrypt with an ECDSA key" );
        if( use_ret == -(POLARSSL_ERR_PK_BAD_INPUT_DATA) )
            polarssl_snprintf( buf, buflen, "PK - Bad input parameters to function" );
        if( use_ret == -(POLARSSL_ERR_PK_FILE_IO_ERROR) )
            polarssl_snprintf( buf, buflen, "PK - Read/write of file failed" );
        if( use_ret == -(POLARSSL_ERR_PK_KEY_INVALID_VERSION) )
            polarssl_snprintf( buf, buflen, "PK - Unsupported key version" );
        if( use_ret == -(POLARSSL_ERR_PK_KEY_INVALID_FORMAT) )
            polarssl_snprintf( buf, buflen, "PK - Invalid key tag or value" );
        if( use_ret == -(POLARSSL_ERR_PK_UNKNOWN_PK_ALG) )
            polarssl_snprintf( buf, buflen, "PK - Key algorithm is unsupported (only RSA and EC are supported)" );
        if( use_ret == -(POLARSSL_ERR_PK_PASSWORD_REQUIRED) )
            polarssl_snprintf( buf, buflen, "PK - Private key password can't be empty" );
        if( use_ret == -(POLARSSL_ERR_PK_PASSWORD_MISMATCH) )
            polarssl_snprintf( buf, buflen, "PK - Given private key password does not allow for correct decryption" );
        if( use_ret == -(POLARSSL_ERR_PK_INVALID_PUBKEY) )
            polarssl_snprintf( buf, buflen, "PK - The pubkey tag or value is invalid (only RSA and EC are supported)" );
        if( use_ret == -(POLARSSL_ERR_PK_INVALID_ALG) )
            polarssl_snprintf( buf, buflen, "PK - The algorithm tag or value is invalid" );
        if( use_ret == -(POLARSSL_ERR_PK_UNKNOWN_NAMED_CURVE) )
            polarssl_snprintf( buf, buflen, "PK - Elliptic curve is unsupported (only NIST curves are supported)" );
        if( use_ret == -(POLARSSL_ERR_PK_FEATURE_UNAVAILABLE) )
            polarssl_snprintf( buf, buflen, "PK - Unavailable feature, e.g. RSA disabled for RSA key" );
        if( use_ret == -(POLARSSL_ERR_PK_SIG_LEN_MISMATCH) )
            polarssl_snprintf( buf, buflen, "PK - The signature is valid but its length is less than expected" );
#endif /* POLARSSL_PK_C */

#if defined(POLARSSL_PKCS12_C)
        if( use_ret == -(POLARSSL_ERR_PKCS12_BAD_INPUT_DATA) )
            polarssl_snprintf( buf, buflen, "PKCS12 - Bad input parameters to function" );
        if( use_ret == -(POLARSSL_ERR_PKCS12_FEATURE_UNAVAILABLE) )
            polarssl_snprintf( buf, buflen, "PKCS12 - Feature not available, e.g. unsupported encryption scheme" );
        if( use_ret == -(POLARSSL_ERR_PKCS12_PBE_INVALID_FORMAT) )
            polarssl_snprintf( buf, buflen, "PKCS12 - PBE ASN.1 data not as expected" );
        if( use_ret == -(POLARSSL_ERR_PKCS12_PASSWORD_MISMATCH) )
            polarssl_snprintf( buf, buflen, "PKCS12 - Given private key password does not allow for correct decryption" );
#endif /* POLARSSL_PKCS12_C */

#if defined(POLARSSL_PKCS5_C)
        if( use_ret == -(POLARSSL_ERR_PKCS5_BAD_INPUT_DATA) )
            polarssl_snprintf( buf, buflen, "PKCS5 - Bad input parameters to function" );
        if( use_ret == -(POLARSSL_ERR_PKCS5_INVALID_FORMAT) )
            polarssl_snprintf( buf, buflen, "PKCS5 - Unexpected ASN.1 data" );
        if( use_ret == -(POLARSSL_ERR_PKCS5_FEATURE_UNAVAILABLE) )
            polarssl_snprintf( buf, buflen, "PKCS5 - Requested encryption or digest alg not available" );
        if( use_ret == -(POLARSSL_ERR_PKCS5_PASSWORD_MISMATCH) )
            polarssl_snprintf( buf, buflen, "PKCS5 - Given private key password does not allow for correct decryption" );
#endif /* POLARSSL_PKCS5_C */

#if defined(POLARSSL_RSA_C)
        if( use_ret == -(POLARSSL_ERR_RSA_BAD_INPUT_DATA) )
            polarssl_snprintf( buf, buflen, "RSA - Bad input parameters to function" );
        if( use_ret == -(POLARSSL_ERR_RSA_INVALID_PADDING) )
            polarssl_snprintf( buf, buflen, "RSA - Input data contains invalid padding and is rejected" );
        if( use_ret == -(POLARSSL_ERR_RSA_KEY_GEN_FAILED) )
            polarssl_snprintf( buf, buflen, "RSA - Something failed during generation of a key" );
        if( use_ret == -(POLARSSL_ERR_RSA_KEY_CHECK_FAILED) )
            polarssl_snprintf( buf, buflen, "RSA - Key failed to pass the library's validity check" );
        if( use_ret == -(POLARSSL_ERR_RSA_PUBLIC_FAILED) )
            polarssl_snprintf( buf, buflen, "RSA - The public key operation failed" );
        if( use_ret == -(POLARSSL_ERR_RSA_PRIVATE_FAILED) )
            polarssl_snprintf( buf, buflen, "RSA - The private key operation failed" );
        if( use_ret == -(POLARSSL_ERR_RSA_VERIFY_FAILED) )
            polarssl_snprintf( buf, buflen, "RSA - The PKCS#1 verification failed" );
        if( use_ret == -(POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE) )
            polarssl_snprintf( buf, buflen, "RSA - The output buffer for decryption is not large enough" );
        if( use_ret == -(POLARSSL_ERR_RSA_RNG_FAILED) )
            polarssl_snprintf( buf, buflen, "RSA - The random generator failed to generate non-zeros" );
#endif /* POLARSSL_RSA_C */

#if defined(POLARSSL_SSL_TLS_C)
        if( use_ret == -(POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE) )
            polarssl_snprintf( buf, buflen, "SSL - The requested feature is not available" );
        if( use_ret == -(POLARSSL_ERR_SSL_BAD_INPUT_DATA) )
            polarssl_snprintf( buf, buflen, "SSL - Bad input parameters to function" );
        if( use_ret == -(POLARSSL_ERR_SSL_INVALID_MAC) )
            polarssl_snprintf( buf, buflen, "SSL - Verification of the message MAC failed" );
        if( use_ret == -(POLARSSL_ERR_SSL_INVALID_RECORD) )
            polarssl_snprintf( buf, buflen, "SSL - An invalid SSL record was received" );
        if( use_ret == -(POLARSSL_ERR_SSL_CONN_EOF) )
            polarssl_snprintf( buf, buflen, "SSL - The connection indicated an EOF" );
        if( use_ret == -(POLARSSL_ERR_SSL_UNKNOWN_CIPHER) )
            polarssl_snprintf( buf, buflen, "SSL - An unknown cipher was received" );
        if( use_ret == -(POLARSSL_ERR_SSL_NO_CIPHER_CHOSEN) )
            polarssl_snprintf( buf, buflen, "SSL - The server has no ciphersuites in common with the client" );
        if( use_ret == -(POLARSSL_ERR_SSL_NO_RNG) )
            polarssl_snprintf( buf, buflen, "SSL - No RNG was provided to the SSL module" );
        if( use_ret == -(POLARSSL_ERR_SSL_NO_CLIENT_CERTIFICATE) )
            polarssl_snprintf( buf, buflen, "SSL - No client certification received from the client, but required by the authentication mode" );
        if( use_ret == -(POLARSSL_ERR_SSL_CERTIFICATE_TOO_LARGE) )
            polarssl_snprintf( buf, buflen, "SSL - Our own certificate(s) is/are too large to send in an SSL message" );
        if( use_ret == -(POLARSSL_ERR_SSL_CERTIFICATE_REQUIRED) )
            polarssl_snprintf( buf, buflen, "SSL - The own certificate is not set, but needed by the server" );
        if( use_ret == -(POLARSSL_ERR_SSL_PRIVATE_KEY_REQUIRED) )
            polarssl_snprintf( buf, buflen, "SSL - The own private key or pre-shared key is not set, but needed" );
        if( use_ret == -(POLARSSL_ERR_SSL_CA_CHAIN_REQUIRED) )
            polarssl_snprintf( buf, buflen, "SSL - No CA Chain is set, but required to operate" );
        if( use_ret == -(POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE) )
            polarssl_snprintf( buf, buflen, "SSL - An unexpected message was received from our peer" );
        if( use_ret == -(POLARSSL_ERR_SSL_FATAL_ALERT_MESSAGE) )
        {
            polarssl_snprintf( buf, buflen, "SSL - A fatal alert message was received from our peer" );
            return;
        }
        if( use_ret == -(POLARSSL_ERR_SSL_PEER_VERIFY_FAILED) )
            polarssl_snprintf( buf, buflen, "SSL - Verification of our peer failed" );
        if( use_ret == -(POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY) )
            polarssl_snprintf( buf, buflen, "SSL - The peer notified us that the connection is going to be closed" );
        if( use_ret == -(POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO) )
            polarssl_snprintf( buf, buflen, "SSL - Processing of the ClientHello handshake message failed" );
        if( use_ret == -(POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO) )
            polarssl_snprintf( buf, buflen, "SSL - Processing of the ServerHello handshake message failed" );
        if( use_ret == -(POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE) )
            polarssl_snprintf( buf, buflen, "SSL - Processing of the Certificate handshake message failed" );
        if( use_ret == -(POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST) )
            polarssl_snprintf( buf, buflen, "SSL - Processing of the CertificateRequest handshake message failed" );
        if( use_ret == -(POLARSSL_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE) )
            polarssl_snprintf( buf, buflen, "SSL - Processing of the ServerKeyExchange handshake message failed" );
        if( use_ret == -(POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO_DONE) )
            polarssl_snprintf( buf, buflen, "SSL - Processing of the ServerHelloDone handshake message failed" );
        if( use_ret == -(POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE) )
            polarssl_snprintf( buf, buflen, "SSL - Processing of the ClientKeyExchange handshake message failed" );
        if( use_ret == -(POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP) )
            polarssl_snprintf( buf, buflen, "SSL - Processing of the ClientKeyExchange handshake message failed in DHM / ECDH Read Public" );
        if( use_ret == -(POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS) )
            polarssl_snprintf( buf, buflen, "SSL - Processing of the ClientKeyExchange handshake message failed in DHM / ECDH Calculate Secret" );
        if( use_ret == -(POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY) )
            polarssl_snprintf( buf, buflen, "SSL - Processing of the CertificateVerify handshake message failed" );
        if( use_ret == -(POLARSSL_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC) )
            polarssl_snprintf( buf, buflen, "SSL - Processing of the ChangeCipherSpec handshake message failed" );
        if( use_ret == -(POLARSSL_ERR_SSL_BAD_HS_FINISHED) )
            polarssl_snprintf( buf, buflen, "SSL - Processing of the Finished handshake message failed" );
        if( use_ret == -(POLARSSL_ERR_SSL_MALLOC_FAILED) )
            polarssl_snprintf( buf, buflen, "SSL - Memory allocation failed" );
        if( use_ret == -(POLARSSL_ERR_SSL_HW_ACCEL_FAILED) )
            polarssl_snprintf( buf, buflen, "SSL - Hardware acceleration function returned with error" );
        if( use_ret == -(POLARSSL_ERR_SSL_HW_ACCEL_FALLTHROUGH) )
            polarssl_snprintf( buf, buflen, "SSL - Hardware acceleration function skipped / left alone data" );
        if( use_ret == -(POLARSSL_ERR_SSL_COMPRESSION_FAILED) )
            polarssl_snprintf( buf, buflen, "SSL - Processing of the compression / decompression failed" );
        if( use_ret == -(POLARSSL_ERR_SSL_BAD_HS_PROTOCOL_VERSION) )
            polarssl_snprintf( buf, buflen, "SSL - Handshake protocol not within min/max boundaries" );
        if( use_ret == -(POLARSSL_ERR_SSL_BAD_HS_NEW_SESSION_TICKET) )
            polarssl_snprintf( buf, buflen, "SSL - Processing of the NewSessionTicket handshake message failed" );
        if( use_ret == -(POLARSSL_ERR_SSL_SESSION_TICKET_EXPIRED) )
            polarssl_snprintf( buf, buflen, "SSL - Session ticket has expired" );
        if( use_ret == -(POLARSSL_ERR_SSL_PK_TYPE_MISMATCH) )
            polarssl_snprintf( buf, buflen, "SSL - Public key type mismatch (eg, asked for RSA key exchange and presented EC key)" );
        if( use_ret == -(POLARSSL_ERR_SSL_UNKNOWN_IDENTITY) )
            polarssl_snprintf( buf, buflen, "SSL - Unknown identity received (eg, PSK identity)" );
        if( use_ret == -(POLARSSL_ERR_SSL_INTERNAL_ERROR) )
            polarssl_snprintf( buf, buflen, "SSL - Internal error (eg, unexpected failure in lower-level module)" );
        if( use_ret == -(POLARSSL_ERR_SSL_COUNTER_WRAPPING) )
            polarssl_snprintf( buf, buflen, "SSL - A counter would wrap (eg, too many messages exchanged)" );
        if( use_ret == -(POLARSSL_ERR_SSL_WAITING_SERVER_HELLO_RENEGO) )
            polarssl_snprintf( buf, buflen, "SSL - Unexpected message at ServerHello in renegotiation" );
        if( use_ret == -(POLARSSL_ERR_SSL_NO_USABLE_CIPHERSUITE) )
            polarssl_snprintf( buf, buflen, "SSL - None of the common ciphersuites is usable (eg, no suitable certificate, see debug messages)" );
#endif /* POLARSSL_SSL_TLS_C */

#if defined(POLARSSL_X509_USE_C) || defined(POLARSSL_X509_CREATE_C)
        if( use_ret == -(POLARSSL_ERR_X509_FEATURE_UNAVAILABLE) )
            polarssl_snprintf( buf, buflen, "X509 - Unavailable feature, e.g. RSA hashing/encryption combination" );
        if( use_ret == -(POLARSSL_ERR_X509_UNKNOWN_OID) )
            polarssl_snprintf( buf, buflen, "X509 - Requested OID is unknown" );
        if( use_ret == -(POLARSSL_ERR_X509_INVALID_FORMAT) )
            polarssl_snprintf( buf, buflen, "X509 - The CRT/CRL/CSR format is invalid, e.g. different type expected" );
        if( use_ret == -(POLARSSL_ERR_X509_INVALID_VERSION) )
            polarssl_snprintf( buf, buflen, "X509 - The CRT/CRL/CSR version element is invalid" );
        if( use_ret == -(POLARSSL_ERR_X509_INVALID_SERIAL) )
            polarssl_snprintf( buf, buflen, "X509 - The serial tag or value is invalid" );
        if( use_ret == -(POLARSSL_ERR_X509_INVALID_ALG) )
            polarssl_snprintf( buf, buflen, "X509 - The algorithm tag or value is invalid" );
        if( use_ret == -(POLARSSL_ERR_X509_INVALID_NAME) )
            polarssl_snprintf( buf, buflen, "X509 - The name tag or value is invalid" );
        if( use_ret == -(POLARSSL_ERR_X509_INVALID_DATE) )
            polarssl_snprintf( buf, buflen, "X509 - The date tag or value is invalid" );
        if( use_ret == -(POLARSSL_ERR_X509_INVALID_SIGNATURE) )
            polarssl_snprintf( buf, buflen, "X509 - The signature tag or value invalid" );
        if( use_ret == -(POLARSSL_ERR_X509_INVALID_EXTENSIONS) )
            polarssl_snprintf( buf, buflen, "X509 - The extension tag or value is invalid" );
        if( use_ret == -(POLARSSL_ERR_X509_UNKNOWN_VERSION) )
            polarssl_snprintf( buf, buflen, "X509 - CRT/CRL/CSR has an unsupported version number" );
        if( use_ret == -(POLARSSL_ERR_X509_UNKNOWN_SIG_ALG) )
            polarssl_snprintf( buf, buflen, "X509 - Signature algorithm (oid) is unsupported" );
        if( use_ret == -(POLARSSL_ERR_X509_SIG_MISMATCH) )
            polarssl_snprintf( buf, buflen, "X509 - Signature algorithms do not match. (see \\c ::x509_crt sig_oid)" );
        if( use_ret == -(POLARSSL_ERR_X509_CERT_VERIFY_FAILED) )
            polarssl_snprintf( buf, buflen, "X509 - Certificate verification failed, e.g. CRL, CA or signature check failed" );
        if( use_ret == -(POLARSSL_ERR_X509_CERT_UNKNOWN_FORMAT) )
            polarssl_snprintf( buf, buflen, "X509 - Format not recognized as DER or PEM" );
        if( use_ret == -(POLARSSL_ERR_X509_BAD_INPUT_DATA) )
            polarssl_snprintf( buf, buflen, "X509 - Input invalid" );
        if( use_ret == -(POLARSSL_ERR_X509_MALLOC_FAILED) )
            polarssl_snprintf( buf, buflen, "X509 - Allocation of memory failed" );
        if( use_ret == -(POLARSSL_ERR_X509_FILE_IO_ERROR) )
            polarssl_snprintf( buf, buflen, "X509 - Read/write of file failed" );
#endif /* POLARSSL_X509_USE,X509_CREATE_C */
        // END generated code

        if( strlen( buf ) == 0 )
            polarssl_snprintf( buf, buflen, "UNKNOWN ERROR CODE (%04X)", use_ret );
    }

    use_ret = ret & ~0xFF80;

    if( use_ret == 0 )
        return;

    // If high level code is present, make a concatenation between both
    // error strings.
    //
    len = strlen( buf );

    if( len > 0 )
    {
        if( buflen - len < 5 )
            return;

        polarssl_snprintf( buf + len, buflen - len, " : " );

        buf += len + 3;
        buflen -= len + 3;
    }

    // Low level error codes
    //
    // BEGIN generated code
#if defined(POLARSSL_AES_C)
    if( use_ret == -(POLARSSL_ERR_AES_INVALID_KEY_LENGTH) )
        polarssl_snprintf( buf, buflen, "AES - Invalid key length" );
    if( use_ret == -(POLARSSL_ERR_AES_INVALID_INPUT_LENGTH) )
        polarssl_snprintf( buf, buflen, "AES - Invalid data input length" );
#endif /* POLARSSL_AES_C */

#if defined(POLARSSL_ASN1_PARSE_C)
    if( use_ret == -(POLARSSL_ERR_ASN1_OUT_OF_DATA) )
        polarssl_snprintf( buf, buflen, "ASN1 - Out of data when parsing an ASN1 data structure" );
    if( use_ret == -(POLARSSL_ERR_ASN1_UNEXPECTED_TAG) )
        polarssl_snprintf( buf, buflen, "ASN1 - ASN1 tag was of an unexpected value" );
    if( use_ret == -(POLARSSL_ERR_ASN1_INVALID_LENGTH) )
        polarssl_snprintf( buf, buflen, "ASN1 - Error when trying to determine the length or invalid length" );
    if( use_ret == -(POLARSSL_ERR_ASN1_LENGTH_MISMATCH) )
        polarssl_snprintf( buf, buflen, "ASN1 - Actual length differs from expected length" );
    if( use_ret == -(POLARSSL_ERR_ASN1_INVALID_DATA) )
        polarssl_snprintf( buf, buflen, "ASN1 - Data is invalid. (not used)" );
    if( use_ret == -(POLARSSL_ERR_ASN1_MALLOC_FAILED) )
        polarssl_snprintf( buf, buflen, "ASN1 - Memory allocation failed" );
    if( use_ret == -(POLARSSL_ERR_ASN1_BUF_TOO_SMALL) )
        polarssl_snprintf( buf, buflen, "ASN1 - Buffer too small when writing ASN.1 data structure" );
#endif /* POLARSSL_ASN1_PARSE_C */

#if defined(POLARSSL_BASE64_C)
    if( use_ret == -(POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL) )
        polarssl_snprintf( buf, buflen, "BASE64 - Output buffer too small" );
    if( use_ret == -(POLARSSL_ERR_BASE64_INVALID_CHARACTER) )
        polarssl_snprintf( buf, buflen, "BASE64 - Invalid character in input" );
#endif /* POLARSSL_BASE64_C */

#if defined(POLARSSL_BIGNUM_C)
    if( use_ret == -(POLARSSL_ERR_MPI_FILE_IO_ERROR) )
        polarssl_snprintf( buf, buflen, "BIGNUM - An error occurred while reading from or writing to a file" );
    if( use_ret == -(POLARSSL_ERR_MPI_BAD_INPUT_DATA) )
        polarssl_snprintf( buf, buflen, "BIGNUM - Bad input parameters to function" );
    if( use_ret == -(POLARSSL_ERR_MPI_INVALID_CHARACTER) )
        polarssl_snprintf( buf, buflen, "BIGNUM - There is an invalid character in the digit string" );
    if( use_ret == -(POLARSSL_ERR_MPI_BUFFER_TOO_SMALL) )
        polarssl_snprintf( buf, buflen, "BIGNUM - The buffer is too small to write to" );
    if( use_ret == -(POLARSSL_ERR_MPI_NEGATIVE_VALUE) )
        polarssl_snprintf( buf, buflen, "BIGNUM - The input arguments are negative or result in illegal output" );
    if( use_ret == -(POLARSSL_ERR_MPI_DIVISION_BY_ZERO) )
        polarssl_snprintf( buf, buflen, "BIGNUM - The input argument for division is zero, which is not allowed" );
    if( use_ret == -(POLARSSL_ERR_MPI_NOT_ACCEPTABLE) )
        polarssl_snprintf( buf, buflen, "BIGNUM - The input arguments are not acceptable" );
    if( use_ret == -(POLARSSL_ERR_MPI_MALLOC_FAILED) )
        polarssl_snprintf( buf, buflen, "BIGNUM - Memory allocation failed" );
#endif /* POLARSSL_BIGNUM_C */

#if defined(POLARSSL_BLOWFISH_C)
    if( use_ret == -(POLARSSL_ERR_BLOWFISH_INVALID_KEY_LENGTH) )
        polarssl_snprintf( buf, buflen, "BLOWFISH - Invalid key length" );
    if( use_ret == -(POLARSSL_ERR_BLOWFISH_INVALID_INPUT_LENGTH) )
        polarssl_snprintf( buf, buflen, "BLOWFISH - Invalid data input length" );
#endif /* POLARSSL_BLOWFISH_C */

#if defined(POLARSSL_CAMELLIA_C)
    if( use_ret == -(POLARSSL_ERR_CAMELLIA_INVALID_KEY_LENGTH) )
        polarssl_snprintf( buf, buflen, "CAMELLIA - Invalid key length" );
    if( use_ret == -(POLARSSL_ERR_CAMELLIA_INVALID_INPUT_LENGTH) )
        polarssl_snprintf( buf, buflen, "CAMELLIA - Invalid data input length" );
#endif /* POLARSSL_CAMELLIA_C */

#if defined(POLARSSL_CCM_C)
    if( use_ret == -(POLARSSL_ERR_CCM_BAD_INPUT) )
        polarssl_snprintf( buf, buflen, "CCM - Bad input parameters to function" );
    if( use_ret == -(POLARSSL_ERR_CCM_AUTH_FAILED) )
        polarssl_snprintf( buf, buflen, "CCM - Authenticated decryption failed" );
#endif /* POLARSSL_CCM_C */

#if defined(POLARSSL_CTR_DRBG_C)
    if( use_ret == -(POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED) )
        polarssl_snprintf( buf, buflen, "CTR_DRBG - The entropy source failed" );
    if( use_ret == -(POLARSSL_ERR_CTR_DRBG_REQUEST_TOO_BIG) )
        polarssl_snprintf( buf, buflen, "CTR_DRBG - Too many random requested in single call" );
    if( use_ret == -(POLARSSL_ERR_CTR_DRBG_INPUT_TOO_BIG) )
        polarssl_snprintf( buf, buflen, "CTR_DRBG - Input too large (Entropy + additional)" );
    if( use_ret == -(POLARSSL_ERR_CTR_DRBG_FILE_IO_ERROR) )
        polarssl_snprintf( buf, buflen, "CTR_DRBG - Read/write error in file" );
#endif /* POLARSSL_CTR_DRBG_C */

#if defined(POLARSSL_DES_C)
    if( use_ret == -(POLARSSL_ERR_DES_INVALID_INPUT_LENGTH) )
        polarssl_snprintf( buf, buflen, "DES - The data input has an invalid length" );
#endif /* POLARSSL_DES_C */

#if defined(POLARSSL_ENTROPY_C)
    if( use_ret == -(POLARSSL_ERR_ENTROPY_SOURCE_FAILED) )
        polarssl_snprintf( buf, buflen, "ENTROPY - Critical entropy source failure" );
    if( use_ret == -(POLARSSL_ERR_ENTROPY_MAX_SOURCES) )
        polarssl_snprintf( buf, buflen, "ENTROPY - No more sources can be added" );
    if( use_ret == -(POLARSSL_ERR_ENTROPY_NO_SOURCES_DEFINED) )
        polarssl_snprintf( buf, buflen, "ENTROPY - No sources have been added to poll" );
    if( use_ret == -(POLARSSL_ERR_ENTROPY_FILE_IO_ERROR) )
        polarssl_snprintf( buf, buflen, "ENTROPY - Read/write error in file" );
#endif /* POLARSSL_ENTROPY_C */

#if defined(POLARSSL_GCM_C)
    if( use_ret == -(POLARSSL_ERR_GCM_AUTH_FAILED) )
        polarssl_snprintf( buf, buflen, "GCM - Authenticated decryption failed" );
    if( use_ret == -(POLARSSL_ERR_GCM_BAD_INPUT) )
        polarssl_snprintf( buf, buflen, "GCM - Bad input parameters to function" );
#endif /* POLARSSL_GCM_C */

#if defined(POLARSSL_HMAC_DRBG_C)
    if( use_ret == -(POLARSSL_ERR_HMAC_DRBG_REQUEST_TOO_BIG) )
        polarssl_snprintf( buf, buflen, "HMAC_DRBG - Too many random requested in single call" );
    if( use_ret == -(POLARSSL_ERR_HMAC_DRBG_INPUT_TOO_BIG) )
        polarssl_snprintf( buf, buflen, "HMAC_DRBG - Input too large (Entropy + additional)" );
    if( use_ret == -(POLARSSL_ERR_HMAC_DRBG_FILE_IO_ERROR) )
        polarssl_snprintf( buf, buflen, "HMAC_DRBG - Read/write error in file" );
    if( use_ret == -(POLARSSL_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED) )
        polarssl_snprintf( buf, buflen, "HMAC_DRBG - The entropy source failed" );
#endif /* POLARSSL_HMAC_DRBG_C */

#if defined(POLARSSL_MD2_C)
    if( use_ret == -(POLARSSL_ERR_MD2_FILE_IO_ERROR) )
        polarssl_snprintf( buf, buflen, "MD2 - Read/write error in file" );
#endif /* POLARSSL_MD2_C */

#if defined(POLARSSL_MD4_C)
    if( use_ret == -(POLARSSL_ERR_MD4_FILE_IO_ERROR) )
        polarssl_snprintf( buf, buflen, "MD4 - Read/write error in file" );
#endif /* POLARSSL_MD4_C */

#if defined(POLARSSL_MD5_C)
    if( use_ret == -(POLARSSL_ERR_MD5_FILE_IO_ERROR) )
        polarssl_snprintf( buf, buflen, "MD5 - Read/write error in file" );
#endif /* POLARSSL_MD5_C */

#if defined(POLARSSL_NET_C)
    if( use_ret == -(POLARSSL_ERR_NET_UNKNOWN_HOST) )
        polarssl_snprintf( buf, buflen, "NET - Failed to get an IP address for the given hostname" );
    if( use_ret == -(POLARSSL_ERR_NET_SOCKET_FAILED) )
        polarssl_snprintf( buf, buflen, "NET - Failed to open a socket" );
    if( use_ret == -(POLARSSL_ERR_NET_CONNECT_FAILED) )
        polarssl_snprintf( buf, buflen, "NET - The connection to the given server / port failed" );
    if( use_ret == -(POLARSSL_ERR_NET_BIND_FAILED) )
        polarssl_snprintf( buf, buflen, "NET - Binding of the socket failed" );
    if( use_ret == -(POLARSSL_ERR_NET_LISTEN_FAILED) )
        polarssl_snprintf( buf, buflen, "NET - Could not listen on the socket" );
    if( use_ret == -(POLARSSL_ERR_NET_ACCEPT_FAILED) )
        polarssl_snprintf( buf, buflen, "NET - Could not accept the incoming connection" );
    if( use_ret == -(POLARSSL_ERR_NET_RECV_FAILED) )
        polarssl_snprintf( buf, buflen, "NET - Reading information from the socket failed" );
    if( use_ret == -(POLARSSL_ERR_NET_SEND_FAILED) )
        polarssl_snprintf( buf, buflen, "NET - Sending information through the socket failed" );
    if( use_ret == -(POLARSSL_ERR_NET_CONN_RESET) )
        polarssl_snprintf( buf, buflen, "NET - Connection was reset by peer" );
    if( use_ret == -(POLARSSL_ERR_NET_WANT_READ) )
        polarssl_snprintf( buf, buflen, "NET - Connection requires a read call" );
    if( use_ret == -(POLARSSL_ERR_NET_WANT_WRITE) )
        polarssl_snprintf( buf, buflen, "NET - Connection requires a write call" );
#endif /* POLARSSL_NET_C */

#if defined(POLARSSL_OID_C)
    if( use_ret == -(POLARSSL_ERR_OID_NOT_FOUND) )
        polarssl_snprintf( buf, buflen, "OID - OID is not found" );
    if( use_ret == -(POLARSSL_ERR_OID_BUF_TOO_SMALL) )
        polarssl_snprintf( buf, buflen, "OID - output buffer is too small" );
#endif /* POLARSSL_OID_C */

#if defined(POLARSSL_PADLOCK_C)
    if( use_ret == -(POLARSSL_ERR_PADLOCK_DATA_MISALIGNED) )
        polarssl_snprintf( buf, buflen, "PADLOCK - Input data should be aligned" );
#endif /* POLARSSL_PADLOCK_C */

#if defined(POLARSSL_PBKDF2_C)
    if( use_ret == -(POLARSSL_ERR_PBKDF2_BAD_INPUT_DATA) )
        polarssl_snprintf( buf, buflen, "PBKDF2 - Bad input parameters to function" );
#endif /* POLARSSL_PBKDF2_C */

#if defined(POLARSSL_RIPEMD160_C)
    if( use_ret == -(POLARSSL_ERR_RIPEMD160_FILE_IO_ERROR) )
        polarssl_snprintf( buf, buflen, "RIPEMD160 - Read/write error in file" );
#endif /* POLARSSL_RIPEMD160_C */

#if defined(POLARSSL_SHA1_C)
    if( use_ret == -(POLARSSL_ERR_SHA1_FILE_IO_ERROR) )
        polarssl_snprintf( buf, buflen, "SHA1 - Read/write error in file" );
#endif /* POLARSSL_SHA1_C */

#if defined(POLARSSL_SHA256_C)
    if( use_ret == -(POLARSSL_ERR_SHA256_FILE_IO_ERROR) )
        polarssl_snprintf( buf, buflen, "SHA256 - Read/write error in file" );
#endif /* POLARSSL_SHA256_C */

#if defined(POLARSSL_SHA512_C)
    if( use_ret == -(POLARSSL_ERR_SHA512_FILE_IO_ERROR) )
        polarssl_snprintf( buf, buflen, "SHA512 - Read/write error in file" );
#endif /* POLARSSL_SHA512_C */

#if defined(POLARSSL_THREADING_C)
    if( use_ret == -(POLARSSL_ERR_THREADING_FEATURE_UNAVAILABLE) )
        polarssl_snprintf( buf, buflen, "THREADING - The selected feature is not available" );
    if( use_ret == -(POLARSSL_ERR_THREADING_BAD_INPUT_DATA) )
        polarssl_snprintf( buf, buflen, "THREADING - Bad input parameters to function" );
    if( use_ret == -(POLARSSL_ERR_THREADING_MUTEX_ERROR) )
        polarssl_snprintf( buf, buflen, "THREADING - Locking / unlocking / free failed with error code" );
#endif /* POLARSSL_THREADING_C */

#if defined(POLARSSL_XTEA_C)
    if( use_ret == -(POLARSSL_ERR_XTEA_INVALID_INPUT_LENGTH) )
        polarssl_snprintf( buf, buflen, "XTEA - The data input has an invalid length" );
#endif /* POLARSSL_XTEA_C */
    // END generated code

    if( strlen( buf ) != 0 )
        return;

    polarssl_snprintf( buf, buflen, "UNKNOWN ERROR CODE (%04X)", use_ret );
}
Ejemplo n.º 13
0
int main( void )
{
    int ret, i;
    x509_crt cacert;
    x509_crl crl;
    char buf[10240];

    x509_crt_init( &cacert );
    x509_crl_init( &crl );

    /*
     * 1.1. Load the trusted CA
     */
    polarssl_printf( "\n  . Loading the CA root certificate ..." );
    fflush( stdout );

    /*
     * Alternatively, you may load the CA certificates from a .pem or
     * .crt file by calling x509_crt_parse_file( &cacert, "myca.crt" ).
     */
    ret = x509_crt_parse_file( &cacert, "ssl/test-ca/test-ca.crt" );
    if( ret != 0 )
    {
        polarssl_printf( " failed\n  !  x509_crt_parse_file returned %d\n\n", ret );
        goto exit;
    }

    polarssl_printf( " ok\n" );

    x509_crt_info( buf, 1024, "CRT: ", &cacert );
    polarssl_printf("%s\n", buf );

    /*
     * 1.2. Load the CRL
     */
    polarssl_printf( "  . Loading the CRL ..." );
    fflush( stdout );

    ret = x509_crl_parse_file( &crl, "ssl/test-ca/crl.pem" );
    if( ret != 0 )
    {
        polarssl_printf( " failed\n  !  x509_crl_parse_file returned %d\n\n", ret );
        goto exit;
    }

    polarssl_printf( " ok\n" );

    x509_crl_info( buf, 1024, "CRL: ", &crl );
    polarssl_printf("%s\n", buf );

    for( i = 0; i < MAX_CLIENT_CERTS; i++ )
    {
        /*
         * 1.3. Load own certificate
         */
        char    name[512];
        int flags;
        x509_crt clicert;
        pk_context pk;

        x509_crt_init( &clicert );
        pk_init( &pk );

        polarssl_snprintf(name, 512, "ssl/test-ca/%s", client_certificates[i]);

        polarssl_printf( "  . Loading the client certificate %s...", name );
        fflush( stdout );

        ret = x509_crt_parse_file( &clicert, name );
        if( ret != 0 )
        {
            polarssl_printf( " failed\n  !  x509_crt_parse_file returned %d\n\n", ret );
            goto exit;
        }

        polarssl_printf( " ok\n" );

        /*
         * 1.4. Verify certificate validity with CA certificate
         */
        polarssl_printf( "  . Verify the client certificate with CA certificate..." );
        fflush( stdout );

        ret = x509_crt_verify( &clicert, &cacert, &crl, NULL, &flags, NULL,
                               NULL );
        if( ret != 0 )
        {
            if( ret == POLARSSL_ERR_X509_CERT_VERIFY_FAILED )
            {
                char vrfy_buf[512];

                polarssl_printf( " failed\n" );
                x509_crt_verify_info( vrfy_buf, sizeof( vrfy_buf ), "  ! ", flags );
                polarssl_printf( "%s\n", vrfy_buf );
            }
            else
            {
                polarssl_printf( " failed\n  !  x509_crt_verify returned %d\n\n", ret );
                goto exit;
            }
        }

        polarssl_printf( " ok\n" );

        /*
         * 1.5. Load own private key
         */
        polarssl_snprintf(name, 512, "ssl/test-ca/%s", client_private_keys[i]);

        polarssl_printf( "  . Loading the client private key %s...", name );
        fflush( stdout );

        ret = pk_parse_keyfile( &pk, name, NULL );
        if( ret != 0 )
        {
            polarssl_printf( " failed\n  !  pk_parse_keyfile returned %d\n\n", ret );
            goto exit;
        }

        polarssl_printf( " ok\n" );

        /*
         * 1.6. Verify certificate validity with private key
         */
        polarssl_printf( "  . Verify the client certificate with private key..." );
        fflush( stdout );


        /* EC NOT IMPLEMENTED YET */
        if( ! pk_can_do( &clicert.pk, POLARSSL_PK_RSA ) )
        {
            polarssl_printf( " failed\n  !  certificate's key is not RSA\n\n" );
            ret = POLARSSL_ERR_X509_FEATURE_UNAVAILABLE;
            goto exit;
        }

        ret = mpi_cmp_mpi(&pk_rsa( pk )->N, &pk_rsa( clicert.pk )->N);
        if( ret != 0 )
        {
            polarssl_printf( " failed\n  !  mpi_cmp_mpi for N returned %d\n\n", ret );
            goto exit;
        }

        ret = mpi_cmp_mpi(&pk_rsa( pk )->E, &pk_rsa( clicert.pk )->E);
        if( ret != 0 )
        {
            polarssl_printf( " failed\n  !  mpi_cmp_mpi for E returned %d\n\n", ret );
            goto exit;
        }

        ret = rsa_check_privkey( pk_rsa( pk ) );
        if( ret != 0 )
        {
            polarssl_printf( " failed\n  !  rsa_check_privkey returned %d\n\n", ret );
            goto exit;
        }

        polarssl_printf( " ok\n" );

        x509_crt_free( &clicert );
        pk_free( &pk );
    }

exit:
    x509_crt_free( &cacert );
    x509_crl_free( &crl );

#if defined(_WIN32)
    polarssl_printf( "  + Press Enter to exit this program.\n" );
    fflush( stdout ); getchar();
#endif

    return( ret );
}
Ejemplo n.º 14
0
/*
 * Create a listening socket on bind_ip:port
 */
int net_bind( int *fd, const char *bind_ip, int port, int proto )
{
#if defined(POLARSSL_HAVE_IPV6)
    int n, ret;
    struct addrinfo hints, *addr_list, *cur;
    char port_str[6];

    if( ( ret = net_prepare() ) != 0 )
        return( ret );

    /* getaddrinfo expects port as a string */
    memset( port_str, 0, sizeof( port_str ) );
    polarssl_snprintf( port_str, sizeof( port_str ), "%d", port );

    /* Bind to IPv6 and/or IPv4, but only in TCP */
    memset( &hints, 0, sizeof( hints ) );
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = proto == NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM;
    hints.ai_protocol = proto == NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP;
    if( bind_ip == NULL )
        hints.ai_flags = AI_PASSIVE;

    if( getaddrinfo( bind_ip, port_str, &hints, &addr_list ) != 0 )
        return( POLARSSL_ERR_NET_UNKNOWN_HOST );

    /* Try the sockaddrs until a binding succeeds */
    ret = POLARSSL_ERR_NET_UNKNOWN_HOST;
    for( cur = addr_list; cur != NULL; cur = cur->ai_next )
    {
        *fd = (int) socket( cur->ai_family, cur->ai_socktype,
                            cur->ai_protocol );
        if( *fd < 0 )
        {
            ret = POLARSSL_ERR_NET_SOCKET_FAILED;
            continue;
        }

        n = 1;
        if( setsockopt( *fd, SOL_SOCKET, SO_REUSEADDR,
                        (const char *) &n, sizeof( n ) ) != 0 )
        {
            close( *fd );
            ret = POLARSSL_ERR_NET_SOCKET_FAILED;
            continue;
        }

        if( bind( *fd, cur->ai_addr, cur->ai_addrlen ) != 0 )
        {
            close( *fd );
            ret = POLARSSL_ERR_NET_BIND_FAILED;
            continue;
        }

        /* Listen only makes sense for TCP */
        if( proto == NET_PROTO_TCP )
        {
            if( listen( *fd, POLARSSL_NET_LISTEN_BACKLOG ) != 0 )
            {
                close( *fd );
                ret = POLARSSL_ERR_NET_LISTEN_FAILED;
                continue;
            }
        }

        /* I we ever get there, it's a success */
        ret = 0;
        break;
    }

    freeaddrinfo( addr_list );

    return( ret );

#else
    /* Legacy IPv4-only version */

    int ret, n, c[4];
    struct sockaddr_in server_addr;

    if( ( ret = net_prepare() ) != 0 )
        return( ret );

    if( ( *fd = (int) socket( AF_INET,
                    proto == NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM,
                    proto == NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP ) ) < 0 )
        return( POLARSSL_ERR_NET_SOCKET_FAILED );

    n = 1;
    setsockopt( *fd, SOL_SOCKET, SO_REUSEADDR,
                (const char *) &n, sizeof( n ) );

    server_addr.sin_addr.s_addr = net_htonl( INADDR_ANY );
    server_addr.sin_family      = AF_INET;
    server_addr.sin_port        = net_htons( port );

    if( bind_ip != NULL )
    {
        memset( c, 0, sizeof( c ) );
        sscanf( bind_ip, "%d.%d.%d.%d", &c[0], &c[1], &c[2], &c[3] );

        for( n = 0; n < 4; n++ )
            if( c[n] < 0 || c[n] > 255 )
                break;

        if( n == 4 )
            server_addr.sin_addr.s_addr = net_htonl(
                ( (uint32_t) c[0] << 24 ) |
                ( (uint32_t) c[1] << 16 ) |
                ( (uint32_t) c[2] <<  8 ) |
                ( (uint32_t) c[3]       ) );
    }

    if( bind( *fd, (struct sockaddr *) &server_addr,
              sizeof( server_addr ) ) < 0 )
    {
        close( *fd );
        return( POLARSSL_ERR_NET_BIND_FAILED );
    }

    /* Listen only makes sense for TCP */
    if( proto == NET_PROTO_TCP )
    {
        if( listen( *fd, POLARSSL_NET_LISTEN_BACKLOG ) != 0 )
        {
            close( *fd );
            return( POLARSSL_ERR_NET_LISTEN_FAILED );
        }
    }

    return( 0 );
#endif /* POLARSSL_HAVE_IPV6 */
}
Ejemplo n.º 15
0
/*
 * Initiate a TCP connection with host:port and the given protocol
 */
int net_connect( int *fd, const char *host, int port, int proto )
{
#if defined(POLARSSL_HAVE_IPV6)
    int ret;
    struct addrinfo hints, *addr_list, *cur;
    char port_str[6];

    if( ( ret = net_prepare() ) != 0 )
        return( ret );

    /* getaddrinfo expects port as a string */
    memset( port_str, 0, sizeof( port_str ) );
    polarssl_snprintf( port_str, sizeof( port_str ), "%d", port );

    /* Do name resolution with both IPv6 and IPv4 */
    memset( &hints, 0, sizeof( hints ) );
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = proto == NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM;
    hints.ai_protocol = proto == NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP;

    if( getaddrinfo( host, port_str, &hints, &addr_list ) != 0 )
        return( POLARSSL_ERR_NET_UNKNOWN_HOST );

    /* Try the sockaddrs until a connection succeeds */
    ret = POLARSSL_ERR_NET_UNKNOWN_HOST;
    for( cur = addr_list; cur != NULL; cur = cur->ai_next )
    {
        *fd = (int) socket( cur->ai_family, cur->ai_socktype,
                            cur->ai_protocol );
        if( *fd < 0 )
        {
            ret = POLARSSL_ERR_NET_SOCKET_FAILED;
            continue;
        }

        if( connect( *fd, cur->ai_addr, cur->ai_addrlen ) == 0 )
        {
            ret = 0;
            break;
        }

        close( *fd );
        ret = POLARSSL_ERR_NET_CONNECT_FAILED;
    }

    freeaddrinfo( addr_list );

    return( ret );

#else
    /* Legacy IPv4-only version */

    int ret;
    struct sockaddr_in server_addr;
    struct hostent *server_host;

    if( ( ret = net_prepare() ) != 0 )
        return( ret );

    if( ( server_host = gethostbyname( host ) ) == NULL )
        return( POLARSSL_ERR_NET_UNKNOWN_HOST );

    if( ( *fd = (int) socket( AF_INET,
                    proto == NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM,
                    proto == NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP ) ) < 0 )
        return( POLARSSL_ERR_NET_SOCKET_FAILED );

    memcpy( (void *) &server_addr.sin_addr,
            (void *) server_host->h_addr,
                     server_host->h_length );

    server_addr.sin_family = AF_INET;
    server_addr.sin_port   = net_htons( port );

    if( connect( *fd, (struct sockaddr *) &server_addr,
                 sizeof( server_addr ) ) < 0 )
    {
        close( *fd );
        return( POLARSSL_ERR_NET_CONNECT_FAILED );
    }

    return( 0 );
#endif /* POLARSSL_HAVE_IPV6 */
}
Ejemplo n.º 16
0
int main( int argc, char *argv[] )
{
    int ret = 0, len, tail_len, server_fd, i, written, frags;
    unsigned char buf[SSL_MAX_CONTENT_LEN + 1];
#if defined(POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED)
    unsigned char psk[POLARSSL_PSK_MAX_LEN];
    size_t psk_len = 0;
#endif
#if defined(POLARSSL_SSL_ALPN)
    const char *alpn_list[10];
#endif
    const char *pers = "ssl_client2";

    entropy_context entropy;
    ctr_drbg_context ctr_drbg;
    ssl_context ssl;
    ssl_session saved_session;
#if defined(POLARSSL_X509_CRT_PARSE_C)
    x509_crt cacert;
    x509_crt clicert;
    pk_context pkey;
#endif
    char *p, *q;
    const int *list;

    /*
     * Make sure memory references are valid.
     */
    server_fd = 0;
    memset( &ssl, 0, sizeof( ssl_context ) );
    memset( &saved_session, 0, sizeof( ssl_session ) );
#if defined(POLARSSL_X509_CRT_PARSE_C)
    x509_crt_init( &cacert );
    x509_crt_init( &clicert );
    pk_init( &pkey );
#endif
#if defined(POLARSSL_SSL_ALPN)
    memset( (void * ) alpn_list, 0, sizeof( alpn_list ) );
#endif

    if( argc == 0 )
    {
    usage:
        if( ret == 0 )
            ret = 1;

        polarssl_printf( USAGE );

        list = ssl_list_ciphersuites();
        while( *list )
        {
            polarssl_printf(" %-42s", ssl_get_ciphersuite_name( *list ) );
            list++;
            if( !*list )
                break;
            polarssl_printf(" %s\n", ssl_get_ciphersuite_name( *list ) );
            list++;
        }
        polarssl_printf("\n");
        goto exit;
    }

    opt.server_name         = DFL_SERVER_NAME;
    opt.server_addr         = DFL_SERVER_ADDR;
    opt.server_port         = DFL_SERVER_PORT;
    opt.debug_level         = DFL_DEBUG_LEVEL;
    opt.nbio                = DFL_NBIO;
    opt.request_page        = DFL_REQUEST_PAGE;
    opt.request_size        = DFL_REQUEST_SIZE;
    opt.ca_file             = DFL_CA_FILE;
    opt.ca_path             = DFL_CA_PATH;
    opt.crt_file            = DFL_CRT_FILE;
    opt.key_file            = DFL_KEY_FILE;
    opt.psk                 = DFL_PSK;
    opt.psk_identity        = DFL_PSK_IDENTITY;
    opt.force_ciphersuite[0]= DFL_FORCE_CIPHER;
    opt.renegotiation       = DFL_RENEGOTIATION;
    opt.allow_legacy        = DFL_ALLOW_LEGACY;
    opt.renegotiate         = DFL_RENEGOTIATE;
    opt.exchanges           = DFL_EXCHANGES;
    opt.min_version         = DFL_MIN_VERSION;
    opt.max_version         = DFL_MAX_VERSION;
    opt.arc4                = DFL_ARC4;
    opt.auth_mode           = DFL_AUTH_MODE;
    opt.mfl_code            = DFL_MFL_CODE;
    opt.trunc_hmac          = DFL_TRUNC_HMAC;
    opt.recsplit            = DFL_RECSPLIT;
    opt.reconnect           = DFL_RECONNECT;
    opt.reco_delay          = DFL_RECO_DELAY;
    opt.tickets             = DFL_TICKETS;
    opt.alpn_string         = DFL_ALPN_STRING;
    opt.fallback            = DFL_FALLBACK;
    opt.extended_ms         = DFL_EXTENDED_MS;
    opt.etm                 = DFL_ETM;

    for( i = 1; i < argc; i++ )
    {
        p = argv[i];
        if( ( q = strchr( p, '=' ) ) == NULL )
            goto usage;
        *q++ = '\0';

        if( strcmp( p, "server_name" ) == 0 )
            opt.server_name = q;
        else if( strcmp( p, "server_addr" ) == 0 )
            opt.server_addr = q;
        else if( strcmp( p, "server_port" ) == 0 )
        {
            opt.server_port = atoi( q );
            if( opt.server_port < 1 || opt.server_port > 65535 )
                goto usage;
        }
        else if( strcmp( p, "debug_level" ) == 0 )
        {
            opt.debug_level = atoi( q );
            if( opt.debug_level < 0 || opt.debug_level > 65535 )
                goto usage;
        }
        else if( strcmp( p, "nbio" ) == 0 )
        {
            opt.nbio = atoi( q );
            if( opt.nbio < 0 || opt.nbio > 2 )
                goto usage;
        }
        else if( strcmp( p, "request_page" ) == 0 )
            opt.request_page = q;
        else if( strcmp( p, "request_size" ) == 0 )
        {
            opt.request_size = atoi( q );
            if( opt.request_size < 0 || opt.request_size > SSL_MAX_CONTENT_LEN )
                goto usage;
        }
        else if( strcmp( p, "ca_file" ) == 0 )
            opt.ca_file = q;
        else if( strcmp( p, "ca_path" ) == 0 )
            opt.ca_path = q;
        else if( strcmp( p, "crt_file" ) == 0 )
            opt.crt_file = q;
        else if( strcmp( p, "key_file" ) == 0 )
            opt.key_file = q;
        else if( strcmp( p, "psk" ) == 0 )
            opt.psk = q;
        else if( strcmp( p, "psk_identity" ) == 0 )
            opt.psk_identity = q;
        else if( strcmp( p, "force_ciphersuite" ) == 0 )
        {
            opt.force_ciphersuite[0] = ssl_get_ciphersuite_id( q );

            if( opt.force_ciphersuite[0] == 0 )
            {
                ret = 2;
                goto usage;
            }
            opt.force_ciphersuite[1] = 0;
        }
        else if( strcmp( p, "renegotiation" ) == 0 )
        {
            opt.renegotiation = (atoi( q )) ? SSL_RENEGOTIATION_ENABLED :
                                              SSL_RENEGOTIATION_DISABLED;
        }
        else if( strcmp( p, "allow_legacy" ) == 0 )
        {
            switch( atoi( q ) )
            {
                case -1: opt.allow_legacy = SSL_LEGACY_BREAK_HANDSHAKE; break;
                case 0:  opt.allow_legacy = SSL_LEGACY_NO_RENEGOTIATION; break;
                case 1:  opt.allow_legacy = SSL_LEGACY_ALLOW_RENEGOTIATION; break;
                default: goto usage;
            }
        }
        else if( strcmp( p, "renegotiate" ) == 0 )
        {
            opt.renegotiate = atoi( q );
            if( opt.renegotiate < 0 || opt.renegotiate > 1 )
                goto usage;
        }
        else if( strcmp( p, "exchanges" ) == 0 )
        {
            opt.exchanges = atoi( q );
            if( opt.exchanges < 1 )
                goto usage;
        }
        else if( strcmp( p, "reconnect" ) == 0 )
        {
            opt.reconnect = atoi( q );
            if( opt.reconnect < 0 || opt.reconnect > 2 )
                goto usage;
        }
        else if( strcmp( p, "reco_delay" ) == 0 )
        {
            opt.reco_delay = atoi( q );
            if( opt.reco_delay < 0 )
                goto usage;
        }
        else if( strcmp( p, "tickets" ) == 0 )
        {
            opt.tickets = atoi( q );
            if( opt.tickets < 0 || opt.tickets > 2 )
                goto usage;
        }
        else if( strcmp( p, "alpn" ) == 0 )
        {
            opt.alpn_string = q;
        }
        else if( strcmp( p, "fallback" ) == 0 )
        {
            switch( atoi( q ) )
            {
                case 0: opt.fallback = SSL_IS_NOT_FALLBACK; break;
                case 1: opt.fallback = SSL_IS_FALLBACK; break;
                default: goto usage;
            }
        }
        else if( strcmp( p, "extended_ms" ) == 0 )
        {
            switch( atoi( q ) )
            {
                case 0: opt.extended_ms = SSL_EXTENDED_MS_DISABLED; break;
                case 1: opt.extended_ms = SSL_EXTENDED_MS_ENABLED; break;
                default: goto usage;
            }
        }
        else if( strcmp( p, "etm" ) == 0 )
        {
            switch( atoi( q ) )
            {
                case 0: opt.etm = SSL_ETM_DISABLED; break;
                case 1: opt.etm = SSL_ETM_ENABLED; break;
                default: goto usage;
            }
        }
        else if( strcmp( p, "min_version" ) == 0 )
        {
            if( strcmp( q, "ssl3" ) == 0 )
                opt.min_version = SSL_MINOR_VERSION_0;
            else if( strcmp( q, "tls1" ) == 0 )
                opt.min_version = SSL_MINOR_VERSION_1;
            else if( strcmp( q, "tls1_1" ) == 0 )
                opt.min_version = SSL_MINOR_VERSION_2;
            else if( strcmp( q, "tls1_2" ) == 0 )
                opt.min_version = SSL_MINOR_VERSION_3;
            else
                goto usage;
        }
        else if( strcmp( p, "max_version" ) == 0 )
        {
            if( strcmp( q, "ssl3" ) == 0 )
                opt.max_version = SSL_MINOR_VERSION_0;
            else if( strcmp( q, "tls1" ) == 0 )
                opt.max_version = SSL_MINOR_VERSION_1;
            else if( strcmp( q, "tls1_1" ) == 0 )
                opt.max_version = SSL_MINOR_VERSION_2;
            else if( strcmp( q, "tls1_2" ) == 0 )
                opt.max_version = SSL_MINOR_VERSION_3;
            else
                goto usage;
        }
        else if( strcmp( p, "arc4" ) == 0 )
        {
            switch( atoi( q ) )
            {
                case 0:     opt.arc4 = SSL_ARC4_DISABLED;   break;
                case 1:     opt.arc4 = SSL_ARC4_ENABLED;    break;
                default:    goto usage;
            }
        }
        else if( strcmp( p, "force_version" ) == 0 )
        {
            if( strcmp( q, "ssl3" ) == 0 )
            {
                opt.min_version = SSL_MINOR_VERSION_0;
                opt.max_version = SSL_MINOR_VERSION_0;
            }
            else if( strcmp( q, "tls1" ) == 0 )
            {
                opt.min_version = SSL_MINOR_VERSION_1;
                opt.max_version = SSL_MINOR_VERSION_1;
            }
            else if( strcmp( q, "tls1_1" ) == 0 )
            {
                opt.min_version = SSL_MINOR_VERSION_2;
                opt.max_version = SSL_MINOR_VERSION_2;
            }
            else if( strcmp( q, "tls1_2" ) == 0 )
            {
                opt.min_version = SSL_MINOR_VERSION_3;
                opt.max_version = SSL_MINOR_VERSION_3;
            }
            else
                goto usage;
        }
        else if( strcmp( p, "auth_mode" ) == 0 )
        {
            if( strcmp( q, "none" ) == 0 )
                opt.auth_mode = SSL_VERIFY_NONE;
            else if( strcmp( q, "optional" ) == 0 )
                opt.auth_mode = SSL_VERIFY_OPTIONAL;
            else if( strcmp( q, "required" ) == 0 )
                opt.auth_mode = SSL_VERIFY_REQUIRED;
            else
                goto usage;
        }
        else if( strcmp( p, "max_frag_len" ) == 0 )
        {
            if( strcmp( q, "512" ) == 0 )
                opt.mfl_code = SSL_MAX_FRAG_LEN_512;
            else if( strcmp( q, "1024" ) == 0 )
                opt.mfl_code = SSL_MAX_FRAG_LEN_1024;
            else if( strcmp( q, "2048" ) == 0 )
                opt.mfl_code = SSL_MAX_FRAG_LEN_2048;
            else if( strcmp( q, "4096" ) == 0 )
                opt.mfl_code = SSL_MAX_FRAG_LEN_4096;
            else
                goto usage;
        }
        else if( strcmp( p, "trunc_hmac" ) == 0 )
        {
            switch( atoi( q ) )
            {
                case 0: opt.trunc_hmac = SSL_TRUNC_HMAC_DISABLED; break;
                case 1: opt.trunc_hmac = SSL_TRUNC_HMAC_ENABLED; break;
                default: goto usage;
            }
        }
        else if( strcmp( p, "recsplit" ) == 0 )
        {
            opt.recsplit = atoi( q );
            if( opt.recsplit < 0 || opt.recsplit > 1 )
                goto usage;
        }
        else
            goto usage;
    }

#if defined(POLARSSL_DEBUG_C)
    debug_set_threshold( opt.debug_level );
#endif

    if( opt.force_ciphersuite[0] > 0 )
    {
        const ssl_ciphersuite_t *ciphersuite_info;
        ciphersuite_info = ssl_ciphersuite_from_id( opt.force_ciphersuite[0] );

        if( opt.max_version != -1 &&
            ciphersuite_info->min_minor_ver > opt.max_version )
        {
            polarssl_printf("forced ciphersuite not allowed with this protocol version\n");
            ret = 2;
            goto usage;
        }
        if( opt.min_version != -1 &&
            ciphersuite_info->max_minor_ver < opt.min_version )
        {
            polarssl_printf("forced ciphersuite not allowed with this protocol version\n");
            ret = 2;
            goto usage;
        }
        if( opt.max_version > ciphersuite_info->max_minor_ver )
            opt.max_version = ciphersuite_info->max_minor_ver;
        if( opt.min_version < ciphersuite_info->min_minor_ver )
            opt.min_version = ciphersuite_info->min_minor_ver;
    }

#if defined(POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED)
    /*
     * Unhexify the pre-shared key if any is given
     */
    if( strlen( opt.psk ) )
    {
        unsigned char c;
        size_t j;

        if( strlen( opt.psk ) % 2 != 0 )
        {
            polarssl_printf("pre-shared key not valid hex\n");
            goto exit;
        }

        psk_len = strlen( opt.psk ) / 2;

        for( j = 0; j < strlen( opt.psk ); j += 2 )
        {
            c = opt.psk[j];
            if( c >= '0' && c <= '9' )
                c -= '0';
            else if( c >= 'a' && c <= 'f' )
                c -= 'a' - 10;
            else if( c >= 'A' && c <= 'F' )
                c -= 'A' - 10;
            else
            {
                polarssl_printf("pre-shared key not valid hex\n");
                goto exit;
            }
            psk[ j / 2 ] = c << 4;

            c = opt.psk[j + 1];
            if( c >= '0' && c <= '9' )
                c -= '0';
            else if( c >= 'a' && c <= 'f' )
                c -= 'a' - 10;
            else if( c >= 'A' && c <= 'F' )
                c -= 'A' - 10;
            else
            {
                polarssl_printf("pre-shared key not valid hex\n");
                goto exit;
            }
            psk[ j / 2 ] |= c;
        }
    }
#endif /* POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED */

#if defined(POLARSSL_SSL_ALPN)
    if( opt.alpn_string != NULL )
    {
        p = (char *) opt.alpn_string;
        i = 0;

        /* Leave room for a final NULL in alpn_list */
        while( i < (int) sizeof alpn_list - 1 && *p != '\0' )
        {
            alpn_list[i++] = p;

            /* Terminate the current string and move on to next one */
            while( *p != ',' && *p != '\0' )
                p++;
            if( *p == ',' )
                *p++ = '\0';
        }
    }
#endif /* POLARSSL_SSL_ALPN */

    /*
     * 0. Initialize the RNG and the session data
     */
    polarssl_printf( "\n  . Seeding the random number generator..." );
    fflush( stdout );

    entropy_init( &entropy );
    if( ( ret = ctr_drbg_init( &ctr_drbg, entropy_func, &entropy,
                               (const unsigned char *) pers,
                               strlen( pers ) ) ) != 0 )
    {
        polarssl_printf( " failed\n  ! ctr_drbg_init returned -0x%x\n", -ret );
        goto exit;
    }

    polarssl_printf( " ok\n" );

#if defined(POLARSSL_X509_CRT_PARSE_C)
    /*
     * 1.1. Load the trusted CA
     */
    polarssl_printf( "  . Loading the CA root certificate ..." );
    fflush( stdout );

#if defined(POLARSSL_FS_IO)
    if( strlen( opt.ca_path ) )
        if( strcmp( opt.ca_path, "none" ) == 0 )
            ret = 0;
        else
            ret = x509_crt_parse_path( &cacert, opt.ca_path );
    else if( strlen( opt.ca_file ) )
        if( strcmp( opt.ca_file, "none" ) == 0 )
            ret = 0;
        else
            ret = x509_crt_parse_file( &cacert, opt.ca_file );
    else
#endif
#if defined(POLARSSL_CERTS_C)
        ret = x509_crt_parse( &cacert, (const unsigned char *) test_ca_list,
                strlen( test_ca_list ) );
#else
    {
        ret = 1;
        polarssl_printf("POLARSSL_CERTS_C not defined.");
    }
#endif
    if( ret < 0 )
    {
        polarssl_printf( " failed\n  !  x509_crt_parse returned -0x%x\n\n", -ret );
        goto exit;
    }

    polarssl_printf( " ok (%d skipped)\n", ret );

    /*
     * 1.2. Load own certificate and private key
     *
     * (can be skipped if client authentication is not required)
     */
    polarssl_printf( "  . Loading the client cert. and key..." );
    fflush( stdout );

#if defined(POLARSSL_FS_IO)
    if( strlen( opt.crt_file ) )
        if( strcmp( opt.crt_file, "none" ) == 0 )
            ret = 0;
        else
            ret = x509_crt_parse_file( &clicert, opt.crt_file );
    else
#endif
#if defined(POLARSSL_CERTS_C)
        ret = x509_crt_parse( &clicert, (const unsigned char *) test_cli_crt,
                strlen( test_cli_crt ) );
#else
    {
        ret = 1;
        polarssl_printf("POLARSSL_CERTS_C not defined.");
    }
#endif
    if( ret != 0 )
    {
        polarssl_printf( " failed\n  !  x509_crt_parse returned -0x%x\n\n", -ret );
        goto exit;
    }

#if defined(POLARSSL_FS_IO)
    if( strlen( opt.key_file ) )
        if( strcmp( opt.key_file, "none" ) == 0 )
            ret = 0;
        else
            ret = pk_parse_keyfile( &pkey, opt.key_file, "" );
    else
#endif
#if defined(POLARSSL_CERTS_C)
        ret = pk_parse_key( &pkey, (const unsigned char *) test_cli_key,
                strlen( test_cli_key ), NULL, 0 );
#else
    {
        ret = 1;
        polarssl_printf("POLARSSL_CERTS_C not defined.");
    }
#endif
    if( ret != 0 )
    {
        polarssl_printf( " failed\n  !  pk_parse_key returned -0x%x\n\n", -ret );
        goto exit;
    }

    polarssl_printf( " ok\n" );
#endif /* POLARSSL_X509_CRT_PARSE_C */

    /*
     * 2. Start the connection
     */
    if( opt.server_addr == NULL)
        opt.server_addr = opt.server_name;

    polarssl_printf( "  . Connecting to tcp/%s/%-4d...", opt.server_addr,
                                                opt.server_port );
    fflush( stdout );

    if( ( ret = net_connect( &server_fd, opt.server_addr,
                                         opt.server_port ) ) != 0 )
    {
        polarssl_printf( " failed\n  ! net_connect returned -0x%x\n\n", -ret );
        goto exit;
    }

    if( opt.nbio > 0 )
        ret = net_set_nonblock( server_fd );
    else
        ret = net_set_block( server_fd );
    if( ret != 0 )
    {
        polarssl_printf( " failed\n  ! net_set_(non)block() returned -0x%x\n\n", -ret );
        goto exit;
    }

    polarssl_printf( " ok\n" );

    /*
     * 3. Setup stuff
     */
    polarssl_printf( "  . Setting up the SSL/TLS structure..." );
    fflush( stdout );

    if( ( ret = ssl_init( &ssl ) ) != 0 )
    {
        polarssl_printf( " failed\n  ! ssl_init returned -0x%x\n\n", -ret );
        goto exit;
    }

    polarssl_printf( " ok\n" );

#if defined(POLARSSL_X509_CRT_PARSE_C)
    if( opt.debug_level > 0 )
        ssl_set_verify( &ssl, my_verify, NULL );
#endif

    ssl_set_endpoint( &ssl, SSL_IS_CLIENT );
    ssl_set_authmode( &ssl, opt.auth_mode );

#if defined(POLARSSL_SSL_MAX_FRAGMENT_LENGTH)
    if( ( ret = ssl_set_max_frag_len( &ssl, opt.mfl_code ) ) != 0 )
    {
        polarssl_printf( " failed\n  ! ssl_set_max_frag_len returned %d\n\n", ret );
        goto exit;
    }
#endif

#if defined(POLARSSL_SSL_TRUNCATED_HMAC)
    if( opt.trunc_hmac != DFL_TRUNC_HMAC )
        ssl_set_truncated_hmac( &ssl, opt.trunc_hmac );
#endif

#if defined(POLARSSL_SSL_EXTENDED_MASTER_SECRET)
    if( opt.extended_ms != DFL_EXTENDED_MS )
        ssl_set_extended_master_secret( &ssl, opt.extended_ms );
#endif

#if defined(POLARSSL_SSL_ENCRYPT_THEN_MAC)
    if( opt.etm != DFL_ETM )
        ssl_set_encrypt_then_mac( &ssl, opt.etm );
#endif

#if defined(POLARSSL_SSL_CBC_RECORD_SPLITTING)
    if( opt.recsplit != DFL_RECSPLIT )
        ssl_set_cbc_record_splitting( &ssl, opt.recsplit
                                    ? SSL_CBC_RECORD_SPLITTING_ENABLED
                                    : SSL_CBC_RECORD_SPLITTING_DISABLED );
#endif

#if defined(POLARSSL_SSL_ALPN)
    if( opt.alpn_string != NULL )
        if( ( ret = ssl_set_alpn_protocols( &ssl, alpn_list ) ) != 0 )
        {
            polarssl_printf( " failed\n  ! ssl_set_alpn_protocols returned %d\n\n", ret );
            goto exit;
        }
#endif

    ssl_set_rng( &ssl, ctr_drbg_random, &ctr_drbg );
    ssl_set_dbg( &ssl, my_debug, stdout );

    if( opt.nbio == 2 )
        ssl_set_bio( &ssl, my_recv, &server_fd, my_send, &server_fd );
    else
        ssl_set_bio( &ssl, net_recv, &server_fd, net_send, &server_fd );

#if defined(POLARSSL_SSL_SESSION_TICKETS)
    if( ( ret = ssl_set_session_tickets( &ssl, opt.tickets ) ) != 0 )
    {
        polarssl_printf( " failed\n  ! ssl_set_session_tickets returned %d\n\n", ret );
        goto exit;
    }
#endif

    /* RC4 setting is redundant if we use only one ciphersuite */
    if( opt.force_ciphersuite[0] != DFL_FORCE_CIPHER )
        ssl_set_ciphersuites( &ssl, opt.force_ciphersuite );
    else
        ssl_set_arc4_support( &ssl, opt.arc4 );

    if( opt.allow_legacy != DFL_ALLOW_LEGACY )
        ssl_legacy_renegotiation( &ssl, opt.allow_legacy );
#if defined(POLARSSL_SSL_RENEGOTIATION)
    ssl_set_renegotiation( &ssl, opt.renegotiation );
#endif

#if defined(POLARSSL_X509_CRT_PARSE_C)
    if( strcmp( opt.ca_path, "none" ) != 0 &&
        strcmp( opt.ca_file, "none" ) != 0 )
    {
        ssl_set_ca_chain( &ssl, &cacert, NULL, opt.server_name );
    }
    if( strcmp( opt.crt_file, "none" ) != 0 &&
        strcmp( opt.key_file, "none" ) != 0 )
    {
        if( ( ret = ssl_set_own_cert( &ssl, &clicert, &pkey ) ) != 0 )
        {
            polarssl_printf( " failed\n  ! ssl_set_own_cert returned %d\n\n", ret );
            goto exit;
        }
    }
#endif

#if defined(POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED)
    if( ( ret = ssl_set_psk( &ssl, psk, psk_len,
                             (const unsigned char *) opt.psk_identity,
                             strlen( opt.psk_identity ) ) ) != 0 )
    {
        polarssl_printf( " failed\n  ! ssl_set_psk returned %d\n\n", ret );
        goto exit;
    }
#endif

#if defined(POLARSSL_SSL_SERVER_NAME_INDICATION)
    if( ( ret = ssl_set_hostname( &ssl, opt.server_name ) ) != 0 )
    {
        polarssl_printf( " failed\n  ! ssl_set_hostname returned %d\n\n", ret );
        goto exit;
    }
#endif

    if( opt.min_version != -1 )
        ssl_set_min_version( &ssl, SSL_MAJOR_VERSION_3, opt.min_version );
    if( opt.max_version != -1 )
        ssl_set_max_version( &ssl, SSL_MAJOR_VERSION_3, opt.max_version );
#if defined(POLARSSL_SSL_FALLBACK_SCSV)
    if( opt.fallback != DFL_FALLBACK )
        ssl_set_fallback( &ssl, opt.fallback );
#endif

    /*
     * 4. Handshake
     */
    polarssl_printf( "  . Performing the SSL/TLS handshake..." );
    fflush( stdout );

    while( ( ret = ssl_handshake( &ssl ) ) != 0 )
    {
        if( ret != POLARSSL_ERR_NET_WANT_READ && ret != POLARSSL_ERR_NET_WANT_WRITE )
        {
            polarssl_printf( " failed\n  ! ssl_handshake returned -0x%x\n", -ret );
            if( ret == POLARSSL_ERR_X509_CERT_VERIFY_FAILED )
                polarssl_printf(
                    "    Unable to verify the server's certificate. "
                        "Either it is invalid,\n"
                    "    or you didn't set ca_file or ca_path "
                        "to an appropriate value.\n"
                    "    Alternatively, you may want to use "
                        "auth_mode=optional for testing purposes.\n" );
            polarssl_printf( "\n" );
            goto exit;
        }
    }

    polarssl_printf( " ok\n    [ Protocol is %s ]\n    [ Ciphersuite is %s ]\n",
            ssl_get_version( &ssl ), ssl_get_ciphersuite( &ssl ) );

#if defined(POLARSSL_SSL_ALPN)
    if( opt.alpn_string != NULL )
    {
        const char *alp = ssl_get_alpn_protocol( &ssl );
        polarssl_printf( "    [ Application Layer Protocol is %s ]\n",
                alp ? alp : "(none)" );
    }
#endif

    if( opt.reconnect != 0 )
    {
        polarssl_printf("  . Saving session for reuse..." );
        fflush( stdout );

        if( ( ret = ssl_get_session( &ssl, &saved_session ) ) != 0 )
        {
            polarssl_printf( " failed\n  ! ssl_get_session returned -0x%x\n\n", -ret );
            goto exit;
        }

        polarssl_printf( " ok\n" );
    }

#if defined(POLARSSL_X509_CRT_PARSE_C)
    /*
     * 5. Verify the server certificate
     */
    polarssl_printf( "  . Verifying peer X.509 certificate..." );

    if( ( ret = ssl_get_verify_result( &ssl ) ) != 0 )
    {
        char vrfy_buf[512];

        polarssl_printf( " failed\n" );

        x509_crt_verify_info( vrfy_buf, sizeof( vrfy_buf ), "  ! ", ret );

        polarssl_printf( "%s\n", vrfy_buf );
    }
    else
        polarssl_printf( " ok\n" );

    if( ssl_get_peer_cert( &ssl ) != NULL )
    {
        polarssl_printf( "  . Peer certificate information    ...\n" );
        x509_crt_info( (char *) buf, sizeof( buf ) - 1, "      ",
                       ssl_get_peer_cert( &ssl ) );
        polarssl_printf( "%s\n", buf );
    }
#endif /* POLARSSL_X509_CRT_PARSE_C */

#if defined(POLARSSL_SSL_RENEGOTIATION)
    if( opt.renegotiate )
    {
        /*
         * Perform renegotiation (this must be done when the server is waiting
         * for input from our side).
         */
        polarssl_printf( "  . Performing renegotiation..." );
        fflush( stdout );
        while( ( ret = ssl_renegotiate( &ssl ) ) != 0 )
        {
            if( ret != POLARSSL_ERR_NET_WANT_READ &&
                ret != POLARSSL_ERR_NET_WANT_WRITE )
            {
                polarssl_printf( " failed\n  ! ssl_renegotiate returned %d\n\n", ret );
                goto exit;
            }
        }
        polarssl_printf( " ok\n" );
    }
#endif /* POLARSSL_SSL_RENEGOTIATION */

    /*
     * 6. Write the GET request
     */
send_request:
    polarssl_printf( "  > Write to server:" );
    fflush( stdout );

    len = polarssl_snprintf( (char *) buf, sizeof(buf) - 1, GET_REQUEST,
                    opt.request_page );
    tail_len = strlen( GET_REQUEST_END );

    /* Add padding to GET request to reach opt.request_size in length */
    if( opt.request_size != DFL_REQUEST_SIZE &&
        len + tail_len < opt.request_size )
    {
        memset( buf + len, 'A', opt.request_size - len - tail_len );
        len += opt.request_size - len - tail_len;
    }

    strncpy( (char *) buf + len, GET_REQUEST_END, sizeof(buf) - len - 1 );
    len += tail_len;

    /* Truncate if request size is smaller than the "natural" size */
    if( opt.request_size != DFL_REQUEST_SIZE &&
        len > opt.request_size )
    {
        len = opt.request_size;

        /* Still end with \r\n unless that's really not possible */
        if( len >= 2 ) buf[len - 2] = '\r';
        if( len >= 1 ) buf[len - 1] = '\n';
    }

    for( written = 0, frags = 0; written < len; written += ret, frags++ )
    {
        while( ( ret = ssl_write( &ssl, buf + written, len - written ) ) <= 0 )
        {
            if( ret != POLARSSL_ERR_NET_WANT_READ && ret != POLARSSL_ERR_NET_WANT_WRITE )
            {
                polarssl_printf( " failed\n  ! ssl_write returned -0x%x\n\n", -ret );
                goto exit;
            }
        }
    }

    buf[written] = '\0';
    polarssl_printf( " %d bytes written in %d fragments\n\n%s\n", written, frags, (char *) buf );

    /*
     * 7. Read the HTTP response
     */
    polarssl_printf( "  < Read from server:" );
    fflush( stdout );

    do
    {
        len = sizeof( buf ) - 1;
        memset( buf, 0, sizeof( buf ) );
        ret = ssl_read( &ssl, buf, len );

        if( ret == POLARSSL_ERR_NET_WANT_READ ||
            ret == POLARSSL_ERR_NET_WANT_WRITE )
            continue;

        if( ret <= 0 )
        {
            switch( ret )
            {
                case POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY:
                    polarssl_printf( " connection was closed gracefully\n" );
                    ret = 0;
                    goto close_notify;

                case 0:
                case POLARSSL_ERR_NET_CONN_RESET:
                    polarssl_printf( " connection was reset by peer\n" );
                    ret = 0;
                    goto reconnect;

                default:
                    polarssl_printf( " ssl_read returned -0x%x\n", -ret );
                    goto exit;
            }
        }

        len = ret;
        buf[len] = '\0';
        polarssl_printf( " %d bytes read\n\n%s", len, (char *) buf );

        /* End of message should be detected according to the syntax of the
         * application protocol (eg HTTP), just use a dummy test here. */
        if( ret > 0 && buf[len-1] == '\n' )
        {
            ret = 0;
            break;
        }
    }
    while( 1 );

    /*
     * 7b. Continue doing data exchanges?
     */
    if( --opt.exchanges > 0 )
        goto send_request;

    /*
     * 8. Done, cleanly close the connection
     */
close_notify:
    polarssl_printf( "  . Closing the connection..." );

    /* No error checking, the connection might be closed already */
    do ret = ssl_close_notify( &ssl );
    while( ret == POLARSSL_ERR_NET_WANT_WRITE );
    ret = 0;

    polarssl_printf( " done\n" );

    /*
     * 9. Reconnect?
     */
reconnect:
    if( opt.reconnect != 0 )
    {
        --opt.reconnect;

        net_close( server_fd );

#if defined(POLARSSL_TIMING_C)
        if( opt.reco_delay > 0 )
            m_sleep( 1000 * opt.reco_delay );
#endif

        polarssl_printf( "  . Reconnecting with saved session..." );
        fflush( stdout );

        if( ( ret = ssl_session_reset( &ssl ) ) != 0 )
        {
            polarssl_printf( " failed\n  ! ssl_session_reset returned -0x%x\n\n", -ret );
            goto exit;
        }

        if( ( ret = ssl_set_session( &ssl, &saved_session ) ) != 0 )
        {
            polarssl_printf( " failed\n  ! ssl_set_session returned %d\n\n", ret );
            goto exit;
        }

        if( ( ret = net_connect( &server_fd, opt.server_addr,
                                             opt.server_port ) ) != 0 )
        {
            polarssl_printf( " failed\n  ! net_connect returned -0x%x\n\n", -ret );
            goto exit;
        }

        while( ( ret = ssl_handshake( &ssl ) ) != 0 )
        {
            if( ret != POLARSSL_ERR_NET_WANT_READ &&
                ret != POLARSSL_ERR_NET_WANT_WRITE )
            {
                polarssl_printf( " failed\n  ! ssl_handshake returned -0x%x\n\n", -ret );
                goto exit;
            }
        }

        polarssl_printf( " ok\n" );

        goto send_request;
    }

    /*
     * Cleanup and exit
     */
exit:
#ifdef POLARSSL_ERROR_C
    if( ret != 0 )
    {
        char error_buf[100];
        polarssl_strerror( ret, error_buf, 100 );
        polarssl_printf("Last error was: -0x%X - %s\n\n", -ret, error_buf );
    }
#endif

    if( server_fd )
        net_close( server_fd );

#if defined(POLARSSL_X509_CRT_PARSE_C)
    x509_crt_free( &clicert );
    x509_crt_free( &cacert );
    pk_free( &pkey );
#endif
    ssl_session_free( &saved_session );
    ssl_free( &ssl );
    ctr_drbg_free( &ctr_drbg );
    entropy_free( &entropy );

#if defined(_WIN32)
    polarssl_printf( "  + Press Enter to exit this program.\n" );
    fflush( stdout ); getchar();
#endif

    // Shell can not handle large exit numbers -> 1 for errors
    if( ret < 0 )
        ret = 1;

    return( ret );
}