sock_tls.h
1 /*
2  * Copyright (C) 2019 Daniele Lacamera
3  *
4  *
5  * This file is subject to the terms and conditions of the GNU Lesser
6  * General Public License v2.1. See the file LICENSE in the top level
7  * directory for more details.
8  */
9 
10 /* @defgroup module sock_tls
11  * @ingroup pkg_wolfssl
12  * @brief Sock submodule for TLS/DTLS sessions
13  *
14  * How To Use
15  * ----------
16  * First you need to @ref including-modules "include" a module that implements
17  * this API in your application's Makefile.
18  *
19  * The `sock_tls` module requires the `wolfssl` package.
20  *
21  * The application's Makefile should at lease contain the following:
22  *
23  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {Makefile}
24  *
25  * USEPKG += wolfssl
26  * USEMODULE+=sock_tls
27  *
28  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
29  *
30  *
31  * ### A Simple DTLS Server
32  *
33  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
34  * #include <wolfssl/ssl.h>
35  * #include <sock_tls.h>
36  *
37  * #include <stdio.h>
38  * #include <inttypes.h>
39  *
40  * #include <net/sock/udp.h>
41  *
42  * #include <stdio.h>
43  * #include <stdlib.h>
44  * #include <string.h>
45  *
46  * #define SERVER_PORT 11111
47  * #define DEBUG 1
48  * extern const unsigned char server_cert[788];
49  * extern const unsigned char server_key[121];
50  * extern unsigned int server_cert_len;
51  * extern unsigned int server_key_len;
52  *
53  * static sock_tls_t skv;
54  * static sock_tls_t *sk = &skv;
55  * static const char Test_dtls_string[] = "DTLS OK!";
56  *
57  * int main(void)
58  * {
59  * char buf[64];
60  * int ret;
61  * sock_udp_ep_t local = SOCK_IPV6_EP_ANY;
62  * local.port = SERVER_PORT;
63  *
64  * if (sock_dtls_create(sk, &local, NULL, 0, wolfDTLSv1_2_server_method()) != 0) {
65  * printf("Failed to create DTLS socket context\r\n");
66  * return -1;
67  * }
68  * if (wolfSSL_CTX_use_certificate_buffer(sk->ctx, server_cert,
69  * server_cert_len, SSL_FILETYPE_ASN1 ) != SSL_SUCCESS)
70  * {
71  * printf("Failed to load certificate from memory.\r\n");
72  * return -1;
73  * }
74  *
75  * if (wolfSSL_CTX_use_PrivateKey_buffer(sk->ctx, server_key,
76  * server_key_len, SSL_FILETYPE_ASN1 ) != SSL_SUCCESS)
77  * {
78  * printf("Failed to load private key from memory.\r\n");
79  * return -1;
80  * }
81  * ret = sock_dtls_session_create(sk);
82  * if (ret < 0)
83  * {
84  * printf("Failed to create DTLS session (err: %s)\r\n", strerror(-ret));
85  * return -1;
86  * }
87  * printf("Listening on %d\n", SERVER_PORT);
88  * while(1) {
89  * ret = wolfSSL_accept(sk->ssl);
90  * if (ret != SSL_SUCCESS) {
91  * continue;
92  * }
93  * printf("Connection accepted\r\n");
94  * ret = wolfSSL_read(sk->ssl, buf, 64);
95  * if (ret > 0) {
96  * buf[ret] = (char)0;
97  * printf("Received '%s'\r\n", buf);
98  * }
99  * printf("Sending 'DTLS OK'...\r\n");
100  * wolfSSL_write(sk->ssl, Test_dtls_string, sizeof(Test_dtls_string));
101  * printf("Closing connection.\r\n");
102  * sock_dtls_session_destroy(sk);
103  * sock_dtls_close(sk);
104  * break;
105  * }
106  * return 0;
107  * }
108  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
109  *
110  * Above you see a simple DTLS echo server. It is important to at least include
111  * @ref including-modules "include" the IPv6 module of your networking
112  * implementation (e.g. `gnrc_ipv6_default` for @ref net_gnrc GNRC) and at least
113  * one network device.
114  * A separate file should define the buffers used as certificate and private key,
115  * in the variables `server_cert`, `private_key` respectively.
116  *
117  * After including all the needed header files, we use a global object to store
118  * the context for incoming DTLS communication. The object contains the reference
119  * to the wolfSSL context, the SSL session and the underlying transport socket.
120  *
121  * For simplicity, we will refer to the address of the object in the static memory,
122  * through the pointer `sk`.
123  *
124  * A constant test string is used later as a reply to incoming connections.
125  *
126  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
127  * static sock_tls_t skv;
128  * static sock_tls_t *sk = &skv;
129  *
130  * static const char Test_dtls_string[] = "DTLS OK!";
131  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
132  *
133  * In the same way as a normal @ref net_sock_udp "UDP socket", in order to be able to
134  * listen for incoming packets, we bind the `sock` by setting a local endpoint with
135  * a port (`11111` in this case).
136  *
137  * We then proceed to create the `sock`. It is bound to `local` and thus listens
138  * for UDP packets with @ref udp_hdr_t::dst_port "destination port" `12345`.
139  * Since we don't need any further configuration we set the flags to 0.
140  * The method argument determines which kind of wolfSSL context is associated to
141  * the socket.
142 *
143  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
144  * sock_udp_ep_t local = SOCK_IPV6_EP_ANY;
145  * local.port = SERVER_PORT;
146  *
147  * if (sock_dtls_create(sk, &local, NULL, 0, wolfDTLSv1_2_server_method()) != 0) {
148  * printf("ERROR: Unable to create DTLS sock\r\n");
149  * return -1;
150  * }
151  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
152  *
153  * By default, all sock_tls operations in a DTLS context are blocking for a
154  * limited amount of time, which depends on the DTLS session timeout. To modify
155  * the timeout, use `wolfSSL_dtls_set_timeout_init(sk->ssl)`.
156  *
157  * Certificate and private key for the server context are loaded from a previously
158  * initialized section in memory:
159  *
160  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
161  * if (wolfSSL_CTX_use_certificate_buffer(sk->ctx, server_cert,
162  * server_cert_len, SSL_FILETYPE_ASN1 ) != SSL_SUCCESS)
163  * {
164  * printf("Failed to load certificate from memory.\r\n");
165  * return -1;
166  * }
167  *
168  * if (wolfSSL_CTX_use_PrivateKey_buffer(sk->ctx, server_key,
169  * server_key_len, SSL_FILETYPE_ASN1 ) != SSL_SUCCESS)
170  * {
171  * printf("Failed to load private key from memory.\r\n");
172  * return -1;
173  * }
174  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
175  *
176  * Once the context is configured, the SSL session can be initialized.
177  *
178  * The listening sock automatically takes care of the DTLS handshake.
179  * When the session is established, `wolfSSL_accept()` will finally return
180  * `SSL_SUCCESS`.
181  *
182  *
183  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
184  * ret = sock_dtls_session_create(sk);
185  * if (ret < 0)
186  * {
187  * printf("Failed to create DTLS session (err: %s)\r\n", strerror(-ret));
188  * return -1;
189  * }
190  * printf("Listening on %d\n", SERVER_PORT);
191  * while(1) {
192  * ret = wolfSSL_accept(sk->ssl);
193  * if (ret != SSL_SUCCESS) {
194  * continue;
195  * }
196  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
197  *
198  * At this point, the session is established, and encrypted data can be exchanged
199  * using `wolfSSL_read()` and `wolfSSL_write()`:
200  *
201  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
202  * ret = wolfSSL_read(sk->ssl, buf, 64);
203  * if (ret > 0) {
204  * buf[ret] = (char)0;
205  * printf("Received '%s'\r\n", buf);
206  * }
207  * printf("Sending 'DTLS OK'...\r\n");
208  * wolfSSL_write(sk->ssl, Test_dtls_string, sizeof(Test_dtls_string));
209  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
210  *
211  * The session is terminated, and the associated socket is closed.
212  *
213  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
214  * sock_dtls_session_destroy(sk);
215  * sock_dtls_close(sk);
216  * break;
217  * }
218  * return 0;
219  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
220  *
221  */
222 
223 #include <string.h>
224 #include <stdlib.h>
225 #include <stdio.h>
226 
227 #include <net/sock.h>
228 #include <wolfssl/ssl.h>
229 
230 #ifndef SOCK_TLS_H
231 #define SOCK_TLS_H
232 #ifdef __cplusplus
233 extern "C" {
234 #endif
235 
285 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);
286 
297 void sock_dtls_set_endpoint(sock_tls_t *sk, const sock_udp_ep_t *addr);
298 
311 int sock_dtls_session_create(sock_tls_t *sk);
312 
321 void sock_dtls_session_destroy(sock_tls_t *sk);
322 
331 void sock_dtls_close(sock_tls_t *sk);
332 
333 #ifdef MODULE_SOCK_TCP
334 # error Only support for UDP/IP provided via GNRC stack.
335 #endif
336 
337 #ifdef __cplusplus
338 }
339 #endif
340 
341 #endif /* SOCK_TLS_H */
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.
void sock_dtls_close(sock_dtls_t *sock)
Closes a DTLS sock.
void sock_dtls_session_destroy(sock_dtls_t *sock, sock_dtls_session_t *remote)
Destroys an existing DTLS session.
Common sock API definitions.
stdio wrapper to extend the C libs stdio
Common IP-based transport layer end point.
Definition: sock.h:215