Hello,
i ran nRF Coap Client and it worked pretty well.
I am working with nRF9160 DK.
Now, I want to add DTLS to this example to secure the data.
Can someone please help me or is there any tutorials on how to do that?
Best regards,
Cedric
Hello,
i ran nRF Coap Client and it worked pretty well.
I am working with nRF9160 DK.
Now, I want to add DTLS to this example to secure the data.
Can someone please help me or is there any tutorials on how to do that?
Best regards,
Cedric
Hello Cedric,
please be aware that DTLS only is experimental and not officially supported in NCS. Except from enabling the mentioned configuration parameter, you have to reconfigure the socket using a DTLS protocol type.
I recommend you to have a look at the Echo Client sample, which demonstrates the usage of the corresponding API.
Regards,
Markus
Hi Markus,
thanks very much for your reply.
I used nRF Connect Trace Collector to capture the trace files of the modem, so i could see if the encrytion has done, but i had some issues with it.
Here is the trace as attachment, you can open it with wireshark and have a look at it and please help me find a solution for the issue.
trace-LTE-M-mit Verschlüsselung.pcapng
Best regards,
Cedric
ced27 said:Here is the trace as attachment, you can open it with wireshark and have a look at it and please help me find a solution for the issue.
Honestly, I’m not quite sure what issue you have. Can you elaborate?
Regards,
Markus
Honestly, I’m not quite sure what issue you have. Can you elaborate?
Actually i am having problems with DTLS connection and my aim is to be able to encrypt all data with a Pre Shared Key (PSK) before sending it to the server.
Here is a sample of my code:
/* * Copyright (c) 2020 Nordic Semiconductor ASA * * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause */ #include <zephyr.h> #include <stdio.h> #include <modem/lte_lc.h> #include <net/socket.h> #include <random/rand32.h> #include <net/coap.h> #include <modem/nrf_modem_lib.h> #include <logging/log.h> #include <sys/printk.h> #include <modem/modem_key_mgmt.h> #include <net/tls_credentials.h> #include <nrfx.h> #include <nrf_socket.h> #include "ui.h" #include "config.h" #define PAYLOAD_BYTES 100 #define PSK_TAG 2 static int sock; // BSD socket API static struct sockaddr_storage server; // structure für CoAP-Server- Addressinformation. static uint16_t token; // request ID static struct pollfd fds; // Benutzeroberflächenmodul. static void ui_evt_handler(struct ui_evt *evt) // Event-Handler für LEDS { if (!evt) { return; } } static int dtls_init(void){ int err; #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS) && defined(CONFIG_MODEM_KEY_MGMT) err = modem_key_mgmt_write(PSK_TAG, MODEM_KEY_MGMT_CRED_TYPE_PSK, client_psk, strlen(client_psk)); if (err < 0) { printk("Bereitstellung des PSK fehlgeschlagen: %d", err); return err; } err = modem_key_mgmt_write(PSK_TAG, MODEM_KEY_MGMT_CRED_TYPE_IDENTITY, psk_id, strlen(psk_id) - 1); if (err < 0) { printk("Bereitstellung der PSK-ID fehlgeschlagen: %d", err); return err; } #endif #if defined(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) // Provision Client PSK. err = tls_credential_add(PSK_TAG, TLS_CREDENTIAL_PSK, client_psk, sizeof(client_psk)); if (err < 0) { printk("Fehler beim Registrieren von PSK: %d", err); return err; } // Provision Client Identity. err = tls_credential_add(PSK_TAG, TLS_CREDENTIAL_PSK_ID, psk_id, sizeof(psk_id) - 1); if (err < 0) { printk("Fehler beim Registrieren von PSK ID: %d", err); return err; } #endif return 0; } static int server_initialisieren(void) { struct sockaddr_in *server4 = ((struct sockaddr_in *)&server); // Socket-Adressstruktur für IPv4 server4->sin_family = AF_INET; // AF_INET = IP Protokoll Version 4 (IPv4) server4->sin_port = htons(CONFIG_SERVER_PORT); //Schreibe Port in Network-Byte-Order in das Feld sin_port inet_pton(AF_INET, CONFIG_SERVER_ADDRESS, &server4->sin_addr); // Schreibe IP-Adresse des Servers in die sockaddr_in-Struktur return 0; } static int server_verbinden(void) { int err; sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_DTLS_1_2); // Erzeuge Socket. SOCK_DGRAM = Datagram socket type // IPPROTO_DTLS_1_2 = DTLS 1.2 protocol sec_tag_t sec_tag_opt[] = {TLS_CREDENTIAL_PSK}; err = nrf_setsockopt(sock, NRF_SOL_SECURE, TLS_SEC_TAG_LIST, sec_tag_opt, sizeof(sec_tag_opt) * ARRAY_SIZE(sec_tag_opt)); // sock=0 => success, sock<0 => fehler if (sock < 0) { printk("Fehler beim Erstellen des CoAP/UDP-Sockets: error %d\n", errno); err = -errno; goto error; } err = connect(sock, (struct sockaddr *)&server, sizeof(struct sockaddr_in)); // Verbindung zum Server herstellen // err=0 => success, err<0 => fehler if (err < 0) { printk("Verbindung fehlgeschlagen: error %d\n", errno); err = -errno; goto error; } /* Initialize FDS, for poll. */ fds.fd = sock; fds.events = POLLIN; /* Randomize token. */ token = sys_rand32_get(); return 0; error: (void)close(sock); // beende die Verbindung zum Socket return err; } static int uebertragung_zu_server_fn(void) { int err; struct coap_packet request; // Anfragepaket uint8_t data[CONFIG_DATA_UPLOAD_SIZE_BYTES]; // Maximale Nachrichtgröße const char payload[PAYLOAD_BYTES]="AAAAAAAAAAAAAAAAAAAAAAAAAAAA"; // Payload, der übertragen wird char uri_path[] = "test"; //Coap Ressource: Californium test Ressouce (URI) // Initialisiere CoAP Anfrage err = coap_packet_init(&request, data, sizeof(data), 1, COAP_TYPE_NON_CON, 0, NULL,COAP_METHOD_PUT, coap_next_id()); if (err < 0) { printk("CoAP-Anfrage konnte nicht erstellt werden, error %d\n", err); return err; } // Fügt eine Option an das Paket an coap_packet_append_option(&request, COAP_OPTION_URI_PATH, uri_path, strlen(uri_path)); // Payload-Marker an CoAP-Paket anhängen coap_packet_append_payload_marker(&request); // Payload an CoAP-Paket anhängen err=coap_packet_append_payload(&request, (uint8_t *)payload, sizeof(payload) - 1); if (err < 0) { printk("Payload konnte nicht angehängt werden, %d\n", err); return err; } err = send(sock, request.data, request.offset, 0); // Daten werden an den Port 5683 gesendet if (err < 0) { printk("Paket konnte nicht übertragen werden,error %d\n", errno); return -errno; } printk("CoAP Anfrage gesendet: token 0x%04x\n", token); printk("Payload von %d bytes wird an die ", sizeof(payload)); // CONFIG_SERVER_ADDRESS = californium.eclipseproject.io // CONFIG_SERVER_PORT = 5683 printk("IP Adresse %s, Port Nummer %d übertragen\n", CONFIG_SERVER_ADDRESS, CONFIG_SERVER_PORT); return 0; } // Ein Semaphore ist ein Kernel-Objekt, das ein traditionelles Zählsemaphor implementiert. // Ein Semaphor wird verwendet, um den Zugriff auf eine Reihe von Ressourcen durch mehrere // Threads zu steuern und um die Verarbeitung zwischen einem produzierenden und einem // verbrauchenden Thread oder Interrupt Service Routine (ISRs) zu synchronisieren. static K_SEM_DEFINE(lte_verbunden, 0, 1); // Semaphore statisch definiert und initialisiert. // lte_verbunden = Name des Semaphores. 0 = anfängliche Semaphorezählung // 1 = maximal zulässige Semaphoranzahl. static void lte_handler(const struct lte_lc_evt *const evt) { switch (evt->type) { case LTE_LC_EVT_NW_REG_STATUS: // emfangenes Ereignis mit Informationen zum Netwerkregistrierungsstatus // des Modems if ((evt->nw_reg_status != LTE_LC_NW_REG_REGISTERED_HOME) && (evt->nw_reg_status != LTE_LC_NW_REG_REGISTERED_ROAMING)) { break; } printk("Netwerkregistrierungsstatus: %s", evt->nw_reg_status == LTE_LC_NW_REG_REGISTERED_HOME ? "verbunden mit Heimnetwerk\n" : "verbunden mit Roaming\n"); k_sem_give(<e_verbunden); // Gib ein Semaphor an. Setzte die Zählung von lte_verbunden auf Null break; // <e_verbunden= Adresse des Semapores case LTE_LC_EVT_PSM_UPDATE: // empfangenes Ereignis mit Informationen zu PSM-Updates. Die Updates enthalten // PSM-Parameter, die vom Netwerk vorgeben wurden. // Das zugehörige Payload ist das Mitglied psm_cfg vom Typ lte_lc_psm_cfg in dem Library lte.lc.h // tau = Periodisches Aktualisierungsintervall des Tracking-Bereichs. // active_time = Aktiv-Zeit (Zeit von RRC Leerlauf bis PSM) printk("PSM-Parameter update: TAU: %d, Active time: %d\n", evt->psm_cfg.tau, evt->psm_cfg.active_time); break; case LTE_LC_EVT_EDRX_UPDATE:{// empfangenes Ereignis mit Informationen zu eDRX-Updates. Die Updates enthalten // eDRX-Parameter, die vom Netwerk vorgeben wurden. // Das zugehörige Payload ist das Mitglied edrx_cfg vom Typ lte_lc_edrx_cfg in dem Library lte.lc.h // edrx = eDRX-Intervallwert [s] // ptw = Paging-Zeitfenster [s] char log_buf[60]; ssize_t len; len = snprintf(log_buf, sizeof(log_buf), "eDRX parameter update: eDRX: %f, PTW: %f\n", evt->edrx_cfg.edrx, evt->edrx_cfg.ptw); if (len > 0) { printk("%s\n", log_buf); } break; } case LTE_LC_EVT_RRC_UPDATE: // empfangenes Ereignis mit Informationen über den // Radio Ressource Control(RRC)-Status des Modems // Das zugehörige Payload ist das Mitglied rrc_mode vom Typ lte_lc_rrc_mode in dem Library lte.lc.h // RRC Modus ist entweder verbunden oder idle. printk("RRC Modus: %s", evt->rrc_mode == LTE_LC_RRC_MODE_CONNECTED ? "verbunden\n" : "Idle\n"); break; case LTE_LC_EVT_CELL_UPDATE: // empfangenes Ereignis mit Informationen über die aktuell verbundene Zelle // Das zugehörige Payload ist das Mitglied Cell vom Typ lte_lc_cell in dem Library lte.lc.h // id = Mobilfunkzellenidentifikation // tac = Tracking area code printk("LTE veränderte Zelle: Zelle ID: %d, Tracking area: %d\n", evt->cell.id, evt->cell.tac); break; case LTE_LC_EVT_LTE_MODE_UPDATE: // Wenn ein Systemmodus konfiguiert ist,der entweder LTE-M oder NB-IoT // aktiviert, kann das Modem den aktuell aktiven LTE-Modus basierend auf // der Netwerkverfügbarkeit ändern. Dieses Ereignis zeigt dann an, welcher // LTE-Modus derzeit vom Modem verwendet wird. printk("Active LTE Modus: %s", evt->lte_mode == LTE_LC_LTE_MODE_NONE ? "None\n" : evt->lte_mode == LTE_LC_LTE_MODE_LTEM ? "LTE-M\n" : evt->lte_mode == LTE_LC_LTE_MODE_NBIOT ? "NB-IoT\n" : "Unknown\n"); break; default: break; } } static void modem_konfigurieren(void) { #if defined(CONFIG_NRF_MODEM_LIB) // CONFIG_NRF_MODEM_LIB = verwende Nordic Modem Library if (IS_ENABLED(CONFIG_LTE_AUTO_INIT_AND_CONNECT)) { // CONFIG_LTE_AUTO_INIT_AND_CONNECT = automatische Registrierung bei LTE-M oder NB-IoT // passiert nichts, falls der Modem bereits konfiguriert und LTE verbunden ist. } else { int err; // integer für errors #if defined(CONFIG_PSM_ENABLE) // CONFIG_PSM_ENABLE fordert PSM vom Modbilfunknetz an. /* Das Anfordern von PSM vor der Verbindung ermöglicht es dem Modem, das * Netwerk bereits während des Verbindungsvorgangs über unseren Wunsch * nach einer bestimmten PSM-Konfiguration zu informieren, anstatt in * einer separaten Anfrage nach der Verbindungsherstellung, die in einigen * Netzwerken abgelehnt werden kann */ err = lte_lc_psm_req(true); // Anfordern des Modems, das Power saving mode zu aktivieren if (err < 0) { // Falls err= negativ => Fehler aufgetreten printk("Power Saving Mode wurde nicht aktiviert, error: %d\n", err); } else{ // falls err=0 => das Anfordern war erfolgreich printk("PSM-Modus aktiviert\n\n"); } #endif #if defined(CONFIG_EDRX_ENABLE) // CONFIG_EDRX_ENABLE fordert eDRX vom Modbilfunknetz an. /** Extended Discontinuous Reception (eDRX) ermöglicht es das Sleep mode in RRC idle mode auf Minuten oder Stunden zu verlängern, was noch deutlichere Einsparungen beim Energieverbrauch bietet*/ err = lte_lc_edrx_req(true); // eDRX wird aktiviert if (err<0) { printk("eDRX wurde nicht aktiviert, error: %d\n", err); }else { printk("eDRX aktiviert\n"); } #endif ui_led_set_pattern(UI_LTE_CONNECTING); // LED3 blinkt, um der Verbindungsherstellungsvorgang // zu signalisieren. printk("Verbindung zum LTE-Netz wird hergestellt\n"); printk("Das kann ein paar Minuten dauern..\n"); // lte_lc_init_and_connect_async initialisiert das LTE-Modul, // konfiguriert das Modem und verbindet sich mit dem LTE-Netzwerk. // lte_lc_init_and_connect_async überprüft zusätzlich die LTE-Ereignisse // vom Typ LTE_LC_EVT_NW_REG_STATUS in lte_handler(), um festzustellen, wann // die LTE-Verbindung besteht. err = lte_lc_init_and_connect_async(lte_handler); if (err) { // err= negativ => Fehler aufgetreten printk("Modem konnte nicht konfiguriert werden, error: %d\n", err); return; } // err=0 => besteht LTE-Verbindung printk("Mit LTE-Netz verbunden\n"); ui_led_set_pattern(UI_LTE_CONNECTED); // LED3 leuchtet, um das Bestehen der Verbindung vorzugeben. } #endif } /* Gibt 0 zurück, wenn Daten verfügbar sind. * Gibt -EAGAIN zurück, wenn eine Zeitüberschreitung aufgetreten ist und keine Daten geschickt sind. * Gibt im Falle eines Poll-Fehlers einen anderen, negativen Fehlercode zurück. */ static int wait(int timeout) { int ret = poll(&fds, 1, timeout); if (ret < 0) { printk("poll error: %d\n", errno); return -errno; } if (ret == 0) { /* Timeout. */ return -EAGAIN; } if ((fds.revents & POLLERR) == POLLERR) { printk("warte: POLLERR\n"); return -EIO; } if ((fds.revents & POLLNVAL) == POLLNVAL) { printk("warte: POLLNVAL\n"); return -EBADF; } if ((fds.revents & POLLIN) != POLLIN) { return -EAGAIN; } return 0; } void main(void) { int64_t next_msg_time = CONFIG_DATA_UPLOAD_FREQUENCY_MS; int err; printk("Startet.....\n"); err = dtls_init(); if (err<0) { printk("DTLS Init Error: %d\n", err); } // Initialisiere das Benutzeroberflächenmodul ui_init(ui_evt_handler); // Modem wird konfiguriert #if defined(CONFIG_NRF_MODEM_LIB) modem_konfigurieren(); k_sem_take(<e_verbunden, K_FOREVER); #endif next_msg_time = k_uptime_get(); // Verbindungsaufbau des Clients zu dem Server err = server_initialisieren(); if (err) { printk("Serververbindung kann nicht initialisiert werden\n"); return; } // Verbindung zum Server herstellen err = server_verbinden(); if (err) { printk("Keine Verbindung zum Server möglich\n"); return; } while (1) { if (k_uptime_get() >= next_msg_time) { if (uebertragung_zu_server_fn() != 0) { printk("Fehler beim Senden der Anfrage, exit...\n"); break; } next_msg_time += CONFIG_DATA_UPLOAD_FREQUENCY_MS; } int64_t remaining = next_msg_time - k_uptime_get(); if (remaining < 0) { remaining = 0; } err = wait(remaining); if (err < 0) { if (err == -EAGAIN) { continue; } printk("Poll error, exit...\n"); break; } } }
Best regards,
Cedric
ced27 said:Actually i am having problems with DTLS connection
The device initiates the DTLS handshake with a "Client Hello", which is correct.
The problem appears to be the destination, which is 0.0.0.0. Which server/IP address are you trying to connect to? What is CONFIG_SERVER_ADRESS defined as?
static int server_initialisieren(void) { struct sockaddr_in *server4 = ((struct sockaddr_in *)&server); // Socket-Adressstruktur für IPv4 server4->sin_family = AF_INET; // AF_INET = IP Protokoll Version 4 (IPv4) server4->sin_port = htons(CONFIG_SERVER_PORT); //Schreibe Port in Network-Byte-Order in das Feld sin_port inet_pton(AF_INET, CONFIG_SERVER_ADDRESS, &server4->sin_addr); // Schreibe IP-Adresse des Servers in die sockaddr_in-Struktur return 0; }
Regards,
Markus