1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Merge pull request #20048 from leandrolanzieri/pr/tinydtls/check_public_key

net/sock_dtls: add public key verification
This commit is contained in:
Teufelchen 2024-03-19 10:32:16 +00:00 committed by GitHub
commit 741d6b3d4a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 592 additions and 207 deletions

View File

@ -20,6 +20,10 @@ USEPKG += tinydtls
# Pull in sock APIs
USEMODULE += sock_dtls
# When using asymmetric cryptography, e.g. ecc,
# this verifies the public key against a known set.
# It does not affect symmetric crypto e.g. PSK.
USEMODULE += sock_dtls_verify_public_key
USEMODULE += sock_udp
# extra utilities for endpoint printing

View File

@ -52,25 +52,25 @@ for more information.
When using Pre-Shared Key (PSK), the client registers two keys to `credman` and
makes them available to the sock. The client registers a PSK callback function,
which allows the application to specify which credential to use with a
particular sock and endpoint. In this application the client will print the
server's endpoint and the sent hint, if any. As per the sock DTLS documentation,
if the application callback fails to determine which credential should be used,
an Identity Hint (https://tools.ietf.org/html/rfc4279#section-5.2) match is
attempted. `credential1` is assigned an Identity Hint, defined as
`PSK_DEFAULT_HINT` in `tinydtls_keys.h`. This hint is used by sock to select the
credential, in case the DTLS server sends such a hint. Finally, if none of the
above attempts succeed in determining which credential to use, sock DTLS will
pick the first valid credential registered in the sock.
particular sock and endpoint, depending on the hint sent by the server. As per
the sock DTLS documentation, if the application callback fails to determine
which credential should be used, an Identity Hint
(https://tools.ietf.org/html/rfc4279#section-5.2) match is attempted.
`credential1` is assigned an Identity Hint, defined as `PSK_DEFAULT_HINT` in
`tinydtls_keys.h`. This hint is used by sock to select the credential, in case
the DTLS server sends such a hint. Finally, if none of the above attempts
succeed in determining which credential to use, sock DTLS will pick the first
valid credential registered in the sock.
The behaviour above can be tested, for example, by removing the hint from the
server (`sock_dtls_set_server_psk_id_hint`). As `credential0` is the first
server (`sock_dtls_set_server_psk_id_hint`). As `psk_credential_0` is the first
registered credential in the client, it will be chosen. As the server does not
have this credential, the handshake will fail.
### ECC
When using ECC Raw Public Key (RPK), the server registers two keys to `credman`
and makes them available to the sock. It also registers an RPK callback
function, which allows the application to specify which credential to use with a
particular sock and endpoint (the client could as well do so). In the particular
case of this example the callback always returns the credential with tag
`SOCK_DTLS_SERVER_TAG_1`.
When using ECC Raw Public Key (RPK), the server registers two private keys to
`credman` and makes them available to the sock. It also registers an RPK
callback function, which allows the application to specify which credential to
use. The used credential can be changed at runtime by calling `dtlss ecc <0|1>`.
As the client also knows both public keys from the server, both options will
work.

View File

@ -29,56 +29,60 @@
#include "net/sock/util.h"
#include "net/utils.h"
#include "tinydtls_keys.h"
#include "dtls_client_credentials.h"
#ifndef DTLS_DEFAULT_PORT
#define DTLS_DEFAULT_PORT 20220 /* DTLS default port */
#define DTLS_DEFAULT_PORT (20220) /* DTLS default port */
#endif
static bool _client_credentials_configured = false;
/* Credman tags to select which credentials to use */
#define SOCK_DTLS_CLIENT_TAG_0 (2)
#define SOCK_DTLS_CLIENT_TAG_1 (3)
#ifdef CONFIG_DTLS_ECC
static const ecdsa_public_key_t other_pubkeys0[] = {
{ .x = ecdsa_pub_key0_x, .y = ecdsa_pub_key0_y },
static const ecdsa_public_key_t server_public_keys[] = {
{ .x = known_server_public_key_0_x, .y = known_server_public_key_0_y },
{ .x = known_server_public_key_1_x, .y = known_server_public_key_1_y },
};
static const credman_credential_t credential0 = {
static const credman_credential_t ecc_credential_0 = {
.type = CREDMAN_TYPE_ECDSA,
.tag = SOCK_DTLS_CLIENT_TAG_0,
.params = {
.ecdsa = {
.private_key = ecdsa_priv_key0,
.private_key = client_private_key_0,
.public_key = {
.x = ecdsa_pub_key0_x,
.y = ecdsa_pub_key0_y,
.x = client_public_key_0_x,
.y = client_public_key_0_y,
},
.client_keys = (ecdsa_public_key_t *)other_pubkeys0,
.client_keys_size = ARRAY_SIZE(other_pubkeys0),
.client_keys = (ecdsa_public_key_t *)server_public_keys,
.client_keys_size = ARRAY_SIZE(server_public_keys),
}
},
};
#else /* ifdef CONFIG_DTLS_PSK */
static const uint8_t psk_id_0[] = PSK_WRONG_IDENTITY;
static const uint8_t psk_key_0[] = PSK_WRONG_KEY;
static const uint8_t psk_id_0[] = CLIENT_PSK_IDENTITY_0;
static const uint8_t psk_key_0[] = CLIENT_PSK_IDENTITY_0_KEY;
static const char psk_id_0_hint[] = CLIENT_PSK_IDENTITY_0_HINT;
static const uint8_t psk_id_1[] = PSK_DEFAULT_IDENTITY;
static const uint8_t psk_key_1[] = PSK_DEFAULT_KEY;
static const char psk_id_1_hint[] = PSK_DEFAULT_HINT;
static const uint8_t psk_id_1[] = CLIENT_PSK_IDENTITY_1;
static const uint8_t psk_key_1[] = CLIENT_PSK_IDENTITY_1_KEY;
static const char psk_id_1_hint[] = CLIENT_PSK_IDENTITY_1_HINT;
static const credman_credential_t credential0 = {
static const credman_credential_t psk_credential_0 = {
.type = CREDMAN_TYPE_PSK,
.tag = SOCK_DTLS_CLIENT_TAG_0,
.params = {
.psk = {
.key = { .s = psk_key_0, .len = sizeof(psk_key_0) - 1, },
.id = { .s = psk_id_0, .len = sizeof(psk_id_0) - 1, },
.hint = { .s = psk_id_0_hint, .len = sizeof(psk_id_0_hint) - 1, },
}
},
};
static const credman_credential_t credential1 = {
static const credman_credential_t psk_credential_1 = {
.type = CREDMAN_TYPE_PSK,
.tag = SOCK_DTLS_CLIENT_TAG_1,
.params = {
@ -89,7 +93,60 @@ static const credman_credential_t credential1 = {
}
},
};
#endif
static credman_tag_t _client_psk_cb(sock_dtls_t *sock, sock_udp_ep_t *ep, credman_tag_t tags[],
unsigned tags_len, const char *hint, size_t hint_len)
{
(void) sock;
(void) tags;
(void) tags_len;
char addrstr[IPV6_ADDR_MAX_STR_LEN];
uint16_t port;
sock_udp_ep_fmt(ep, addrstr, &port);
printf("From [%s]:%" PRIu16" \n", addrstr, port);
/* if we got a hint, try to use it to determine which PSK to use */
if (hint && hint_len) {
printf("Client got hint: %.*s\n", (unsigned)hint_len, hint);
if (hint_len == sizeof(psk_id_0_hint) &&
!memcmp(hint, psk_id_0_hint, sizeof(psk_id_0_hint) - 1)) {
return SOCK_DTLS_CLIENT_TAG_0;
}
if (hint_len == sizeof(psk_id_1_hint) &&
!memcmp(hint, psk_id_1_hint, sizeof(psk_id_1_hint) - 1)) {
return SOCK_DTLS_CLIENT_TAG_1;
}
}
return CREDMAN_TAG_EMPTY;
}
static int _configure_client_credentials(void)
{
/* register the credentials on credman */
if (IS_ACTIVE(CONFIG_DTLS_ECC)) {
if (credman_add(&ecc_credential_0) != CREDMAN_OK) {
puts("Error cannot add ECC credential 0 to system");
return -1;
}
}
else if (IS_ACTIVE(CONFIG_DTLS_PSK)) {
if (credman_add(&psk_credential_0) != CREDMAN_OK) {
puts("Error cannot add PSK credential 0 to system");
return -1;
}
if (credman_add(&psk_credential_1) != CREDMAN_OK) {
puts("Error cannot add PSK credential 1 to system");
return -1;
}
}
return 0;
}
static int client_send(char *addr_str, char *data, size_t datalen)
{
@ -102,7 +159,6 @@ static int client_send(char *addr_str, char *data, size_t datalen)
local.port = 12345;
remote.port = DTLS_DEFAULT_PORT;
uint8_t buf[DTLS_HANDSHAKE_BUFSIZE];
credman_tag_t tag = SOCK_DTLS_CLIENT_TAG_0;
/* get interface */
netif_t *netif;
@ -115,34 +171,48 @@ static int client_send(char *addr_str, char *data, size_t datalen)
remote.netif = netif_get_id(netif);
}
res = credman_add(&credential0);
if (res < 0 && res != CREDMAN_EXIST) {
/* ignore duplicate credentials */
printf("Error cannot add credential to system: %" PRIdSIZE "\n", res);
if (sock_udp_create(&udp_sock, &local, NULL, 0) < 0) {
puts("Error creating UDP sock");
return -1;
}
/*
* Currently DTLS sock needs one and only one credential for the
* initialization. Subsequent credentials are made available to the sock
* by means of `sock_dtls_add_credential`.
*/
if (sock_dtls_create(&dtls_sock, &udp_sock, SOCK_DTLS_CLIENT_TAG_0,
SOCK_DTLS_1_2, SOCK_DTLS_CLIENT) < 0) {
puts("Error creating DTLS sock");
sock_udp_close(&udp_sock);
return -1;
}
#if IS_ACTIVE(CONFIG_DTLS_PSK)
/* register a second PSK credential */
res = credman_add(&credential1);
if (res < 0 && res != CREDMAN_EXIST) {
/* ignore duplicate credentials */
printf("Error cannot add credential to system: %" PRIdSIZE "\n", res);
sock_udp_close(&udp_sock);
return -1;
}
tag = SOCK_DTLS_CLIENT_TAG_1;
#endif
if (IS_ACTIVE(CONFIG_DTLS_PSK)) {
/* make the new credential available to the sock */
if (sock_dtls_add_credential(&dtls_sock, SOCK_DTLS_CLIENT_TAG_1) < 0) {
puts("Error cannot add second PSK credential to the sock");
return -1;
}
res = sock_dtls_establish_session(&udp_sock, &dtls_sock, &session, tag,
&local, &remote, buf, sizeof(buf));
if (res) {
sock_udp_close(&udp_sock);
printf("Error establishing connection: %d\n", (int)res);
/* register a callback for PSK credential selection */
sock_dtls_set_client_psk_cb(&dtls_sock, _client_psk_cb);
}
res = sock_dtls_session_init(&dtls_sock, &remote, &session);
if (res <= 0) {
return res;
}
res = sock_dtls_recv(&dtls_sock, &session, buf, sizeof(buf),
SOCK_NO_TIMEOUT);
if (res != -SOCK_DTLS_HANDSHAKE) {
printf("Error creating session: %" PRIiSIZE "\n", res);
sock_dtls_close(&dtls_sock);
sock_udp_close(&udp_sock);
return -1;
}
printf("Connection to server successful\n");
if (sock_dtls_send(&dtls_sock, &session, data, datalen, 0) < 0) {
@ -172,5 +242,13 @@ int dtls_client_cmd(int argc, char **argv)
return 1;
}
if (!_client_credentials_configured) {
int res = _configure_client_credentials();
if (res < 0) {
return res;
}
_client_credentials_configured = true;
}
return client_send(argv[1], argv[2], strlen(argv[2]));
}

View File

@ -14,6 +14,7 @@
* @brief DTLS sock server example
*
* @author Aiman Ismail <muhammadaimanbin.ismail@haw-hamburg.de>
* @author Leandro Lanzieri <leandro.lanzieri@haw-hamburg.de>
*/
#include <stdio.h>
@ -27,59 +28,64 @@
#include "thread.h"
#include "timex.h"
#include "tinydtls_keys.h"
#include "dtls_server_credentials.h"
#ifndef DTLS_DEFAULT_PORT
#define DTLS_DEFAULT_PORT (20220) /* DTLS default port */
#endif
static bool _server_credentials_configured = false;
/* Credman tags to select which credentials to use */
#define SOCK_DTLS_SERVER_TAG_0 (10)
#define SOCK_DTLS_SERVER_TAG_1 (11)
#define DTLS_STOP_SERVER_MSG 0x4001 /* Custom IPC type msg. */
#define READER_QUEUE_SIZE (8U)
char _dtls_server_stack[THREAD_STACKSIZE_MAIN +
THREAD_EXTRA_STACKSIZE_PRINTF];
char _dtls_server_stack[THREAD_STACKSIZE_MAIN + THREAD_EXTRA_STACKSIZE_PRINTF];
static kernel_pid_t _dtls_server_pid = KERNEL_PID_UNDEF;
#ifdef CONFIG_DTLS_ECC
static const ecdsa_public_key_t other_pubkeys[] = {
{ .x = ecdsa_pub_key0_x, .y = ecdsa_pub_key0_y },
static unsigned int _ecc_credential = 0;
/*
* Each credman_credential_t acts as a sort of keyring, containing a single
* private / public key pair and a list of public keys of clients that are
* known.
*/
static const ecdsa_public_key_t known_client_pub_keys[] = {
{ .x = known_client_public_key_0_x, .y = known_client_public_key_0_y }
};
static const credman_credential_t credential0 = {
static const credman_credential_t ecc_credential_0 = {
.type = CREDMAN_TYPE_ECDSA,
.tag = SOCK_DTLS_SERVER_TAG_0,
.params = {
.ecdsa = {
.private_key = ecdsa_priv_key0,
.private_key = server_private_key_0,
.public_key = {
.x = ecdsa_pub_key0_x,
.y = ecdsa_pub_key0_y,
.x = server_public_key_0_x,
.y = server_public_key_0_y,
},
.client_keys = (ecdsa_public_key_t *)other_pubkeys,
.client_keys_size = ARRAY_SIZE(other_pubkeys),
.client_keys = (ecdsa_public_key_t *)known_client_pub_keys,
.client_keys_size = ARRAY_SIZE(known_client_pub_keys),
},
},
};
static const ecdsa_public_key_t other_pubkeys1[] = {
{ .x = ecdsa_pub_key1_x, .y = ecdsa_pub_key1_y },
};
static const credman_credential_t credential1 = {
static const credman_credential_t ecc_credential_1 = {
.type = CREDMAN_TYPE_ECDSA,
.tag = SOCK_DTLS_SERVER_TAG_1,
.params = {
.ecdsa = {
.private_key = ecdsa_priv_key1,
.private_key = server_private_key_1,
.public_key = {
.x = ecdsa_pub_key1_x,
.y = ecdsa_pub_key1_y,
.x = server_public_key_1_x,
.y = server_public_key_1_y,
},
.client_keys = (ecdsa_public_key_t *)other_pubkeys1,
.client_keys_size = ARRAY_SIZE(other_pubkeys1),
.client_keys = (ecdsa_public_key_t *)known_client_pub_keys,
.client_keys_size = ARRAY_SIZE(known_client_pub_keys),
}
},
};
@ -98,24 +104,53 @@ static credman_tag_t _rpk_cb(sock_dtls_t *sock, sock_udp_ep_t *ep, credman_tag_t
sock_udp_ep_fmt(ep, addrstr, &port);
printf("From [%s]:%d\n", addrstr, port);
return SOCK_DTLS_SERVER_TAG_1;
if (!_ecc_credential) {
return SOCK_DTLS_SERVER_TAG_0;
}
else {
return SOCK_DTLS_SERVER_TAG_1;
}
}
#else /* #ifdef CONFIG_DTLS_PSK */
static const uint8_t psk_id_0[] = PSK_DEFAULT_IDENTITY;
static const uint8_t psk_key_0[] = PSK_DEFAULT_KEY;
/*
* We have a single PSK.
*/
static const uint8_t psk_id[] = SERVER_PSK_IDENTITY;
static const uint8_t psk_key[] = SERVER_PSK_IDENTITY_KEY;
static const credman_credential_t credential0 = {
static const credman_credential_t psk_credential_0 = {
.type = CREDMAN_TYPE_PSK,
.tag = SOCK_DTLS_SERVER_TAG_0,
.params = {
.psk = {
.key = { .s = psk_key_0, .len = sizeof(psk_key_0) - 1, },
.id = { .s = psk_id_0, .len = sizeof(psk_id_0) - 1, },
.key = { .s = psk_key, .len = sizeof(psk_key) - 1, },
.id = { .s = psk_id, .len = sizeof(psk_id) - 1, },
},
},
};
#endif
static int _configure_server_credentials(void)
{
/* register the credentials on credman */
if (IS_ACTIVE(CONFIG_DTLS_ECC)) {
if (credman_add(&ecc_credential_0) != CREDMAN_OK) {
puts("Error cannot add ECC credential 0 to system");
return -1;
}
if (credman_add(&ecc_credential_1) != CREDMAN_OK) {
puts("Error cannot add ECC credential 1 to system");
return -1;
}
}
else if (IS_ACTIVE(CONFIG_DTLS_PSK)) {
if (credman_add(&psk_credential_0) != CREDMAN_OK) {
puts("Error cannot add PSK credential 0 to system");
return -1;
}
}
return 0;
}
void *dtls_server_wrapper(void *arg)
{
@ -136,13 +171,11 @@ void *dtls_server_wrapper(void *arg)
local.port = DTLS_DEFAULT_PORT;
sock_udp_create(&udp_sock, &local, NULL, 0);
res = credman_add(&credential0);
if (res < 0 && res != CREDMAN_EXIST) {
/* ignore duplicate credentials */
printf("Error cannot add credential to system: %" PRIdSIZE "\n", res);
return NULL;
}
/*
* Currently DTLS sock needs one and only one credential for the
* initialization. Subsequent credentials are made available to the sock
* by means of `sock_dtls_add_credential`.
*/
res = sock_dtls_create(&sock, &udp_sock, SOCK_DTLS_SERVER_TAG_0,
SOCK_DTLS_1_2, SOCK_DTLS_SERVER);
if (res < 0) {
@ -150,33 +183,24 @@ void *dtls_server_wrapper(void *arg)
return NULL;
}
/* set PSK Identity hint, this is optional and application-specific */
#if IS_ACTIVE(CONFIG_DTLS_PSK)
if (sock_dtls_set_server_psk_id_hint(&sock, PSK_DEFAULT_HINT) < 0) {
puts("Error setting PSK Identity hint");
return NULL;
}
#endif
if (IS_ACTIVE(CONFIG_DTLS_ECC)) {
/* make the second ECC credential available to the sock */
if (sock_dtls_add_credential(&sock, SOCK_DTLS_SERVER_TAG_1) < 0) {
puts("Error cannot add second ECC credential to the sock");
return NULL;
}
#if IS_ACTIVE(CONFIG_DTLS_ECC)
/* register a second RPK */
res = credman_add(&credential1);
if (res < 0 && res != CREDMAN_EXIST) {
/* ignore duplicate credentials */
printf("Error cannot add credential to system: %" PRIdSIZE "\n", res);
return NULL;
/* register a callback for RPK credential selection */
sock_dtls_set_rpk_cb(&sock, _rpk_cb);
}
/* make the new credential available to the sock */
if (sock_dtls_add_credential(&sock, SOCK_DTLS_SERVER_TAG_1) < 0) {
printf("Error cannot add credential to the sock: %" PRIdSIZE "\n", res);
return NULL;
else if (IS_ACTIVE(CONFIG_DTLS_PSK)) {
/* set PSK Identity hint, this is optional and application-specific */
if (sock_dtls_set_server_psk_id_hint(&sock, SERVER_PSK_IDENTITY_HINT) < 0) {
puts("Error setting PSK Identity hint");
return NULL;
}
}
/* register a callback for RPK credential selection */
sock_dtls_set_rpk_cb(&sock, _rpk_cb);
#endif
while (active) {
if ((msg_try_receive(&msg) == 1) &&
(msg.type == DTLS_STOP_SERVER_MSG)){
@ -249,20 +273,55 @@ static void stop_server(void)
puts("Success: DTLS server stopped");
}
void _print_usage(const char *cmd)
{
if (IS_ACTIVE(CONFIG_DTLS_ECC)) {
printf("usage: %s start | stop | ecc <0|1>\n", cmd);
}
else {
printf("usage: %s start | stop\n", cmd);
}
}
int dtls_server_cmd(int argc, char **argv)
{
if (argc < 2) {
printf("usage: %s start | stop\n", argv[0]);
_print_usage(argv[0]);
return 1;
}
if (strcmp(argv[1], "start") == 0) {
if (!_server_credentials_configured) {
int res = _configure_server_credentials();
if (res < 0) {
return res;
}
_server_credentials_configured = true;
}
start_server();
}
else if (strcmp(argv[1], "stop") == 0) {
stop_server();
}
else if (IS_ACTIVE(CONFIG_DTLS_ECC) && strcmp(argv[1], "ecc") == 0) {
/* if using ECC, allow choosing which key to use on handshakes at runtime */
if (argc < 3) {
_print_usage(argv[0]);
return 1;
}
int value = atoi(argv[2]);
if (value != 0 && value != 1) {
printf("Error: invalid value, should be 0 or 1, got %i\n", value);
return 1;
}
else {
_ecc_credential = value;
}
}
else {
printf("Error: invalid command. Usage: %s start | stop\n", argv[0]);
printf("Error: invalid command.");
_print_usage(argv[0]);
return 1;
}
return 0;

View File

@ -0,0 +1,139 @@
/*
* Copyright (C) 2024 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup examples
* @{
*
* @file
* @brief PSK and RPK client credentials for the dtls-sock example.
*
* @author Leandro Lanzieri <leandro.lanzieri@haw-hamburg.de
*
* @}
*/
#ifndef DTLS_CLIENT_CREDENTIALS_H
#define DTLS_CLIENT_CREDENTIALS_H
#ifdef __cplusplus
extern "C" {
#endif
/*
* Pre-Shared Key (PSK) credentials (client and server must have a copy)
*/
/**
* @brief The identity of the PSK 0
*/
#define CLIENT_PSK_IDENTITY_0 "Identity_0"
/**
* @brief The PSK 0 itself.
*/
#define CLIENT_PSK_IDENTITY_0_KEY "secretPSK"
/**
* @brief The identity hint of the PSK 0
*/
#define CLIENT_PSK_IDENTITY_0_HINT "Prefer_Id_0"
/**
* @brief The identity of the PSK 1
*/
#define CLIENT_PSK_IDENTITY_1 "Identity_1"
/**
* @brief The PSK 1 itself.
*/
#define CLIENT_PSK_IDENTITY_1_KEY "yetAnotherSecret"
/**
* @brief The identity hint of the PSK 1
*/
#define CLIENT_PSK_IDENTITY_1_HINT "Prefer_Id_1"
/*
* Raw Public Key (RPK) credentials
*/
/**
* @brief The private part of the client key 0.
*/
static const unsigned char client_private_key_0[] = {
0x41, 0xC1, 0xCB, 0x6B, 0x51, 0x24, 0x7A, 0x14,
0x43, 0x21, 0x43, 0x5B, 0x7A, 0x80, 0xE7, 0x14,
0x89, 0x6A, 0x33, 0xBB, 0xAD, 0x72, 0x94, 0xCA,
0x40, 0x14, 0x55, 0xA1, 0x94, 0xA9, 0x49, 0xFA
};
/**
* @brief The x coordinate of the public part of the client key 0.
*/
static const unsigned char client_public_key_0_x[] = {
0x36, 0xDF, 0xE2, 0xC6, 0xF9, 0xF2, 0xED, 0x29,
0xDA, 0x0A, 0x9A, 0x8F, 0x62, 0x68, 0x4E, 0x91,
0x63, 0x75, 0xBA, 0x10, 0x30, 0x0C, 0x28, 0xC5,
0xE4, 0x7C, 0xFB, 0xF2, 0x5F, 0xA5, 0x8F, 0x52
};
/**
* @brief The y coordinate of the public part of the client key 0.
*/
static const unsigned char client_public_key_0_y[] = {
0x71, 0xA0, 0xD4, 0xFC, 0xDE, 0x1A, 0xB8, 0x78,
0x5A, 0x3C, 0x78, 0x69, 0x35, 0xA7, 0xCF, 0xAB,
0xE9, 0x3F, 0x98, 0x72, 0x09, 0xDA, 0xED, 0x0B,
0x4F, 0xAB, 0xC3, 0x6F, 0xC7, 0x72, 0xF8, 0x29
};
/**
* @brief The x coordinate of the public part of the server key 0.
*/
static const unsigned char known_server_public_key_0_x[] = {
0xef, 0x30, 0x0c, 0x57, 0x0a, 0x65, 0x7b, 0x98,
0x53, 0x34, 0xfa, 0x52, 0x81, 0xd7, 0x9b, 0x72,
0xb4, 0xe9, 0x48, 0xf0, 0x56, 0x37, 0xd0, 0x53,
0xa7, 0x35, 0x61, 0x3c, 0x06, 0xfb, 0x9c, 0xe7,
};
/**
* @brief The y coordinate of the public part of the server key 0.
*/
static const unsigned char known_server_public_key_0_y[] = {
0xd1, 0x98, 0xe6, 0x0a, 0x96, 0x41, 0xc7, 0x8a,
0xac, 0x69, 0x09, 0x47, 0x64, 0x24, 0x30, 0x5f,
0x1b, 0x70, 0xad, 0x2c, 0xf0, 0xba, 0xa2, 0xd7,
0xdb, 0x6d, 0x11, 0xe0, 0x36, 0xb9, 0x1e, 0x87
};
/**
* @brief The x coordinate of the public part of the server key 1.
*/
static const unsigned char known_server_public_key_1_x[] = {
0x54, 0xe4, 0x3a, 0xa6, 0xe1, 0x19, 0xaf, 0x85,
0xe4, 0x50, 0x0b, 0x67, 0x89, 0x57, 0x02, 0x82,
0xad, 0x68, 0x90, 0xe1, 0xfb, 0xd0, 0x2a, 0x2b,
0xc0, 0xfc, 0xc2, 0xeb, 0xdc, 0x48, 0x7f, 0x92
};
/**
* @brief The y coordinate of the public part of the server key 1.
*/
static const unsigned char known_server_public_key_1_y[] = {
0x25, 0x5f, 0x92, 0x94, 0x38, 0x73, 0xb4, 0xfd,
0x17, 0x9e, 0xe0, 0x7f, 0x12, 0x93, 0xb9, 0xf4,
0xa5, 0x70, 0x4e, 0xea, 0x09, 0x5f, 0xdf, 0xc1,
0x8a, 0x66, 0x75, 0x86, 0xc3, 0x34, 0x39, 0x8b
};
#ifdef __cplusplus
}
#endif
#endif /* DTLS_CLIENT_CREDENTIALS_H */

View File

@ -0,0 +1,135 @@
/*
* Copyright (C) 2024 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup examples
* @{
*
* @file
* @brief PSK and RPK server credentials for the dtls-sock example.
*
* @author Leandro Lanzieri <leandro.lanzieri@haw-hamburg.de
*
* @}
*/
#ifndef DTLS_SERVER_CREDENTIALS_H
#define DTLS_SERVER_CREDENTIALS_H
#ifdef __cplusplus
extern "C" {
#endif
/*
* Pre-Shared Key (PSK) credentials (client and server must have a copy)
*/
/**
* @brief The identity is used to indicate which key is used during the handshake.
*/
#define SERVER_PSK_IDENTITY "Identity_1"
/**
* @brief The pre-shared key itself.
*/
#define SERVER_PSK_IDENTITY_KEY "yetAnotherSecret"
/**
* @brief The identity hint is sent by the server to the client to help it decide on
* which identity to use.
*/
#define SERVER_PSK_IDENTITY_HINT "Prefer_Id_1"
/*
* Raw Public Key (RPK) credentials
*/
/**
* @brief The private part of the server key 0.
*/
static const unsigned char server_private_key_0[] = {
0x23, 0xbd, 0xd3, 0x6c, 0x10, 0x17, 0xe9, 0x0d,
0xc1, 0x0a, 0x8f, 0x02, 0xf2, 0x0e, 0xe9, 0x5d,
0xbe, 0x37, 0x38, 0x35, 0xb6, 0x4b, 0x8a, 0x1b,
0x20, 0xa6, 0xa7, 0x86, 0x2f, 0xd1, 0xc8, 0xe5
};
/**
* @brief The x coordinate of the public part of the server key 0.
*/
static const unsigned char server_public_key_0_x[] = {
0xef, 0x30, 0x0c, 0x57, 0x0a, 0x65, 0x7b, 0x98,
0x53, 0x34, 0xfa, 0x52, 0x81, 0xd7, 0x9b, 0x72,
0xb4, 0xe9, 0x48, 0xf0, 0x56, 0x37, 0xd0, 0x53,
0xa7, 0x35, 0x61, 0x3c, 0x06, 0xfb, 0x9c, 0xe7,
};
/**
* @brief The y coordinate of the public part of the server key 0.
*/
static const unsigned char server_public_key_0_y[] = {
0xd1, 0x98, 0xe6, 0x0a, 0x96, 0x41, 0xc7, 0x8a,
0xac, 0x69, 0x09, 0x47, 0x64, 0x24, 0x30, 0x5f,
0x1b, 0x70, 0xad, 0x2c, 0xf0, 0xba, 0xa2, 0xd7,
0xdb, 0x6d, 0x11, 0xe0, 0x36, 0xb9, 0x1e, 0x87
};
/**
* @brief The private part of the server key 1.
*/
static const unsigned char server_private_key_1[] = {
0xac, 0x40, 0x25, 0x94, 0xd2, 0xd7, 0x33, 0x0b,
0xaa, 0xd5, 0x51, 0x27, 0xd6, 0x76, 0xe8, 0xb7,
0x23, 0xe3, 0x20, 0x9b, 0x90, 0xa0, 0xa0, 0xd0,
0xcf, 0x3d, 0x8b, 0x7a, 0x0d, 0x38, 0x03, 0x00
};
/**
* @brief The x coordinate of the public part of the server key 1.
*/
static const unsigned char server_public_key_1_x[] = {
0x54, 0xe4, 0x3a, 0xa6, 0xe1, 0x19, 0xaf, 0x85,
0xe4, 0x50, 0x0b, 0x67, 0x89, 0x57, 0x02, 0x82,
0xad, 0x68, 0x90, 0xe1, 0xfb, 0xd0, 0x2a, 0x2b,
0xc0, 0xfc, 0xc2, 0xeb, 0xdc, 0x48, 0x7f, 0x92
};
/**
* @brief The y coordinate of the public part of the server key 1.
*/
static const unsigned char server_public_key_1_y[] = {
0x25, 0x5f, 0x92, 0x94, 0x38, 0x73, 0xb4, 0xfd,
0x17, 0x9e, 0xe0, 0x7f, 0x12, 0x93, 0xb9, 0xf4,
0xa5, 0x70, 0x4e, 0xea, 0x09, 0x5f, 0xdf, 0xc1,
0x8a, 0x66, 0x75, 0x86, 0xc3, 0x34, 0x39, 0x8b
};
/**
* @brief The x coordinate of the public part of the key 0 of a known client.
*/
static const unsigned char known_client_public_key_0_x[] = {
0x36, 0xDF, 0xE2, 0xC6, 0xF9, 0xF2, 0xED, 0x29,
0xDA, 0x0A, 0x9A, 0x8F, 0x62, 0x68, 0x4E, 0x91,
0x63, 0x75, 0xBA, 0x10, 0x30, 0x0C, 0x28, 0xC5,
0xE4, 0x7C, 0xFB, 0xF2, 0x5F, 0xA5, 0x8F, 0x52
};
/**
* @brief The y coordinate of the public part of the key 0 of a known client.
*/
static const unsigned char known_client_public_key_0_y[] = {
0x71, 0xA0, 0xD4, 0xFC, 0xDE, 0x1A, 0xB8, 0x78,
0x5A, 0x3C, 0x78, 0x69, 0x35, 0xA7, 0xCF, 0xAB,
0xE9, 0x3F, 0x98, 0x72, 0x09, 0xDA, 0xED, 0x0B,
0x4F, 0xAB, 0xC3, 0x6F, 0xC7, 0x72, 0xF8, 0x29
};
#ifdef __cplusplus
}
#endif
#endif /* DTLS_SERVER_CREDENTIALS_H */

View File

@ -1,88 +0,0 @@
/*
* Copyright (C) 2018 Inria
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup examples
* @{
*
* @file
* @brief PSK and RPK keys for the dtls-sock example.
*
* @author Raul Fuentes <raul.fuentes-samaniego@inria.fr>
*
* @}
*/
#ifndef TINYDTLS_KEYS_H
#define TINYDTLS_KEYS_H
#ifdef __cplusplus
extern "C" {
#endif
/*
* Default keys examples for tinyDTLS (for RIOT, Linux and Contiki)
*/
#ifdef CONFIG_DTLS_PSK
#define PSK_WRONG_IDENTITY "Wrong_identity"
#define PSK_WRONG_KEY "wrong_secret"
#define PSK_DEFAULT_IDENTITY "Client_identity"
#define PSK_DEFAULT_KEY "secretPSK"
#define PSK_DEFAULT_HINT "hint"
#endif /* CONFIG_DTLS_PSK */
#ifdef CONFIG_DTLS_ECC
static const unsigned char ecdsa_priv_key0[] = {
0x41, 0xC1, 0xCB, 0x6B, 0x51, 0x24, 0x7A, 0x14,
0x43, 0x21, 0x43, 0x5B, 0x7A, 0x80, 0xE7, 0x14,
0x89, 0x6A, 0x33, 0xBB, 0xAD, 0x72, 0x94, 0xCA,
0x40, 0x14, 0x55, 0xA1, 0x94, 0xA9, 0x49, 0xFA
};
static const unsigned char ecdsa_pub_key0_x[] = {
0x36, 0xDF, 0xE2, 0xC6, 0xF9, 0xF2, 0xED, 0x29,
0xDA, 0x0A, 0x9A, 0x8F, 0x62, 0x68, 0x4E, 0x91,
0x63, 0x75, 0xBA, 0x10, 0x30, 0x0C, 0x28, 0xC5,
0xE4, 0x7C, 0xFB, 0xF2, 0x5F, 0xA5, 0x8F, 0x52
};
static const unsigned char ecdsa_pub_key0_y[] = {
0x71, 0xA0, 0xD4, 0xFC, 0xDE, 0x1A, 0xB8, 0x78,
0x5A, 0x3C, 0x78, 0x69, 0x35, 0xA7, 0xCF, 0xAB,
0xE9, 0x3F, 0x98, 0x72, 0x09, 0xDA, 0xED, 0x0B,
0x4F, 0xAB, 0xC3, 0x6F, 0xC7, 0x72, 0xF8, 0x29
};
static const unsigned char ecdsa_priv_key1[] = {
0x99, 0x1b, 0x1c, 0xf1, 0x52, 0xa3, 0xf5, 0xac,
0xce, 0x58, 0x00, 0x45, 0xdc, 0xa7, 0x45, 0x45,
0x9e, 0xc6, 0xd8, 0x68, 0x21, 0xd4, 0x82, 0xb7,
0x17, 0x84, 0x0a, 0xdc, 0x1d, 0xf1, 0x09, 0x57
};
static const unsigned char ecdsa_pub_key1_x[] = {
0xb7, 0x4e, 0xa0, 0x62, 0x96, 0xc5, 0xb9, 0x09,
0xad, 0x36, 0x10, 0xab, 0xb1, 0xd8, 0x54, 0x69,
0xef, 0x2b, 0x15, 0x5a, 0xb5, 0x28, 0x21, 0x21,
0x9f, 0xa3, 0x9e, 0x6a, 0x02, 0xce, 0xb8, 0xb9
};
static const unsigned char ecdsa_pub_key1_y[] = {
0xcc, 0x0e, 0x88, 0x88, 0x91, 0x80, 0x7a, 0xdd,
0xf7, 0x4e, 0x2e, 0xe6, 0x6e, 0xd4, 0x22, 0xde,
0xbc, 0x68, 0xcd, 0x8f, 0xd9, 0x5a, 0xa0, 0xcd,
0x5f, 0x4a, 0x1a, 0xb7, 0x2f, 0x95, 0xfc, 0x76
};
#endif /* CONFIG_DTLS_ECC */
#ifdef __cplusplus
}
#endif
#endif /* TINYDTLS_KEYS_H */

View File

@ -453,6 +453,7 @@ PSEUDOMODULES += sock_aux_rssi
PSEUDOMODULES += sock_aux_timestamp
PSEUDOMODULES += sock_aux_ttl
PSEUDOMODULES += sock_dtls
PSEUDOMODULES += sock_dtls_verify_public_key
PSEUDOMODULES += sock_ip
PSEUDOMODULES += sock_tcp
PSEUDOMODULES += sock_udp

View File

@ -20,6 +20,7 @@
#include <assert.h>
#include "dtls.h"
#include "crypto.h"
#include "log.h"
#include "net/sock/dtls.h"
#include "net/credman.h"
@ -363,11 +364,59 @@ static int _get_ecdsa_key(struct dtls_context_t *ctx, const session_t *session,
return 0;
}
static int _verify_public_ecdsa_key(credman_credential_t *credential,
const unsigned char *other_pub_x,
const unsigned char *other_pub_y)
{
/* check if any of the available client keys match the provided one */
for (unsigned i = 0; i < credential->params.ecdsa.client_keys_size; i++) {
if (memcmp(credential->params.ecdsa.client_keys[i].x, other_pub_x, DTLS_EC_KEY_SIZE) == 0 &&
memcmp(credential->params.ecdsa.client_keys[i].y, other_pub_y, DTLS_EC_KEY_SIZE) == 0) {
DEBUG("sock_dtls: client key %d matches\n", i);
return 0;
}
}
DEBUG("sock_dtls: credential does not match\n");
return 1;
}
static int _verify_ecdsa_key(struct dtls_context_t *ctx,
const session_t *session,
const unsigned char *other_pub_x,
const unsigned char *other_pub_y, size_t key_size)
{
if (IS_USED(MODULE_SOCK_DTLS_VERIFY_PUBLIC_KEY)) {
int ret;
credman_credential_t credential;
sock_dtls_t *sock = (sock_dtls_t *)dtls_get_app_data(ctx);
credential.tag = CREDMAN_TAG_EMPTY;
DEBUG("sock_dtls: verifying ECDSA public key of the other peer\n");
/* first check public key size */
if (key_size != DTLS_EC_KEY_SIZE) {
DEBUG("sock_dtls: invalid key length: %d (expected %d)\n", key_size, DTLS_EC_KEY_SIZE);
return dtls_alert_fatal_create(DTLS_ALERT_BAD_CERTIFICATE);
}
/* check if any of the available credentials match the provided one */
for (unsigned i = 0; i < sock->tags_len; i++) {
ret = credman_get(&credential, sock->tags[i], CREDMAN_TYPE_ECDSA);
if (ret != CREDMAN_OK) {
continue;
}
if (!_verify_public_ecdsa_key(&credential, other_pub_x, other_pub_y)) {
return 0;
}
}
/* we could not find a valid credential */
DEBUG("sock_dtls: no valid credential registered\n");
return dtls_alert_fatal_create(DTLS_ALERT_BAD_CERTIFICATE);
}
(void)ctx;
(void)session;
(void)other_pub_y;

View File

@ -507,6 +507,13 @@
* registered credential in the Sock's credential list, that matches the needed type. The first
* one that matches is used.
*
* #### Public key verification when using ECC
*
* By enabling the pseudomodule `sock_dtls_verify_public_key` the DTLS sock will verify the
* public key of the remote peer. When enabled, the DTLS sock will only accept a connection if
* the provided public key is in the list of public keys assigned to the specified sock. This only
* applies when using ECC ciphersuites (i.e., not PSK).
*
* @{
*
* @file
@ -517,6 +524,7 @@
* @author Raul A. Fuentes Samaniego <raul.fuentes-samaniego@inria.fr>
* @author Daniele Lacamera <daniele@wolfssl.com>
* @author Ken Bannister <kb2ma@runbox.com>
* @author Leandro Lanzieri <leandro.lanzieri@haw-hamburg.de>
*/
#ifndef NET_SOCK_DTLS_H