Mistake on this page?
Report an issue in GitHub or email us
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  */
59 class TLSSocketWrapper : public Socket {
60 public:
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  */
81  ~TLSSocketWrapper() override;
82 
83  /** Set hostname.
84  *
85  * @note Implementation is inside following defines:
86  * #if defined(MBEDTLS_X509_CRT_PARSE_C) && !defined(MBEDTLS_X509_REMOVE_HOSTNAME_VERIFICATION)
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  /** Sets client certificate, and client private key.
120  *
121  * @param client_cert Client certification in PEM or DER format.
122  * @param client_cert_len Certificate size including the terminating null byte for PEM data.
123  * @param client_private_key_pem Client private key in PEM or DER format.
124  * @param client_private_key_len Key size including the terminating null byte for PEM data
125  * @retval NSAPI_ERROR_OK on success.
126  * @retval NSAPI_ERROR_PARAMETER in case the provided root_ca parameter failed parsing.
127  */
128  nsapi_error_t set_client_cert_key(const void *client_cert, size_t client_cert_len,
129  const void *client_private_key_pem, size_t client_private_key_len);
130 
131  /** Sets client certificate, and client private key.
132  *
133  * @param client_cert_pem Client certification in PEM format.
134  * @param client_private_key_pem Client private key in PEM format.
135  * @retval NSAPI_ERROR_OK on success.
136  * @retval NSAPI_ERROR_PARAMETER in case the provided root_ca parameter failed parsing.
137  */
138  nsapi_error_t set_client_cert_key(const char *client_cert_pem, const char *client_private_key_pem);
139 
140  /** Send data over a TLS socket.
141  *
142  * The socket must be connected to a remote host. Returns the number of
143  * bytes sent from the buffer.
144  *
145  * @param data Buffer of data to send to the host.
146  * @param size Size of the buffer in bytes.
147  * @retval int Number of sent bytes on success
148  * @retval NSAPI_ERROR_NO_SOCKET in case socket was not created correctly.
149  * @retval NSAPI_ERROR_WOULD_BLOCK in case non-blocking mode is enabled
150  * and send cannot be performed immediately.
151  * @retval NSAPI_ERROR_DEVICE_ERROR in case of tls-related errors.
152  * See @ref mbedtls_ssl_write.
153  */
154  nsapi_error_t send(const void *data, nsapi_size_t size) override;
155 
156  /** Receive data over a TLS socket.
157  *
158  * The socket must be connected to a remote host. Returns the number of
159  * bytes received into the buffer.
160  *
161  * @param data Destination buffer for data received from the host.
162  * @param size Size of the buffer in bytes.
163  * @retval int Number of sent bytes on success
164  * @retval NSAPI_ERROR_NO_SOCKET in case socket was not created correctly.
165  * @retval NSAPI_ERROR_WOULD_BLOCK in case non-blocking mode is enabled
166  * and send cannot be performed immediately.
167  * @retval NSAPI_ERROR_DEVICE_ERROR in case of tls-related errors.
168  * See @ref mbedtls_ssl_read.
169  * @return 0 if no data is available to be received
170  * and the peer has performed an orderly shutdown.
171  */
172  nsapi_size_or_error_t recv(void *data, nsapi_size_t size) override;
173 
174  /* = Functions inherited from Socket = */
175  nsapi_error_t close() override;
176  /**
177  * Connect the transport socket and start handshake.
178  *
179  * @note: In case connect() returns an error, the state of the socket is
180  * unspecified. A new socket should be created before reconnecting.
181  *
182  * See @ref Socket::connect and @ref start_handshake
183  */
184  nsapi_error_t connect(const SocketAddress &address = SocketAddress()) override;
185  nsapi_size_or_error_t sendto(const SocketAddress &address, const void *data, nsapi_size_t size) override;
187  void *data, nsapi_size_t size) override;
188 
190  const void *data, nsapi_size_t size,
191  nsapi_msghdr_t *control, nsapi_size_t control_size) override;
193  void *data, nsapi_size_t size,
194  nsapi_msghdr_t *control, nsapi_size_t control_size) override;
195 
196  nsapi_error_t bind(const SocketAddress &address) override;
197  void set_blocking(bool blocking) override;
198  void set_timeout(int timeout) override;
199  void sigio(mbed::Callback<void()> func) override;
200  nsapi_error_t setsockopt(int level, int optname, const void *optval, unsigned optlen) override;
201  nsapi_error_t getsockopt(int level, int optname, void *optval, unsigned *optlen) override;
202  Socket *accept(nsapi_error_t *error = NULL) override;
203  nsapi_error_t listen(int backlog = 1) override;
204  nsapi_error_t getpeername(SocketAddress *address) override;
205 
206 #if defined(MBEDTLS_X509_CRT_PARSE_C) || defined(DOXYGEN_ONLY)
207  /** Get own certificate directly from Mbed TLS.
208  *
209  * @return Internal Mbed TLS X509 structure.
210  */
211  mbedtls_x509_crt *get_own_cert();
212 
213  /** Set own certificate directly to Mbed TLS.
214  *
215  * @param crt Mbed TLS X509 certificate chain.
216  * @return error code from mbedtls_ssl_conf_own_cert().
217  */
218  int set_own_cert(mbedtls_x509_crt *crt);
219 
220  /** Get CA chain structure.
221  *
222  * @return Mbed TLS X509 certificate chain.
223  */
224  mbedtls_x509_crt *get_ca_chain();
225 
226  /** Set CA chain directly to Mbed TLS.
227  *
228  * @param crt Mbed TLS X509 certificate chain.
229  */
230  void set_ca_chain(mbedtls_x509_crt *crt);
231 #endif
232 
233  /** Get internal Mbed TLS configuration structure.
234  *
235  * @return Mbed TLS SSL config.
236  */
237  mbedtls_ssl_config *get_ssl_config();
238 
239  /** Override Mbed TLS configuration.
240  *
241  * @param conf Mbed TLS SSL configuration structure.
242  */
243  void set_ssl_config(mbedtls_ssl_config *conf);
244 
245  /** Get internal Mbed TLS context structure.
246  *
247  * @return SSL context.
248  */
249  mbedtls_ssl_context *get_ssl_context();
250 
251 protected:
252 #ifndef DOXYGEN_ONLY
253  /** Initiates TLS Handshake.
254  *
255  * Initiates a TLS handshake to a remote peer.
256  * Underlying transport socket should already be connected.
257  *
258  * Root CA certification must be set by set_ssl_ca_pem() before
259  * calling this function.
260  *
261  * For non-blocking purposes, this functions needs to know whether this
262  * was a first call to Socket::connect() API so that NSAPI_ERROR_INPROGRESS
263  * does not happen twice.
264  *
265  * @param first_call is this a first call to Socket::connect() API.
266  * @retval NSAPI_ERROR_OK if we happen to complete the request on the first call.
267  * @retval NSAPI_ERROR_IN_PROGRESS if the first call did not complete the request.
268  * @retval NSAPI_ERROR_NO_SOCKET in case the transport socket was not created correctly.
269  * @retval NSAPI_ERROR_AUTH_FAILURE in case of tls-related authentication errors.
270  * See @ref mbedtls_ctr_drbg_seed or @ref mbedtls_hmac_drbg_seed, @ref mbedtls_ssl_setup. @ref mbedtls_ssl_handshake.
271  */
272  nsapi_error_t start_handshake(bool first_call);
273 
274  bool is_handshake_started() const;
275 
276  void event();
277 #endif
278 
279 
280 
281 private:
282  /** Continue already initialized handshake */
283  nsapi_error_t continue_handshake();
284  /**
285  * Helper for pretty-printing Mbed TLS error codes
286  */
287  static void print_mbedtls_error(const char *name, int err);
288 
289 #if MBED_CONF_TLS_SOCKET_DEBUG_LEVEL > 0
290  /**
291  * Debug callback for Mbed TLS
292  * Just prints on the USB serial port
293  */
294  static void my_debug(void *ctx, int level, const char *file, int line,
295  const char *str);
296 
297  /**
298  * Certificate verification callback for Mbed TLS
299  * Here we only use it to display information on each cert in the chain
300  */
301  static int my_verify(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags);
302 
303 #endif /* MBED_CONF_TLS_SOCKET_DEBUG_LEVEL > 0 */
304 
305  /**
306  * Receive callback for Mbed TLS
307  */
308  static int ssl_recv(void *ctx, unsigned char *buf, size_t len);
309 
310  /**
311  * Send callback for Mbed TLS
312  */
313  static int ssl_send(void *ctx, const unsigned char *buf, size_t len);
314 
315  mbedtls_ssl_context _ssl;
316 #ifdef MBEDTLS_X509_CRT_PARSE_C
317  mbedtls_pk_context _pkctx;
318 #endif
319 
320  DRBG_CTX _drbg;
321 
322  mbedtls_entropy_context _entropy;
323 
324  rtos::EventFlags _event_flag;
325  mbed::Callback<void()> _sigio;
326  Socket *_transport;
327  int _timeout = -1;
328 
329 #ifdef MBEDTLS_X509_CRT_PARSE_C
330  mbedtls_x509_crt *_cacert = nullptr;
331  mbedtls_x509_crt *_clicert = nullptr;
332 #endif
333  mbedtls_ssl_config *_ssl_conf = nullptr;
334 
335  bool _connect_transport: 1;
336  bool _close_transport: 1;
337  bool _tls_initialized: 1;
338  bool _handshake_completed: 1;
339  bool _cacert_allocated: 1;
340  bool _clicert_allocated: 1;
341  bool _ssl_conf_allocated: 1;
342 
343 };
344 
345 #endif /* MBEDTLS_SSL_CLI_C */
346 #endif // _MBED_HTTPS_TLS_SOCKET_WRAPPER_H_
347 /** @} */
nsapi_msghdr
Definition: nsapi_types.h:414
nsapi_size_or_error_t recvfrom(SocketAddress *address, void *data, nsapi_size_t size) override
Receive a data from a socket.
nsapi_error_t listen(int backlog=1) override
Listen for incoming connections.
nsapi_error_t getsockopt(int level, int optname, void *optval, unsigned *optlen) override
Get socket options.
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.
The EventFlags class is used to control event flags or wait for event flags other threads control...
Definition: EventFlags.h:53
Socket * accept(nsapi_error_t *error=NULL) override
Accepts a connection on a socket.
TLSSocket is a wrapper around Socket for interacting with TLS servers.
nsapi_error_t close() override
Closes the socket.
signed int nsapi_error_t
Type used to represent error codes.
Definition: nsapi_types.h:142
mbedtls_ssl_config * get_ssl_config()
Get internal Mbed TLS configuration structure.
nsapi_error_t bind(const SocketAddress &address) override
Bind a specific address to a socket.
signed int nsapi_size_or_error_t
Type used to represent either a size or error passed through sockets.
Definition: nsapi_types.h:153
nsapi_size_or_error_t sendto(const SocketAddress &address, const void *data, nsapi_size_t size) override
Send a message on a socket.
Abstract Socket interface.
Does call only connect() on transport socket.
Does call close() on transport socket.
mbedtls_x509_crt * get_ca_chain()
Get CA chain structure.
int set_own_cert(mbedtls_x509_crt *crt)
Set own certificate directly to Mbed TLS.
nsapi_error_t getpeername(SocketAddress *address) override
Get the remote-end peer associated with this socket.
nsapi_error_t set_root_ca_cert(const void *root_ca, size_t len)
Sets the certification of Root CA.
void set_timeout(int timeout) override
Set timeout on blocking socket operations.
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.
SocketAddress class.
Definition: SocketAddress.h:37
void set_ca_chain(mbedtls_x509_crt *crt)
Set CA chain 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.
void set_hostname(const char *hostname)
Set hostname.
nsapi_size_or_error_t recv(void *data, nsapi_size_t size) override
Receive data over a TLS socket.
nsapi_error_t setsockopt(int level, int optname, const void *optval, unsigned optlen) override
Set socket options.
mbedtls_x509_crt * get_own_cert()
Get own certificate directly from Mbed TLS.
Socket interface.
Definition: Socket.h:40
~TLSSocketWrapper() override
Destroy a socket wrapper.
Doesn&#39;t call connect() or close() on transport socket.
void set_ssl_config(mbedtls_ssl_config *conf)
Override Mbed TLS configuration.
Does call connect() and close() on transport socket.
unsigned int nsapi_size_t
Type used to represent the size of data passed through sockets.
Definition: nsapi_types.h:146
control_transport
Transport modes.
void sigio(mbed::Callback< void()> func) override
Register a callback on state change 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.
TLSSocketWrapper(Socket *transport, const char *hostname=NULL, control_transport control=TRANSPORT_CONNECT_AND_CLOSE)
Create a TLSSocketWrapper.
Callback class based on template specialization.
Definition: Callback.h:53
nsapi_error_t send(const void *data, nsapi_size_t size) override
Send data over a TLS socket.
mbedtls_ssl_context * get_ssl_context()
Get internal Mbed TLS context structure.
void set_blocking(bool blocking) override
Set blocking or non-blocking mode of the socket.
Important Information for this Arm website

This site uses cookies to store information on your computer. By continuing to use our site, you consent to our cookies. If you are not happy with the use of these cookies, please review our Cookie Policy to learn how they can be disabled. By disabling cookies, some features of the site will not work.