DTLS PSK Handshake Failure on nRF9151 DK

7762.wireshark_trace_clienthello_only_scsv.pcapng

Summary

We are trying to perform a DTLS 1.2 handshake using PSK (Pre-Shared Key)
from an **nRF9151 module running NCS v3.0.2, using modem-offloaded DTLS (IPPROTO_DTLS_1_2).

  • LTE connects successfully
  • PSK Identity + Key are provisioned to security tag 42
  • The socket is configured with `TLS_SEC_TAG_LIST` and `TLS_PEER_VERIFY_NONE`
  • DTLS handshake always fails with `errno = 111` (`ECONNREFUSED`)
  • Wireshark trace shows the modem sends a DTLS ClientHello containing only: that means no usable cipher suites get advertised.

Expected Behavior

The client should send a DTLS ClientHello advertising PSK cipher suites such as:

  • - `TLS_PSK_WITH_AES_128_CCM_8`
  • - `TLS_PSK_WITH_AES_128_CCM`

And the server should reply with ServerHello → PSK Key Exchange.

This works correctly using:
Heavy check mark OpenSSL-based client  
Heavy check mark Go client (Pion/dtls)  
Heavy multiplication x Fails only with the nRF91 modem-based DTLS client

Actual Behavior

  • Although PSK identity and key are provisioned correctly inside the modem, the ClientHello sent by the nRF9151 does not include any PSK cipher suite (e.g., TLS_PSK_WITH_AES_128_CCM_8). Instead, it offers only ECDHE-based certificate cipher suites followed by TLS_EMPTY_RENEGOTIATION_INFO_SCSV (0x00FF). As a result, the DTLS handshake fails with no shared cipher suite.
  • Server (Go or OpenSSL) rejects handshake
  • Client receives errno=111.


Files Included

| File | Description |
|------|-------------|
| `main.c` | Full C source used on nRF9151 |
| `prj.conf` | Project configuration |
| `wireshark_trace_clienthello_only_scsv.pcapng` | Modem trace export |
| `server_log.txt` | Output from Go/openssl servers (no shared cipher) |


Test with OpenSSL

> openssl s_server -dtls -accept 5684 -nocert -psk 73757065727365637265746b6579313233 -psk_identity device001 -cipher "PSK-AES128-CCM8:PSK-AES128-CCM:PSK-AES128-CBC-HA"
Returns:

Using default temp DH parameters
ACCEPT
ERROR
4057EA2E827B0000:error:0A0000C1:SSL routines:tls_post_process_client_hello:no shared cipher:../ssl/statem/statem_srvr.c:2220:
shutting down SSL
CONNECTION CLOSED

PSK Used

Identity: device001
Key: supersecretkey123
Confirmed stored under SEC_TAG=42.

Questions to Nordic

Why does modem DTLS not include PSK ciphers in ClientHello?

Is IPPROTO_DTLS_1_2 + TLS_SEC_TAG_LIST enough to enable PSK?

Do we need to explicitly set TLS_DTLS_VERSION, TLS_CIPHERSUITE_LIST, or something undocumented?

Is this a known issue in nRF9151 modem firmware v1.x?

Can you help me to get the DTLS handshake complete with success?

In the final product, the DTLS stuff must coexist with the LwM2M (which I already successfully tested 0m nRF9161 platform using Eclipse Leshan together with lwm2m client sample) one on nRF9151.

Thank you in advance for your support!

Parents
  • Cannot connect to LwM2M server with X509 DTLS. Wireshark shows empty client certificate.

    That's the vice versa. It doesn't work, if certificate and PSK credentials are mixed into one sec_tag.

    You may check, if that applies with

    AT%CMNG=1,42

    If that show's more than your PSK credentials, remove the others.

  • Hello,  AT%%CMNG=1,42 returned:

    42,3,"A4E05CEFA49CFFE2BB25E5E0793625C1199CB4ED83FF1B155BD6591EB043E9F1"

    42,4,"54CCD4B043ECEC38BFB890596F7BD99FC8E6058517882A75F3BF37B9475972A1"

    Which are the result of:

        modem_key_mgmt_write(SEC_TAG, MODEM_KEY_MGMT_CRED_TYPE_IDENTITY,
                             PSK_ID, strlen(PSK_ID));
        modem_key_mgmt_write(SEC_TAG, MODEM_KEY_MGMT_CRED_TYPE_PSK,
                             PSK_KEY, strlen(PSK_KEY));

    So no other credentials than PSK ID and KEY. To be 100% sure the right stuff is injected into the modem now always delete all credentials for tag 42 and then re-enter them using modem_key_mgmt_write.

    *** Booting nRF Connect SDK v3.0.2-89ba1294ac9b ***
    *** Using Zephyr OS v4.0.99-f791c49f492c ***
    [00:00:00.388,000] <inf> main: === LTE + DTLS Handshake Test ===
    [00:00:00.388,000] <inf> main: Client PSK Key (ASCII) hex:
    73 75 70 65 72 73 65 63 72 65 74 6B 65 79 31 32 33 
    [00:00:00.388,336] <inf> main: Initializing modem...
    [00:00:00.646,270] <inf> nrf_modem_lib_trace: Trace thread ready
    [00:00:00.648,071] <inf> nrf_modem_lib_trace: Trace level override: 2
    [00:00:00.792,694] <inf> main: Set CFUN to 0 to reset the SIM: OK

    [00:00:03.031,860] <inf> main: Cleared credentials type 3 fotr Tag 42
    [00:00:03.136,932] <inf> main: Cleared credentials type 4 fotr Tag 42
    [00:00:03.260,986] <inf> main: Credentials of Tag 42 are wiped
    [00:00:03.261,016] <inf> main: Provisioning  Tag 42 with new credentials
    [00:00:03.474,914] <inf> main: New credentials for Tag 42 -> ID:1 PSK:1
    [00:00:06.546,813] <inf> main: Connecting LTE...
    +CEREG: 1,"057D","01017406",7,,,"00001111","00101101"
    [00:00:07.181,976] main: White check mark LTE connected!
    [00:00:07.375,427] <inf> main: Connecting to GIMSServer.mooo.com (84.55.253.71):5684
    [00:00:07.375,732] <inf> main: Performing DTLS handshake with GIMSServer.mooo.com:5684...
    [00:00:07.527,954] main: X DTLS handshake failed, errno=111

    Nothing changed I still get errno=111.

  • I'm assuming NRF uses DTLS 1_2. Is this correct ?

    AFAIK, that's correct. Wireshark shows 1.0 for the record of the Client_Hello, because some implementations interpret the negotiation of the version in that way. The handshake message version is than 1.2. 

    DTLS 1.3 implementations are not that widespread, I mainly know, that wolf SSL has one. 

  • I get compilation errors when I try to build with 3.1.0. Sure this is the fixed code for 3.1.0 ?

    Regards, Joel 

  • west build -b nrf9151dk/nrf9151/ns -p -- -DSNIPPET="nrf91-modem-trace-uart"
    -- west build: generating a build system
    Loading Zephyr module(s) (Zephyr base): sysbuild_default
    -- Found Python3: /usr/bin/python3 (found suitable version "3.10.12", minimum required is "3.10") found components: Interpreter
    -- Cache files will be written to: /home/achim/.cache/zephyr
    -- Found west (found suitable version "1.2.0", minimum required is "0.14.0")
    -- Board: nrf9151dk, qualifiers: nrf9151/ns
    -- Snippet(s): nrf91-modem-trace-uart
    Parsing /home/achim/repos/zephyr/zephyr-coaps-client/zephyr/share/sysbuild/Kconfig
    Loaded configuration '/home/achim/repos/zephyr/zephyr-coaps-client/cellfund_less5_exer2_solution/build/_sysbuild/empty.conf'
    Merged configuration '/home/achim/repos/zephyr/zephyr-coaps-client/cellfund_less5_exer2_solution/build/_sysbuild/empty.conf'
    Configuration saved to '/home/achim/repos/zephyr/zephyr-coaps-client/cellfund_less5_exer2_solution/build/zephyr/.config'
    Kconfig header saved to '/home/achim/repos/zephyr/zephyr-coaps-client/cellfund_less5_exer2_solution/build/_sysbuild/autoconf.h'
    -- 
       ***************************************************
       * Running CMake for cellfund_less5_exer2_solution *
       ***************************************************
    
    Loading Zephyr default modules (Zephyr base).
    -- Application: /home/achim/repos/zephyr/zephyr-coaps-client/cellfund_less5_exer2_solution
    -- CMake version: 4.1.2
    -- Found Python3: /usr/bin/python3 (found suitable version "3.10.12", minimum required is "3.10") found components: Interpreter
    -- Cache files will be written to: /home/achim/.cache/zephyr
    -- Zephyr version: 4.1.99 (/home/achim/repos/zephyr/zephyr-coaps-client/zephyr)
    -- Found west (found suitable version "1.2.0", minimum required is "0.14.0")
    -- Board: nrf9151dk, qualifiers: nrf9151/ns
    -- Snippet(s): nrf91-modem-trace-uart
    -- ZEPHYR_TOOLCHAIN_VARIANT not set, trying to locate Zephyr SDK
    -- Found host-tools: zephyr 0.17.2 (/home/achim/zephyr-sdk-0.17.2)
    -- Found toolchain: zephyr 0.17.2 (/home/achim/zephyr-sdk-0.17.2)
    -- Found Dtc: /home/achim/zephyr-sdk-0.17.2/sysroots/x86_64-pokysdk-linux/usr/bin/dtc (found suitable version "1.7.0", minimum required is "1.4.6")
    -- Found BOARD.dts: /home/achim/repos/zephyr/zephyr-coaps-client/zephyr/boards/nordic/nrf9151dk/nrf9151dk_nrf9151_ns.dts
    -- Found devicetree overlay: /home/achim/repos/zephyr/zephyr-coaps-client/nrf/snippets/nrf91-modem-trace-uart/modem-trace-uart-nrf91.overlay
    -- Generated zephyr.dts: /home/achim/repos/zephyr/zephyr-coaps-client/cellfund_less5_exer2_solution/build/cellfund_less5_exer2_solution/zephyr/zephyr.dts
    -- Generated pickled edt: /home/achim/repos/zephyr/zephyr-coaps-client/cellfund_less5_exer2_solution/build/cellfund_less5_exer2_solution/zephyr/edt.pickle
    -- Generated devicetree_generated.h: /home/achim/repos/zephyr/zephyr-coaps-client/cellfund_less5_exer2_solution/build/cellfund_less5_exer2_solution/zephyr/include/generated/zephyr/devicetree_generated.h
    Parsing /home/achim/repos/zephyr/zephyr-coaps-client/cellfund_less5_exer2_solution/Kconfig
    Loaded configuration '/home/achim/repos/zephyr/zephyr-coaps-client/zephyr/boards/nordic/nrf9151dk/nrf9151dk_nrf9151_ns_defconfig'
    Merged configuration '/home/achim/repos/zephyr/zephyr-coaps-client/cellfund_less5_exer2_solution/prj.conf'
    Merged configuration '/home/achim/repos/zephyr/zephyr-coaps-client/nrf/snippets/nrf91-modem-trace-uart/modem-trace-uart-common.conf'
    Merged configuration '/home/achim/repos/zephyr/zephyr-coaps-client/nrf/snippets/nrf91-modem-trace-uart/modem-trace-uart-nrf91.conf'
    Merged configuration '/home/achim/repos/zephyr/zephyr-coaps-client/cellfund_less5_exer2_solution/build/cellfund_less5_exer2_solution/zephyr/.config.sysbuild'
    Configuration saved to '/home/achim/repos/zephyr/zephyr-coaps-client/cellfund_less5_exer2_solution/build/cellfund_less5_exer2_solution/zephyr/.config'
    Kconfig header saved to '/home/achim/repos/zephyr/zephyr-coaps-client/cellfund_less5_exer2_solution/build/cellfund_less5_exer2_solution/zephyr/include/generated/zephyr/autoconf.h'
    -- Found GnuLd: /home/achim/zephyr-sdk-0.17.2/arm-zephyr-eabi/arm-zephyr-eabi/bin/ld.bfd (found version "2.38")
    -- The C compiler identification is GNU 12.2.0
    -- The CXX compiler identification is GNU 12.2.0
    -- The ASM compiler identification is GNU
    -- Found assembler: /home/achim/zephyr-sdk-0.17.2/arm-zephyr-eabi/bin/arm-zephyr-eabi-gcc
    =========== Generating psa_crypto_config ===============
    Backup: CONFIG_MBEDTLS_PSA_CRYPTO_SPM: False
    Backup: CONFIG_MBEDTLS_PSA_CRYPTO_C: False
    Backup: CONFIG_MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER: False
    Backup: CONFIG_MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT: False
    Backup: CONFIG_MBEDTLS_THREADING_C: True
    Backup: CONFIG_MBEDTLS_THREADING_ALT: False
    =========== Checkpoint: backup ===============
    Restore: CONFIG_MBEDTLS_PSA_CRYPTO_SPM: False
    Restore: CONFIG_MBEDTLS_PSA_CRYPTO_C: False
    Restore: CONFIG_MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER: False
    Restore: CONFIG_MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT: False
    Restore: CONFIG_MBEDTLS_THREADING_C: True
    Restore: CONFIG_MBEDTLS_THREADING_ALT: False
    =========== End psa_crypto_config ===============
    =========== Generating psa_crypto_library_config ===============
    Backup: CONFIG_MBEDTLS_PSA_CRYPTO_C: False
    Backup: CONFIG_MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER: False
    Backup: CONFIG_MBEDTLS_PSA_CRYPTO_SPM: False
    Backup: CONFIG_MBEDTLS_USE_PSA_CRYPTO: True
    Backup: CONFIG_MBEDTLS_PLATFORM_PRINTF_ALT: False
    Backup: CONFIG_MBEDTLS_THREADING_C: True
    Backup: CONFIG_MBEDTLS_THREADING_ALT: False
    =========== Checkpoint: backup ===============
    Restore: CONFIG_MBEDTLS_PSA_CRYPTO_C: False
    Restore: CONFIG_MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER: False
    Restore: CONFIG_MBEDTLS_PSA_CRYPTO_SPM: False
    Restore: CONFIG_MBEDTLS_USE_PSA_CRYPTO: True
    Restore: CONFIG_MBEDTLS_PLATFORM_PRINTF_ALT: False
    Restore: CONFIG_MBEDTLS_THREADING_C: True
    Restore: CONFIG_MBEDTLS_THREADING_ALT: False
    =========== End psa_crypto_library_config ===============
    -- Using ccache: /usr/bin/ccache
    -- Found gen_kobject_list: /home/achim/repos/zephyr/zephyr-coaps-client/zephyr/scripts/build/gen_kobject_list.py
    -- Configuring done (8.2s)
    -- Generating done (0.3s)
    -- Build files have been written to: /home/achim/repos/zephyr/zephyr-coaps-client/cellfund_less5_exer2_solution/build/cellfund_less5_exer2_solution
    Dropping partition 'nonsecure_storage' since it is empty.
    -- Configuring done (12.2s)
    -- Generating done (0.0s)
    -- Build files have been written to: /home/achim/repos/zephyr/zephyr-coaps-client/cellfund_less5_exer2_solution/build
    -- west build: building application
    [5/10] Performing build step for 'cellfund_less5_exer2_solution'
    [1/342] Preparing syscall dependency handling
    
    [5/342] Generating include/generated/zephyr/version.h
    -- Zephyr version: 4.1.99 (/home/achim/repos/zephyr/zephyr-coaps-client/zephyr), build: ncs-v3.1.0-1-gecccacad8c3a
    [12/342] Generating ../../tfm/CMakeCache.txt
    -- Found Git: /usr/bin/git (found version "2.34.1")
    -- The C compiler identification is GNU 12.2.0
    -- The CXX compiler identification is GNU 12.2.0
    -- The ASM compiler identification is GNU
    -- Found assembler: /home/achim/zephyr-sdk-0.17.2/arm-zephyr-eabi/bin/arm-zephyr-eabi-gcc
    -- Found Python3: /usr/bin/python3 (found version "3.10.12") found components: Interpreter
    -- Found Python3: /usr/bin/python3 (found suitable version "3.10.12", minimum required is "3.10") found components: Interpreter
    -- Cache files will be written to: /home/achim/.cache/zephyr
    CMake Warning (dev) at /home/achim/repos/zephyr/zephyr-coaps-client/nrf/modules/trusted-firmware-m/tfm_boards/nrf9120/CMakeLists.txt:24 (install):
      Policy CMP0177 is not set: install() DESTINATION paths are normalized.  Run
      "cmake --help-policy CMP0177" for policy details.  Use the cmake_policy
      command to set the policy and suppress this warning.
    This warning is for project developers.  Use -Wno-dev to suppress it.
    
    -- Configuring done (0.8s)
    -- Generating done (0.1s)
    -- Build files have been written to: /home/achim/repos/zephyr/zephyr-coaps-client/cellfund_less5_exer2_solution/build/cellfund_less5_exer2_solution/tfm
    [17/342] Performing build step for 'tfm'
    [137/141] Linking C executable bin/tfm_s.axf
    Memory region         Used Size  Region Size  %age Used
               FLASH:       32092 B        32 KB     97.94%
                 RAM:       10404 B        32 KB     31.75%
    [141/141] Linking C static library secure_fw/libtfm_s_veneers.a
    [19/342] Performing install step for 'tfm'
    -- Install configuration: "MinSizeRel"
    ----- Installing platform NS -----
    [342/342] Linking C executable zephyr/zephyr.elf
    Memory region         Used Size  Region Size  %age Used
               FLASH:       88928 B       992 KB      8.75%
                 RAM:       25200 B     195224 B     12.91%
            IDT_LIST:          0 GB        32 KB      0.00%
    Generating files from /home/achim/repos/zephyr/zephyr-coaps-client/cellfund_less5_exer2_solution/build/cellfund_less5_exer2_solution/zephyr/zephyr.elf for board: nrf9151dk
    [10/10] Generating ../merged.hex
    
    

    I don't get build errors.

    If the "nrf_modem_at_printf" are added, it may require to add 

    #include <nrf_modem_at.h>

    as well. With that it builds again without errors.

    Just to mention: for the very first tests you don't need your own server, just take leshan or californium. Both will do the handshake. Therefore I only added the lines for the PIN:

            /* 3) Bring modem online */
        nrf_modem_at_printf("AT+CFUN=41");
        k_msleep(2000);
        /* My IoT sim has a PIN */
        nrf_modem_at_printf("AT+CPIN=\"xyza\"");
        k_msleep(1000);

        err = lte_lc_connect_async(lte_handler);

    ( I used to CFUN=41 for SIM only stuff, but I've also tested it with CFUN=1).

    Also with that modification, the client works.

    5808.merged.hex

    (Prebuild image with enabled modem trace and your PIN. If you like use that and check the modem trace with the cellular monitor.)

  • Thanks ... at this point I was able to get the DTLS handshake succeed with this code. If I change the server url to point to my DTLS UDP server or a oepenSSL server instance,I get the usual error 111. 

  • If you would use the Cellular Monitor and provide the ip capture (wireshark), I would easily see, that the error 111 is caused by different things. This ticket started with PSK credentials but the wrong cipher suites (only no PSK). I'm not sure, if this is still the case. I can now change the to your server url, to see, if that really changes the proposed cipher suites, but I would prefer, if you start to provide the traces.

    Once a Nordic engineer works on this, you may anyway need a modem trace.

Reply
  • If you would use the Cellular Monitor and provide the ip capture (wireshark), I would easily see, that the error 111 is caused by different things. This ticket started with PSK credentials but the wrong cipher suites (only no PSK). I'm not sure, if this is still the case. I can now change the to your server url, to see, if that really changes the proposed cipher suites, but I would prefer, if you start to provide the traces.

    Once a Nordic engineer works on this, you may anyway need a modem trace.

Children
No Data
Related