Sock submodule for DTLS. More...
Sock submodule for DTLS.
DTLS sock acts as a wrapper for the underlying DTLS module to provide encryption for applications using the UDP sock API.
First, we need to include a module that implements this API in our applications Makefile. For example the module that implements this API for tinydtls is called ‘tinydtls_sock_dtls’.
The corresponding pkg providing the DTLS implementation will be automatically included so there is no need to use USEPKG
to add the pkg manually.
Each DTLS implementation may have its own configuration options and caveat. This can be found at DTLS.
Before using this API, either as a server or a client, we first need to add the credentials to be used for the encryption using credman. Note that credman does not copy the credentials given into the system, it only has information about the credentials and where it is located at. So it is your responsibility to make sure that the credential is valid during the lifetime of your application.
Above we see an example of how to register a PSK and an ECC credential.
First, we need to include the header file for the API.
We tell credman which credential to add by filling in the credentials information in a struct credman_credential_t. For PSK credentials, we use enum CREDMAN_TYPE_PSK for the type.
Next, we must assign a tag for the credential. Tags are unsigned integer values used to identify which DTLS sock has access to which credentials. Each DTLS sock will also be assigned a list of tags. As a result, a sock can only use credentials that have the same tag as the ones in the list.
After credential information is filled, we can add it to the credential pool using credman_add().
For adding credentials of other types, you can follow the steps above except credman_credential_t::type and credman_credential_t::params depend on the type of credential used.
After credentials are added, we can start the server.
This is an example of a DTLS echo server.
DTLS sock uses an initialized UDP sock to send and receive encrypted packets. Therefore, the listening port for the server also needs to be set here.
Using the initialized UDP sock, we can then create our DTLS sock. We use SOCK_DTLS_SERVER_TAG, which is defined as 10
in our application code beforehand, as our tag. Using SOCK_DTLS_1_2 and SOCK_DTLS_SERVER, we set our DTLS endpoint to use DTLS version 1.2 and act as a DTLS server.
Note that some DTLS implementation do not support earlier versions of DTLS. In this case, sock_dtls_create() will return an error. A list of supported DTLS version for each DTLS implementation can be found at this page. In case of error, the program is stopped.
Now we can listen to incoming packets using sock_dtls_recv(). The application waits indefinitely for new packets. If we want to timeout this wait period we could alternatively set the timeout
parameter of the function to a value != SOCK_NO_TIMEOUT. If an error occurs we just ignore it and continue looping. We can reply to an incoming message using its session
.
This is an example of a DTLS echo client.
Like the server, we must first create the UDP sock.
After that, we set the address of the remote endpoint and its listening port, which is DTLS_DEFAULT_PORT (20220).
After the UDP sock is created, we can proceed with creating the DTLS sock. Before sending the packet, we must first initiate a session handshake with the remote endpoint using sock_dtls_session_init(). We will need to call sock_dtls_recv() to receive and process all the handshake packets. If the handshake is successful and the session is created, we send packets to it using sock_dtls_send(). As we already know the session exists, we can set the timeout to 0
and listen to the reply with sock_dtls_recv().
Alternatively, set the timeout to of sock_dtls_send() to the duration we want to wait for the handshake process. We can also set the timeout to SOCK_NO_TIMEOUT to block indefinitely until handshake is complete. After handshake completes, the packet will be sent.
sock_dtls_init(), sock_dtls_recv and sock_dtls_close() only manages the DTLS layer. That means we still have to clean up the created UDP sock from before by calling sock_udp_close() on our UDP sock in case of error or we reached the end of the application.
Each sock needs at least one credential tag to operate. sock_dtls_create
allows to optionally assign an initial credential. Extra credentials can be added and removed using sock_dtls_add_credential and sock_dtls_remove_credential respectively (found in net/sock/dtls/creds.h
).
In the case of PSK, a server can optionally indicate a hint to help the client to decide which PSK Identity to use, using sock_dtls_set_server_psk_id_hint (see https://tools.ietf.org/html/rfc4279#section-5.2). The client application can decide which credential to use based on the sent hint and/or the session information, by registering a callback with sock_dtls_set_client_psk_cb. If no callback is registered, or fails to chose a tag (i.e. it returns CREDMAN_TAG_EMPTY), the credential is chosen as follows: if a hint is sent by the server, all credentials registered to the sock are checked for a matching hint. A credential is selected on matching hint. If no credential matches the hint or no hint is provided, the first PSK credential registered in the sock is used.
When using ECC both client and server applications can register a callback to decide which of the registered credentials should be used, based on the session information. This is done using sock_dtls_set_rpk_cb.
In both cases, if no callbacks are registered, the sock implementation will try to find a registered credential in the Sock's credential list, that matches the needed type. The first one that matches is used.
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).
Modules | |
DTLS sock credentials API | |
Credential handling for DTLS sock. | |
SOCK DTLS compile configuration | |
Files | |
file | dtls.h |
DTLS sock definitions. | |
Macros | |
#define | DTLS_HANDSHAKE_BUFSIZE (1 << CONFIG_DTLS_HANDSHAKE_BUFSIZE_EXP) |
Size buffer used in handshake to hold credentials. | |
#define | SOCK_DTLS_HANDSHAKE (EXDEV) |
Return value for a successful handshake. | |
#define | CONFIG_DTLS_FORCE_EXTENDED_MASTER_SECRET 1 |
Force extended master secret extension. | |
#define | CONFIG_DTLS_FORCE_RENEGOTIATION_INFO 1 |
Force renegotiation info extension. | |
Typedefs | |
typedef struct sock_dtls | sock_dtls_t |
Type for a DTLS sock object. | |
typedef struct sock_dtls_session | sock_dtls_session_t |
Information about a created session. | |
typedef sock_udp_aux_rx_t | sock_dtls_aux_rx_t |
Auxiliary data provided when receiving using an DTLS sock object. | |
typedef sock_udp_aux_tx_t | sock_dtls_aux_tx_t |
Auxiliary data provided when sending using an DTLS sock object. | |
Functions | |
void | sock_dtls_init (void) |
Called exactly once during auto_init . | |
int | sock_dtls_create (sock_dtls_t *sock, sock_udp_t *udp_sock, credman_tag_t tag, unsigned version, unsigned role) |
Creates a new DTLS sock object. | |
sock_udp_t * | sock_dtls_get_udp_sock (sock_dtls_t *sock) |
Get underlying UDP sock. | |
int | sock_dtls_session_init (sock_dtls_t *sock, const sock_udp_ep_t *ep, sock_dtls_session_t *remote) |
Initialize session handshake. | |
void | sock_dtls_session_destroy (sock_dtls_t *sock, sock_dtls_session_t *remote) |
Destroys an existing DTLS session. | |
void | sock_dtls_session_get_udp_ep (const sock_dtls_session_t *session, sock_udp_ep_t *ep) |
Get the remote UDP endpoint from a session. | |
void | sock_dtls_session_set_udp_ep (sock_dtls_session_t *session, const sock_udp_ep_t *ep) |
Set the remote UDP endpoint from a session. | |
ssize_t | sock_dtls_recv_aux (sock_dtls_t *sock, sock_dtls_session_t *remote, void *data, size_t maxlen, uint32_t timeout, sock_dtls_aux_rx_t *aux) |
Receive handshake messages and application data from remote peer. | |
static ssize_t | sock_dtls_recv (sock_dtls_t *sock, sock_dtls_session_t *remote, void *data, size_t maxlen, uint32_t timeout) |
Receive handshake messages and application data from remote peer. | |
ssize_t | sock_dtls_recv_buf_aux (sock_dtls_t *sock, sock_dtls_session_t *remote, void **data, void **buf_ctx, uint32_t timeout, sock_dtls_aux_rx_t *aux) |
Decrypts and provides stack-internal buffer space containing a message from a remote peer. | |
static ssize_t | sock_dtls_recv_buf (sock_dtls_t *sock, sock_dtls_session_t *remote, void **data, void **buf_ctx, uint32_t timeout) |
Decrypts and provides stack-internal buffer space containing a message from a remote peer. | |
ssize_t | sock_dtls_sendv_aux (sock_dtls_t *sock, sock_dtls_session_t *remote, const iolist_t *snips, uint32_t timeout, sock_dtls_aux_tx_t *aux) |
Encrypts and sends a message to a remote peer with non-continous payload. | |
static ssize_t | sock_dtls_send_aux (sock_dtls_t *sock, sock_dtls_session_t *remote, const void *data, size_t len, uint32_t timeout, sock_dtls_aux_tx_t *aux) |
Encrypts and sends a message to a remote peer. | |
static ssize_t | sock_dtls_send (sock_dtls_t *sock, sock_dtls_session_t *remote, const void *data, size_t len, uint32_t timeout) |
Encrypts and sends a message to a remote peer. | |
static ssize_t | sock_dtls_sendv (sock_dtls_t *sock, sock_dtls_session_t *remote, const iolist_t *snips, uint32_t timeout) |
Encrypts and sends a message to a remote peer with non-continous payload. | |
void | sock_dtls_close (sock_dtls_t *sock) |
Closes a DTLS sock. | |
enum | { SOCK_DTLS_1_0 = 1 , SOCK_DTLS_1_2 = 2 , SOCK_DTLS_1_3 = 3 } |
DTLS version number . More... | |
enum | { SOCK_DTLS_CLIENT = 1 , SOCK_DTLS_SERVER = 2 } |
DTLS role . More... | |
#define CONFIG_DTLS_FORCE_EXTENDED_MASTER_SECRET 1 |
#define CONFIG_DTLS_FORCE_RENEGOTIATION_INFO 1 |
#define DTLS_HANDSHAKE_BUFSIZE (1 << CONFIG_DTLS_HANDSHAKE_BUFSIZE_EXP) |
#define SOCK_DTLS_HANDSHAKE (EXDEV) |
typedef sock_udp_aux_rx_t sock_dtls_aux_rx_t |
Auxiliary data provided when receiving using an DTLS sock object.
typedef sock_udp_aux_tx_t sock_dtls_aux_tx_t |
Auxiliary data provided when sending using an DTLS sock object.
typedef struct sock_dtls_session sock_dtls_session_t |
typedef struct sock_dtls sock_dtls_t |
Type for a DTLS sock object.
struct sock_dtls
needs to be defined by an implementation-specific sock_dtls_types.h
. anonymous enum |
anonymous enum |
void sock_dtls_close | ( | sock_dtls_t * | sock | ) |
Closes a DTLS sock.
Releases any memory allocated by sock_dtls_create(). This function does NOT close the UDP sock used by the DTLS sock. After the call to this function, user will have to call sock_udp_close() to close the UDP sock.
(sock != NULL)
sock | DTLS sock to close |
int sock_dtls_create | ( | sock_dtls_t * | sock, |
sock_udp_t * | udp_sock, | ||
credman_tag_t | tag, | ||
unsigned | version, | ||
unsigned | role | ||
) |
Creates a new DTLS sock object.
Takes an initialized UDP sock and uses it for the transport. Memory allocation functions required by the underlying DTLS stack can be called in this function.
[out] | sock | The resulting DTLS sock object |
[in] | udp_sock | Existing UDP sock initialized with sock_udp_create() to be used underneath. |
[in] | tag | Credential tag of sock . The sock will only use credentials with the tags registered to it (see sock_dtls_add_credential). Set to CREDMAN_TAG_EMPTY to create a sock with an empty tag list. |
[in] | version | DTLS version to use. |
[in] | role | Role of the endpoint. |
sock_udp_t * sock_dtls_get_udp_sock | ( | sock_dtls_t * | sock | ) |
Get underlying UDP sock.
sock != NULL
.[in] | sock | DTLS sock to get UDP sock from. |
void sock_dtls_init | ( | void | ) |
Called exactly once during auto_init
.
Calls the initialization function required by the DTLS stack used.
|
inlinestatic |
Receive handshake messages and application data from remote peer.
[in] | sock | DTLS sock to use. |
[out] | remote | Remote DTLS session of the received data. Cannot be NULL. |
[out] | data | Pointer where the received data should be stored. |
[in] | maxlen | Maximum space available at data . |
[in] | timeout | Receive timeout in microseconds. If 0 and no data is available, the function returns immediately. May be SOCK_NO_TIMEOUT to wait until data is available. |
timeout
!= 0sock
is not set. timeout
is 0
and no data is available. remote
is invalid or sock
is not properly initialized (or closed while sock_dtls_recv() blocks). data
. timeout
expired. ssize_t sock_dtls_recv_aux | ( | sock_dtls_t * | sock, |
sock_dtls_session_t * | remote, | ||
void * | data, | ||
size_t | maxlen, | ||
uint32_t | timeout, | ||
sock_dtls_aux_rx_t * | aux | ||
) |
Receive handshake messages and application data from remote peer.
[in] | sock | DTLS sock to use. |
[out] | remote | Remote DTLS session of the received data. Cannot be NULL. |
[out] | data | Pointer where the received data should be stored. |
[in] | maxlen | Maximum space available at data . |
[in] | timeout | Receive timeout in microseconds. If 0 and no data is available, the function returns immediately. May be SOCK_NO_TIMEOUT to wait until data is available. |
[out] | aux | Auxiliary data about the received datagram. May be NULL , if it is not required by the application. |
timeout
!= 0sock
is not set. timeout
is 0
and no data is available. remote
is invalid or sock
is not properly initialized (or closed while sock_dtls_recv() blocks). data
. timeout
expired.
|
inlinestatic |
Decrypts and provides stack-internal buffer space containing a message from a remote peer.
[in] | sock | DTLS sock to use. |
[out] | remote | Remote DTLS session of the received data. Cannot be NULL. |
[out] | data | Pointer to a stack-internal buffer space containing the received data. |
[in,out] | buf_ctx | Stack-internal buffer context. If it points to a NULL pointer, the stack returns a new buffer space for a new packet. If it does not point to a NULL pointer, an existing context is assumed to get a next segment in a buffer. |
[in] | timeout | Receive timeout in microseconds. If 0 and no data is available, the function returns immediately. May be SOCK_NO_TIMEOUT to wait until data is available. |
timeout
!= 0buf_ctx
to get more buffers until result is 0 or an error. buf_ctx
was provided, it was released. sock
is not set. timeout
is 0
and no data is available. remote
is invalid or sock
is not properly initialized (or closed while sock_dtls_recv() blocks). data
. timeout
expired. ssize_t sock_dtls_recv_buf_aux | ( | sock_dtls_t * | sock, |
sock_dtls_session_t * | remote, | ||
void ** | data, | ||
void ** | buf_ctx, | ||
uint32_t | timeout, | ||
sock_dtls_aux_rx_t * | aux | ||
) |
Decrypts and provides stack-internal buffer space containing a message from a remote peer.
[in] | sock | DTLS sock to use. |
[out] | remote | Remote DTLS session of the received data. Cannot be NULL. |
[out] | data | Pointer to a stack-internal buffer space containing the received data. |
[in,out] | buf_ctx | Stack-internal buffer context. If it points to a NULL pointer, the stack returns a new buffer space for a new packet. If it does not point to a NULL pointer, an existing context is assumed to get a next segment in a buffer. |
[in] | timeout | Receive timeout in microseconds. If 0 and no data is available, the function returns immediately. May be SOCK_NO_TIMEOUT to wait until data is available. |
[out] | aux | Auxiliary data about the received datagram. May be NULL , if it is not required by the application. |
timeout
!= 0buf_ctx
to get more buffers until result is 0 or an error. buf_ctx
was provided, it was released. sock
is not set. timeout
is 0
and no data is available. remote
is invalid or sock
is not properly initialized (or closed while sock_dtls_recv() blocks). data
. timeout
expired.
|
inlinestatic |
Encrypts and sends a message to a remote peer.
[in] | sock | DTLS sock to use |
[in] | remote | DTLS session to use. A new session will be created if no session exist between client and server. |
[in] | data | Pointer where the data to be send are stored |
[in] | len | Length of data to be send |
[in] | timeout | Handshake timeout in microseconds. If timeout > 0 , will start a new handshake if no session exists yet. The function will block until handshake completed or timed out. May be SOCK_NO_TIMEOUT to block indefinitely until handshake complete. |
timeout == 0
and no existing session exists with remote
remote->ep != NULL
and sock_dtls_session_t::ep::family of remote
is != AF_UNSPEC and not supported. remote->ep
is an invalid address. remote->ep
is 0. data
. 0 < timeout < SOCK_NO_TIMEOUT
and timed out.
|
inlinestatic |
Encrypts and sends a message to a remote peer.
[in] | sock | DTLS sock to use |
[in] | remote | DTLS session to use. A new session will be created if no session exist between client and server. |
[in] | data | Pointer where the data to be send are stored |
[in] | len | Length of data to be send |
[in] | timeout | Handshake timeout in microseconds. If timeout > 0 , will start a new handshake if no session exists yet. The function will block until handshake completed or timed out. May be SOCK_NO_TIMEOUT to block indefinitely until handshake complete. |
[out] | aux | Auxiliary data about the transmission. May be NULL , if it is not required by the application. |
timeout == 0
and no existing session exists with remote
remote->ep != NULL
and sock_dtls_session_t::ep::family of remote
is != AF_UNSPEC and not supported. remote->ep
is an invalid address. remote->ep
is 0. data
. 0 < timeout < SOCK_NO_TIMEOUT
and timed out.
|
inlinestatic |
Encrypts and sends a message to a remote peer with non-continous payload.
[in] | sock | DTLS sock to use |
[in] | remote | DTLS session to use. A new session will be created if no session exist between client and server. |
[in] | snips | List of payload chunks, will be processed in order. May be NULL . |
[in] | timeout | Handshake timeout in microseconds. If timeout > 0 , will start a new handshake if no session exists yet. The function will block until handshake completed or timed out. May be SOCK_NO_TIMEOUT to block indefinitely until handshake complete. |
timeout == 0
and no existing session exists with remote
remote->ep != NULL
and sock_dtls_session_t::ep::family of remote
is != AF_UNSPEC and not supported. remote->ep
is an invalid address. remote->ep
is 0. data
. 0 < timeout < SOCK_NO_TIMEOUT
and timed out. ssize_t sock_dtls_sendv_aux | ( | sock_dtls_t * | sock, |
sock_dtls_session_t * | remote, | ||
const iolist_t * | snips, | ||
uint32_t | timeout, | ||
sock_dtls_aux_tx_t * | aux | ||
) |
Encrypts and sends a message to a remote peer with non-continous payload.
[in] | sock | DTLS sock to use |
[in] | remote | DTLS session to use. A new session will be created if no session exist between client and server. |
[in] | snips | List of payload chunks, will be processed in order. May be NULL . |
[in] | timeout | Handshake timeout in microseconds. If timeout > 0 , will start a new handshake if no session exists yet. The function will block until handshake completed or timed out. May be SOCK_NO_TIMEOUT to block indefinitely until handshake complete. |
[out] | aux | Auxiliary data about the transmission. May be NULL , if it is not required by the application. |
timeout == 0
and no existing session exists with remote
remote->ep != NULL
and sock_dtls_session_t::ep::family of remote
is != AF_UNSPEC and not supported. remote->ep
is an invalid address. remote->ep
is 0. data
. 0 < timeout < SOCK_NO_TIMEOUT
and timed out. void sock_dtls_session_destroy | ( | sock_dtls_t * | sock, |
sock_dtls_session_t * | remote | ||
) |
Destroys an existing DTLS session.
(sock != NULL) && (ep != NULL)
[in] | sock | sock_dtls_t, which the session is created on |
[in] | remote | Remote session to destroy |
void sock_dtls_session_get_udp_ep | ( | const sock_dtls_session_t * | session, |
sock_udp_ep_t * | ep | ||
) |
Get the remote UDP endpoint from a session.
(session != NULL) && (ep != NULL)
[in] | session | DTLS session |
[out] | ep | UDP endpoint |
int sock_dtls_session_init | ( | sock_dtls_t * | sock, |
const sock_udp_ep_t * | ep, | ||
sock_dtls_session_t * | remote | ||
) |
Initialize session handshake.
Sends a ClientHello message to initialize the handshake. Call sock_dtls_recv() to finish the handshake.
[in] | sock | DTLS sock to use |
[in] | ep | Remote endpoint to start a handshake with |
[out] | remote | Resulting session |
sock
is not set. remote
is invalid or sock
is not properly initialized (or closed while sock_udp_recv() blocks). void sock_dtls_session_set_udp_ep | ( | sock_dtls_session_t * | session, |
const sock_udp_ep_t * | ep | ||
) |
Set the remote UDP endpoint from a session.
(session != NULL) && (ep != NULL)
[in] | session | DTLS session |
[in] | ep | UDP endpoint |