From 91fa8a2b639931f25351710cfbfe35a45c17ca4f Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Mon, 26 Aug 2024 15:44:58 +0200 Subject: [PATCH] tests: net: socket_tls: test different TLS configurations with sockets This commit adds a test to showcase how to configure TLS 1.2 and 1.3 socket connections against an OpenSSL server. Only a limited number of combinations are available for now: - TLS 1.2 - RSA certificate and key exchange. - ECDSA certificate and ECDHE key exchange. - TLS 1.3 only supports ephemeral (ECDHE) key exchange with/without session tickets. Since the goal is to test TLS connection and not low level ethernet functionalities or similar, the only supported platform is "native_sim" where Linux sockets are used to connect to the OpenSSL server locally. The idea is that the Zephyr application acts a client and tries to connect to the OpenSSL server running on the same PC. For sake of simplificity a bash script is provided to start the OpenSSL server properly. For completeness a bash script is also provided to re-generate certificates and keys. Signed-off-by: Valerio Setti --- .../socket/tls_configurations/CMakeLists.txt | 27 ++ tests/net/socket/tls_configurations/Kconfig | 8 + .../credentials/ec-priv.key | 5 + .../tls_configurations/credentials/ec.crt | 10 + .../credentials/rsa-priv.key | 28 ++ .../tls_configurations/credentials/rsa.crt | 19 ++ .../socket/tls_configurations/overlay-ec.conf | 5 + .../tls_configurations/overlay-rsa.conf | 4 + .../tls_configurations/overlay-tls12.conf | 8 + .../tls_configurations/overlay-tls13.conf | 8 + tests/net/socket/tls_configurations/prj.conf | 52 ++++ .../tls_configurations/pytest/conftest.py | 17 ++ .../pytest/test_app_vs_openssl.py | 80 ++++++ .../net/socket/tls_configurations/src/main.c | 254 ++++++++++++++++++ .../socket/tls_configurations/testcase.yaml | 53 ++++ 15 files changed, 578 insertions(+) create mode 100644 tests/net/socket/tls_configurations/CMakeLists.txt create mode 100644 tests/net/socket/tls_configurations/Kconfig create mode 100644 tests/net/socket/tls_configurations/credentials/ec-priv.key create mode 100644 tests/net/socket/tls_configurations/credentials/ec.crt create mode 100644 tests/net/socket/tls_configurations/credentials/rsa-priv.key create mode 100644 tests/net/socket/tls_configurations/credentials/rsa.crt create mode 100644 tests/net/socket/tls_configurations/overlay-ec.conf create mode 100644 tests/net/socket/tls_configurations/overlay-rsa.conf create mode 100644 tests/net/socket/tls_configurations/overlay-tls12.conf create mode 100644 tests/net/socket/tls_configurations/overlay-tls13.conf create mode 100644 tests/net/socket/tls_configurations/prj.conf create mode 100644 tests/net/socket/tls_configurations/pytest/conftest.py create mode 100755 tests/net/socket/tls_configurations/pytest/test_app_vs_openssl.py create mode 100644 tests/net/socket/tls_configurations/src/main.c create mode 100644 tests/net/socket/tls_configurations/testcase.yaml diff --git a/tests/net/socket/tls_configurations/CMakeLists.txt b/tests/net/socket/tls_configurations/CMakeLists.txt new file mode 100644 index 00000000000..d7cb36f6a59 --- /dev/null +++ b/tests/net/socket/tls_configurations/CMakeLists.txt @@ -0,0 +1,27 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(tls_configurations) + +target_sources(app PRIVATE src/main.c) + +set(gen_dir ${ZEPHYR_BINARY_DIR}/include/generated/) + +# Helper function to convert the content of a PEM file (generated by OpenSSL) +# to a C string that can be parsed by Mbed TLS. The format is unchanged, it's +# still PEM, but new lines are replaced by "\n", so that both C compiler and +# Mbed TLS parser are happy. +function(pem_to_mbedtls target input_file) + file(READ credentials/${input_file} input_file_content) + string(REGEX REPLACE "\n" "\\\\n" input_file_content ${input_file_content}) + set(GENERATED_FILE ${gen_dir}/${input_file}.inc) + file(WRITE ${GENERATED_FILE} "\"${input_file_content}\"\n") + generate_unique_target_name_from_filename(${input_file} generated_target_name) + add_custom_target(${generated_target_name} DEPENDS ${GENERATED_FILE}) + add_dependencies(${target} ${generated_target_name}) +endfunction() + +pem_to_mbedtls(app ec.crt) +pem_to_mbedtls(app rsa.crt) diff --git a/tests/net/socket/tls_configurations/Kconfig b/tests/net/socket/tls_configurations/Kconfig new file mode 100644 index 00000000000..e7c74b9f999 --- /dev/null +++ b/tests/net/socket/tls_configurations/Kconfig @@ -0,0 +1,8 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config SERVER_PORT + int "Server port to connect to" + default 4242 + +source "Kconfig.zephyr" diff --git a/tests/net/socket/tls_configurations/credentials/ec-priv.key b/tests/net/socket/tls_configurations/credentials/ec-priv.key new file mode 100644 index 00000000000..782c19d3fa0 --- /dev/null +++ b/tests/net/socket/tls_configurations/credentials/ec-priv.key @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgwecn6Plv8ONZs2cF +IIlr4B4xaoPYEMHm9mSG4esgQ2uhRANCAARVR4/COFJhHmmGdERod/1DhM5hBcq/ +xQHuUtxC1a977tMFCzINWTy155+/E8uj35FUhsLeFMoyGtgvKHKIBpgt +-----END PRIVATE KEY----- diff --git a/tests/net/socket/tls_configurations/credentials/ec.crt b/tests/net/socket/tls_configurations/credentials/ec.crt new file mode 100644 index 00000000000..8ee9a3598fe --- /dev/null +++ b/tests/net/socket/tls_configurations/credentials/ec.crt @@ -0,0 +1,10 @@ +-----BEGIN CERTIFICATE----- +MIIBfDCCASOgAwIBAgIUW0crZnSm9CwlYmnYdDSohFSG5UwwCgYIKoZIzj0EAwIw +FDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI0MDgyNzA5NDcxN1oXDTM0MDgyNTA5 +NDcxN1owFDESMBAGA1UEAwwJbG9jYWxob3N0MFkwEwYHKoZIzj0CAQYIKoZIzj0D +AQcDQgAEVUePwjhSYR5phnREaHf9Q4TOYQXKv8UB7lLcQtWve+7TBQsyDVk8teef +vxPLo9+RVIbC3hTKMhrYLyhyiAaYLaNTMFEwHQYDVR0OBBYEFDi6b5XH5Z5d4cSe +S5OVBHaWjB8SMB8GA1UdIwQYMBaAFDi6b5XH5Z5d4cSeS5OVBHaWjB8SMA8GA1Ud +EwEB/wQFMAMBAf8wCgYIKoZIzj0EAwIDRwAwRAIgMEnVFWqIHRphQtWn5CbXomkH +H/mDhf4ux5k55dmRRH8CIFwL0gYBrp26n0AsRSpVN1RroAt7M1MpCgEycVr3QNMQ +-----END CERTIFICATE----- diff --git a/tests/net/socket/tls_configurations/credentials/rsa-priv.key b/tests/net/socket/tls_configurations/credentials/rsa-priv.key new file mode 100644 index 00000000000..700fc006574 --- /dev/null +++ b/tests/net/socket/tls_configurations/credentials/rsa-priv.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDRaXhTWuxKafRh +fsewYRSRjpeOQJPqY1u38eTFFgcb4oAZOguoubEpJHui3olEWdcyfREx+GsDUo1n +5G6az6m65tCSAKEoFumREhDngt3crdw91hnrnBPjnpCNzeGQ1EqBFbW9mwjp1xQY +pBG0pCwdGIxlzW9ufVrtTbmLp1xcz3U7/RJBwDTX1o+u1oV5mJ9+oYtMQ1b8mOcr +f8Wdg01CWk0ag/C2os07XmRNOCUdO1kh1BHQuPV5K+tgdgHOZdYBBHv8LCgT+FO9 +8r3lhuzVsWTyJLGYYTFnT5b8EtpilnsTDZykmTqzTF3tFejY4OgWS8kmUgEG6QLn ++Q+ewaKxAgMBAAECggEAdA3fgVKCYTsXFHEOedFTdNdxZoSjdOJbkjWccx0iE3IT +S+e/TmKarBJr8nch259ug6yMOwVRSSYW99zA70rm5Y3FSSTQK0eHab55X9RG4GX6 +CMr+0nRNEXhu5CeVOo5sO92sOsgQyIdJu94xccsKJ5XTORgBCVqvaZQJoDvAFC5j +ErZpwYYl0P9Dx/jRSrqC0llOBASj0EMfPVSoImxuiGIKrT+flD2GR0IBJ6BjD+k8 +wgWNdqv8pq4MGs/lodqA8DPnealcCVaCwobIzUWHjjW06m++iFL9d3LDr9rHMDG8 +rp6pE9D2fn8wb43wiTe++n6zFNLnzVfNQS/P33jCAQKBgQD/Gj9+ypciFMuWedDl +9qgmttjzUcEyyAViD4FWSsef98MLgcxDdz9o/BxS4xJUbxPj/lAaakEFVIStoFo5 +Meu5cHGYA35Wm5193g9i7YQI/wLyS/SnHV3O8GixqIwI5Mci/MXbvKb5TwQBRS3+ +3MXqBewL7OTXmkqXmpF9BSE3PQKBgQDSJhJocS8cheIAmWp94SLmTrCuxy1HeDFL +0PiIMlWbxvpdO0RUd1hg1IOk21z/7llwxh8JPtFYcQogJA4/WfBHy4Vqh483SYj8 +8aOrkxbRNE3j3+VSCTZReX6ACRsReHJTktEsI07iU3Bnmpwg2x3d6D4JUqVZA4PX +nbimkP6whQKBgQCCLT/HkNQstRXq9MCwCP1nvBjbmZWQN1ff4W+rvD9AF2u1nIfC +ycBW74f4mB1Lbt9kkesIf74sXSPTgidoVlwm5gVhgC7hPUnR6BZL8k5VVOSJBk+T +U74CEtYqCotjInOoG/tPlWZThInTqBy/mKN6N4lr0Hg6uWZlFKA3fv2jNQKBgGvw +fjgDGs2tvt3L7zTk9MYS2RGM4Kb7B2cH2QArymkPFP3aOUihXFWwEkYVHnmedXZF +bR+Ukna46RiFLIRBr/dQhCCprFgbfy9c9lJkZK3kDbXkBKfUb3/9xYoCI1Mf6Kkg +mivvns8FSJEOiu8dXQPkDClBuAg2k/ul2XhEtWz5AoGBAN8LRCutUDkBT7kr072O +m0fGQFzKq3jN8otsSfdBb40pqZqBCNAn/ojBAc2wcqLMUMHU9cHvEntsXZCbDmmO +5Mx3UF3mUCYAqcl6YCP9qiL6etBqD0q8TGngAT2MoMweh3xaHpSOcT4qISunW5ZG +6LTYdd5z+ab+sHB0pUTrsFER +-----END PRIVATE KEY----- diff --git a/tests/net/socket/tls_configurations/credentials/rsa.crt b/tests/net/socket/tls_configurations/credentials/rsa.crt new file mode 100644 index 00000000000..6dc850751bb --- /dev/null +++ b/tests/net/socket/tls_configurations/credentials/rsa.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDCTCCAfGgAwIBAgIUQxMu5/uGKh0/cmqChP7kIeSFm5wwDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI0MDgyNzA5NDcxN1oXDTM0MDgy +NTA5NDcxN1owFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEA0Wl4U1rsSmn0YX7HsGEUkY6XjkCT6mNbt/HkxRYHG+KA +GToLqLmxKSR7ot6JRFnXMn0RMfhrA1KNZ+Rums+puubQkgChKBbpkRIQ54Ld3K3c +PdYZ65wT456Qjc3hkNRKgRW1vZsI6dcUGKQRtKQsHRiMZc1vbn1a7U25i6dcXM91 +O/0SQcA019aPrtaFeZiffqGLTENW/JjnK3/FnYNNQlpNGoPwtqLNO15kTTglHTtZ +IdQR0Lj1eSvrYHYBzmXWAQR7/CwoE/hTvfK95Ybs1bFk8iSxmGExZ0+W/BLaYpZ7 +Ew2cpJk6s0xd7RXo2ODoFkvJJlIBBukC5/kPnsGisQIDAQABo1MwUTAdBgNVHQ4E +FgQU76/m3HsYiudPteCzusB4UmGFb5UwHwYDVR0jBBgwFoAU76/m3HsYiudPteCz +usB4UmGFb5UwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAXhaB +lnyVhD5NSAEx4K6jCB3qTkk4QX90C2m2WVPP+8CXVcvbGWeSWpRUS4Xh1Cv3Ic1g +Zb+QZL5d+KWwC+u2Ih44bVuO0xNqhya+SBDzF8h/hmeR4dWerwrWUE5NCHzByxDM +tcyKRzINIOta9fSuiacD+k/3I4ns9UcXWLRwAD2g/M03dYir5GjJySW7q9pRxKdy +SvkhZOXdPsDjJveJJztMurox8rsXANsWsMrjJ3EEkhxCZRjdjq0CrCtryHHIJSTf +Cu9MFtWpV1xvJQeIoCKBed076T1XPYUG5q1TO96GZgv+1o6+Mbd8j4myyt2KkuP4 +6tvuNznVD1ykZK3OdQ== +-----END CERTIFICATE----- diff --git a/tests/net/socket/tls_configurations/overlay-ec.conf b/tests/net/socket/tls_configurations/overlay-ec.conf new file mode 100644 index 00000000000..b53dc4bcb55 --- /dev/null +++ b/tests/net/socket/tls_configurations/overlay-ec.conf @@ -0,0 +1,5 @@ +CONFIG_PSA_WANT_ALG_ECDH=y +CONFIG_PSA_WANT_ALG_ECDSA=y +CONFIG_PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC=y +CONFIG_PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE=y +CONFIG_PSA_WANT_ECC_SECP_R1_256=y diff --git a/tests/net/socket/tls_configurations/overlay-rsa.conf b/tests/net/socket/tls_configurations/overlay-rsa.conf new file mode 100644 index 00000000000..c8fc3e29b10 --- /dev/null +++ b/tests/net/socket/tls_configurations/overlay-rsa.conf @@ -0,0 +1,4 @@ +CONFIG_PSA_WANT_ALG_RSA_OAEP=y +CONFIG_PSA_WANT_ALG_RSA_PKCS1V15_CRYPT=y +CONFIG_PSA_WANT_ALG_RSA_PKCS1V15_SIGN=y +CONFIG_PSA_WANT_ALG_RSA_PSS=y diff --git a/tests/net/socket/tls_configurations/overlay-tls12.conf b/tests/net/socket/tls_configurations/overlay-tls12.conf new file mode 100644 index 00000000000..bb53e827e99 --- /dev/null +++ b/tests/net/socket/tls_configurations/overlay-tls12.conf @@ -0,0 +1,8 @@ +CONFIG_MBEDTLS_TLS_VERSION_1_2=y +CONFIG_PSA_WANT_ALG_TLS12_PRF=y +CONFIG_PSA_WANT_KEY_TYPE_AES=y +CONFIG_PSA_WANT_ALG_CBC_NO_PADDING=y +CONFIG_PSA_WANT_ALG_SHA_256=y +CONFIG_PSA_WANT_ALG_SHA_384=y +CONFIG_PSA_WANT_KEY_TYPE_HMAC=y +CONFIG_PSA_WANT_ALG_HMAC=y diff --git a/tests/net/socket/tls_configurations/overlay-tls13.conf b/tests/net/socket/tls_configurations/overlay-tls13.conf new file mode 100644 index 00000000000..5c311f3027c --- /dev/null +++ b/tests/net/socket/tls_configurations/overlay-tls13.conf @@ -0,0 +1,8 @@ +CONFIG_MBEDTLS_TLS_VERSION_1_3=y +CONFIG_PSA_WANT_ALG_HKDF_EXTRACT=y +CONFIG_PSA_WANT_ALG_HKDF_EXPAND=y + +CONFIG_PSA_WANT_ALG_GCM=y +CONFIG_PSA_WANT_KEY_TYPE_AES=y +CONFIG_PSA_WANT_ALG_CBC_NO_PADDING=y +CONFIG_PSA_WANT_ALG_SHA_256=y diff --git a/tests/net/socket/tls_configurations/prj.conf b/tests/net/socket/tls_configurations/prj.conf new file mode 100644 index 00000000000..93a8c0f8b12 --- /dev/null +++ b/tests/net/socket/tls_configurations/prj.conf @@ -0,0 +1,52 @@ +# Kernel options +CONFIG_MAIN_STACK_SIZE=4096 +CONFIG_POSIX_API=y +CONFIG_HEAP_MEM_POOL_SIZE=2048 + +# Generic networking options +CONFIG_NETWORKING=y + +# Socket +CONFIG_NET_SOCKETS=y +CONFIG_NET_SOCKETS_SOCKOPT_TLS=y + +# Disable native ethernet driver (using native sockets instead) +CONFIG_ETH_NATIVE_POSIX=n + +# Use native sockets +CONFIG_NET_SOCKETS=y +CONFIG_NET_SOCKETS_OFFLOAD=y +CONFIG_NET_DRIVERS=y +CONFIG_NET_NATIVE_OFFLOADED_SOCKETS=y + +# Mbed TLS configuration +CONFIG_MBEDTLS=y +CONFIG_MBEDTLS_BUILTIN=y +CONFIG_MBEDTLS_ENABLE_HEAP=y +CONFIG_MBEDTLS_HEAP_SIZE=60000 +CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=2048 +CONFIG_MBEDTLS_PEM_CERTIFICATE_FORMAT=y +# Build the PSA Crypto core so that the TLS stack uses the PSA crypto API. +CONFIG_MBEDTLS_PSA_CRYPTO_C=y +CONFIG_MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG=y +CONFIG_ENTROPY_GENERATOR=y + +# Disable some Kconfigs that are implied by CONFIG_NET_SOCKETS_SOCKOPT_TLS. +# These are not wrong in general, but specific to a certain case (TLS 1.2 + RSA +# key exchange/certificate + AES encryption). What we want here instead is to +# have a basic configuration in this "prj.conf" file and then add algorithm +# support in overlay files. +CONFIG_MBEDTLS_TLS_VERSION_1_2=n +CONFIG_MBEDTLS_KEY_EXCHANGE_RSA_ENABLED=n +CONFIG_MBEDTLS_CIPHER_AES_ENABLED=n +CONFIG_PSA_WANT_KEY_TYPE_AES=n +CONFIG_PSA_WANT_ALG_CBC_NO_PADDING=n + +# Logging +CONFIG_LOG=y +CONFIG_PRINTK=y + +# Debug log options (optional) +# CONFIG_NET_LOG=y +# CONFIG_MBEDTLS_LOG_LEVEL_DBG=y +# CONFIG_MBEDTLS_DEBUG=y diff --git a/tests/net/socket/tls_configurations/pytest/conftest.py b/tests/net/socket/tls_configurations/pytest/conftest.py new file mode 100644 index 00000000000..4546d15594a --- /dev/null +++ b/tests/net/socket/tls_configurations/pytest/conftest.py @@ -0,0 +1,17 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +import pytest + +def pytest_addoption(parser): + parser.addoption('--server-type') + parser.addoption('--port') + +@pytest.fixture() +def server_type(request): + return request.config.getoption('--server-type') + +@pytest.fixture() +def port(request): + return request.config.getoption('--port') diff --git a/tests/net/socket/tls_configurations/pytest/test_app_vs_openssl.py b/tests/net/socket/tls_configurations/pytest/test_app_vs_openssl.py new file mode 100755 index 00000000000..0d5ed654ee6 --- /dev/null +++ b/tests/net/socket/tls_configurations/pytest/test_app_vs_openssl.py @@ -0,0 +1,80 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +import logging +import os +import subprocess +from twister_harness import DeviceAdapter + +logger = logging.getLogger(__name__) + +def get_arguments_from_server_type(server_type, port): + this_path = os.path.dirname(os.path.abspath(__file__)) + certs_path = os.path.join(this_path, "..", "credentials") + + args = ["openssl", "s_server"] + if server_type == "1.2-rsa": + args.extend(["-cert", "{}/rsa.crt".format(certs_path), + "-key", "{}/rsa-priv.key".format(certs_path), + "-certform", "PEM", + "-tls1_2", + "-cipher", "AES128-SHA256,AES256-SHA256"]) + elif server_type == "1.2-ec": + args.extend(["-cert", "{}/ec.crt".format(certs_path), + "-key", "{}/ec-priv.key".format(certs_path), + "-certform", "PEM", + "-tls1_2", + "-cipher", "ECDHE-ECDSA-AES128-SHA256"]) + elif server_type == "1.3-ephemeral": + args.extend(["-cert", "{}/ec.crt".format(certs_path), + "-key", "{}/ec-priv.key".format(certs_path), + "-certform", "PEM", + "-tls1_3", + "-ciphersuites", "TLS_AES_128_GCM_SHA256", + "-num_tickets", "0"]) + elif server_type == "1.3-ephemeral-tickets": + args.extend(["-cert", "{}/ec.crt".format(certs_path), + "-key", "{}/ec-priv.key".format(certs_path), + "-certform", "PEM", + "-tls1_3", + "-ciphersuites", "TLS_AES_128_GCM_SHA256"]) + elif server_type == "1.3-psk-tickets": + args.extend(["-tls1_3", + "-ciphersuites", "TLS_AES_128_GCM_SHA256", + "-psk_identity", "PSK_identity", "-psk", "0102030405", + "-allow_no_dhe_kex", "-nocert"]) + else: + raise Exception("Wrong server type") + + args.extend(["-serverpref", "-state", "-debug", "-status_verbose", "-rev", + "-accept", "{}".format(port)]) + return args + +def start_server(server_type, port): + logger.info("Server type: " + server_type) + args = get_arguments_from_server_type(server_type, port) + logger.info("Launch command:") + print(" ".join(args)) + openssl = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + + try: + openssl.wait(1) + logger.error("Server startup failed. Here's the logs from OpenSSL:") + for line in openssl.stdout.readlines(): + logger.error(line) + raise Exception("Server startup failed") + except subprocess.TimeoutExpired: + logger.info("Server is up") + + return openssl + +def test_app_vs_openssl(dut: DeviceAdapter, server_type, port): + server = start_server(server_type, port) + + logger.info("Launch Zephyr application") + dut.launch() + dut.readlines_until("Test PASSED", timeout=3.0) + + logger.info("Kill server") + server.kill() diff --git a/tests/net/socket/tls_configurations/src/main.c b/tests/net/socket/tls_configurations/src/main.c new file mode 100644 index 00000000000..35598ee5759 --- /dev/null +++ b/tests/net/socket/tls_configurations/src/main.c @@ -0,0 +1,254 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright (c) 2024 Nordic Semiconductor ASA + */ + +#include +LOG_MODULE_REGISTER(tls_configuration_sample, LOG_LEVEL_INF); + +#include +#include +#include + +#include + +#include +#include +#include +#include + +/* This include is required for the definition of the Mbed TLS internal symbol + * MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED. + */ +#include + +#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED) +static const unsigned char psk[] = { 0x01, 0x02, 0x03, 0x04, 0x05 }; +static const char psk_id[] = "PSK_identity"; +#endif /* MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED */ + +/* Following certificates (*.inc files) are: + * - generated from "create-certs.sh" script + * - converted in C array shape in the CMakeList file + */ +#if defined(CONFIG_PSA_WANT_ALG_RSA_PKCS1V15_SIGN) || defined(CONFIG_PSA_WANT_ALG_RSA_PSS) +#define USE_CERTIFICATE +static const unsigned char certificate[] = { +#include "rsa.crt.inc" +}; +#elif defined(CONFIG_PSA_WANT_ALG_ECDSA) +#define USE_CERTIFICATE +static const unsigned char certificate[] = { +#include "ec.crt.inc" +}; +#endif + +#define APP_BANNER "TLS socket configuration sample" + +#define INVALID_SOCKET (-1) + +enum { + _PLACEHOLDER_TAG_ = 0, +#if defined(USE_CERTIFICATE) + CA_CERTIFICATE_TAG, +#endif +#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED) + PSK_TAG, +#endif +}; + +static int socket_fd = INVALID_SOCKET; +static struct pollfd fds[1]; + +/* Keep the new line because openssl uses that to start processing the incoming data */ +#define TEST_STRING "hello world\n" +static uint8_t test_buf[sizeof(TEST_STRING)]; + +static int wait_for_event(void) +{ + int ret; + + /* Wait for event on any socket used. Once event occurs, + * we'll check them all. + */ + ret = poll(fds, ARRAY_SIZE(fds), -1); + if (ret < 0) { + LOG_ERR("Error in poll (%d)", errno); + return ret; + } + + return 0; +} + +static int create_socket(void) +{ + int ret = 0; + struct sockaddr_in addr; + + addr.sin_family = AF_INET; + addr.sin_port = htons(CONFIG_SERVER_PORT); + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr); + +#if defined(CONFIG_MBEDTLS_TLS_VERSION_1_3) + socket_fd = socket(addr.sin_family, SOCK_STREAM, IPPROTO_TLS_1_3); +#else + socket_fd = socket(addr.sin_family, SOCK_STREAM, IPPROTO_TLS_1_2); +#endif + if (socket_fd < 0) { + LOG_ERR("Failed to create TLS socket (%d)", errno); + return -errno; + } + + sec_tag_t sec_tag_list[] = { +#if defined(USE_CERTIFICATE) + CA_CERTIFICATE_TAG, +#endif +#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED) + PSK_TAG, +#endif + }; + + ret = setsockopt(socket_fd, SOL_TLS, TLS_SEC_TAG_LIST, + sec_tag_list, sizeof(sec_tag_list)); + if (ret < 0) { + LOG_ERR("Failed to set TLS_SEC_TAG_LIST option (%d)", errno); + return -errno; + } + + /* HOSTNAME is only required for key exchanges that use a certificate. */ +#if defined(USE_CERTIFICATE) + ret = setsockopt(socket_fd, SOL_TLS, TLS_HOSTNAME, + "localhost", sizeof("localhost")); + if (ret < 0) { + LOG_ERR("Failed to set TLS_HOSTNAME option (%d)", errno); + return -errno; + } +#endif + + ret = connect(socket_fd, (struct sockaddr *) &addr, sizeof(addr)); + if (ret < 0) { + LOG_ERR("Cannot connect to TCP remote (%d)", errno); + return -errno; + } + + /* Prepare file descriptor for polling */ + fds[0].fd = socket_fd; + fds[0].events = POLLIN; + + return ret; +} + +void close_socket(void) +{ + if (socket_fd != INVALID_SOCKET) { + close(socket_fd); + } +} + +static int setup_credentials(void) +{ + int err; + +#if defined(USE_CERTIFICATE) + err = tls_credential_add(CA_CERTIFICATE_TAG, + TLS_CREDENTIAL_CA_CERTIFICATE, + certificate, + sizeof(certificate)); + if (err < 0) { + LOG_ERR("Failed to register certificate: %d", err); + return err; + } +#endif + +#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED) + err = tls_credential_add(PSK_TAG, + TLS_CREDENTIAL_PSK, + psk, + sizeof(psk)); + if (err < 0) { + LOG_ERR("Failed to register PSK: %d", err); + } + err = tls_credential_add(PSK_TAG, + TLS_CREDENTIAL_PSK_ID, + psk_id, + sizeof(psk_id) - 1); + if (err < 0) { + LOG_ERR("Failed to register PSK ID: %d", err); + } +#endif + + return 0; +} + +int main(void) +{ + int ret; + size_t data_len; + + LOG_INF(APP_BANNER); + + setup_credentials(); + + ret = create_socket(); + if (ret < 0) { + LOG_ERR("Socket creation failed (%d)", ret); + goto exit; + } + + memcpy(test_buf, TEST_STRING, sizeof(TEST_STRING)); + /* The -1 here is because sizeof() accounts for "\0" but that's not + * needed for socket functions send/recv. + */ + data_len = sizeof(TEST_STRING) - 1; + + /* OpenSSL s_server has only the "-rev" option as echo-like behavior + * which echoes back the data that we send it in reversed order. So + * in the following we send the test buffer twice (in the 1st iteration + * it will contain the original TEST_STRING, whereas in the 2nd one + * it will contain TEST_STRING reversed) so that in the end we can + * just memcmp() it against the original TEST_STRING. + */ + for (int i = 0; i < 2; i++) { + LOG_DBG("Send: %s", test_buf); + ret = send(socket_fd, test_buf, data_len, 0); + if (ret < 0) { + LOG_ERR("Error sending test string (%d)", errno); + goto exit; + } + + memset(test_buf, 0, sizeof(test_buf)); + + wait_for_event(); + + ret = recv(socket_fd, test_buf, data_len, MSG_WAITALL); + if (ret == 0) { + LOG_ERR("Server terminated unexpectedly"); + ret = -EIO; + goto exit; + } else if (ret < 0) { + LOG_ERR("Error receiving data (%d)", errno); + goto exit; + } + if (ret != data_len) { + LOG_ERR("Sent %d bytes, but received %d", data_len, ret); + ret = -EINVAL; + goto exit; + } + LOG_DBG("Received: %s", test_buf); + } + + ret = memcmp(TEST_STRING, test_buf, data_len); + if (ret != 0) { + LOG_ERR("Received data does not match with TEST_STRING"); + LOG_HEXDUMP_ERR(test_buf, data_len, "Received:"); + LOG_HEXDUMP_ERR(TEST_STRING, data_len, "Expected:"); + ret = -EINVAL; + } + +exit: + LOG_INF("Test %s", (ret < 0) ? "FAILED" : "PASSED"); + + close_socket(); + + return 0; +} diff --git a/tests/net/socket/tls_configurations/testcase.yaml b/tests/net/socket/tls_configurations/testcase.yaml new file mode 100644 index 00000000000..90236eaf067 --- /dev/null +++ b/tests/net/socket/tls_configurations/testcase.yaml @@ -0,0 +1,53 @@ +common: + tags: + - crypto.mbedtls + - net.socket + platform_allow: + - native_sim + - native_sim/native/64 + integration_platforms: + - native_sim + harness: pytest +tests: + net.sockets.tls12.rsa_kex: + extra_args: + - EXTRA_CONF_FILE=overlay-tls12.conf;overlay-rsa.conf + extra_configs: + - CONFIG_MBEDTLS_KEY_EXCHANGE_RSA_ENABLED=y + - CONFIG_SERVER_PORT=4000 + harness_config: + pytest_args: ["--server-type", "1.2-rsa", "--port", "4000"] + net.sockets.tls12.ec_kex: + extra_args: + - EXTRA_CONF_FILE=overlay-tls12.conf;overlay-ec.conf + extra_configs: + - CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED=y + - CONFIG_SERVER_PORT=4001 + harness_config: + pytest_args: ["--server-type", "1.2-ec", "--port", "4001"] + net.sockets.tls13.ephemeral_kex: + extra_args: + - EXTRA_CONF_FILE=overlay-tls13.conf;overlay-ec.conf + extra_configs: + - CONFIG_MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED=y + - CONFIG_SERVER_PORT=4002 + harness_config: + pytest_args: ["--server-type", "1.3-ephemeral", "--port", "4002"] + net.sockets.tls13.ephemeral_kex.tickets: + extra_args: + - EXTRA_CONF_FILE=overlay-tls13.conf;overlay-ec.conf + extra_configs: + - CONFIG_MBEDTLS_TLS_SESSION_TICKETS=y + - CONFIG_MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED=y + - CONFIG_SERVER_PORT=4003 + harness_config: + pytest_args: ["--server-type", "1.3-ephemeral-tickets", "--port", "4003"] + net.sockets.tls13.psk_kex.tickets: + extra_args: + - EXTRA_CONF_FILE=overlay-tls13.conf + extra_configs: + - CONFIG_MBEDTLS_TLS_SESSION_TICKETS=y + - CONFIG_MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED=y + - CONFIG_SERVER_PORT=4004 + harness_config: + pytest_args: ["--server-type", "1.3-psk-tickets", "--port", "4004"]