Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handshake takes too long time. #9288

Open
leventf16 opened this issue Jun 19, 2024 · 3 comments
Open

Handshake takes too long time. #9288

leventf16 opened this issue Jun 19, 2024 · 3 comments

Comments

@leventf16
Copy link

leventf16 commented Jun 19, 2024

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
Copy link
Contributor

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.

  • 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 for a non-authenticating client using RSA, there is a performance regression in Mbed TLS 3.6.0 which we hope to fix in 3.6.1.
  • For the key exchange, make sure to use ECDHE (not DHE).
  • In terms of elliptic curves, make sure to use secp256r1, or perhaps secp256r1 and Curve25519 (I think Curve25519 is faster but it only works for ECDHE, not for ECDSA, so you need secp256r1 for ECDSA). @mpg If performance is the goal and not code size, should MBEDTLS_PSA_P256M_DRIVER_ENABLED be enabled (@leventf16 this selects between two implementations of secp256r1)?
  • Make sure to use SHA256, not SHA384/SHA512.
  • If you have no cryptographic acceleration then favor ChachaPoly over AES. (If you had AES acceleration, AES would be the way to go.)

@leventf16
Copy link
Author

leventf16 commented Jun 19, 2024

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
Copy link
Contributor

mpg commented Jun 20, 2024

  • 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:

  • on M0 the default implementation was significantly faster than p256-m on signature generation and key generation on M0, and slightly slower for other operations (verification, key agreement) - overall default was faster on the (unweighted) sum of those 4.
  • on M4 the default implementation was a bit faster on sign/keygen, and slower on the other two - overall default was slower on the sum.
  • on M3 I hadn't done any measurements.

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants