net: sockets: tls: Implement TLS_DTLS_CID option

Add TLS_DTLS_CID socket option, which enables to use the Connection ID
extension for the DTLS session.

The option provides control of the use of CID with the `setsockopt()`
function. The value provided can disable, enable, and control whether to
provide a CID to the peer. It uses a random self CID (if told to provide
one to the peer) unless TLS_DTLS_CID_VALUE set previously.

Add TLS_DTLS_CID_VALUE to get or set the CID sent to the peer, if any.

Add TLS_DTLS_PEER_CID_VALUE to get the CID value provided by the peer,
if any.

Add TLS_DTLS_CID_STATUS to determine if CID used, and whether
bidirectional or one way.

Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
Signed-off-by: Pete Skeggs <peter.skeggs@nordicsemi.no>
This commit is contained in:
Robert Lubos 2021-06-22 06:56:23 -07:00 committed by Carles Cufí
parent 232e4ad6b8
commit d8a96b1be0
2 changed files with 261 additions and 1 deletions

View file

@ -140,6 +140,7 @@ struct zsock_pollfd {
*/
#define TLS_DTLS_HANDSHAKE_TIMEOUT_MIN 8
#define TLS_DTLS_HANDSHAKE_TIMEOUT_MAX 9
/** Socket option for preventing certificates from being copied to the mbedTLS
* heap if possible. The option is only effective for DER certificates and is
* ignored for PEM certificates.
@ -165,7 +166,40 @@ struct zsock_pollfd {
* This option accepts any value.
*/
#define TLS_SESSION_CACHE_PURGE 13
/** Write-only socket option to control DTLS CID.
* The option accepts an integer, indicating the setting.
* Accepted vaules for the option are: 0, 1 and 2.
* Effective when set before connecting to the socket.
* - 0 - DTLS CID will be disabled.
* - 1 - DTLS CID will be enabled, and a 0 length CID value to be sent to the
* peer.
* - 2 - DTLS CID will be enabled, and the most recent value set with
* TLS_DTLS_CID_VALUE will be sent to the peer. Otherwise, a random value
* will be used.
*/
#define TLS_DTLS_CID 14
/** Read-only socket option to get DTLS CID status.
* The option accepts a pointer to an integer, indicating the setting upon
* return.
* Returned vaules for the option are:
* - 0 - DTLS CID is disabled.
* - 1 - DTLS CID is received on the downlink.
* - 2 - DTLS CID is sent to the uplink.
* - 3 - DTLS CID is used in both directions.
*/
#define TLS_DTLS_CID_STATUS 15
/** Socket option to set or get the value of the DTLS connection ID to be
* used for the DTLS session.
* The option accepts a byte array, holding the CID value.
*/
#define TLS_DTLS_CID_VALUE 16
/** Read-only socket option to get the value of the DTLS connection ID
* received from the peer.
* The option accepts a pointer to a byte array, holding the CID value upon
* return. The optlen returned will be 0 if the peer did not provide a
* connection ID, otherwise will contain the length of the CID value.
*/
#define TLS_DTLS_PEER_CID_VALUE 17
/** @} */
/* Valid values for TLS_PEER_VERIFY option */
@ -185,6 +219,17 @@ struct zsock_pollfd {
#define TLS_SESSION_CACHE_DISABLED 0 /**< Disable TLS session caching. */
#define TLS_SESSION_CACHE_ENABLED 1 /**< Enable TLS session caching. */
/* Valid values for TLS_DTLS_CID option */
#define TLS_DTLS_CID_DISABLED 0
#define TLS_DTLS_CID_SUPPORTED 1
#define TLS_DTLS_CID_ENABLED 2
/* Valid values for TLS_DTLS_CID_STATUS option */
#define TLS_DTLS_CID_STATUS_DISABLED 0
#define TLS_DTLS_CID_STATUS_DOWNLINK 1
#define TLS_DTLS_CID_STATUS_UPLINK 2
#define TLS_DTLS_CID_STATUS_BIDIRECTIONAL 3
struct zsock_addrinfo {
struct zsock_addrinfo *ai_next;
int ai_flags;

View file

@ -112,6 +112,15 @@ struct tls_session_cache {
size_t session_len;
};
#if defined(CONFIG_NET_SOCKETS_ENABLE_DTLS)
struct tls_dtls_cid {
bool enabled;
unsigned char cid[MAX(MBEDTLS_SSL_CID_OUT_LEN_MAX,
MBEDTLS_SSL_CID_IN_LEN_MAX)];
size_t cid_len;
};
#endif
/** TLS context information. */
__net_socket struct tls_context {
/** Information whether TLS context is used. */
@ -185,6 +194,8 @@ __net_socket struct tls_context {
/* DTLS handshake timeout */
uint32_t dtls_handshake_timeout_min;
uint32_t dtls_handshake_timeout_max;
struct tls_dtls_cid dtls_cid;
#endif /* CONFIG_NET_SOCKETS_ENABLE_DTLS */
} options;
@ -446,6 +457,8 @@ static struct tls_context *tls_alloc(void)
MBEDTLS_SSL_DTLS_TIMEOUT_DFL_MIN;
tls->options.dtls_handshake_timeout_max =
MBEDTLS_SSL_DTLS_TIMEOUT_DFL_MAX;
tls->options.dtls_cid.cid_len = 0;
tls->options.dtls_cid.enabled = false;
#endif
#if defined(MBEDTLS_X509_CRT_PARSE_C)
mbedtls_x509_crt_init(&tls->ca_chain);
@ -1291,6 +1304,18 @@ static int tls_mbedtls_init(struct tls_context *context, bool is_server)
context->options.dtls_handshake_timeout_min,
context->options.dtls_handshake_timeout_max);
#if defined(CONFIG_MBEDTLS_SSL_DTLS_CONNECTION_ID)
if (context->options.dtls_cid.enabled) {
ret = mbedtls_ssl_conf_cid(
&context->config,
context->options.dtls_cid.cid_len,
MBEDTLS_SSL_UNEXPECTED_CID_IGNORE);
if (ret != 0) {
return -EINVAL;
}
}
#endif /* CONFIG_MBEDTLS_SSL_DTLS_CONNECTION_ID */
/* Configure cookie for DTLS server */
if (role == MBEDTLS_SSL_IS_SERVER) {
ret = mbedtls_ssl_cookie_setup(&context->cookie,
@ -1373,6 +1398,19 @@ static int tls_mbedtls_init(struct tls_context *context, bool is_server)
return -ENOMEM;
}
#if defined(CONFIG_NET_SOCKETS_ENABLE_DTLS) && defined(CONFIG_MBEDTLS_SSL_DTLS_CONNECTION_ID)
if (type == MBEDTLS_SSL_TRANSPORT_DATAGRAM) {
if (context->options.dtls_cid.enabled) {
ret = mbedtls_ssl_set_cid(&context->ssl, MBEDTLS_SSL_CID_ENABLED,
context->options.dtls_cid.cid,
context->options.dtls_cid.cid_len);
if (ret != 0) {
return -EINVAL;
}
}
}
#endif /* CONFIG_NET_SOCKETS_ENABLE_DTLS && CONFIG_MBEDTLS_SSL_DTLS_CONNECTION_ID */
context->is_initialized = true;
return 0;
@ -1613,6 +1651,160 @@ static int tls_opt_dtls_handshake_timeout_set(struct tls_context *context,
return 0;
}
static int tls_opt_dtls_connection_id_set(struct tls_context *context,
const void *optval, socklen_t optlen)
{
#if defined(CONFIG_MBEDTLS_SSL_DTLS_CONNECTION_ID)
int value;
if (optlen > 0 && optval == NULL) {
return -EINVAL;
}
if (optlen != sizeof(int)) {
return -EINVAL;
}
value = *((int *)optval);
switch (value) {
case TLS_DTLS_CID_DISABLED:
context->options.dtls_cid.enabled = false;
context->options.dtls_cid.cid_len = 0;
break;
case TLS_DTLS_CID_SUPPORTED:
context->options.dtls_cid.enabled = true;
context->options.dtls_cid.cid_len = 0;
break;
case TLS_DTLS_CID_ENABLED:
context->options.dtls_cid.enabled = true;
if (context->options.dtls_cid.cid_len == 0) {
/* generate random self cid */
#if defined(CONFIG_ENTROPY_HAS_DRIVER)
sys_csrand_get(context->options.dtls_cid.cid,
MBEDTLS_SSL_CID_OUT_LEN_MAX);
#else
sys_rand_get(context->options.dtls_cid.cid,
MBEDTLS_SSL_CID_OUT_LEN_MAX);
#endif
context->options.dtls_cid.cid_len = MBEDTLS_SSL_CID_OUT_LEN_MAX;
}
break;
default:
return -EINVAL;
}
return 0;
#else
return -ENOPROTOOPT;
#endif /* CONFIG_MBEDTLS_SSL_DTLS_CONNECTION_ID */
}
static int tls_opt_dtls_connection_id_value_set(struct tls_context *context,
const void *optval,
socklen_t optlen)
{
#if defined(CONFIG_MBEDTLS_SSL_DTLS_CONNECTION_ID)
if (optlen > 0 && optval == NULL) {
return -EINVAL;
}
if (optlen > MBEDTLS_SSL_CID_IN_LEN_MAX) {
return -EINVAL;
}
context->options.dtls_cid.cid_len = optlen;
memcpy(context->options.dtls_cid.cid, optval, optlen);
return 0;
#else
return -ENOPROTOOPT;
#endif /* CONFIG_MBEDTLS_SSL_DTLS_CONNECTION_ID */
}
static int tls_opt_dtls_connection_id_value_get(struct tls_context *context,
void *optval, socklen_t *optlen)
{
#if defined(CONFIG_MBEDTLS_SSL_DTLS_CONNECTION_ID)
if (*optlen < context->options.dtls_cid.cid_len) {
return -EINVAL;
}
*optlen = context->options.dtls_cid.cid_len;
memcpy(optval, context->options.dtls_cid.cid, *optlen);
return 0;
#else
return -ENOPROTOOPT;
#endif
}
static int tls_opt_dtls_peer_connection_id_value_get(struct tls_context *context,
void *optval,
socklen_t *optlen)
{
#if defined(CONFIG_MBEDTLS_SSL_DTLS_CONNECTION_ID)
int enabled = false;
int ret;
ret = mbedtls_ssl_get_peer_cid(&context->ssl, &enabled, optval, optlen);
if (!enabled) {
*optlen = 0;
}
return ret;
#else
return -ENOPROTOOPT;
#endif
}
static int tls_opt_dtls_connection_id_status_get(struct tls_context *context,
void *optval, socklen_t *optlen)
{
#if defined(CONFIG_MBEDTLS_SSL_DTLS_CONNECTION_ID)
struct tls_dtls_cid cid;
int ret;
int val;
int enabled;
bool have_self_cid;
bool have_peer_cid;
if (sizeof(int) != *optlen) {
return -EINVAL;
}
ret = mbedtls_ssl_get_peer_cid(&context->ssl, &enabled,
cid.cid,
&cid.cid_len);
if (ret) {
/* Handshake is not complete */
return -EAGAIN;
}
cid.enabled = (enabled == MBEDTLS_SSL_CID_ENABLED);
have_self_cid = (context->options.dtls_cid.cid_len != 0);
have_peer_cid = (cid.cid_len != 0);
if (!context->options.dtls_cid.enabled) {
val = TLS_DTLS_CID_STATUS_DISABLED;
} else if (have_self_cid && have_peer_cid) {
val = TLS_DTLS_CID_STATUS_BIDIRECTIONAL;
} else if (have_self_cid) {
val = TLS_DTLS_CID_STATUS_DOWNLINK;
} else if (have_peer_cid) {
val = TLS_DTLS_CID_STATUS_UPLINK;
} else {
val = TLS_DTLS_CID_STATUS_DISABLED;
}
*((int *)optval) = val;
return 0;
#else
return -ENOPROTOOPT;
#endif
}
#endif /* CONFIG_NET_SOCKETS_ENABLE_DTLS */
static int tls_opt_alpn_list_get(struct tls_context *context,
@ -3004,6 +3196,20 @@ int ztls_getsockopt_ctx(struct tls_context *ctx, int level, int optname,
err = tls_opt_dtls_handshake_timeout_get(ctx, optval,
optlen, true);
break;
case TLS_DTLS_CID_STATUS:
err = tls_opt_dtls_connection_id_status_get(ctx, optval,
optlen);
break;
case TLS_DTLS_CID_VALUE:
err = tls_opt_dtls_connection_id_value_get(ctx, optval, optlen);
break;
case TLS_DTLS_PEER_CID_VALUE:
err = tls_opt_dtls_peer_connection_id_value_get(ctx, optval,
optlen);
break;
#endif /* CONFIG_NET_SOCKETS_ENABLE_DTLS */
default:
@ -3108,6 +3314,15 @@ int ztls_setsockopt_ctx(struct tls_context *ctx, int level, int optname,
err = tls_opt_dtls_handshake_timeout_set(ctx, optval,
optlen, true);
break;
case TLS_DTLS_CID:
err = tls_opt_dtls_connection_id_set(ctx, optval, optlen);
break;
case TLS_DTLS_CID_VALUE:
err = tls_opt_dtls_connection_id_value_set(ctx, optval, optlen);
break;
#endif /* CONFIG_NET_SOCKETS_ENABLE_DTLS */
case TLS_NATIVE: