1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/pkg/wolfssl/sock_tls/sock_tls.h
2021-08-13 19:50:38 +02:00

342 lines
12 KiB
C

/*
* Copyright (C) 2019 Daniele Lacamera
*
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/* @defgroup module sock_tls
* @ingroup pkg_wolfssl
* @brief Sock submodule for TLS/DTLS sessions
*
* How To Use
* ----------
* First you need to @ref including-modules "include" a module that implements
* this API in your application's Makefile.
*
* The `sock_tls` module requires the `wolfssl` package.
*
* The application's Makefile should at lease contain the following:
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {Makefile}
*
* USEPKG += wolfssl
* USEMODULE+=sock_tls
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
*
* ### A Simple DTLS Server
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
* #include <wolfssl/ssl.h>
* #include <sock_tls.h>
*
* #include <stdio.h>
* #include <inttypes.h>
*
* #include <net/sock/udp.h>
*
* #include <stdio.h>
* #include <stdlib.h>
* #include <string.h>
*
* #define SERVER_PORT 11111
* #define DEBUG 1
* extern const unsigned char server_cert[788];
* extern const unsigned char server_key[121];
* extern unsigned int server_cert_len;
* extern unsigned int server_key_len;
*
* static sock_tls_t skv;
* static sock_tls_t *sk = &skv;
* static const char Test_dtls_string[] = "DTLS OK!";
*
* int main(void)
* {
* char buf[64];
* int ret;
* sock_udp_ep_t local = SOCK_IPV6_EP_ANY;
* local.port = SERVER_PORT;
*
* if (sock_dtls_create(sk, &local, NULL, 0, wolfDTLSv1_2_server_method()) != 0) {
* printf("Failed to create DTLS socket context\r\n");
* return -1;
* }
* if (wolfSSL_CTX_use_certificate_buffer(sk->ctx, server_cert,
* server_cert_len, SSL_FILETYPE_ASN1 ) != SSL_SUCCESS)
* {
* printf("Failed to load certificate from memory.\r\n");
* return -1;
* }
*
* if (wolfSSL_CTX_use_PrivateKey_buffer(sk->ctx, server_key,
* server_key_len, SSL_FILETYPE_ASN1 ) != SSL_SUCCESS)
* {
* printf("Failed to load private key from memory.\r\n");
* return -1;
* }
* ret = sock_dtls_session_create(sk);
* if (ret < 0)
* {
* printf("Failed to create DTLS session (err: %s)\r\n", strerror(-ret));
* return -1;
* }
* printf("Listening on %d\n", SERVER_PORT);
* while(1) {
* ret = wolfSSL_accept(sk->ssl);
* if (ret != SSL_SUCCESS) {
* continue;
* }
* printf("Connection accepted\r\n");
* ret = wolfSSL_read(sk->ssl, buf, 64);
* if (ret > 0) {
* buf[ret] = (char)0;
* printf("Received '%s'\r\n", buf);
* }
* printf("Sending 'DTLS OK'...\r\n");
* wolfSSL_write(sk->ssl, Test_dtls_string, sizeof(Test_dtls_string));
* printf("Closing connection.\r\n");
* sock_dtls_session_destroy(sk);
* sock_dtls_close(sk);
* break;
* }
* return 0;
* }
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* Above you see a simple DTLS echo server. It is important to at least include
* @ref including-modules "include" the IPv6 module of your networking
* implementation (e.g. `gnrc_ipv6_default` for @ref net_gnrc GNRC) and at least
* one network device.
* A separate file should define the buffers used as certificate and private key,
* in the variables `server_cert`, `private_key` respectively.
*
* After including all the needed header files, we use a global object to store
* the context for incoming DTLS communication. The object contains the reference
* to the wolfSSL context, the SSL session and the underlying transport socket.
*
* For simplicity, we will refer to the address of the object in the static memory,
* through the pointer `sk`.
*
* A constant test string is used later as a reply to incoming connections.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
* static sock_tls_t skv;
* static sock_tls_t *sk = &skv;
*
* static const char Test_dtls_string[] = "DTLS OK!";
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* In the same way as a normal @ref net_sock_udp "UDP socket", in order to be able to
* listen for incoming packets, we bind the `sock` by setting a local endpoint with
* a port (`11111` in this case).
*
* We then proceed to create the `sock`. It is bound to `local` and thus listens
* for UDP packets with @ref udp_hdr_t::dst_port "destination port" `12345`.
* Since we don't need any further configuration we set the flags to 0.
* The method argument determines which kind of wolfSSL context is associated to
* the socket.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
* sock_udp_ep_t local = SOCK_IPV6_EP_ANY;
* local.port = SERVER_PORT;
*
* if (sock_dtls_create(sk, &local, NULL, 0, wolfDTLSv1_2_server_method()) != 0) {
* printf("ERROR: Unable to create DTLS sock\r\n");
* return -1;
* }
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* By default, all sock_tls operations in a DTLS context are blocking for a
* limited amount of time, which depends on the DTLS session timeout. To modify
* the timeout, use `wolfSSL_dtls_set_timeout_init(sk->ssl)`.
*
* Certificate and private key for the server context are loaded from a previously
* initialized section in memory:
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
* if (wolfSSL_CTX_use_certificate_buffer(sk->ctx, server_cert,
* server_cert_len, SSL_FILETYPE_ASN1 ) != SSL_SUCCESS)
* {
* printf("Failed to load certificate from memory.\r\n");
* return -1;
* }
*
* if (wolfSSL_CTX_use_PrivateKey_buffer(sk->ctx, server_key,
* server_key_len, SSL_FILETYPE_ASN1 ) != SSL_SUCCESS)
* {
* printf("Failed to load private key from memory.\r\n");
* return -1;
* }
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* Once the context is configured, the SSL session can be initialized.
*
* The listening sock automatically takes care of the DTLS handshake.
* When the session is established, `wolfSSL_accept()` will finally return
* `SSL_SUCCESS`.
*
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
* ret = sock_dtls_session_create(sk);
* if (ret < 0)
* {
* printf("Failed to create DTLS session (err: %s)\r\n", strerror(-ret));
* return -1;
* }
* printf("Listening on %d\n", SERVER_PORT);
* while(1) {
* ret = wolfSSL_accept(sk->ssl);
* if (ret != SSL_SUCCESS) {
* continue;
* }
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* At this point, the session is established, and encrypted data can be exchanged
* using `wolfSSL_read()` and `wolfSSL_write()`:
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
* ret = wolfSSL_read(sk->ssl, buf, 64);
* if (ret > 0) {
* buf[ret] = (char)0;
* printf("Received '%s'\r\n", buf);
* }
* printf("Sending 'DTLS OK'...\r\n");
* wolfSSL_write(sk->ssl, Test_dtls_string, sizeof(Test_dtls_string));
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* The session is terminated, and the associated socket is closed.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
* sock_dtls_session_destroy(sk);
* sock_dtls_close(sk);
* break;
* }
* return 0;
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
*/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <net/sock.h>
#include <wolfssl/ssl.h>
#ifndef SOCK_TLS_H
#define SOCK_TLS_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Creates a new DTLS sock object.
*
* @pre `(sock != NULL)`
* @pre `(remote == NULL) || (remote->port != 0)`
*
* @param[out] sock The resulting sock object.
* @param[in] local Local end point for the sock object.
* May be NULL.
* sock_udp_ep_t::netif must either be
* @ref SOCK_ADDR_ANY_NETIF or equal to
* sock_udp_ep_t::netif of @p remote if `remote != NULL`.
* If NULL @ref sock_udp_send() may bind implicitly.
* sock_udp_ep_t::port may also be 0 to bind the `sock` to
* an ephemeral port.
* @param[in] remote Remote end point for the sock object.
* May be `NULL` but then the `remote` parameter of
* @ref sock_udp_send() may not be `NULL` or it will
* always error with return value -ENOTCONN.
* sock_udp_ep_t::port must not be 0 if `remote != NULL`.
* sock_udp_ep_t::netif must either be
* @ref SOCK_ADDR_ANY_NETIF or equal to sock_udp_ep_t::netif
* of @p local if `local != NULL`.
* @param[in] flags Flags for the sock object. See also
* [sock flags](@ref net_sock_flags).
* May be 0.
* @param[in] method Defines the SSL or TLS protocol for the client or server to use.
* There are several options for selecting the desired protocol.
* wolfSSL currently supports DTLS 1.0, and DTLS 1.2. Each of these
* protocols have a corresponding function that can be used as last
* argument to `sock_dtls_create`. The possible client and server
* protocol options are: `wolfDTLSv1_client_method()`, `wolfDTLSv1_server_method()`,
* `wolfDTLSv1_2_client_method()` and `wolfDTLSv1_server_method`.
*
* @return 0 on success.
* @return -EADDRINUSE, if `local != NULL` and @p local is already used
* elsewhere or if `local->port == 0` but the pool of ephemeral ports
* is depleted
* @return -EAFNOSUPPORT, if `local != NULL` or `remote != NULL` and
* sock_udp_ep_t::family of @p local or @p remote is not supported.
* @return -EINVAL, if sock_udp_ep_t::addr of @p remote is an invalid address.
* @return -EINVAL, if sock_udp_ep_t::netif of @p local or @p remote are not a
* valid interfaces or contradict each other (i.e.
* `(local->netif != remote->netif) &&
* ((local->netif != SOCK_ADDR_ANY_NETIF) ||
* (remote->netif != SOCK_ADDR_ANY_NETIF))` if neither is `NULL`).
* @return -ENOMEM, if not enough resources can be provided for `sock` to be
* created.
*/
int sock_dtls_create(sock_tls_t *sock, const sock_udp_ep_t *local, const sock_udp_ep_t *remote, uint16_t flags, WOLFSSL_METHOD *method);
/**
* @brief Sets the endpoint address for the remote DTLS peer associated to this sock object
*
* @pre `(sk != NULL)`
* @pre `(addr != NULL)`
*
* @param[in] sk The resulting sock object.
* @param[in] addr Remote end point for the DTLS session.
*
*/
void sock_dtls_set_endpoint(sock_tls_t *sk, const sock_udp_ep_t *addr);
/**
* @brief Creates a new DTLS session from an existing `sock_tls_t` object.
*
* @pre `(sk != NULL)`
*
* @param[in] sk The sock object previously created using @ref sock_dtls_create
*
* @return 0 on success.
* @return -EINVAL, if @sock is null or the SSL context is not initialized yet.
* @return -ENOMEM, if not enough resources can be provided for the session to be
* created
*/
int sock_dtls_session_create(sock_tls_t *sk);
/**
* @brief Destroys the DTLS session associated to the sock object.
*
* @pre `(sk != NULL)`
*
* @param[in] sk The sock object containing the session to destroy.
*
*/
void sock_dtls_session_destroy(sock_tls_t *sk);
/**
* @brief Closes the socket connection associated to the DTLS session.
*
* @pre `(sk != NULL)`
*
* @param[in] sk The sock object containing the UDP socket to close.
*
*/
void sock_dtls_close(sock_tls_t *sk);
#ifdef MODULE_SOCK_TCP
# error Only support for UDP/IP provided via GNRC stack.
#endif
#ifdef __cplusplus
}
#endif
#endif /* SOCK_TLS_H */