Skip to content

Commit

Permalink
Merge pull request #20048 from leandrolanzieri/pr/tinydtls/check_publ…
Browse files Browse the repository at this point in the history
…ic_key

net/sock_dtls: add public key verification
  • Loading branch information
Teufelchen1 authored Mar 19, 2024
2 parents c571039 + 6d9a9a3 commit 741d6b3
Show file tree
Hide file tree
Showing 10 changed files with 590 additions and 205 deletions.
4 changes: 4 additions & 0 deletions examples/dtls-sock/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
32 changes: 16 additions & 16 deletions examples/dtls-sock/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
156 changes: 117 additions & 39 deletions examples/dtls-sock/dtls-client.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand All @@ -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)
{
Expand All @@ -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;
Expand All @@ -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);
sock_udp_close(&udp_sock);
if (sock_udp_create(&udp_sock, &local, NULL, 0) < 0) {
puts("Error creating 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);
/*
* 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;
}
tag = SOCK_DTLS_CLIENT_TAG_1;
#endif

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);
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;
}

/* 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) {
Expand Down Expand Up @@ -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]));
}
Loading

0 comments on commit 741d6b3

Please sign in to comment.