Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers TLSSocketWrapper.h Source File

TLSSocketWrapper.h

Go to the documentation of this file.
00001 /** @file TLSSocketWrapper.h TLSSocketWrapper */
00002 /*
00003  * Copyright (c) 2018 ARM Limited
00004  * SPDX-License-Identifier: Apache-2.0
00005  *
00006  * Licensed under the Apache License, Version 2.0 (the "License");
00007  * you may not use this file except in compliance with the License.
00008  * You may obtain a copy of the License at
00009  *
00010  *     http://www.apache.org/licenses/LICENSE-2.0
00011  *
00012  * Unless required by applicable law or agreed to in writing, software
00013  * distributed under the License is distributed on an "AS IS" BASIS,
00014  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015  * See the License for the specific language governing permissions and
00016  * limitations under the License.
00017  */
00018 /** @addtogroup netsocket
00019 * @{
00020 */
00021 
00022 #ifndef _MBED_HTTPS_TLS_SOCKET_WRAPPER_H_
00023 #define _MBED_HTTPS_TLS_SOCKET_WRAPPER_H_
00024 
00025 #include "netsocket/Socket.h"
00026 #include "rtos/EventFlags.h"
00027 #include "platform/Callback.h"
00028 #include "mbedtls/platform.h"
00029 #include "mbedtls/ssl.h"
00030 #include "mbedtls/entropy.h"
00031 #include "mbedtls/ctr_drbg.h"
00032 #include "mbedtls/error.h"
00033 
00034 // This class requires Mbed TLS SSL/TLS client code
00035 #if defined(MBEDTLS_SSL_CLI_C) || defined(DOXYGEN_ONLY)
00036 
00037 /**
00038  * TLSSocket is a wrapper around Socket for interacting with TLS servers.
00039  *
00040  * TLSSocketWrapper can use any Socket as a transport. After
00041  * completing the TLS handshake, it can be used as any Socket would be used.
00042  *
00043  */
00044 class TLSSocketWrapper : public Socket {
00045 public:
00046     /** Transport modes */
00047     enum control_transport {
00048         TRANSPORT_KEEP,                 /**< Doesn't call connect() or close() on transport socket */
00049         TRANSPORT_CONNECT_AND_CLOSE,    /**< Does call connect() and close() on transport socket */
00050         TRANSPORT_CONNECT,              /**< Does call only connect() on transport socket */
00051         TRANSPORT_CLOSE,                /**< Does call close() on transport socket */
00052     };
00053 
00054     /** Create a TLSSocketWrapper.
00055      *
00056      * @param transport    Underlying transport socket to wrap.
00057      * @param hostname     Hostname of the remote host, used for certificate checking.
00058      * @param control      Transport control mode. See @ref control_transport.
00059      */
00060     TLSSocketWrapper(Socket *transport, const char *hostname = NULL, control_transport control = TRANSPORT_CONNECT_AND_CLOSE);
00061 
00062     /** Destroy a socket wrapper.
00063      *
00064      *  Closes socket wrapper if the socket wrapper is still open.
00065      */
00066     virtual ~TLSSocketWrapper();
00067 
00068     /** Set hostname.
00069      *
00070      * TLSSocket requires hostname used to verify the certificate.
00071      * If hostname is not given in constructor, this function must be used before
00072      * starting the TLS handshake.
00073      *
00074      * @param hostname     Hostname of the remote host, used for certificate checking.
00075      */
00076     void set_hostname(const char *hostname);
00077 
00078     /** Sets the certification of Root CA.
00079      *
00080      * @note Must be called before calling connect()
00081      *
00082      * @param root_ca Root CA Certificate in any Mbed TLS-supported format.
00083      * @param len     Length of certificate (including terminating 0 for PEM).
00084      * @retval NSAPI_ERROR_OK on success.
00085      * @retval NSAPI_ERROR_NO_MEMORY in case there is not enough memory to allocate certificate.
00086      * @retval NSAPI_ERROR_PARAMETER in case the provided root_ca parameter failed parsing.
00087      */
00088     nsapi_error_t set_root_ca_cert(const void *root_ca, size_t len);
00089 
00090     /** Sets the certification of Root CA.
00091      *
00092      * @note Must be called before calling connect()
00093      *
00094      * @param root_ca_pem Root CA Certificate in PEM format.
00095      * @retval NSAPI_ERROR_OK on success.
00096      * @retval NSAPI_ERROR_NO_MEMORY in case there is not enough memory to allocate certificate.
00097      * @retval NSAPI_ERROR_PARAMETER in case the provided root_ca parameter failed parsing.
00098      */
00099     nsapi_error_t set_root_ca_cert(const char *root_ca_pem);
00100 
00101     /** Sets client certificate, and client private key.
00102      *
00103      * @param client_cert Client certification in PEM or DER format.
00104      * @param client_cert_len Certificate size including the terminating null byte for PEM data.
00105      * @param client_private_key_pem Client private key in PEM or DER format.
00106      * @param client_private_key_len Key size including the terminating null byte for PEM data
00107      * @retval NSAPI_ERROR_OK on success.
00108      * @retval NSAPI_ERROR_PARAMETER in case the provided root_ca parameter failed parsing.
00109      */
00110     nsapi_error_t set_client_cert_key(const void *client_cert, size_t client_cert_len,
00111                                       const void *client_private_key_pem, size_t client_private_key_len);
00112 
00113     /** Sets client certificate, and client private key.
00114      *
00115      * @param client_cert_pem Client certification in PEM format.
00116      * @param client_private_key_pem Client private key in PEM format.
00117      * @retval NSAPI_ERROR_OK on success.
00118      * @retval NSAPI_ERROR_PARAMETER in case the provided root_ca parameter failed parsing.
00119      */
00120     nsapi_error_t set_client_cert_key(const char *client_cert_pem, const char *client_private_key_pem);
00121 
00122     /** Send data over a TLS socket.
00123      *
00124      *  The socket must be connected to a remote host. Returns the number of
00125      *  bytes sent from the buffer.
00126      *
00127      *  @param data     Buffer of data to send to the host.
00128      *  @param size     Size of the buffer in bytes.
00129      *  @retval         int Number of sent bytes on success
00130      *  @retval         NSAPI_ERROR_NO_SOCKET in case socket was not created correctly.
00131      *  @retval         NSAPI_ERROR_WOULD_BLOCK in case non-blocking mode is enabled
00132      *                  and send cannot be performed immediately.
00133      *  @retval         NSAPI_ERROR_DEVICE_ERROR in case of tls-related errors.
00134      *                  See @ref mbedtls_ssl_write.
00135      */
00136     virtual nsapi_error_t send(const void *data, nsapi_size_t size);
00137 
00138     /** Receive data over a TLS socket.
00139      *
00140      *  The socket must be connected to a remote host. Returns the number of
00141      *  bytes received into the buffer.
00142      *
00143      *  @param data     Destination buffer for data received from the host.
00144      *  @param size     Size of the buffer in bytes.
00145      *  @retval         int Number of sent bytes on success
00146      *  @retval         NSAPI_ERROR_NO_SOCKET in case socket was not created correctly.
00147      *  @retval         NSAPI_ERROR_WOULD_BLOCK in case non-blocking mode is enabled
00148      *                  and send cannot be performed immediately.
00149      *  @retval         NSAPI_ERROR_DEVICE_ERROR in case of tls-related errors.
00150      *                  See @ref mbedtls_ssl_read.
00151      *  @return         0 if no data is available to be received
00152      *                  and the peer has performed an orderly shutdown.
00153      */
00154     virtual nsapi_size_or_error_t recv(void *data, nsapi_size_t size);
00155 
00156     /* = Functions inherited from Socket = */
00157     virtual nsapi_error_t close();
00158     /**
00159      *  Connect the transport socket and start handshake.
00160      *
00161      *  @note: In case connect() returns an error, the state of the socket is
00162      *  unspecified. A new socket should be created before reconnecting.
00163      *
00164      *  See @ref Socket::connect and @ref start_handshake
00165      */
00166     virtual nsapi_error_t connect(const SocketAddress &address = SocketAddress());
00167     virtual nsapi_size_or_error_t sendto(const SocketAddress &address, const void *data, nsapi_size_t size);
00168     virtual nsapi_size_or_error_t recvfrom(SocketAddress *address,
00169                                            void *data, nsapi_size_t size);
00170     virtual nsapi_error_t bind(const SocketAddress &address);
00171     virtual void set_blocking(bool blocking);
00172     virtual void set_timeout(int timeout);
00173     virtual void sigio(mbed::Callback<void()> func);
00174     virtual nsapi_error_t setsockopt(int level, int optname, const void *optval, unsigned optlen);
00175     virtual nsapi_error_t getsockopt(int level, int optname, void *optval, unsigned *optlen);
00176     virtual Socket *accept(nsapi_error_t *error = NULL);
00177     virtual nsapi_error_t listen(int backlog = 1);
00178     virtual nsapi_error_t getpeername(SocketAddress *address);
00179 
00180 #if defined(MBEDTLS_X509_CRT_PARSE_C) || defined(DOXYGEN_ONLY)
00181     /** Get own certificate directly from Mbed TLS.
00182      *
00183      * @return Internal Mbed TLS X509 structure.
00184      */
00185     mbedtls_x509_crt *get_own_cert();
00186 
00187     /** Set own certificate directly to Mbed TLS.
00188      *
00189      * @param crt Mbed TLS X509 certificate chain.
00190      * @return error code from mbedtls_ssl_conf_own_cert().
00191      */
00192     int set_own_cert(mbedtls_x509_crt *crt);
00193 
00194     /** Get CA chain structure.
00195      *
00196      * @return Mbed TLS X509 certificate chain.
00197      */
00198     mbedtls_x509_crt *get_ca_chain();
00199 
00200     /** Set CA chain directly to Mbed TLS.
00201      *
00202      * @param crt Mbed TLS X509 certificate chain.
00203      */
00204     void set_ca_chain(mbedtls_x509_crt *crt);
00205 #endif
00206 
00207     /** Get internal Mbed TLS configuration structure.
00208      *
00209      * @return Mbed TLS SSL config.
00210      */
00211     mbedtls_ssl_config *get_ssl_config();
00212 
00213     /** Override Mbed TLS configuration.
00214      *
00215      * @param conf Mbed TLS SSL configuration structure.
00216      */
00217     void set_ssl_config(mbedtls_ssl_config *conf);
00218 
00219     /** Get internal Mbed TLS context structure.
00220      *
00221      * @return SSL context.
00222      */
00223     mbedtls_ssl_context *get_ssl_context();
00224 
00225 protected:
00226 #ifndef DOXYGEN_ONLY
00227     /** Initiates TLS Handshake.
00228      *
00229      *  Initiates a TLS handshake to a remote peer.
00230      *  Underlying transport socket should already be connected.
00231      *
00232      *  Root CA certification must be set by set_ssl_ca_pem() before
00233      *  calling this function.
00234      *
00235      *  For non-blocking purposes, this functions needs to know whether this
00236      *  was a first call to Socket::connect() API so that NSAPI_ERROR_INPROGRESS
00237      *  does not happen twice.
00238      *
00239      *  @param        first_call is this a first call to Socket::connect() API.
00240      *  @retval       NSAPI_ERROR_OK if we happen to complete the request on the first call.
00241      *  @retval       NSAPI_ERROR_IN_PROGRESS if the first call did not complete the request.
00242      *  @retval       NSAPI_ERROR_NO_SOCKET in case the transport socket was not created correctly.
00243      *  @retval       NSAPI_ERROR_AUTH_FAILURE in case of tls-related authentication errors.
00244      *                See @ref mbedtls_ctr_drbg_seed, @ref mbedtls_ssl_setup. @ref mbedtls_ssl_handshake.
00245      */
00246     nsapi_error_t start_handshake(bool first_call);
00247 
00248     bool is_handshake_started() const;
00249 
00250     void event();
00251 #endif
00252 
00253 
00254 
00255 private:
00256     /** Continue already initialized handshake */
00257     nsapi_error_t continue_handshake();
00258     /**
00259      * Helper for pretty-printing Mbed TLS error codes
00260      */
00261     static void print_mbedtls_error(const char *name, int err);
00262 
00263 #if MBED_CONF_TLS_SOCKET_DEBUG_LEVEL > 0
00264     /**
00265      * Debug callback for Mbed TLS
00266      * Just prints on the USB serial port
00267      */
00268     static void my_debug(void *ctx, int level, const char *file, int line,
00269                          const char *str);
00270 
00271     /**
00272      * Certificate verification callback for Mbed TLS
00273      * Here we only use it to display information on each cert in the chain
00274      */
00275     static int my_verify(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags);
00276 
00277 #endif /* MBED_CONF_TLS_SOCKET_DEBUG_LEVEL > 0 */
00278 
00279     /**
00280      * Receive callback for Mbed TLS
00281      */
00282     static int ssl_recv(void *ctx, unsigned char *buf, size_t len);
00283 
00284     /**
00285      * Send callback for Mbed TLS
00286      */
00287     static int ssl_send(void *ctx, const unsigned char *buf, size_t len);
00288 
00289     mbedtls_ssl_context _ssl;
00290 #ifdef MBEDTLS_X509_CRT_PARSE_C
00291     mbedtls_pk_context _pkctx;
00292 #endif
00293     mbedtls_ctr_drbg_context _ctr_drbg;
00294     mbedtls_entropy_context _entropy;
00295 
00296     rtos::EventFlags _event_flag;
00297     mbed::Callback<void()> _sigio;
00298     Socket *_transport;
00299     int _timeout;
00300 
00301 #ifdef MBEDTLS_X509_CRT_PARSE_C
00302     mbedtls_x509_crt *_cacert;
00303     mbedtls_x509_crt *_clicert;
00304 #endif
00305     mbedtls_ssl_config *_ssl_conf;
00306 
00307     bool _connect_transport: 1;
00308     bool _close_transport: 1;
00309     bool _tls_initialized: 1;
00310     bool _handshake_completed: 1;
00311     bool _cacert_allocated: 1;
00312     bool _clicert_allocated: 1;
00313     bool _ssl_conf_allocated: 1;
00314 
00315 };
00316 
00317 #endif /* MBEDTLS_SSL_CLI_C */
00318 #endif // _MBED_HTTPS_TLS_SOCKET_WRAPPER_H_
00319 /** @} */