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

TLSSocketWrapper::close() hangs if status of underlining network interface changes beforehand #15209

Open
zhiyong-ft opened this issue Jan 18, 2022 · 1 comment

Comments

@zhiyong-ft
Copy link

Description of defect

System hangs if TLSSocketWrapper::close() is called after the status of underlining network interfaces changes, such as caused by unplugging Ethernet cable.

I was testing a WebSocket client and found some weird behavior when TLSSocket is used but not with TCPSocket. The problem was eventually tracked down to the following line of code:

nsapi_error_t TLSSocketWrapper::close()
{
    if (!_transport) {
        return NSAPI_ERROR_NO_SOCKET;
    }

    tr_info("Closing TLS");

    int ret = 0;
    if (_handshake_completed) {
        _transport->set_blocking(true);
        ret = mbedtls_ssl_close_notify(&_ssl);   // <--This line hangs
        if (ret) {
            print_mbedtls_error("mbedtls_ssl_close_notify", ret);
        }
        _handshake_completed = false;
    }

    if (_close_transport) {
        int ret2 = _transport->close();
        if (!ret) {
            ret = ret2;
        }
    }

    _transport = nullptr;

    return ret;
}

I suspect this issue is related to the following issue when PPP/cellular connection is used.
#13505

Target(s) affected by this defect ?

NUCELO_F429ZI

Toolchain(s) (name and version) displaying this defect ?

Mbed Studio with ARMC6, and GCC_ARM(both V9, and V10)

What version of Mbed-os are you using (tag or sha) ?

mbed-os-6.15.1-57-g1443257e40
mbed-os-5.15.7

What version(s) of tools are you using. List all that apply (E.g. mbed-cli)

Mbed-Studio, VS Code with GCC_ARM

How is this defect reproduced ?

  1. include the following line in mbed_app.json macros section, otherwise there will be errors related to CA parsing at run time.
"MBEDTLS_SHA1_C=1"
  1. Compile and load the following code into a board that supports TLS, such as NUCLEO_F429ZI. The code is mostly the same as TLSSocket example for Mbed-OS 6.5 and 6.6, with two added line to pause system to give time to unplug Ethernet cable. Example code for later version uses WiFi and are not convenient to test.
#include "ThisThread.h"
#include "mbed.h"
#include "mbed_trace.h"

#ifndef DEVICE_TRNG
#error "mbed-os-example-tls-socket requires a device which supports TRNG"
#else

const char cert[] = \
    "-----BEGIN CERTIFICATE-----\n"
    "MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ\n"
    "RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD\n"
    "VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX\n"
    "DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y\n"
    "ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy\n"
    "VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr\n"
    "mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr\n"
    "IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK\n"
    "mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu\n"
    "XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy\n"
    "dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye\n"
    "jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1\n"
    "BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3\n"
    "DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92\n"
    "9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx\n"
    "jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0\n"
    "Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz\n"
    "ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS\n"
    "R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp\n"
    "-----END CERTIFICATE-----";

int main(void)
{
    char *buffer = new char[256];
    nsapi_size_or_error_t result;
    nsapi_size_t size;
    const char query[] = "GET / HTTP/1.1\r\nHost: ifconfig.io\r\nConnection: close\r\n\r\n";

    mbed_trace_init();

    printf("TLSSocket Example.\n");
    printf("Mbed OS version: %d.%d.%d\n\n", MBED_MAJOR_VERSION, MBED_MINOR_VERSION, MBED_PATCH_VERSION);

    NetworkInterface *net = NetworkInterface::get_default_instance();

    if (!net) {
        printf("Error! No network inteface found.\n");
        return 0;
    }

    printf("Connecting to network\n");
    result = net->connect();
    if (result != NSAPI_ERROR_OK) {
        printf("Error! net->connect() returned: %d\n", result);
        return result;
    }

    printf("Connecting to ifconfig.io\n");
    SocketAddress addr;
    result = net->gethostbyname("ifconfig.io", &addr);
    if (result != NSAPI_ERROR_OK) {
	printf("Error! DNS resolution for ifconfig.io failed with %d\n", result);
    }
    addr.set_port(443);

    TLSSocket *socket = new TLSSocket;
    result = socket->open(net);
    if (result != NSAPI_ERROR_OK) {
        printf("Error! socket->open() returned: %d\n", result);
        return result;
    }

    socket->set_hostname("ifconfig.io");

    result = socket->set_root_ca_cert(cert);
    if (result != NSAPI_ERROR_OK) {
        printf("Error: socket->set_root_ca_cert() returned %d\n", result);
        return result;
    }

    result = socket->connect(addr);
    if (result != NSAPI_ERROR_OK) {
        printf("Error! socket->connect() returned: %d\n", result);
        goto DISCONNECT;
    }

    // Send a simple http request
    size = strlen(query);
    result = socket->send(query, size);
    if (result != size) {
        printf("Error! socket->send() returned: %d\n", result);
        goto DISCONNECT;
    }

    // Receieve an HTTP response and print out the response line
    while ((result = socket->recv(buffer, 255)) > 0) {
        buffer[result] = 0;
        printf("%s", buffer);
    }
    printf("\n");

    if (result < 0) {
        printf("Error! socket->recv() returned: %d\n", result);
        goto DISCONNECT;
    }


DISCONNECT:
    delete[] buffer;
    // Close the socket to return its memory
    printf("About to close socket, please unplug ethernet cable\n");
    ThisThread::sleep_for(15000);
    socket->close();
    delete socket;

    // Bring down the network interface
    net->disconnect();
    printf("Done\n");
}
#endif
  1. Run the code, and unplug Ethernet cable once the following line is printed out of console.
About to close socket, please unplug ethernet cable
  1. Check console output, the last line "Done" never shows up.
About to close socket, please unplug ethernet cable
[INFO][STE1]: emac_link_state_cb set to false
[INFO][TLSW]: Closing TLS
// Done <-- this line of output never shows up.
@zhiyong-ft
Copy link
Author

Upon plugging Ethernet cable back or set timeout to a finite number such as

nsapi_error_t TLSSocketWrapper::close()
{
    if (!_transport) {
        return NSAPI_ERROR_NO_SOCKET;
    }

    tr_info("Closing TLS");

    int ret = 0;
    if (_handshake_completed) {
        //_transport->set_blocking(true);
        _transport->set_timeout(5000); // <-- change timeout to a finite number
        ret = mbedtls_ssl_close_notify(&_ssl);
        if (ret) {
            print_mbedtls_error("mbedtls_ssl_close_notify", ret);
        }
        _handshake_completed = false;
    }

    if (_close_transport) {
        int ret2 = _transport->close();
        if (!ret) {
            ret = ret2;
        }
    }

    _transport = nullptr;

    return ret;
}

I get the following error in console:

[ERR ][TLSW]: mbedtls_ssl_close_notify() failed: -0x6880 (-26752): SSL - Connection requires a write call

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Issue Workflow
Needs Triage
Development

No branches or pull requests

2 participants