This library is used to make HTTP and HTTPS calls from mbed OS 5 applications.

Fork of mbed-http by sandbox

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers tls_socket.h Source File

tls_socket.h

00001 /*
00002  * PackageLicenseDeclared: Apache-2.0
00003  * Copyright (c) 2017 ARM Limited
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License");
00006  * you may not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  *     http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 #ifndef _MBED_HTTPS_TLS_SOCKET_H_
00019 #define _MBED_HTTPS_TLS_SOCKET_H_
00020 
00021 /* Change to a number between 1 and 4 to debug the TLS connection */
00022 #define DEBUG_LEVEL 0
00023 
00024 #include <string>
00025 #include <vector>
00026 #include <map>
00027 #include "http_parser.h"
00028 #include "http_response.h"
00029 #include "http_request_builder.h"
00030 #include "http_request_parser.h"
00031 #include "http_parsed_url.h"
00032 
00033 #include "mbedtls/platform.h"
00034 #include "mbedtls/ssl.h"
00035 #include "mbedtls/entropy.h"
00036 #include "mbedtls/ctr_drbg.h"
00037 #include "mbedtls/error.h"
00038 
00039 #if DEBUG_LEVEL > 0
00040 #include "mbedtls/debug.h"
00041 #endif
00042 
00043 /**
00044  * \brief TLSSocket a wrapper around TCPSocket for interacting with TLS servers
00045  */
00046 class TLSSocket {
00047 public:
00048     TLSSocket(NetworkInterface* net_iface, const char* hostname, uint16_t port, const char* ssl_ca_pem) {
00049         _tcpsocket = new TCPSocket(net_iface);
00050         _ssl_ca_pem = ssl_ca_pem;
00051         _is_connected = false;
00052         _debug = false;
00053         _hostname = hostname;
00054         _port = port;
00055         _error = 0;
00056 
00057         DRBG_PERS = "mbed TLS helloword client";
00058 
00059         mbedtls_entropy_init(&_entropy);
00060         mbedtls_ctr_drbg_init(&_ctr_drbg);
00061         mbedtls_x509_crt_init(&_cacert);
00062         mbedtls_ssl_init(&_ssl);
00063         mbedtls_ssl_config_init(&_ssl_conf);
00064     }
00065 
00066     ~TLSSocket() {
00067         mbedtls_entropy_free(&_entropy);
00068         mbedtls_ctr_drbg_free(&_ctr_drbg);
00069         mbedtls_x509_crt_free(&_cacert);
00070         mbedtls_ssl_free(&_ssl);
00071         mbedtls_ssl_config_free(&_ssl_conf);
00072 
00073         if (_tcpsocket) {
00074             _tcpsocket->close();
00075             delete _tcpsocket;
00076         }
00077 
00078         // @todo: free DRBG_PERS ?
00079     }
00080 
00081     nsapi_error_t connect() {
00082         /* Initialize the flags */
00083         /*
00084          * Initialize TLS-related stuf.
00085          */
00086         int ret;
00087         if ((ret = mbedtls_ctr_drbg_seed(&_ctr_drbg, mbedtls_entropy_func, &_entropy,
00088                           (const unsigned char *) DRBG_PERS,
00089                           sizeof (DRBG_PERS))) != 0) {
00090             print_mbedtls_error("mbedtls_crt_drbg_init", ret);
00091             _error = ret;
00092             return _error;
00093         }
00094 
00095         if ((ret = mbedtls_x509_crt_parse(&_cacert, (const unsigned char *)_ssl_ca_pem,
00096                            strlen(_ssl_ca_pem) + 1)) != 0) {
00097             print_mbedtls_error("mbedtls_x509_crt_parse", ret);
00098             _error = ret;
00099             return _error;
00100         }
00101 
00102         if ((ret = mbedtls_ssl_config_defaults(&_ssl_conf,
00103                         MBEDTLS_SSL_IS_CLIENT,
00104                         MBEDTLS_SSL_TRANSPORT_STREAM,
00105                         MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
00106             print_mbedtls_error("mbedtls_ssl_config_defaults", ret);
00107             _error = ret;
00108             return _error;
00109         }
00110 
00111         mbedtls_ssl_conf_ca_chain(&_ssl_conf, &_cacert, NULL);
00112         mbedtls_ssl_conf_rng(&_ssl_conf, mbedtls_ctr_drbg_random, &_ctr_drbg);
00113 
00114         /* It is possible to disable authentication by passing
00115          * MBEDTLS_SSL_VERIFY_NONE in the call to mbedtls_ssl_conf_authmode()
00116          */
00117         mbedtls_ssl_conf_authmode(&_ssl_conf, MBEDTLS_SSL_VERIFY_REQUIRED);
00118 
00119 #if DEBUG_LEVEL > 0
00120         mbedtls_ssl_conf_verify(&_ssl_conf, my_verify, NULL);
00121         mbedtls_ssl_conf_dbg(&_ssl_conf, my_debug, NULL);
00122         mbedtls_debug_set_threshold(DEBUG_LEVEL);
00123 #endif
00124 
00125         if ((ret = mbedtls_ssl_setup(&_ssl, &_ssl_conf)) != 0) {
00126             print_mbedtls_error("mbedtls_ssl_setup", ret);
00127             _error = ret;
00128             return _error;
00129         }
00130 
00131         mbedtls_ssl_set_hostname(&_ssl, _hostname);
00132 
00133         mbedtls_ssl_set_bio(&_ssl, static_cast<void *>(_tcpsocket),
00134                                    ssl_send, ssl_recv, NULL );
00135 
00136         /* Connect to the server */
00137         if (_debug) mbedtls_printf("Connecting to %s:%d\r\n", _hostname, _port);
00138         ret = _tcpsocket->connect(_hostname, _port);
00139         if (ret != NSAPI_ERROR_OK) {
00140             if (_debug) mbedtls_printf("Failed to connect\r\n");
00141             onError(_tcpsocket, -1);
00142             return _error;
00143         }
00144 
00145        /* Start the handshake, the rest will be done in onReceive() */
00146         if (_debug) mbedtls_printf("Starting the TLS handshake...\r\n");
00147         ret = mbedtls_ssl_handshake(&_ssl);
00148         if (ret < 0) {
00149             if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
00150                 ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
00151                 print_mbedtls_error("mbedtls_ssl_handshake", ret);
00152                 onError(_tcpsocket, -1);
00153             }
00154             else {
00155                 _error = ret;
00156             }
00157             return _error;
00158         }
00159 
00160         /* It also means the handshake is done, time to print info */
00161         if (_debug) mbedtls_printf("TLS connection to %s:%d established\r\n", _hostname, _port);
00162 
00163         const uint32_t buf_size = 1024;
00164         char buf[buf_size] = { 0 };
00165         mbedtls_x509_crt_info(buf, buf_size, "\r    ",
00166                         mbedtls_ssl_get_peer_cert(&_ssl));
00167         if (_debug) mbedtls_printf("Server certificate:\r\n%s\r", buf);
00168 
00169         uint32_t flags = mbedtls_ssl_get_verify_result(&_ssl);
00170         if( flags != 0 )
00171         {
00172             mbedtls_x509_crt_verify_info(buf, buf_size, "\r  ! ", flags);
00173             if (_debug) mbedtls_printf("Certificate verification failed:\r\n%s\r\r\n", buf);
00174         }
00175         else {
00176             if (_debug) mbedtls_printf("Certificate verification passed\r\n\r\n");
00177         }
00178 
00179         _is_connected = true;
00180 
00181         return 0;
00182     }
00183 
00184     bool connected() {
00185         return _is_connected;
00186     }
00187 
00188     nsapi_error_t error() {
00189         return _error;
00190     }
00191 
00192     TCPSocket* get_tcp_socket() {
00193         return _tcpsocket;
00194     }
00195 
00196     mbedtls_ssl_context* get_ssl_context() {
00197         return &_ssl;
00198     }
00199 
00200     /**
00201      * Set the debug flag.
00202      *
00203      * If this flag is set, debug information from mbed TLS will be logged to stdout.
00204      */
00205     void set_debug(bool debug) {
00206         _debug = debug;
00207     }
00208 
00209 protected:
00210     /**
00211      * Helper for pretty-printing mbed TLS error codes
00212      */
00213     static void print_mbedtls_error(const char *name, int err) {
00214         char buf[128];
00215         mbedtls_strerror(err, buf, sizeof (buf));
00216         mbedtls_printf("%s() failed: -0x%04x (%d): %s\r\n", name, -err, err, buf);
00217     }
00218 
00219 #if DEBUG_LEVEL > 0
00220     /**
00221      * Debug callback for mbed TLS
00222      * Just prints on the USB serial port
00223      */
00224     static void my_debug(void *ctx, int level, const char *file, int line,
00225                          const char *str)
00226     {
00227         const char *p, *basename;
00228         (void) ctx;
00229 
00230         /* Extract basename from file */
00231         for(p = basename = file; *p != '\0'; p++) {
00232             if(*p == '/' || *p == '\\') {
00233                 basename = p + 1;
00234             }
00235         }
00236 
00237         if (_debug) {
00238             mbedtls_printf("%s:%04d: |%d| %s", basename, line, level, str);
00239         }
00240     }
00241 
00242     /**
00243      * Certificate verification callback for mbed TLS
00244      * Here we only use it to display information on each cert in the chain
00245      */
00246     static int my_verify(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags)
00247     {
00248         const uint32_t buf_size = 1024;
00249         char *buf = new char[buf_size];
00250         (void) data;
00251 
00252         if (_debug) mbedtls_printf("\nVerifying certificate at depth %d:\n", depth);
00253         mbedtls_x509_crt_info(buf, buf_size - 1, "  ", crt);
00254         if (_debug) mbedtls_printf("%s", buf);
00255 
00256         if (*flags == 0)
00257             if (_debug) mbedtls_printf("No verification issue for this certificate\n");
00258         else
00259         {
00260             mbedtls_x509_crt_verify_info(buf, buf_size, "  ! ", *flags);
00261             if (_debug) mbedtls_printf("%s\n", buf);
00262         }
00263 
00264         delete[] buf;
00265         return 0;
00266     }
00267 #endif
00268 
00269     /**
00270      * Receive callback for mbed TLS
00271      */
00272     static int ssl_recv(void *ctx, unsigned char *buf, size_t len) {
00273         int recv = -1;
00274         TCPSocket *socket = static_cast<TCPSocket *>(ctx);
00275         recv = socket->recv(buf, len);
00276 
00277         if (NSAPI_ERROR_WOULD_BLOCK == recv) {
00278             return MBEDTLS_ERR_SSL_WANT_READ;
00279         }
00280         else if (recv < 0) {
00281             return -1;
00282         }
00283         else {
00284             return recv;
00285         }
00286    }
00287 
00288     /**
00289      * Send callback for mbed TLS
00290      */
00291     static int ssl_send(void *ctx, const unsigned char *buf, size_t len) {
00292        int size = -1;
00293         TCPSocket *socket = static_cast<TCPSocket *>(ctx);
00294         size = socket->send(buf, len);
00295 
00296         if(NSAPI_ERROR_WOULD_BLOCK == size) {
00297             return len;
00298         }
00299         else if (size < 0){
00300             return -1;
00301         }
00302         else {
00303             return size;
00304         }
00305     }
00306 
00307 private:
00308     void onError(TCPSocket *s, int error) {
00309         s->close();
00310         _error = error;
00311     }
00312 
00313     TCPSocket* _tcpsocket;
00314 
00315     const char* DRBG_PERS;
00316     const char* _ssl_ca_pem;
00317     const char* _hostname;
00318     uint16_t _port;
00319 
00320     bool _debug;
00321     bool _is_connected;
00322 
00323     nsapi_error_t _error;
00324 
00325     mbedtls_entropy_context _entropy;
00326     mbedtls_ctr_drbg_context _ctr_drbg;
00327     mbedtls_x509_crt _cacert;
00328     mbedtls_ssl_context _ssl;
00329     mbedtls_ssl_config _ssl_conf;
00330 };
00331 
00332 #endif // _MBED_HTTPS_TLS_SOCKET_H_