Mbed OS Reference
Loading...
Searching...
No Matches
TLSSocketWrapper.h
Go to the documentation of this file.
1/** @file TLSSocketWrapper.h TLSSocketWrapper */
2/*
3 * Copyright (c) 2018 ARM Limited
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18/** @addtogroup NetSocket
19* @{
20*/
21
22#ifndef _MBED_HTTPS_TLS_SOCKET_WRAPPER_H_
23#define _MBED_HTTPS_TLS_SOCKET_WRAPPER_H_
24
25#include "netsocket/Socket.h"
26#include "rtos/EventFlags.h"
27#include "platform/Callback.h"
28#include "mbedtls/platform.h"
29#include "mbedtls/ssl.h"
30#include "mbedtls/entropy.h"
31#include "mbedtls/ctr_drbg.h"
32#include "mbedtls/hmac_drbg.h"
33#include "mbedtls/error.h"
34
35// This class requires Mbed TLS SSL/TLS client code
36#if defined(MBEDTLS_SSL_CLI_C) || defined(DOXYGEN_ONLY)
37
38#if defined(MBEDTLS_CTR_DRBG_C)
39#define DRBG_CTX mbedtls_ctr_drbg_context
40#define DRBG_INIT mbedtls_ctr_drbg_init
41#define DRBG_RANDOM mbedtls_ctr_drbg_random
42#define DRBG_FREE mbedtls_ctr_drbg_free
43#elif defined(MBEDTLS_HMAC_DRBG_C)
44#define DRBG_CTX mbedtls_hmac_drbg_context
45#define DRBG_INIT mbedtls_hmac_drbg_init
46#define DRBG_RANDOM mbedtls_hmac_drbg_random
47#define DRBG_FREE mbedtls_hmac_drbg_free
48#else
49#error "CTR or HMAC must be defined for TLSSocketWrapper!"
50#endif
51
52/**
53 * TLSSocket is a wrapper around Socket for interacting with TLS servers.
54 *
55 * TLSSocketWrapper can use any Socket as a transport. After
56 * completing the TLS handshake, it can be used as any Socket would be used.
57 *
58 */
59class TLSSocketWrapper : public Socket {
60public:
61 /** Transport modes */
63 TRANSPORT_KEEP, /**< Doesn't call connect() or close() on transport socket */
64 TRANSPORT_CONNECT_AND_CLOSE, /**< Does call connect() and close() on transport socket */
65 TRANSPORT_CONNECT, /**< Does call only connect() on transport socket */
66 TRANSPORT_CLOSE, /**< Does call close() on transport socket */
67 };
68
69 /** Create a TLSSocketWrapper.
70 *
71 * @param transport Underlying transport socket to wrap.
72 * @param hostname Hostname of the remote host, used for certificate checking.
73 * @param control Transport control mode. See @ref control_transport.
74 */
75 TLSSocketWrapper(Socket *transport, const char *hostname = NULL, control_transport control = TRANSPORT_CONNECT_AND_CLOSE);
76
77 /** Destroy a socket wrapper.
78 *
79 * Closes socket wrapper if the socket wrapper is still open.
80 */
82
83 /** Set hostname.
84 *
85 * @note Implementation is a no-op unless MBEDTLS_X509_CRT_PARSE_C is defined and
86 * MBEDTLS_X509_REMOVE_HOSTNAME_VERIFICATION is not defined.
87 *
88 * TLSSocket requires hostname used to verify the certificate.
89 * If hostname is not given in constructor, this function must be used before
90 * starting the TLS handshake.
91 *
92 * @param hostname Hostname of the remote host, used for certificate checking.
93 */
94 void set_hostname(const char *hostname);
95
96 /** Sets the certification of Root CA.
97 *
98 * @note Must be called before calling connect()
99 *
100 * @param root_ca Root CA Certificate in any Mbed TLS-supported format.
101 * @param len Length of certificate (including terminating 0 for PEM).
102 * @retval NSAPI_ERROR_OK on success.
103 * @retval NSAPI_ERROR_NO_MEMORY in case there is not enough memory to allocate certificate.
104 * @retval NSAPI_ERROR_PARAMETER in case the provided root_ca parameter failed parsing.
105 */
106 nsapi_error_t set_root_ca_cert(const void *root_ca, size_t len);
107
108 /** Sets the certification of Root CA.
109 *
110 * @note Must be called before calling connect()
111 *
112 * @param root_ca_pem Root CA Certificate in PEM format.
113 * @retval NSAPI_ERROR_OK on success.
114 * @retval NSAPI_ERROR_NO_MEMORY in case there is not enough memory to allocate certificate.
115 * @retval NSAPI_ERROR_PARAMETER in case the provided root_ca parameter failed parsing.
116 */
117 nsapi_error_t set_root_ca_cert(const char *root_ca_pem);
118
119 /**
120 * @brief Sets the Root CA certificate to a collection of files on the filesystem.
121 *
122 * All files in the supplied directory will be scanned. Note that to set up a filesystem,
123 * you must mount one or more block devices before calling this function.
124 *
125 * @note Must be called before calling connect()
126 *
127 * @param root_ca_path Path containing Root CA Certificate files in any Mbed TLS-supported format.
128 * This can point to a directory on any mounted filesystem.
129 * @retval NSAPI_ERROR_OK on success.
130 * @retval NSAPI_ERROR_NO_MEMORY in case there is not enough memory to allocate certificate.
131 * @retval NSAPI_ERROR_PARAMETER in case the provided root_ca parameter failed parsing.
132 *
133 */
134 nsapi_error_t set_root_ca_cert_path(const char *root_ca_path);
135
136 /** Appends the certificate to an existing CA chain.
137 *
138 * @note Must be called before calling connect()
139 *
140 * @param root_ca Root CA Certificate in any Mbed TLS-supported format.
141 * @param len Length of certificate (including terminating 0 for PEM).
142 * @retval NSAPI_ERROR_OK on success.
143 * @retval NSAPI_ERROR_NO_MEMORY in case there is not enough memory to allocate certificate.
144 * @retval NSAPI_ERROR_PARAMETER in case the provided root_ca parameter failed parsing.
145 */
146 nsapi_error_t append_root_ca_cert(const void *root_ca, size_t len);
147
148 /** Appends the certificate to an existing CA chain.
149 *
150 * @note Must be called before calling connect()
151 *
152 * @param root_ca_pem Root CA Certificate in PEM format.
153 * @retval NSAPI_ERROR_OK on success.
154 * @retval NSAPI_ERROR_NO_MEMORY in case there is not enough memory to allocate certificate.
155 * @retval NSAPI_ERROR_PARAMETER in case the provided root_ca parameter failed parsing.
156 */
157 nsapi_error_t append_root_ca_cert(const char *root_ca_pem);
158
159 /** Sets client certificate, and client private key.
160 *
161 * @param client_cert Client certification in PEM or DER format.
162 * @param client_cert_len Certificate size including the terminating null byte for PEM data.
163 * @param client_private_key_pem Client private key in PEM or DER format.
164 * @param client_private_key_len Key size including the terminating null byte for PEM data
165 * @retval NSAPI_ERROR_OK on success.
166 * @retval NSAPI_ERROR_PARAMETER in case the provided root_ca parameter failed parsing.
167 */
168 nsapi_error_t set_client_cert_key(const void *client_cert, size_t client_cert_len,
169 const void *client_private_key_pem, size_t client_private_key_len);
170
171 /** Sets client certificate, and client private key.
172 *
173 * @param client_cert_pem Client certification in PEM format.
174 * @param client_private_key_pem Client private key in PEM format.
175 * @retval NSAPI_ERROR_OK on success.
176 * @retval NSAPI_ERROR_PARAMETER in case the provided root_ca parameter failed parsing.
177 */
178 nsapi_error_t set_client_cert_key(const char *client_cert_pem, const char *client_private_key_pem);
179
180 /** Send data over a TLS socket.
181 *
182 * The socket must be connected to a remote host. Returns the number of
183 * bytes sent from the buffer.
184 *
185 * @param data Buffer of data to send to the host.
186 * @param size Size of the buffer in bytes.
187 * @retval int Number of sent bytes on success
188 * @retval NSAPI_ERROR_NO_SOCKET in case socket was not created correctly.
189 * @retval NSAPI_ERROR_WOULD_BLOCK in case non-blocking mode is enabled
190 * and send cannot be performed immediately.
191 * @retval NSAPI_ERROR_DEVICE_ERROR in case of tls-related errors.
192 * See <a href="https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/ssl_8h/#ssl_8h_1a5bbda87d484de82df730758b475f32e5">mbedtls_ssl_write</a>.
193 */
194 nsapi_error_t send(const void *data, nsapi_size_t size) override;
195
196 /** Receive data over a TLS socket.
197 *
198 * The socket must be connected to a remote host. Returns the number of
199 * bytes received into the buffer.
200 *
201 * @param data Destination buffer for data received from the host.
202 * @param size Size of the buffer in bytes.
203 * @retval int Number of sent bytes on success
204 * @retval NSAPI_ERROR_NO_SOCKET in case socket was not created correctly.
205 * @retval NSAPI_ERROR_WOULD_BLOCK in case non-blocking mode is enabled
206 * and send cannot be performed immediately.
207 * @retval NSAPI_ERROR_DEVICE_ERROR in case of tls-related errors.
208 * See <a href="https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/ssl_8h/#_CPPv416mbedtls_ssl_readP19mbedtls_ssl_contextPh6size_t">mbedtls_ssl_read</a>.
209 * @return 0 if no data is available to be received
210 * and the peer has performed an orderly shutdown.
211 */
212 nsapi_size_or_error_t recv(void *data, nsapi_size_t size) override;
213
214 /* = Functions inherited from Socket = */
216 /**
217 * Connect the transport socket and start handshake.
218 *
219 * @note: In case connect() returns an error, the state of the socket is
220 * unspecified. A new socket should be created before reconnecting.
221 *
222 * See @ref Socket::connect and @ref start_handshake
223 */
224 nsapi_error_t connect(const SocketAddress &address = SocketAddress()) override;
225 nsapi_size_or_error_t sendto(const SocketAddress &address, const void *data, nsapi_size_t size) override;
227 void *data, nsapi_size_t size) override;
228
230 const void *data, nsapi_size_t size,
231 nsapi_msghdr_t *control, nsapi_size_t control_size) override;
233 void *data, nsapi_size_t size,
234 nsapi_msghdr_t *control, nsapi_size_t control_size) override;
235
236 nsapi_error_t bind(const SocketAddress &address) override;
237 void set_blocking(bool blocking) override;
238 void set_timeout(int timeout) override;
239 void sigio(mbed::Callback<void()> func) override;
240 nsapi_error_t setsockopt(int level, int optname, const void *optval, unsigned optlen) override;
241 nsapi_error_t getsockopt(int level, int optname, void *optval, unsigned *optlen) override;
242 Socket *accept(nsapi_error_t *error = NULL) override;
243 nsapi_error_t listen(int backlog = 1) override;
245
246#if defined(MBEDTLS_X509_CRT_PARSE_C) || defined(DOXYGEN_ONLY)
247 /** Get own certificate directly from Mbed TLS.
248 *
249 * @return Internal Mbed TLS X509 structure.
250 */
251 mbedtls_x509_crt *get_own_cert();
252
253 /** Set own certificate directly to Mbed TLS.
254 *
255 * @param crt Mbed TLS X509 certificate chain.
256 * @return error code from mbedtls_ssl_conf_own_cert().
257 */
258 int set_own_cert(mbedtls_x509_crt *crt);
259
260 /** Get CA chain structure.
261 *
262 * @return Mbed TLS X509 certificate chain.
263 */
264 mbedtls_x509_crt *get_ca_chain();
265
266 /** Set CA chain directly to Mbed TLS.
267 *
268 * @param crt Mbed TLS X509 certificate chain.
269 */
270 void set_ca_chain(mbedtls_x509_crt *crt);
271#endif
272
273 /** Get internal Mbed TLS configuration structure.
274 *
275 * @return Mbed TLS SSL config.
276 */
277 mbedtls_ssl_config *get_ssl_config();
278
279 /** Override Mbed TLS configuration.
280 *
281 * @param conf Mbed TLS SSL configuration structure.
282 */
283 void set_ssl_config(mbedtls_ssl_config *conf);
284
285 /** Get internal Mbed TLS context structure.
286 *
287 * @return SSL context.
288 */
289 mbedtls_ssl_context *get_ssl_context();
290
291protected:
292 /** Initiates TLS Handshake.
293 *
294 * Initiates a TLS handshake to a remote peer.
295 * Underlying transport socket should already be connected.
296 *
297 * Root CA certification must be set by set_ssl_ca_pem() before
298 * calling this function.
299 *
300 * For non-blocking purposes, this functions needs to know whether this
301 * was a first call to Socket::connect() API so that NSAPI_ERROR_INPROGRESS
302 * does not happen twice.
303 *
304 * @param first_call is this a first call to Socket::connect() API.
305 * @retval NSAPI_ERROR_OK if we happen to complete the request on the first call.
306 * @retval NSAPI_ERROR_IN_PROGRESS if the first call did not complete the request.
307 * @retval NSAPI_ERROR_NO_SOCKET in case the transport socket was not created correctly.
308 * @retval NSAPI_ERROR_AUTH_FAILURE in case of tls-related authentication errors.
309 * See <a href="https://mbed-tls.readthedocs.io/projects/api/en/v2.28.7/api/file/ctr__drbg_8h/#ctr__drbg_8h_1ad93d675f998550b4478c1fe6f4f34ebc">mbedtls_ctr_drbg_seed</a>,
310 * <a href="https://mbed-tls.readthedocs.io/projects/api/en/v3.6.3/api/file/hmac__drbg_8h/#hmac__drbg_8h_1a0af34e5c68f15dfe714b5da94bce8f74">mbedtls_hmac_drbg_seed</a>,
311 * <a href="https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/ssl_8h/#ssl_8h_1af79cb539a0ee6ac20cf9c574f4c3b343">mbedtls_ssl_setup</a>,
312 * <a href="https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/ssl_8h/#ssl_8h_1a4a37e497cd08c896870a42b1b618186e">mbedtls_ssl_handshake</a>.
313 */
315
316#ifndef DOXYGEN_ONLY
317 bool is_handshake_started() const;
318
319 void event();
320#endif
321
322
323
324private:
325 /** Continue already initialized handshake */
326 nsapi_error_t continue_handshake();
327 /**
328 * Helper for pretty-printing Mbed TLS error codes
329 */
330 static void print_mbedtls_error(const char *name, int err);
331
332#if MBED_CONF_TLS_SOCKET_DEBUG_LEVEL > 0
333 /**
334 * Debug callback for Mbed TLS
335 * Just prints on the USB serial port
336 */
337 static void my_debug(void *ctx, int level, const char *file, int line,
338 const char *str);
339
340 /**
341 * Certificate verification callback for Mbed TLS
342 * Here we only use it to display information on each cert in the chain
343 */
344 static int my_verify(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags);
345
346#endif /* MBED_CONF_TLS_SOCKET_DEBUG_LEVEL > 0 */
347
348 /**
349 * Receive callback for Mbed TLS
350 */
351 static int ssl_recv(void *ctx, unsigned char *buf, size_t len);
352
353 /**
354 * Send callback for Mbed TLS
355 */
356 static int ssl_send(void *ctx, const unsigned char *buf, size_t len);
357
358 mbedtls_ssl_context _ssl;
359#ifdef MBEDTLS_X509_CRT_PARSE_C
360 mbedtls_pk_context _pkctx;
361#endif
362
363 DRBG_CTX _drbg;
364
365 mbedtls_entropy_context _entropy;
366
367 rtos::EventFlags _event_flag;
368 mbed::Callback<void()> _sigio;
369 Socket *_transport;
370 int _timeout = -1;
371
372#ifdef MBEDTLS_X509_CRT_PARSE_C
373 mbedtls_x509_crt *_cacert = nullptr;
374 mbedtls_x509_crt *_clicert = nullptr;
375#endif
376 mbedtls_ssl_config *_ssl_conf = nullptr;
377
378 bool _connect_transport: 1;
379 bool _close_transport: 1;
380 bool _tls_initialized: 1;
381 bool _handshake_completed: 1;
382 bool _cacert_allocated: 1;
383 bool _clicert_allocated: 1;
384 bool _ssl_conf_allocated: 1;
385
386};
387
388#endif /* MBEDTLS_SSL_CLI_C */
389#endif // _MBED_HTTPS_TLS_SOCKET_WRAPPER_H_
390/** @} */
Abstract Socket interface.
Representation of an IP (v4 or v6) address and port pair.
Socket interface.
Definition Socket.h:41
TLSSocket is a wrapper around Socket for interacting with TLS servers.
mbedtls_x509_crt * get_ca_chain()
Get CA chain structure.
nsapi_error_t append_root_ca_cert(const char *root_ca_pem)
Appends the certificate to an existing CA chain.
int set_own_cert(mbedtls_x509_crt *crt)
Set own certificate directly to Mbed TLS.
nsapi_size_or_error_t sendto_control(const SocketAddress &address, const void *data, nsapi_size_t size, nsapi_msghdr_t *control, nsapi_size_t control_size) override
Send a message on a socket.
nsapi_error_t set_client_cert_key(const char *client_cert_pem, const char *client_private_key_pem)
Sets client certificate, and client private key.
nsapi_error_t bind(const SocketAddress &address) override
Bind a specific address to a socket.
nsapi_error_t listen(int backlog=1) override
Listen for incoming connections.
void set_hostname(const char *hostname)
Set hostname.
nsapi_error_t set_root_ca_cert(const void *root_ca, size_t len)
Sets the certification of Root CA.
void sigio(mbed::Callback< void()> func) override
Register a callback on state change of the socket.
mbedtls_ssl_context * get_ssl_context()
Get internal Mbed TLS context structure.
nsapi_size_or_error_t sendto(const SocketAddress &address, const void *data, nsapi_size_t size) override
Send a message on a socket.
TLSSocketWrapper(Socket *transport, const char *hostname=NULL, control_transport control=TRANSPORT_CONNECT_AND_CLOSE)
Create a TLSSocketWrapper.
void set_ssl_config(mbedtls_ssl_config *conf)
Override Mbed TLS configuration.
nsapi_error_t set_root_ca_cert(const char *root_ca_pem)
Sets the certification of Root CA.
void set_blocking(bool blocking) override
Set blocking or non-blocking mode of the socket.
nsapi_error_t connect(const SocketAddress &address=SocketAddress()) override
Connect the transport socket and start handshake.
nsapi_size_or_error_t recvfrom_control(SocketAddress *address, void *data, nsapi_size_t size, nsapi_msghdr_t *control, nsapi_size_t control_size) override
Receive a data from a socket.
nsapi_error_t set_root_ca_cert_path(const char *root_ca_path)
Sets the Root CA certificate to a collection of files on the filesystem.
mbedtls_ssl_config * get_ssl_config()
Get internal Mbed TLS configuration structure.
control_transport
Transport modes.
@ TRANSPORT_CLOSE
Does call close() on transport socket.
@ TRANSPORT_CONNECT_AND_CLOSE
Does call connect() and close() on transport socket.
@ TRANSPORT_CONNECT
Does call only connect() on transport socket.
@ TRANSPORT_KEEP
Doesn't call connect() or close() on transport socket.
void set_timeout(int timeout) override
Set timeout on blocking socket operations.
Socket * accept(nsapi_error_t *error=NULL) override
Waits for a client to try to connect to this socket, then returns a socket for the new connection.
nsapi_error_t getsockopt(int level, int optname, void *optval, unsigned *optlen) override
Get socket options.
nsapi_error_t append_root_ca_cert(const void *root_ca, size_t len)
Appends the certificate to an existing CA chain.
void set_ca_chain(mbedtls_x509_crt *crt)
Set CA chain directly to Mbed TLS.
nsapi_error_t close() override
Closes the socket.
nsapi_error_t send(const void *data, nsapi_size_t size) override
Send data over a TLS socket.
mbedtls_x509_crt * get_own_cert()
Get own certificate directly from Mbed TLS.
nsapi_size_or_error_t recv(void *data, nsapi_size_t size) override
Receive data over a TLS socket.
nsapi_error_t start_handshake(bool first_call)
Initiates TLS Handshake.
nsapi_size_or_error_t recvfrom(SocketAddress *address, void *data, nsapi_size_t size) override
Receive a data from a socket.
nsapi_error_t getpeername(SocketAddress *address) override
Get the remote-end peer associated with this socket.
~TLSSocketWrapper() override
Destroy a socket wrapper.
nsapi_error_t setsockopt(int level, int optname, const void *optval, unsigned optlen) override
Set socket options.
nsapi_error_t set_client_cert_key(const void *client_cert, size_t client_cert_len, const void *client_private_key_pem, size_t client_private_key_len)
Sets client certificate, and client private key.
Callback class based on template specialization.
Definition Callback.h:53
The EventFlags class is used to control event flags or wait for event flags other threads control.
Definition EventFlags.h:53
signed int nsapi_size_or_error_t
Type used to represent either a size or error passed through sockets.
signed int nsapi_error_t
Type used to represent error codes.
unsigned int nsapi_size_t
Type used to represent the size of data passed through sockets.
MBED_NORETURN void error(const char *format,...) MBED_PRINTF(1
To generate a fatal compile-time error, you can use the pre-processor error directive.
Header structure for control info.