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 value that is used to identify which DTLS sock has access to which credential. Each DTLS sock will also be assigned a tag. As a result, a sock can only use credentials that have the same tag as its assigned tag.
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 create a session with the remote endpoint using sock_dtls_session_create(). We can set the timeout to 0
if we want the function returns immediately after starting the handshake. In that case, 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_create() 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.
Modules | |
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. | |
Typedefs | |
typedef struct sock_dtls | sock_dtls_t |
Type for a DTLS sock object. More... | |
typedef struct sock_dtls_session | sock_dtls_session_t |
Information about a created session. | |
Functions | |
void | sock_dtls_init (void) |
Called exactly once during auto_init . More... | |
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. More... | |
sock_udp_t * | sock_dtls_get_udp_sock (sock_dtls_t *sock) |
Get underlying UDP sock. More... | |
int | sock_dtls_session_init (sock_dtls_t *sock, const sock_udp_ep_t *ep, sock_dtls_session_t *remote) |
Initialize session handshake. More... | |
void | sock_dtls_session_destroy (sock_dtls_t *sock, sock_dtls_session_t *remote) |
Destroys an existing DTLS session. More... | |
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. More... | |
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. More... | |
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. More... | |
void | sock_dtls_close (sock_dtls_t *sock) |
Closes a DTLS sock. More... | |
static int | sock_dtls_session_create (sock_dtls_t *sock, const sock_udp_ep_t *ep, sock_dtls_session_t *remote, unsigned timeout) |
Creates a new DTLS session. More... | |
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... | |
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 same tag given here. |
[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.
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.
[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_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.
[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_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.
[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 |
Creates a new DTLS session.
Initiates a handshake with a DTLS server at ep
and wait until it completes or timed out.
[in] | sock | DLTS sock to use |
[in] | ep | Remote endpoint of the session |
[out] | remote | The created session, cannot be NULL |
[in] | timeout | Timeout to wait for handshake to finish. Returns immediately if 0. May be SOCK_NO_TIMEOUT to wait indefinitely until handshake complete. |
sock
is not set. remote
is invalid or sock
is not properly initialized (or closed while sock_udp_recv() blocks). 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 |
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).