Example #1
0
static int check_bl3x_key_cert(const unsigned char *buf, size_t len,
			       const unsigned char *i_key, size_t i_key_len,
			       unsigned char *s_key, size_t *s_key_len,
			       const char *key_oid)
{
	const unsigned char *p;
	size_t sz;
	int err, flags;

	x509_crt_init(&cert);

	/* Parse key certificate */
	err = x509_crt_parse(&cert, buf, len);
	if (err) {
		ERROR("Key certificate parse error %d.\n", err);
		goto error;
	}

	/* Verify certificate */
	err = x509_crt_verify(&cert, &cert, NULL, NULL, &flags, NULL, NULL);
	if (err) {
		ERROR("Key certificate verification error %d. Flags: "
				"0x%x.\n", err, flags);
		goto error;
	}

	/* Check that the certificate has been signed by the issuer */
	err = pk_write_pubkey_der(&cert.pk, pk_buf, sizeof(pk_buf));
	if (err < 0) {
		ERROR("Error loading key in DER format %d.\n", err);
		goto error;
	}

	sz = (size_t)err;
	p = pk_buf + sizeof(pk_buf) - sz;
	if ((sz != i_key_len) || memcmp(p, i_key, sz)) {
		ERROR("Key certificate not signed with issuer key\n");
		err = 1;
		goto error;
	}

	/* Get the content certificate key */
	err = x509_get_crt_ext_data(&p, &sz, &cert, key_oid);
	if (err) {
		ERROR("Extension %s not found in Key certificate\n", key_oid);
		goto error;
	}

	assert(sz <= RSA_PUB_DER_MAX_BYTES);
	memcpy(s_key, p, sz);
	*s_key_len = sz;

error:
	x509_crt_free(&cert);

	return err;
}
Example #2
0
/*
 * Parse and verify the BL2 certificate
 *
 * This function verifies the integrity of the BL2 certificate, checks that it
 * has been signed with the ROT key and extracts the BL2 hash stored in the
 * certificate so it can be matched later against the calculated hash.
 *
 * Return: 0 = success, Otherwise = error
 */
static int check_bl2_cert(unsigned char *buf, size_t len)
{
	const unsigned char *p;
	size_t sz;
	int err, flags;

	x509_crt_init(&cert);

	/* Parse the BL2 certificate */
	err = x509_crt_parse(&cert, buf, len);
	if (err) {
		ERROR("BL2 certificate parse error %d.\n", err);
		goto error;
	}

	/* Check that it has been signed with the ROT key */
	err = pk_write_pubkey_der(&cert.pk, pk_buf, sizeof(pk_buf));
	if (err < 0) {
		ERROR("Error loading ROT key in DER format %d.\n", err);
		goto error;
	}

	sz = (size_t)err;
	p = pk_buf + sizeof(pk_buf) - sz;

	err = plat_match_rotpk(p, sz);
	if (err) {
		ERROR("ROT and BL2 certificate key mismatch\n");
		goto error;
	}

	/* Verify certificate */
	err = x509_crt_verify(&cert, &cert, NULL, NULL, &flags, NULL, NULL);
	if (err) {
		ERROR("BL2 certificate verification error %d. Flags: 0x%x.\n",
				err, flags);
		goto error;
	}

	/* Extract BL2 image hash from certificate */
	err = x509_get_crt_ext_data(&p, &sz, &cert, BL2_HASH_OID);
	if (err) {
		ERROR("Cannot read BL2 hash from certificate\n");
		goto error;
	}

	assert(sz == SHA_BYTES + 2);

	/* Skip the tag and length bytes and copy the hash */
	p += 2;
	memcpy(sha_bl2, p, SHA_BYTES);

error:
	x509_crt_free(&cert);

	return err;
}
Example #3
0
static int check_bl3x_cert(unsigned char *buf, size_t len,
		       const unsigned char *i_key, size_t i_key_len,
		       const char *hash_oid, unsigned char *sha)
{
	const unsigned char *p;
	size_t sz;
	int err, flags;

	x509_crt_init(&cert);

	/* Parse BL31 content certificate */
	err = x509_crt_parse(&cert, buf, len);
	if (err) {
		ERROR("Content certificate parse error %d.\n", err);
		goto error;
	}

	/* Verify certificate */
	err = x509_crt_verify(&cert, &cert, NULL, NULL, &flags, NULL, NULL);
	if (err) {
		ERROR("Content certificate verification error %d. Flags: "
				"0x%x.\n", err, flags);
		goto error;
	}

	/* Check that content certificate has been signed with the content
	 * certificate key corresponding to this image */
	sz = pk_write_pubkey_der(&cert.pk, pk_buf, sizeof(pk_buf));
	p = pk_buf + sizeof(pk_buf) - sz;

	if ((sz != i_key_len) || memcmp(p, i_key, sz)) {
		ERROR("Content certificate not signed with content "
				"certificate key\n");
		err = 1;
		goto error;
	}

	/* Extract image hash from certificate */
	err = x509_get_crt_ext_data(&p, &sz, &cert, hash_oid);
	if (err) {
		ERROR("Cannot read hash from certificate\n");
		goto error;
	}

	assert(sz == SHA_BYTES + 2);

	/* Skip the tag and length bytes and copy the hash */
	p += 2;
	memcpy(sha, p, SHA_BYTES);

error:
	x509_crt_free(&cert);

	return err;
}
Example #4
0
result_t X509Cert::verify(X509Cert_base *cert, bool &retVal, exlib::AsyncEvent *ac)
{
    int ret;
    int flags;

    ret = x509_crt_verify(&(((X509Cert *)cert)->m_crt), &m_crt, NULL, NULL, &flags,
                          NULL, NULL);
    if (ret == POLARSSL_ERR_X509_CERT_VERIFY_FAILED)
    {
        retVal = false;
        return 0;
    }
    else if (ret != 0)
        return CHECK_ERROR(_ssl::setError(ret));

    retVal = true;
    return 0;
}
static
int
__pkcs11h_crypto_mbedtls_certificate_is_issuer (
	IN void * const global_data,
	IN const unsigned char * const issuer_blob,
	IN const size_t issuer_blob_size,
	IN const unsigned char * const cert_blob,
	IN const size_t cert_blob_size
) {
	x509_crt x509_issuer;
	x509_crt x509_cert;
	uint32_t verify_flags = 0;

	PKCS11H_BOOL is_issuer = FALSE;

	(void)global_data;

	/*_PKCS11H_ASSERT (global_data!=NULL); NOT NEEDED*/
	_PKCS11H_ASSERT (issuer_blob!=NULL);
	_PKCS11H_ASSERT (cert_blob!=NULL);

	memset(&x509_issuer, 0, sizeof(x509_issuer));
	if (0 != x509_crt_parse (&x509_issuer, issuer_blob, issuer_blob_size)) {
		goto cleanup;
	}

	memset(&x509_cert, 0, sizeof(x509_cert));
	if (0 != x509_crt_parse (&x509_cert, cert_blob, cert_blob_size)) {
		goto cleanup;
	}

	if ( 0 == x509_crt_verify(&x509_cert, &x509_issuer, NULL, NULL,
		&verify_flags, NULL, NULL )) {
		is_issuer = TRUE;
	}

cleanup:
	x509_crt_free(&x509_cert);
	x509_crt_free(&x509_issuer);

	return is_issuer;
}
Example #6
0
int main( int argc, char *argv[] )
{
    int ret = 0, server_fd;
    unsigned char buf[1024];
    entropy_context entropy;
    ctr_drbg_context ctr_drbg;
    ssl_context ssl;
    x509_crt cacert;
    x509_crt clicert;
    pk_context pkey;
    int i, j;
    int flags, verify = 0;
    char *p, *q;
    const char *pers = "cert_app";

    /*
     * Set to sane values
     */
    server_fd = 0;
    x509_crt_init( &cacert );
    x509_crt_init( &clicert );
    pk_init( &pkey );

    if( argc == 0 )
    {
    usage:
        printf( USAGE );
        goto exit;
    }

    opt.mode                = DFL_MODE;
    opt.filename            = DFL_FILENAME;
    opt.ca_file             = DFL_CA_FILE;
    opt.ca_path             = DFL_CA_PATH;
    opt.server_name         = DFL_SERVER_NAME;
    opt.server_port         = DFL_SERVER_PORT;
    opt.debug_level         = DFL_DEBUG_LEVEL;
    opt.permissive          = DFL_PERMISSIVE;

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

        for( j = 0; p + j < q; j++ )
        {
            if( argv[i][j] >= 'A' && argv[i][j] <= 'Z' )
                argv[i][j] |= 0x20;
        }

        if( strcmp( p, "mode" ) == 0 )
        {
            if( strcmp( q, "file" ) == 0 )
                opt.mode = MODE_FILE;
            else if( strcmp( q, "ssl" ) == 0 )
                opt.mode = MODE_SSL;
            else
                goto usage;
        }
        else if( strcmp( p, "filename" ) == 0 )
            opt.filename = q;
        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, "server_name" ) == 0 )
            opt.server_name = 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, "permissive" ) == 0 )
        {
            opt.permissive = atoi( q );
            if( opt.permissive < 0 || opt.permissive > 1 )
                goto usage;
        }
        else
            goto usage;
    }

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

    if( strlen( opt.ca_path ) )
    {
        ret = x509_crt_parse_path( &cacert, opt.ca_path );
        verify = 1;
    }
    else if( strlen( opt.ca_file ) )
    {
        ret = x509_crt_parse_file( &cacert, opt.ca_file );
        verify = 1;
    }

    if( ret < 0 )
    {
        printf( " failed\n  !  x509_crt_parse returned -0x%x\n\n", -ret );
        goto exit;
    }

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

    if( opt.mode == MODE_FILE )
    {
        x509_crt crt;
        x509_crt *cur = &crt;
        x509_crt_init( &crt );

        /*
         * 1.1. Load the certificate(s)
         */
        printf( "\n  . Loading the certificate(s) ..." );
        fflush( stdout );

        ret = x509_crt_parse_file( &crt, opt.filename );

        if( ret < 0 )
        {
            printf( " failed\n  !  x509_crt_parse_file returned %d\n\n", ret );
            x509_crt_free( &crt );
            goto exit;
        }

        if( opt.permissive == 0 && ret > 0 )
        {
            printf( " failed\n  !  x509_crt_parse failed to parse %d certificates\n\n", ret );
            x509_crt_free( &crt );
            goto exit;
        }

        printf( " ok\n" );

        /*
         * 1.2 Print the certificate(s)
         */
        while( cur != NULL )
        {
            printf( "  . Peer certificate information    ...\n" );
            ret = x509_crt_info( (char *) buf, sizeof( buf ) - 1, "      ",
                                 cur );
            if( ret == -1 )
            {
                printf( " failed\n  !  x509_crt_info returned %d\n\n", ret );
                x509_crt_free( &crt );
                goto exit;
            }

            printf( "%s\n", buf );

            cur = cur->next;
        }

        /*
         * 1.3 Verify the certificate
         */
        if( verify )
        {
            printf( "  . Verifying X.509 certificate..." );

            if( ( ret = x509_crt_verify( &crt, &cacert, NULL, NULL, &flags,
                                         my_verify, NULL ) ) != 0 )
            {
                printf( " failed\n" );

                if( ( ret & BADCERT_EXPIRED ) != 0 )
                    printf( "  ! server certificate has expired\n" );

                if( ( ret & BADCERT_REVOKED ) != 0 )
                    printf( "  ! server certificate has been revoked\n" );

                if( ( ret & BADCERT_CN_MISMATCH ) != 0 )
                    printf( "  ! CN mismatch (expected CN=%s)\n", opt.server_name );

                if( ( ret & BADCERT_NOT_TRUSTED ) != 0 )
                    printf( "  ! self-signed or not signed by a trusted CA\n" );

                printf( "\n" );
            }
            else
                printf( " ok\n" );
        }

        x509_crt_free( &crt );
    }
    else if( opt.mode == MODE_SSL )
    {
        /*
         * 1. Initialize the RNG and the session data
         */
        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 )
        {
            printf( " failed\n  ! ctr_drbg_init returned %d\n", ret );
            goto exit;
        }

        printf( " ok\n" );

        /*
         * 2. Start the connection
         */
        printf( "  . SSL connection to tcp/%s/%-4d...", opt.server_name,
                                                        opt.server_port );
        fflush( stdout );

        if( ( ret = net_connect( &server_fd, opt.server_name,
                                             opt.server_port ) ) != 0 )
        {
            printf( " failed\n  ! net_connect returned %d\n\n", ret );
            goto exit;
        }

        /*
         * 3. Setup stuff
         */
        if( ( ret = ssl_init( &ssl ) ) != 0 )
        {
            printf( " failed\n  ! ssl_init returned %d\n\n", ret );
            goto exit;
        }

        ssl_set_endpoint( &ssl, SSL_IS_CLIENT );
        if( verify )
        {
            ssl_set_authmode( &ssl, SSL_VERIFY_REQUIRED );
            ssl_set_ca_chain( &ssl, &cacert, NULL, opt.server_name );
            ssl_set_verify( &ssl, my_verify, NULL );
        }
        else
            ssl_set_authmode( &ssl, SSL_VERIFY_NONE );

        ssl_set_rng( &ssl, ctr_drbg_random, &ctr_drbg );
        ssl_set_dbg( &ssl, my_debug, stdout );
        ssl_set_bio( &ssl, net_recv, &server_fd,
                net_send, &server_fd );

        ssl_set_own_cert( &ssl, &clicert, &pkey );

#if defined(POLARSSL_SSL_SERVER_NAME_INDICATION)
        ssl_set_hostname( &ssl, opt.server_name );
#endif

        /*
         * 4. Handshake
         */
        while( ( ret = ssl_handshake( &ssl ) ) != 0 )
        {
            if( ret != POLARSSL_ERR_NET_WANT_READ && ret != POLARSSL_ERR_NET_WANT_WRITE )
            {
                printf( " failed\n  ! ssl_handshake returned %d\n\n", ret );
                ssl_free( &ssl );
                goto exit;
            }
        }

        printf( " ok\n" );

        /*
         * 5. Print the certificate
         */
        printf( "  . Peer certificate information    ...\n" );
        ret = x509_crt_info( (char *) buf, sizeof( buf ) - 1, "      ",
                             ssl.session->peer_cert );
        if( ret == -1 )
        {
            printf( " failed\n  !  x509_crt_info returned %d\n\n", ret );
            ssl_free( &ssl );
            goto exit;
        }

        printf( "%s\n", buf );

        ssl_close_notify( &ssl );
        ssl_free( &ssl );
    }
    else
        goto usage;

exit:

    if( server_fd )
        net_close( server_fd );
    x509_crt_free( &cacert );
    x509_crt_free( &clicert );
    pk_free( &pkey );
    entropy_free( &entropy );

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

    return( ret );
}
Example #7
0
File: x509.c Project: ftes/opensgx
/*
 * Checkup routine
 */
int x509_self_test( int verbose )
{
#if defined(POLARSSL_CERTS_C) && defined(POLARSSL_SHA1_C)
    int ret;
    int flags;
    x509_crt cacert;
    x509_crt clicert;

    if( verbose != 0 )
        polarssl_printf( "  X.509 certificate load: " );

    x509_crt_init( &clicert );

    ret = x509_crt_parse( &clicert, (const unsigned char *) test_cli_crt,
                          strlen( test_cli_crt ) );
    if( ret != 0 )
    {
        if( verbose != 0 )
            polarssl_printf( "failed\n" );

        return( ret );
    }

    x509_crt_init( &cacert );

    ret = x509_crt_parse( &cacert, (const unsigned char *) test_ca_crt,
                          strlen( test_ca_crt ) );
    if( ret != 0 )
    {
        if( verbose != 0 )
            polarssl_printf( "failed\n" );

        return( ret );
    }

    if( verbose != 0 )
        polarssl_printf( "passed\n  X.509 signature verify: ");

    ret = x509_crt_verify( &clicert, &cacert, NULL, NULL, &flags, NULL, NULL );
    if( ret != 0 )
    {
        if( verbose != 0 )
            polarssl_printf( "failed\n" );

        polarssl_printf( "ret = %d, &flags = %04x\n", ret, flags );

        return( ret );
    }

    if( verbose != 0 )
        polarssl_printf( "passed\n\n");

    x509_crt_free( &cacert  );
    x509_crt_free( &clicert );

    return( 0 );
#else
    ((void) verbose);
    return( POLARSSL_ERR_X509_FEATURE_UNAVAILABLE );
#endif /* POLARSSL_CERTS_C && POLARSSL_SHA1_C */
}
Example #8
0
static int check_trusted_key_cert(unsigned char *buf, size_t len)
{
	const unsigned char *p;
	size_t sz;
	int err, flags;

	x509_crt_init(&cert);

	/* Parse the Trusted Key certificate */
	err = x509_crt_parse(&cert, buf, len);
	if (err) {
		ERROR("Trusted Key certificate parse error %d.\n", err);
		goto error;
	}

	/* Verify Trusted Key certificate */
	err = x509_crt_verify(&cert, &cert, NULL, NULL, &flags, NULL, NULL);
	if (err) {
		ERROR("Trusted Key certificate verification error %d. Flags: "
				"0x%x.\n", err, flags);
		goto error;
	}

	/* Check that it has been signed with the ROT key */
	err = pk_write_pubkey_der(&cert.pk, pk_buf, sizeof(pk_buf));
	if (err < 0) {
		ERROR("Error loading ROT key in DER format %d.\n", err);
		goto error;
	}

	sz = (size_t)err;
	p = pk_buf + sizeof(pk_buf) - sz;

	if (plat_match_rotpk(p, sz)) {
		ERROR("ROT and Trusted Key certificate key mismatch\n");
		goto error;
	}

	/* Extract Trusted World key from extensions */
	err = x509_get_crt_ext_data(&p, &tz_world_pk_len,
			&cert, TZ_WORLD_PK_OID);
	if (err) {
		ERROR("Cannot read Trusted World key\n");
		goto error;
	}

	assert(tz_world_pk_len <= RSA_PUB_DER_MAX_BYTES);
	memcpy(tz_world_pk, p, tz_world_pk_len);

	/* Extract Non-Trusted World key from extensions */
	err = x509_get_crt_ext_data(&p, &ntz_world_pk_len,
			&cert, NTZ_WORLD_PK_OID);
	if (err) {
		ERROR("Cannot read Non-Trusted World key\n");
		goto error;
	}

	assert(tz_world_pk_len <= RSA_PUB_DER_MAX_BYTES);
	memcpy(ntz_world_pk, p, ntz_world_pk_len);

error:
	x509_crt_free(&cert);

	return err;
}
char *test_SSL_verify_cert() 
{

    x509_crt crt;
    memset( &crt, 0, sizeof crt );

    x509_crt ca_crt;
    memset( &ca_crt, 0, sizeof ca_crt );

    x509_crl crl;
    memset( &crl, 0, sizeof crl );

    int ret = 0;

    ret =x509_crt_parse_file( &crt, "tests/ca/certs/m2-cert.pem" );

    mu_assert(ret == 0, "failed to parse cert m2-cert.pem");

    ret =x509_crt_parse_file( &ca_crt, "tests/ca/none.pem" );

    mu_assert(ret != 0, "failed to fail on non-existent pem none.pem");

    ret =x509_crt_parse_file( &ca_crt, "tests/ca/cacert.pem" );

    mu_assert(ret == 0, "failed to parse cert cacert.pem");

    ret =x509_crl_parse_file( &crl, "tests/ca/crl.pem" );

    mu_assert(ret == 0, "failed to parse cert crl.pem");

    /*
     * Validate the cert.  Since these certs are only valid within a certain time period, this test
     * will fail when the current time is outside this period.  To avoid false failures (eg. when
     * building/testing this version of the software in the distant future), adjust the expected
     * test outcome accordingly.  However, log the failure to stderr so that the maintainer can
     * detect the expiry of the cert, and generate/commit a new one from time to time.
     */
    int flags = 0;
    ret =x509_crt_verify( &crt, &ca_crt, NULL, NULL, &flags, NULL, NULL);
    if ( ret ) {
	char buf[1024];
	buf[0] = 0;
	polarssl_strerror( ret, buf, sizeof buf );
	fprintf( stderr, "*** x509_crt_verify of m2-cert.pem: %d: %s\n", ret, buf );
    }
    int valid_from = x509_time_expired( &crt.valid_from );
    int valid_to   = x509_time_expired( &crt.valid_to );

    int expected = 0;
    if ( valid_from == BADCERT_EXPIRED && valid_to == BADCERT_EXPIRED ) {
	/*
	 * This cert hasn't yet become active, or has already expired; expect
	 * X509 cert failure (-0x2700)
	 */
	fprintf( stderr, "*** x509_crt_verify WILL FAIL because current data is outside: valid_from '%d/%d/%d %d:%d:%d': %d, valid_to '%d/%d/%d %d:%d:%d': %d\n",
	       crt.valid_from.year, crt.valid_from.mon, crt.valid_from.day, crt.valid_from.hour, crt.valid_from.min, crt.valid_from.sec, valid_from,
	       crt.valid_to  .year, crt.valid_to  .mon, crt.valid_to  .day, crt.valid_to  .hour, crt.valid_to  .min, crt.valid_to  .sec, valid_to );
	fprintf( stderr, "*** If this is the currently supported version, generate and commit a new tests/ca/m2-cert.pem with valid dates\n" );
	expected = POLARSSL_ERR_X509_CERT_VERIFY_FAILED;
    }
    mu_assert(ret == expected, "failed to verify cert m2-cert.pem");

    x509_crt_free( &crt );
    x509_crt_free( &ca_crt );
    x509_crl_free( &crl );

    return NULL;
}
Example #10
0
int main( int argc, char *argv[] )
{
    int ret, i;
    x509_crt cacert;
    x509_crl crl;
    char buf[10240];

    ((void) argc);
    ((void) argv);

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

    /*
     * 1.1. Load the trusted CA
     */
    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 )
    {
        printf( " failed\n  !  x509_crt_parse_file returned %d\n\n", ret );
        goto exit;
    }

    printf( " ok\n" );

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

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

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

    printf( " ok\n" );

    x509_crl_info( buf, 1024, "CRL: ", &crl );
    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 );

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

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

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

        printf( " ok\n" );

        /*
         * 1.4. Verify certificate validity with CA certificate
         */
        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 )
            {
                if( flags & BADCERT_CN_MISMATCH )
                    printf( " CN_MISMATCH " );
                if( flags & BADCERT_EXPIRED )
                    printf( " EXPIRED " );
                if( flags & BADCERT_REVOKED )
                    printf( " REVOKED " );
                if( flags & BADCERT_NOT_TRUSTED )
                    printf( " NOT_TRUSTED " );
                if( flags & BADCRL_NOT_TRUSTED )
                    printf( " CRL_NOT_TRUSTED " );
                if( flags & BADCRL_EXPIRED )
                    printf( " CRL_EXPIRED " );
            } else {
                printf( " failed\n  !  x509_crt_verify returned %d\n\n", ret );
                goto exit;
            }
        }

        printf( " ok\n" );

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

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

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

        printf( " ok\n" );

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


        /* EC NOT IMPLEMENTED YET */
        if( ! pk_can_do( &clicert.pk, POLARSSL_PK_RSA ) )
        {
            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 )
        {
            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 )
        {
            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 )
        {
            printf( " failed\n  !  rsa_check_privkey returned %d\n\n", ret );
            goto exit;
        }

        printf( " ok\n" );

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

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

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

    return( ret );
}