This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

TLS-PSK with mqtt_simple handshake failure

Development OS: Ubuntu 16.04

Toolchain: gnuarmemb

Hardware: nRF9160 DK, modem firmware 1.0.1

EDIT: board setting in build system is nrf9160_pca10090ns

Software: nRF SDK master and v1.0.0

-----

I am trying to modify the mqtt_simple example to use TLS-PSK with a 64-byte PSK, but am only having luck using certificates. I have reviewed other DevZone questions about PSK and MQTT, but unfortunately the issue I am having seems unrelated to those.

The nrf9160 is able to successfully store a test PSK of 64Bytes and corresponding client ID using nrf_inbuilt_key library. I confirmed that the same client_id and psk could successfully establish a TLS session with the broker by running:

gnutls-cli <broker ip> -p 8883 --pskusername=<client id> --pskkey=<key> --priority=SECURE128:SECURE256:+PSK

I am testing mostly with the master branch of the NRF SDK as v1.0.0 has a multiple definition problem when I enable mbedTLS for PSK ciphersuites.

The client is able to bring up the LTE Link and establish a TCP connection to the broker without issue, but fails in the TLS handshake when using PSKs. (Using certs with the same broker on a different port successfully establishes an MQTT connection). The failure occurs during the process of the mqtt_connect() function.

I captured several packets during the process of the client attempting to connect and inspection with wireshark indicates that the server issues a fatal "unexpected message" alert after the client sends a "Client Key Exchange, ChangeCipherSpec" message. The cipher agreed upon in "Client Hello -> Server Hello, Server Hello Done" sequence was TLS_PSK_WITH_AES_256_CBC_SHA (enabled on the nrf9160 using menuconfig path (Top) → Zephyr Kernel → Modules → TLS configuration → Ciphersuite configuration).

Does anyone have any advice on how to resolve or debug this connection problem? I'm sure that it's just a configuration or API that I'm missing, but after tons of blind changes in menuconfig I need another set of eyes. I'll happily provide any additional information, but the packet captures contain some sensitive info so I cannot publicly provide those. Attached please find my test code, CMakeLists.txt, and prj.conf. Thanks for any assistance you can provide.

mqtt_psk_src.zip

  • Hello,

    How are you writing the PSK to the modem? The code below shows how certificates are written to the modem in nrf_cloud_transport.c. Perhaps you can follow a similar procedure.

    		int err;
    
    		/* Delete certificates */
    		nrf_sec_tag_t sec_tag = CONFIG_NRF_CLOUD_SEC_TAG;
    
    		for (nrf_key_mgnt_cred_type_t type = 0; type < 5; type++) {
    			err = nrf_inbuilt_key_delete(sec_tag, type);
    			LOG_DBG("nrf_inbuilt_key_delete(%lu, %d) => result=%d",
    				sec_tag, type, err);
    		}
    
    		/* Provision CA Certificate. */
    		err = nrf_inbuilt_key_write(CONFIG_NRF_CLOUD_SEC_TAG,
    					NRF_KEY_MGMT_CRED_TYPE_CA_CHAIN,
    					NRF_CLOUD_CA_CERTIFICATE,
    					sizeof(NRF_CLOUD_CA_CERTIFICATE));
    		if (err) {
    			LOG_DBG("NRF_CLOUD_CA_CERTIFICATE error!");
    			return err;
    		}
    
    		/* Provision Private Certificate. */
    		err = nrf_inbuilt_key_write(
    			CONFIG_NRF_CLOUD_SEC_TAG,
    			NRF_KEY_MGMT_CRED_TYPE_PRIVATE_CERT,
    			NRF_CLOUD_CLIENT_PRIVATE_KEY,
    			sizeof(NRF_CLOUD_CLIENT_PRIVATE_KEY));
    		if (err) {
    			LOG_DBG("NRF_CLOUD_CLIENT_PRIVATE_KEY error! ");
    			return err;
    		}
    
    		/* Provision Public Certificate. */
    		err = nrf_inbuilt_key_write(
    			CONFIG_NRF_CLOUD_SEC_TAG,
    			NRF_KEY_MGMT_CRED_TYPE_PUBLIC_CERT,
    			NRF_CLOUD_CLIENT_PUBLIC_CERTIFICATE,
    			sizeof(NRF_CLOUD_CLIENT_PUBLIC_CERTIFICATE));
    		if (err) {
    			LOG_DBG("NRF_CLOUD_CLIENT_PUBLIC_CERTIFICATE error!");
    			return err;
    		}

  • Hi Hakon,

    I am using that set of functions like so, using a separate sec_tag for PSK and Cert storage. I read in the API reference that the modem must be offline when writing credentials this way, so I am using LTE_LINK_CONTROL=y to wait until successful credential storage to call lte_lc_init_and_connect(). I believe the credentials are being written properly, as I am able to identify the PSK identity in the TLS handshake packets.

    static int provision_psk_nrf(nrf_sec_tag_t sec_tag)
    {
        int err = 0;
    
        for (nrf_key_mgnt_cred_type_t type = 0; type < 5; type++) {
            err = nrf_inbuilt_key_delete(sec_tag, type);
            LOG_INF("nrf_inbuilt_key_delete(%X, %d) => result=%d\n",
                    sec_tag, type, err);
        }
    
        /* Provision PSK. */
        err = nrf_inbuilt_key_write(sec_tag, NRF_KEY_MGMT_CRED_TYPE_PSK,
                test_psk, ARRAY_SIZE(test_psk));
    
        if (err) {
            LOG_ERR("Failed to load psk: %d - %s", err, nrf_err_str(err));
        }
    
        /* Provision PSK ID. */
        err = nrf_inbuilt_key_write(
                  sec_tag, NRF_KEY_MGMT_CRED_TYPE_IDENTITY,
                  CONFIG_DEMO_MQTT_CLIENT_ID, strlen(CONFIG_DEMO_MQTT_CLIENT_ID));
    
        if (err) {
            LOG_ERR("Failed to load client_id: %d - %s", err, nrf_err_str(err));
        }
    
        return err;
    }

    EDIT: To clarify, the function nrf_err_str() in the above sample is a basic function I wrote to print nrf_errno values, as I didn't find a reference to an official nrf error string function when I was looking through docs.

    To my understanding mbedTLS is the SSL/TLS backend for nrfxlib, is this correct? By default mbedTLS defines the max PSK length as 32 bytes, while I am using 64 byte keys. Could this be a cause for the issue? I have tried #undef'ing and changing the max to 64 to no avail, but perhaps I need to do so using Kconfig or other similar method. Thank you for your help.

  • Try replacing the ARRAY_SIZE() call with strlen().

Related