Skip to content

Commit

Permalink
coap-client.c: Fix SNI generation
Browse files Browse the repository at this point in the history
Move requirements for client to determine how to set up the SNI for
PSK/PKI encrypted communications down into libcoap. The client just
needs to indicate the host to connect to in the client_sni field of
coap_dtls_cpsk_t or coap_dtls_pki_t.

New internal function coap_sanitize_client_sni() makes sure that
the SNI sent follows RFC 6066.  As per
https://datatracker.ietf.org/doc/html/rfc6066#section-3

  Literal IPv4 and IPv6 addresses are not permitted in "HostName".

all IPv4 and IPv6 addresses are dropped for the SNI, and so no SNI is
sent.  DNS hostnames will get transmitted as the SNI.
  • Loading branch information
mrdeep1 committed Jun 8, 2024
1 parent e095d5e commit d1d4e9b
Show file tree
Hide file tree
Showing 9 changed files with 162 additions and 66 deletions.
17 changes: 4 additions & 13 deletions examples/coap-client.c
Original file line number Diff line number Diff line change
Expand Up @@ -1381,7 +1381,6 @@ setup_pki(coap_context_t *ctx) {
}
}

memset(client_sni, 0, sizeof(client_sni));
memset(&dtls_pki, 0, sizeof(dtls_pki));
dtls_pki.version = COAP_DTLS_PKI_SETUP_VERSION;
if (ca_file || root_ca_file) {
Expand All @@ -1408,12 +1407,8 @@ setup_pki(coap_context_t *ctx) {
}
dtls_pki.is_rpk_not_cert = is_rpk_not_cert;
dtls_pki.validate_cn_call_back = verify_cn_callback;
if ((uri.host.length == 3 && memcmp(uri.host.s, "::1", 3) != 0) ||
(uri.host.length == 9 && memcmp(uri.host.s, "127.0.0.1", 9) != 0))
memcpy(client_sni, uri.host.s, min(uri.host.length, sizeof(client_sni)-1));
else
memcpy(client_sni, "localhost", 9);

snprintf(client_sni, sizeof(client_sni), "%*.*s", (int)uri.host.length, (int)uri.host.length,
uri.host.s);
dtls_pki.client_sni = client_sni;
if (doing_tls_engine) {
dtls_pki.pki_key.key_type = COAP_PKI_KEY_DEFINE;
Expand Down Expand Up @@ -1465,18 +1460,14 @@ setup_psk(const uint8_t *identity,
static coap_dtls_cpsk_t dtls_psk;
static char client_sni[256];

memset(client_sni, 0, sizeof(client_sni));
memset(&dtls_psk, 0, sizeof(dtls_psk));
dtls_psk.version = COAP_DTLS_CPSK_SETUP_VERSION;
if (valid_ihs.count) {
dtls_psk.validate_ih_call_back = verify_ih_callback;
}
dtls_psk.ih_call_back_arg = &dtls_psk.psk_info;
if ((uri.host.length == 3 && memcmp(uri.host.s, "::1", 3) != 0) ||
(uri.host.length == 9 && memcmp(uri.host.s, "127.0.0.1", 9) != 0))
memcpy(client_sni, uri.host.s, min(uri.host.length, sizeof(client_sni)-1));
else
memcpy(client_sni, "localhost", 9);
snprintf(client_sni, sizeof(client_sni), "%*.*s", (int)uri.host.length, (int)uri.host.length,
uri.host.s);
dtls_psk.client_sni = client_sni;
dtls_psk.psk_info.identity.s = identity;
dtls_psk.psk_info.identity.length = identity_len;
Expand Down
8 changes: 1 addition & 7 deletions examples/coap-server.c
Original file line number Diff line number Diff line change
Expand Up @@ -939,13 +939,7 @@ get_ongoing_proxy_session(coap_session_t *session,
case COAP_URI_SCHEME_COAPS:
case COAP_URI_SCHEME_COAPS_TCP:
case COAP_URI_SCHEME_COAPS_WS:
memset(client_sni, 0, sizeof(client_sni));
if ((server.length == 3 && memcmp(server.s, "::1", 3) != 0) ||
(server.length == 9 && memcmp(server.s, "127.0.0.1", 9) != 0))
memcpy(client_sni, server.s, min(server.length, sizeof(client_sni)-1));
else
memcpy(client_sni, "localhost", 9);

snprintf(client_sni, sizeof(client_sni), "%*.*s", (int)server.length, (int)server.length, server.s);
if (!key_defined) {
/* Use our defined PKI certs (or NULL) */
coap_dtls_pki_t *dtls_pki = setup_pki(context, COAP_DTLS_ROLE_CLIENT,
Expand Down
8 changes: 2 additions & 6 deletions examples/lwip/client-coap.c
Original file line number Diff line number Diff line change
Expand Up @@ -182,14 +182,10 @@ client_coap_init(coap_lwip_input_wait_handler_t input_wait, void *input_arg,
static coap_dtls_cpsk_t dtls_psk;
static char client_sni[256];

memset(client_sni, 0, sizeof(client_sni));
memset(&dtls_psk, 0, sizeof(dtls_psk));
dtls_psk.version = COAP_DTLS_CPSK_SETUP_VERSION;
if (uri.host.length)
memcpy(client_sni, uri.host.s,
min(uri.host.length, sizeof(client_sni) - 1));
else
memcpy(client_sni, "localhost", 9);
snprintf(client_sni, sizeof(client_sni), "%*.*s", (int)uri.host.length, (int)uri.host.length,
uri.host.s);
dtls_psk.client_sni = client_sni;
dtls_psk.psk_info.identity.s = (const uint8_t *)use_id;
dtls_psk.psk_info.identity.length = strlen(use_id);
Expand Down
9 changes: 1 addition & 8 deletions examples/riot/examples_libcoap_client/client-coap.c
Original file line number Diff line number Diff line change
Expand Up @@ -183,16 +183,9 @@ client_coap_init(int argc, char **argv)
static coap_dtls_cpsk_t dtls_psk;
static char client_sni[256];

memset(client_sni, 0, sizeof(client_sni));
memset(&dtls_psk, 0, sizeof(dtls_psk));
dtls_psk.version = COAP_DTLS_CPSK_SETUP_VERSION;
if (uri.host.length) {
memcpy(client_sni, uri.host.s,
MIN(uri.host.length, sizeof(client_sni) - 1));
}
else {
memcpy(client_sni, "localhost", 9);
}
snprintf(client_sni, sizeof(client_sni), "%*.*s", (int)uri.host.length, (int)uri.host.length, uri.host.s);
dtls_psk.client_sni = client_sni;
dtls_psk.psk_info.identity.s = (const uint8_t *)COAP_USE_PSK_ID;
dtls_psk.psk_info.identity.length = strlen(COAP_USE_PSK_ID);
Expand Down
12 changes: 7 additions & 5 deletions include/coap3/coap_dtls.h
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,8 @@ struct coap_dtls_pki_t {

char *client_sni; /**< If not NULL, SNI to use in client TLS setup.
Owned by the client app and must remain valid
during the call to coap_new_client_session_pki() */
during the call to coap_new_client_session_pki().
Note: Ignored if literal IPv4 or IPv6 address. */

coap_dtls_key_t pki_key; /**< PKI key definition */
};
Expand Down Expand Up @@ -469,10 +470,11 @@ typedef struct coap_dtls_cpsk_t {
void *ih_call_back_arg; /**< Passed in to the Identity Hint callback
function */

char *client_sni; /**< If not NULL, SNI to use in client TLS setup.
Owned by the client app and must remain valid
during the call to coap_new_client_session_psk2()
Note: Not supported by TinyDTLS. */
char *client_sni; /**< If not NULL, SNI to use in client TLS setup.
Owned by the client app and must remain valid
during the call to coap_new_client_session_psk2().
Note: Ignored if literal IPv4 or IPv6 address.
Note: Not supported by TinyDTLS. */

coap_dtls_cpsk_info_t psk_info; /**< Client PSK definition */
} coap_dtls_cpsk_t;
Expand Down
15 changes: 9 additions & 6 deletions man/coap_encryption.txt.in
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ typedef struct coap_dtls_cpsk_t {
char* client_sni; /* If not NULL, SNI to use in client TLS setup.
Owned by the client app and must remain valid
during the call to coap_new_client_session_pki().
Note: Ignored if literal IPv4 or IPv6 address.
Note: Not supported by TinyDTLS. */

coap_dtls_cpsk_info_t psk_info; /* Client PSK definition */
Expand Down Expand Up @@ -229,6 +230,8 @@ trying to contact. The server is then able to decide, based on the name in the
SNI extension, whether, for example, a different Hint and/or Pre-Shared Key is
to be used.

*NOTE:* Ignored if literal IPv4 or IPv6 address.

*NOTE:* Not supported by TinyDTLS.

*SECTION: PSK Client: coap_dtls_cpsk_t: PSK Client Definitions*
Expand Down Expand Up @@ -474,7 +477,8 @@ typedef struct coap_dtls_pki_t {

char* client_sni; /* If not NULL, SNI to use in client TLS setup.
Owned by the client app and must remain valid
during the call to coap_new_client_session_pki() */
during the call to coap_new_client_session_pki().
Note: Ignored if literal IPv4 or IPv6 address. */

coap_dtls_key_t pki_key; /* PKI key definition */
} coap_dtls_pki_t;
Expand Down Expand Up @@ -680,6 +684,8 @@ trying to contact. This is only used by a client application and the server
is then able to decide, based on the name in the SNI extension, whether, for
example, a different certificate should be provided.

*NOTE:* Ignored if literal IPv4 or IPv6 address.

*SECTION: PKI/RPK: coap_dtls_pki_t: Key Type Definition*
[source, c]
----
Expand Down Expand Up @@ -1289,7 +1295,7 @@ static coap_dtls_cpsk_t dtls_psk;
static char client_sni[256];

static coap_session_t *
setup_client_session_psk(const char *uri,
setup_client_session_psk(const char *host,
struct in_addr ip_address,
const uint8_t *identity,
unsigned int identity_len,
Expand Down Expand Up @@ -1317,10 +1323,7 @@ setup_client_session_psk(const char *uri,
dtls_psk.version = COAP_DTLS_CPSK_SETUP_VERSION;
dtls_psk.validate_ih_call_back = verify_ih_callback;
dtls_psk.ih_call_back_arg = &dtls_psk.psk_info;
if (uri)
memcpy(client_sni, uri, min(strlen(uri), sizeof(client_sni)-1));
else
memcpy(client_sni, "localhost", 9);
snprintf(client_sni, sizeof(client_sni), "%s", host);
dtls_psk.client_sni = client_sni;
dtls_psk.psk_info.identity.s = identity;
dtls_psk.psk_info.identity.length = identity_len;
Expand Down
17 changes: 10 additions & 7 deletions man/coap_endpoint_client.txt.in
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ setup_client_session(const char *server_ud) {
----
#include <coap@LIBCOAP_API_VERSION@/coap.h>

#include <stdio.h>
#include <netinet/in.h>

static int
Expand All @@ -329,8 +330,11 @@ verify_cn_callback(const char *cn,
return 1;
}

static char client_sni[256];

static coap_session_t *
setup_client_session_pki(struct in_addr ip_address,
setup_client_session_pki(const char *host,
struct in_addr ip_address,
const char *public_cert_file,
const char *private_key_file,
const char *ca_file) {
Expand All @@ -355,6 +359,8 @@ setup_client_session_pki(struct in_addr ip_address,

memset(&dtls_pki, 0, sizeof(dtls_pki));

snprintf(client_sni, sizeof(client_sni), "%s", host);

/* See coap_encryption(3) */
dtls_pki.version = COAP_DTLS_PKI_SETUP_VERSION;
dtls_pki.verify_peer_cert = 1;
Expand All @@ -374,7 +380,7 @@ setup_client_session_pki(struct in_addr ip_address,
dtls_pki.validate_sni_call_back = NULL;
dtls_pki.sni_call_back_arg = NULL;
dtls_pki.additional_tls_setup_call_back = NULL;
dtls_pki.client_sni = NULL;
dtls_pki.client_sni = client_sni;
dtls_pki.pki_key.key_type = COAP_PKI_KEY_PEM;
dtls_pki.pki_key.key.pem.ca_file = ca_file;
dtls_pki.pki_key.key.pem.public_cert = public_cert_file;
Expand Down Expand Up @@ -421,7 +427,7 @@ static coap_dtls_cpsk_t dtls_psk;
static char client_sni[256];

static coap_session_t *
setup_client_session_psk(const char *uri,
setup_client_session_psk(const char *host,
struct in_addr ip_address,
const uint8_t *identity,
unsigned int identity_len,
Expand Down Expand Up @@ -450,10 +456,7 @@ setup_client_session_psk(const char *uri,
dtls_psk.version = COAP_DTLS_CPSK_SETUP_VERSION;
dtls_psk.validate_ih_call_back = verify_ih_callback;
dtls_psk.ih_call_back_arg = &dtls_psk.psk_info;
if (uri)
memcpy(client_sni, uri, min(strlen(uri), sizeof(client_sni)-1));
else
memcpy(client_sni, "localhost", 9);
snprintf(client_sni, sizeof(client_sni), "%s", host);
dtls_psk.client_sni = client_sni;
dtls_psk.psk_info.identity.s = identity;
dtls_psk.psk_info.identity.length = identity_len;
Expand Down
3 changes: 2 additions & 1 deletion man/coap_endpoint_server.txt.in
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ FUNCTIONS

The *coap_context_set_pki*() function, for a specific _context_, is used to
configure the (D)TLS context using the _setup_data_ PKI variables as defined in
the coap_dtls_pki_t structure - see *coap_encryption*(3).
the coap_dtls_pki_t structure - see *coap_encryption*(3). This should not be
used for setting up client sessions.

*Function: coap_context_set_pki_root_cas()*

Expand Down
Loading

0 comments on commit d1d4e9b

Please sign in to comment.