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  nsapi_error_t bind(const SocketAddress &address) override;
189  void set_blocking(bool blocking) override;
190  void set_timeout(int timeout) override;
191  void sigio(mbed::Callback<void()> func) override;
192  nsapi_error_t setsockopt(int level, int optname, const void *optval, unsigned optlen) override;
193  nsapi_error_t getsockopt(int level, int optname, void *optval, unsigned *optlen) override;
194  Socket *accept(nsapi_error_t *error = NULL) override;
195  nsapi_error_t listen(int backlog = 1) override;
196  nsapi_error_t getpeername(SocketAddress *address) override;
197 
198 #if defined(MBEDTLS_X509_CRT_PARSE_C) || defined(DOXYGEN_ONLY)
199  /** Get own certificate directly from Mbed TLS.
200  *
201  * @return Internal Mbed TLS X509 structure.
202  */
203  mbedtls_x509_crt *get_own_cert();
204 
205  /** Set own certificate directly to Mbed TLS.
206  *
207  * @param crt Mbed TLS X509 certificate chain.
208  * @return error code from mbedtls_ssl_conf_own_cert().
209  */
210  int set_own_cert(mbedtls_x509_crt *crt);
211 
212  /** Get CA chain structure.
213  *
214  * @return Mbed TLS X509 certificate chain.
215  */
216  mbedtls_x509_crt *get_ca_chain();
217 
218  /** Set CA chain directly to Mbed TLS.
219  *
220  * @param crt Mbed TLS X509 certificate chain.
221  */
222  void set_ca_chain(mbedtls_x509_crt *crt);
223 #endif
224 
225  /** Get internal Mbed TLS configuration structure.
226  *
227  * @return Mbed TLS SSL config.
228  */
229  mbedtls_ssl_config *get_ssl_config();
230 
231  /** Override Mbed TLS configuration.
232  *
233  * @param conf Mbed TLS SSL configuration structure.
234  */
235  void set_ssl_config(mbedtls_ssl_config *conf);
236 
237  /** Get internal Mbed TLS context structure.
238  *
239  * @return SSL context.
240  */
241  mbedtls_ssl_context *get_ssl_context();
242 
243 protected:
244 #ifndef DOXYGEN_ONLY
245  /** Initiates TLS Handshake.
246  *
247  * Initiates a TLS handshake to a remote peer.
248  * Underlying transport socket should already be connected.
249  *
250  * Root CA certification must be set by set_ssl_ca_pem() before
251  * calling this function.
252  *
253  * For non-blocking purposes, this functions needs to know whether this
254  * was a first call to Socket::connect() API so that NSAPI_ERROR_INPROGRESS
255  * does not happen twice.
256  *
257  * @param first_call is this a first call to Socket::connect() API.
258  * @retval NSAPI_ERROR_OK if we happen to complete the request on the first call.
259  * @retval NSAPI_ERROR_IN_PROGRESS if the first call did not complete the request.
260  * @retval NSAPI_ERROR_NO_SOCKET in case the transport socket was not created correctly.
261  * @retval NSAPI_ERROR_AUTH_FAILURE in case of tls-related authentication errors.
262  * See @ref mbedtls_ctr_drbg_seed or @ref mbedtls_hmac_drbg_seed, @ref mbedtls_ssl_setup. @ref mbedtls_ssl_handshake.
263  */
264  nsapi_error_t start_handshake(bool first_call);
265 
266  bool is_handshake_started() const;
267 
268  void event();
269 #endif
270 
271 
272 
273 private:
274  /** Continue already initialized handshake */
275  nsapi_error_t continue_handshake();
276  /**
277  * Helper for pretty-printing Mbed TLS error codes
278  */
279  static void print_mbedtls_error(const char *name, int err);
280 
281 #if MBED_CONF_TLS_SOCKET_DEBUG_LEVEL > 0
282  /**
283  * Debug callback for Mbed TLS
284  * Just prints on the USB serial port
285  */
286  static void my_debug(void *ctx, int level, const char *file, int line,
287  const char *str);
288 
289  /**
290  * Certificate verification callback for Mbed TLS
291  * Here we only use it to display information on each cert in the chain
292  */
293  static int my_verify(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags);
294 
295 #endif /* MBED_CONF_TLS_SOCKET_DEBUG_LEVEL > 0 */
296 
297  /**
298  * Receive callback for Mbed TLS
299  */
300  static int ssl_recv(void *ctx, unsigned char *buf, size_t len);
301 
302  /**
303  * Send callback for Mbed TLS
304  */
305  static int ssl_send(void *ctx, const unsigned char *buf, size_t len);
306 
307  mbedtls_ssl_context _ssl;
308 #ifdef MBEDTLS_X509_CRT_PARSE_C
309  mbedtls_pk_context _pkctx;
310 #endif
311 
312  DRBG_CTX _drbg;
313 
314  mbedtls_entropy_context _entropy;
315 
316  rtos::EventFlags _event_flag;
317  mbed::Callback<void()> _sigio;
318  Socket *_transport;
319  int _timeout = -1;
320 
321 #ifdef MBEDTLS_X509_CRT_PARSE_C
322  mbedtls_x509_crt *_cacert = nullptr;
323  mbedtls_x509_crt *_clicert = nullptr;
324 #endif
325  mbedtls_ssl_config *_ssl_conf = nullptr;
326 
327  bool _connect_transport: 1;
328  bool _close_transport: 1;
329  bool _tls_initialized: 1;
330  bool _handshake_completed: 1;
331  bool _cacert_allocated: 1;
332  bool _clicert_allocated: 1;
333  bool _ssl_conf_allocated: 1;
334 
335 };
336 
337 #endif /* MBEDTLS_SSL_CLI_C */
338 #endif // _MBED_HTTPS_TLS_SOCKET_WRAPPER_H_
339 /** @} */
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:95
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:106
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:36
void set_ca_chain(mbedtls_x509_crt *crt)
Set CA chain directly to Mbed TLS.
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:39
~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:99
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.
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.