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