Mbed-TLS / mbedtls

An open source, portable, easy to use, readable and flexible TLS library, and reference implementation of the PSA Cryptography API. Releases are on a varying cadence, typically around 3 - 6 months between releases.
https://www.trustedfirmware.org/projects/mbed-tls/
Other
5.02k stars 2.5k forks source link

Handshake takes too long time. #9288

Open leventf16 opened 1 week ago

leventf16 commented 1 week ago

Suggested enhancement

This code takes too long time - around 8 seconds:

LogDebug(("\n\nSSL state connect : %d ", pMbedTLSParams->ssl.state));
LogDebug(("  . Performing the SSL/TLS handshake..."));
while((ret = mbedtls_ssl_handshake(&(pMbedTLSParams->ssl))) != 0) {
    if(ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
        LogError((" failed\n  ! mbedtls_ssl_handshake returned -0x%x\n", -ret));
        if(ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) {
            LogError(("    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"));
        }
        return SSL_CONNECTION_ERROR;
    }
}

How can we speedup handshake process? This delay affects our connection process duration. We are connecting to AWS IoT MQTT broker. We are using ARM Cortex M3 processor running at 32MHz.

gilles-peskine-arm commented 1 week ago

How much time is spent in CPU computation vs network exchanges?

What is the underlying network protocol?

What cipher suite, protocol version and options are negotiated? Realistically, this is the most obvious adjustment variable: make sure that you're using the fastest cryptographic primitives for your configuration.

leventf16 commented 1 week ago

The time spent in the while loop is around 8 seconds. After that we have successful connection to the AWS IoT. We made changes suggested by you but there isn't any change - the time spend in the while loop again is around 8 seconds. We added this to our code: mbedtls_ssl_context ssl; mbedtls_ssl_config conf;

mbedtls_ssl_init(&ssl); mbedtls_ssl_config_init(&conf);

// Set up SSL/TLS configuration mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);

// Specify the elliptic curves to use (secp256r1 and Curve25519) const mbedtls_ecp_group_id curves[] = { MBEDTLS_ECP_DP_SECP256R1, MBEDTLS_ECP_DP_CURVE25519, MBEDTLS_ECP_DP_NONE }; mbedtls_ssl_conf_curves(&conf, curves);

// Specify the ciphersuites to use (ChaCha20-Poly1305 first) const int ciphersuites[] = { MBEDTLS_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, MBEDTLS_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 // End of list }; mbedtls_ssl_conf_ciphersuites(&conf, ciphersuites);

// Setup SSL context mbedtls_ssl_setup(&ssl, &conf);

// Cleanup mbedtls_ssl_free(&ssl); mbedtls_ssl_config_free(&conf);

mpg commented 1 week ago
  • If you're doing client authentication, make sure to use ECDSA, not RSA. If you're not doing client authentication, then ECDHE+RSA is faster on the client than ECDHE+ECDSA: RSA is slower than ECDSA in total, but RSA puts most of the calculation on the server

Note that the client and server can authenticate using different algs, so if you're trying to minimize the load on the client, for a handshake with client authentication you best bet is still ECDHE-RSA + provisioning an ECDSA certificate on the client.

To put some numbers on what you wrote (generated with programs/test/benchmark rsa ecdsa on my 64-bit Intel laptop - units are operations per second, so more is better):

  RSA-2048                 :    3117  public/s
  RSA-2048                 :     350 private/s
  ECDSA-secp256r1          :    2227 sign/s
  ECDSA-secp256r1          :     637 verify/s

When A authenticates itself to B: A will perform RSA-private or ECDSA-sign, and B will perform RSA-public or ECDSA-verify. Server authentication is mandatory, and as a client we want that to use RSA so we do a cheap RSA-public; client authentication is optional but if we do it we want to perform the cheaper ECDSA-sign.

So, as a client who doesn't want to perform too much computation, we want ECDHE-RSA all the time, and if we authenticate ourselves, we want to do so using an ECC certificate.

(Note: ECDHE-RSA is for TLS 1.2, with TLS 1.3 the negociation is different, I guess we want to use mbedtls_ssl_conf_sig_algs() instead.)

@mpg If performance is the goal and not code size, should MBEDTLS_PSA_P256M_DRIVER_ENABLED be enabled

The last comparisons I've done are quite old (Mbed TLS 2.23) but the answer is "it depends" - on the platform, your config of Mbed TLS, and the distribution of operations you're doing. For speed, you want to keep the default values of MBEDTLS_ECP_WINDOW_SIZE, MBEDTLS_ECP_FIXED_POINT_OPTIM, MBEDTLS_ECP_NIST_OPTIM. With those values:

So overall if you care, you need to measure it on your board with a realistic workload.