ARMmbed

Help testing TLS client connection with openssl server with ECC certificate

Hi,
I am trying to test some code I wrote which should establish a TLS client connection, using ECC certificate. I am creating self signed certificate using openssl (see process below) and then I started the openssl server. I keep getting the error code MBEDTLS_ERR_X509_CERT_VERIFY_FAILED when I try to do the handshake. This only happens when I set the authentication mode to MBEDTLS_SSL_VERIFY_REQUIRED.

I am not entirely sure where I may be going wrong. Please see code snippets below.

I then take “certificate.pem” and assign it to “ctx->cert_signer” this is the ca certificate (Or do I have that wrong?). The certificate.pem, is generated using the openSSL command below.

The call Int_Client_Credentials() doesn’t do anything but just return success.

Code

static const int CIPHER_SUITES[] =
{
    MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
    0
};

mbedtls_ssl_init(&(ctx->ssl_ctx));
mbedtls_ssl_config_init(&(ctx->ssl_config));
mbedtls_x509_crt_init(&(ctx->cert_signer));

/*Parse & load the signer cert*/
int rc = mbedtls_x509_crt_parse(&(ctx->cert_signer), config->signer_cert.buf, config->signer_cert.size);
ASSERT_DEBUG_RETURN_RELEASE(0 == rc, rc);

/*Init TLS/SSL protocol defaults*/
rc = mbedtls_ssl_config_defaults(&(ctx->ssl_config), MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
ASSERT_DEBUG_RETURN_RELEASE(0 == rc, rc);

/*FIXME is this required?*/
mbedtls_ssl_conf_ciphersuites(&(ctx->ssl_config), CIPHER_SUITES);

/* Server certificate validation is mandatory. */
mbedtls_ssl_conf_authmode(&(ctx->ssl_config), MBEDTLS_SSL_VERIFY_REQUIRED);

/* Set the RNG callback. */
mbedtls_ssl_conf_rng(&(ctx->ssl_config), DRNG_Callback, NULL);

/*Setup the chain of trust. The issuer cert for the device cert is the signer cert*/
mbedtls_ssl_conf_ca_chain(&(ctx->ssl_config), &ctx->cert_signer, NULL);

/*FIXME This currently does nothing*/
rc = Int_Client_Credentials(ctx, config);
ASSERT_DEBUG_RETURN_RELEASE(0 == rc, rc);

/* Set the resulting protocol configuration. */
rc = mbedtls_ssl_setup(&(ctx->ssl_ctx), &(ctx->ssl_config));
ASSERT_DEBUG_RETURN_RELEASE(0 == rc, rc);

/*Set the server to connect to, optional must make sure we always connecto to this server only*/
rc = mbedtls_ssl_set_hostname(&(ctx->ssl_ctx), config->server_url);
ASSERT_DEBUG_RETURN_RELEASE(0 == rc, rc);

/* Set the socket Callback for TLS*/
mbedtls_ssl_set_bio(&(ctx->ssl_ctx), ctx->sock, Socket_Send_Callback, Socket_Recv_Callback, NULL);

Openssl Command To Generate Cert
openssl ecparam -genkey -name prime256v1 -out key.pem
openssl req -new -sha256 -key key.pem -out csr.csr
openssl req -x509 -sha256 -days 365 -key key.pem -in csr.csr -out certificate.pem

PenSSL start the server
The certifcate.pem is the same one i use in the code.
openssl s_server -status_verbose -key key.pem -cert certificate.pem -accept 30000 -www

Hi,
There are several reasons why you get the MBEDTLS_ERR_X509_CERT_VERIFY_FAILED. It’s reasonable that you get the error only when MBEDTLS_SSL_VERIFY_REQUIRED is set, because this is the only mode that the certificate verification is checked. You should keep this mode, for security reasons.
I assume you set ctx->cert_signer using the mbedtls_x509_crt_parse_file() API. After that, you can just assign the ctx->cert_signer to config->signer_cert.
I suggest you add a call to mbedtls_ssl_get_verify_result on failure, to see reason for verification failure.
In addition, Please look at this article for you to gather more information.
Possible reasons for failure are:

  1. The cert_signer is not really the root certificate.
  2. The hostname is not set as the Common Name in the certificate.
  3. Other reason

Hi Ron,

I’m not using mbedtls_x509_crt_parse_file() to parse the certificate.

This is in a RTOS enviroment and has no file system. The OpenSSL command that generated certificate.pem, I just copy the data directly out of that file and assign it to the variable cert_signer variable.

I’ll give what you said a try and get back to you.

Hi John,
You can’t assign cert_signer the data from certificate.pem. You should parse the data into cert_signer. If you don’t have a file Sytstem, you should have the content of the certificate copied to a buffer, and then parse the data into ctx->cert_signer
a simple example of what I am saying, according to your code:

unsigned char buf[4096] = {0}; // Here set a sufficient size for the buffer
mbedtls_x509_crt crt;
mbedtls_ssl_context ssl;
mbedtls_ssl_config conf;
int rc = 0;

memcpy( buf, <certificate.pem>, <length of certificate with teminating '\0'> );
rc = mbedtls_x509_crt_parse( &crt, buf, strlen( buf ) + 1 );

rc = mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
ASSERT_DEBUG_RETURN_RELEASE(0 == rc, rc);

/*FIXME is this required?*/
mbedtls_ssl_conf_ciphersuites(&conf, CIPHER_SUITES);

/* Server certificate validation is mandatory. */
mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_REQUIRED);

/* Set the RNG callback. */
mbedtls_ssl_conf_rng(&conf, DRNG_Callback, NULL);

/*Setup the chain of trust. The issuer cert for the device cert is the signer cert*/
mbedtls_ssl_conf_ca_chain(&conf, &crt, NULL);

rc = mbedtls_ssl_setup( &ssl, &conf );
ASSERT_DEBUG_RETURN_RELEASE(0 == rc, rc);

A few other comments on you code:

  1. as you can see in the implementation of mbedtls_ssl_setup():
    ssl->conf = conf; , so assigning the pointer to itself doesn’t have a point.
  2. the configuration member of the ssl context is a pointer, as you can see here, so you can’t use this member when you use the mbedtls_ssl_conf_xxx() functions. At least not before you call mbedtls_ssl_setup().
    Please follow the example applications on how to use the certificates and establish a TLS handshake. Although they are tested on Linux and Windows, and use file system, you can look at them for reference. They are located in the x509 and ssl sample application folders.
    If your ctx member is not an Mbed TLS context, but your own context holding the Mbed TLS structures, disregard my additional comments.

Hi Ron,

The buffer is parsed, using mbedtls_x509_crt_parse(). Please see the code I first posted.

I assign the certificate.pem to config->signer_cert.buf, then its parsed ctx->cert_signer.

Are you saying the certificate that I created using OpenSSL cannot be directly assigned to

config->signer_cert.buf using a copy and paste of its content. When I do this and parse the content the function mbedtls_x509_crt_parse() does not return an error. So I am figuring it can parse it correctly.

I think I am making the certificate incorrectly. How do I correctly make a self signed certificate using OpenSSL so that I can use mbedtls as a client to connect to the openssl server?

All of this is running on my local machine for testing.

Hi,
The code you first posted is confusing, as you are usign config and context, which at first I thought were meant to be the mbedtls_ssl_context and mbedtls_ssl_config
If you are copying the content of the certificate to a buffer, and then parse that buffer to your certificate, it should be OK, if you didn’t get any parsing failure.
Please look at debug logs and the verify result, as I suggested you in my first reply, to see reason for failure. The failure you are receiving is a verification failure, not a parsing failure, so it is most likely that the certificate is Ok.

All good now. I was use the incorrect common name in the certificate.

Glad to hear.
Note that you can change the CN you want to check with mbedtls_ssl_set_hostname() , for example if the CN is different than the server address.

Hi Ron,

I want to use mbedtls_x509_crt_parse(), to parse 2 certificates at once.

The certificate are in DER format, so I’m guessing all I need to do is to concatenate each certificate into a single buffer and make one call to mbedtls_x509_crt_parse().

Do I have that correct?

Hi,
According to the code:

    /*
     * Determine buffer content. Buffer contains either one DER certificate or
     * one or more PEM certificates.
     */

So I doubt it will work. I have created a github issue to clarify this.
You can consider converting your certificates to PEM, and concatenate them, if you are not constrained with memory on your platform.

Solved wrote a wrapper to parse 1 cert at a time.