Avnet / Mbed 2 deprecated WNCInterface_tls_client_example

Dependencies:   WNCInterface mbed-rtos mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

Go to the documentation of this file.
00001 /*
00002  *  Hello world example of a TLS client: fetch an HTTPS page
00003  *
00004  *  Copyright (C) 2006-2016, ARM Limited, All Rights Reserved
00005  *  SPDX-License-Identifier: Apache-2.0
00006  *
00007  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
00008  *  not use this file except in compliance with the License.
00009  *  You may obtain a copy of the License at
00010  *
00011  *  http://www.apache.org/licenses/LICENSE-2.0
00012  *
00013  *  Unless required by applicable law or agreed to in writing, software
00014  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
00015  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00016  *  See the License for the specific language governing permissions and
00017  *  limitations under the License.
00018  *
00019  *  This file is part of mbed TLS (https://tls.mbed.org)
00020  */
00021 
00022 /** \file main.cpp
00023  *  \brief An example TLS Client application
00024  *  This application sends an HTTPS request to developer.mbed.org and searches for a string in
00025  *  the result.
00026  *
00027  *  This example is implemented as a logic class (HelloHTTPS) wrapping a TCP socket.
00028  *  The logic class handles all events, leaving the main loop to just check if the process
00029  *  has finished.
00030  */
00031 
00032 /* Change to a number between 1 and 4 to debug the TLS connection */
00033 #define DEBUG_LEVEL 0
00034 
00035 #include "mbed.h"
00036 //#include "NetworkStack.h"
00037 
00038 #include "WNCInterface.h"
00039 #include "TCPSocketConnection.h"
00040 
00041 #include "mbedtls/platform.h"
00042 #include "mbedtls/ssl.h"
00043 #include "mbedtls/entropy.h"
00044 #include "mbedtls/ctr_drbg.h"
00045 #include "mbedtls/error.h"
00046 
00047 #define CRLF    "\r\n"
00048 
00049 #if DEBUG_LEVEL > 0
00050 #include "mbedtls/debug.h"
00051 #endif
00052 
00053 namespace {
00054 
00055 const char *HTTPS_SERVER_NAME = "developer.mbed.org";
00056 const int HTTPS_SERVER_PORT = 443;
00057 const int RECV_BUFFER_SIZE = 600;
00058 
00059 const char HTTPS_PATH[] = "/media/uploads/mbed_official/hello.txt";
00060 //const size_t HTTPS_PATH_LEN = sizeof(HTTPS_PATH) - 1;
00061 
00062 /* Test related data */
00063 const char *HTTPS_OK_STR = "200 OK";
00064 const char *HTTPS_HELLO_STR = "Hello world!";
00065 
00066 /* personalization string for the drbg */
00067 const char *DRBG_PERS = "mbed TLS helloword client";
00068 
00069 /* List of trusted root CA certificates
00070  * currently only GlobalSign, the CA for developer.mbed.org
00071  *
00072  * To add more than one root, just concatenate them.
00073  */
00074 const char SSL_CA_PEM[] = "-----BEGIN CERTIFICATE-----\n"
00075     "MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG\n"
00076     "A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv\n"
00077     "b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw\n"
00078     "MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i\n"
00079     "YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT\n"
00080     "aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ\n"
00081     "jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp\n"
00082     "xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp\n"
00083     "1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG\n"
00084     "snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ\n"
00085     "U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8\n"
00086     "9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E\n"
00087     "BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B\n"
00088     "AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz\n"
00089     "yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE\n"
00090     "38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP\n"
00091     "AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad\n"
00092     "DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME\n"
00093     "HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==\n"
00094     "-----END CERTIFICATE-----\n";
00095 
00096 }
00097 
00098 /**
00099  * \brief HelloHTTPS implements the logic for fetching a file from a webserver
00100  * using a TCP socket and parsing the result.
00101  */
00102 class HelloHTTPS {
00103 public:
00104     /**
00105      * HelloHTTPS Constructor
00106      * Initializes the TCP socket, sets up event handlers and flags.
00107      *
00108      * @param[in] domain The domain name to fetch from
00109      * @param[in] port The port of the HTTPS server
00110      */
00111     HelloHTTPS(const char * domain, const uint16_t port, WNCInterface *net_iface) :
00112             _domain(domain), _port(port)
00113     {
00114 
00115         _error = false;
00116         _gothello = false;
00117         _got200 = false;
00118         _bpos = 0;
00119         _request_sent = 0;
00120         _tcpsocket = new TCPSocketConnection;
00121 
00122         mbedtls_entropy_init(&_entropy);
00123         mbedtls_ctr_drbg_init(&_ctr_drbg);
00124         mbedtls_x509_crt_init(&_cacert);
00125         mbedtls_ssl_init(&_ssl);
00126         mbedtls_ssl_config_init(&_ssl_conf);
00127     }
00128     /**
00129      * HelloHTTPS Desctructor
00130      */
00131     ~HelloHTTPS() {
00132         mbedtls_entropy_free(&_entropy);
00133         mbedtls_ctr_drbg_free(&_ctr_drbg);
00134         mbedtls_x509_crt_free(&_cacert);
00135         mbedtls_ssl_free(&_ssl);
00136         mbedtls_ssl_config_free(&_ssl_conf);
00137     }
00138     /**
00139      * Start the test.
00140      *
00141      * Starts by clearing test flags, then resolves the address with DNS.
00142      *
00143      * @param[in] path The path of the file to fetch from the HTTPS server
00144      * @return SOCKET_ERROR_NONE on success, or an error code on failure
00145      */
00146     void startTest(const char *path) {
00147         /* Initialize the flags */
00148         _got200 = false;
00149         _gothello = false;
00150         _error = false;
00151         _disconnected = false;
00152         _request_sent = false;
00153         /* Fill the request buffer */
00154         _bpos = snprintf(_buffer, sizeof(_buffer) - 1, "GET %s HTTP/1.1\nHost: %s\n\n", path, HTTPS_SERVER_NAME);
00155 
00156         /*
00157          * Initialize TLS-related stuf.
00158          */
00159         int ret;
00160         if ((ret = mbedtls_ctr_drbg_seed(&_ctr_drbg, mbedtls_entropy_func, &_entropy,
00161                           (const unsigned char *) DRBG_PERS,
00162                           sizeof (DRBG_PERS))) != 0) {
00163             print_mbedtls_error("mbedtls_crt_drbg_init", ret);
00164             _error = true;
00165             return;
00166         }
00167 
00168         if ((ret = mbedtls_x509_crt_parse(&_cacert, (const unsigned char *) SSL_CA_PEM,
00169                            sizeof (SSL_CA_PEM))) != 0) {
00170             print_mbedtls_error("mbedtls_x509_crt_parse", ret);
00171             _error = true;
00172             return;
00173         }
00174 
00175         if ((ret = mbedtls_ssl_config_defaults(&_ssl_conf,
00176                         MBEDTLS_SSL_IS_CLIENT,
00177                         MBEDTLS_SSL_TRANSPORT_STREAM,
00178                         MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
00179             print_mbedtls_error("mbedtls_ssl_config_defaults", ret);
00180             _error = true;
00181             return;
00182         }
00183 
00184         mbedtls_ssl_conf_ca_chain(&_ssl_conf, &_cacert, NULL);
00185         mbedtls_ssl_conf_rng(&_ssl_conf, mbedtls_ctr_drbg_random, &_ctr_drbg);
00186 
00187         /* It is possible to disable authentication by passing
00188          * MBEDTLS_SSL_VERIFY_NONE in the call to mbedtls_ssl_conf_authmode()
00189          */
00190         mbedtls_ssl_conf_authmode(&_ssl_conf, MBEDTLS_SSL_VERIFY_REQUIRED);
00191 
00192 #if DEBUG_LEVEL > 0
00193         mbedtls_ssl_conf_verify(&_ssl_conf, my_verify, NULL);
00194         mbedtls_ssl_conf_dbg(&_ssl_conf, my_debug, NULL);
00195         mbedtls_debug_set_threshold(DEBUG_LEVEL);
00196 #endif
00197 
00198         if ((ret = mbedtls_ssl_setup(&_ssl, &_ssl_conf)) != 0) {
00199             print_mbedtls_error("mbedtls_ssl_setup", ret);
00200             _error = true;
00201             return;
00202         }
00203 
00204         mbedtls_ssl_set_hostname(&_ssl, HTTPS_SERVER_NAME);
00205 
00206         mbedtls_ssl_set_bio(&_ssl, static_cast<void *>(_tcpsocket),
00207                                    ssl_send, ssl_recv, NULL );
00208 
00209 
00210         /* Connect to the server */
00211         mbedtls_printf("Connecting with %s\r\n", _domain);
00212         ret = _tcpsocket->connect(_domain, _port);
00213         _tcpsocket->set_blocking (false,1500);
00214         
00215        /* Start the handshake, the rest will be done in onReceive() */
00216         mbedtls_printf("Starting the TLS handshake...\r\n");
00217         ret = mbedtls_ssl_handshake(&_ssl);
00218         if (ret < 0) {
00219             if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
00220                 ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
00221                 print_mbedtls_error("mbedtls_ssl_handshake", ret);
00222                 onError(_tcpsocket, -1 );
00223             }
00224             return;
00225         }
00226 
00227         ret = mbedtls_ssl_write(&_ssl, (const unsigned char *) _buffer, _bpos);
00228         if (ret < 0) {
00229             if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
00230                 ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
00231                 print_mbedtls_error("mbedtls_ssl_write", ret);
00232                 onError(_tcpsocket, -1 );
00233             }
00234             return;
00235         }
00236 
00237         /* It also means the handshake is done, time to print info */
00238         mbedtls_printf("TLS connection to %s established\r\n", HTTPS_SERVER_NAME);
00239 
00240         const uint32_t buf_size = 1024;
00241         char *buf = new char[buf_size];
00242         mbedtls_x509_crt_info(buf, buf_size, "\r    ",
00243                         mbedtls_ssl_get_peer_cert(&_ssl));
00244         mbedtls_printf("Server certificate:\r\n%s\r", buf);
00245 
00246         uint32_t flags = mbedtls_ssl_get_verify_result(&_ssl);
00247         if( flags != 0 )
00248         {
00249             mbedtls_x509_crt_verify_info(buf, buf_size, "\r  ! ", flags);
00250             mbedtls_printf("Certificate verification failed:\r\n%s\r\r\n", buf);
00251         }
00252         else
00253             mbedtls_printf("Certificate verification passed\r\n\r\n");
00254 
00255 
00256         /* Read data out of the socket */
00257         ret = mbedtls_ssl_read(&_ssl, (unsigned char *) _buffer, sizeof(_buffer));
00258         if (ret < 0) {
00259             if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
00260                 print_mbedtls_error("mbedtls_ssl_read", ret);
00261                 onError(_tcpsocket, -1 );
00262             }
00263             delete[] buf;
00264             return;
00265         }
00266         _bpos = static_cast<size_t>(ret);
00267 
00268         _buffer[_bpos] = 0;
00269 
00270         /* Check each of the flags */
00271         _got200 = _got200 || strstr(_buffer, HTTPS_OK_STR) != NULL;
00272         _gothello = _gothello || strstr(_buffer, HTTPS_HELLO_STR) != NULL;
00273 
00274         /* Print status messages */
00275         mbedtls_printf("HTTPS: Received %d chars from server\r\n", _bpos);
00276         mbedtls_printf("HTTPS: Received 200 OK status ... %s\r\n", _got200 ? "[OK]" : "[FAIL]");
00277         mbedtls_printf("HTTPS: Received '%s' status ... %s\r\n", HTTPS_HELLO_STR, _gothello ? "[OK]" : "[FAIL]");
00278         mbedtls_printf("HTTPS: Received message:\r\n\r\n");
00279         mbedtls_printf("%s", _buffer);
00280         _error = !(_got200 && _gothello);
00281 
00282         _tcpsocket->close();
00283         delete[] buf;
00284     }
00285 protected:
00286     /**
00287      * Helper for pretty-printing mbed TLS error codes
00288      */
00289     static void print_mbedtls_error(const char *name, int err) {
00290         char buf[128];
00291         mbedtls_strerror(err, buf, sizeof (buf));
00292         mbedtls_printf("%s() failed: -0x%04x (%d): %s\r\n", name, -err, err, buf);
00293     }
00294 
00295 #if DEBUG_LEVEL > 0
00296     /**
00297      * Debug callback for mbed TLS
00298      * Just prints on the USB serial port
00299      */
00300     static void my_debug(void *ctx, int level, const char *file, int line,
00301                          const char *str)
00302     {
00303         const char *p, *basename;
00304         (void) ctx;
00305 
00306         /* Extract basename from file */
00307         for(p = basename = file; *p != '\0'; p++) {
00308             if(*p == '/' || *p == '\\') {
00309                 basename = p + 1;
00310             }
00311         }
00312 
00313         mbedtls_printf("%s:%04d: |%d| %s", basename, line, level, str);
00314     }
00315 
00316     /**
00317      * Certificate verification callback for mbed TLS
00318      * Here we only use it to display information on each cert in the chain
00319      */
00320     static int my_verify(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags)
00321     {
00322         const uint32_t buf_size = 1024;
00323         char *buf = new char[buf_size];
00324         (void) data;
00325 
00326         mbedtls_printf("\nVerifying certificate at depth %d:\n", depth);
00327         mbedtls_x509_crt_info(buf, buf_size - 1, "  ", crt);
00328         mbedtls_printf("%s", buf);
00329 
00330         if (*flags == 0)
00331             mbedtls_printf("No verification issue for this certificate\n");
00332         else
00333         {
00334             mbedtls_x509_crt_verify_info(buf, buf_size, "  ! ", *flags);
00335             mbedtls_printf("%s\n", buf);
00336         }
00337 
00338         delete[] buf;
00339         return 0;
00340     }
00341 #endif
00342 
00343     /**
00344      * Receive callback for mbed TLS
00345      */
00346     static int ssl_recv(void *ctx, unsigned char *buf, size_t len) {
00347         TCPSocketConnection *socket = static_cast<TCPSocketConnection *>(ctx);
00348         return (int)socket->receive((char*)buf, len);
00349    }
00350 
00351     /**
00352      * Send callback for mbed TLS
00353      */
00354     static int ssl_send(void *ctx, const unsigned char *buf, size_t len) {
00355         TCPSocketConnection *socket = static_cast<TCPSocketConnection *>(ctx);
00356         return socket->send((char*)buf, len);
00357     }
00358 
00359     void onError(TCPSocketConnection *s, int error) {
00360         mbedtls_printf("MBED: Socket Error: %d\r\n", error);
00361         s->close();
00362         _error = true;
00363     }
00364 
00365 protected:
00366     TCPSocketConnection* _tcpsocket;
00367 
00368     const char *_domain;            /**< The domain name of the HTTPS server */
00369     const uint16_t _port;           /**< The HTTPS server port */
00370     char _buffer[RECV_BUFFER_SIZE]; /**< The response buffer */
00371     size_t _bpos;                   /**< The current offset in the response buffer */
00372     volatile bool _got200;          /**< Status flag for HTTPS 200 */
00373     volatile bool _gothello;        /**< Status flag for finding the test string */
00374     volatile bool _error;           /**< Status flag for an error */
00375     volatile bool _disconnected;
00376     volatile bool _request_sent;
00377 
00378     mbedtls_entropy_context _entropy;
00379     mbedtls_ctr_drbg_context _ctr_drbg;
00380     mbedtls_x509_crt _cacert;
00381     mbedtls_ssl_context _ssl;
00382     mbedtls_ssl_config _ssl_conf;
00383 };
00384 
00385 MODSERIAL pc(USBTX,USBRX,256,256);   
00386 
00387 #ifdef __cplusplus
00388 extern "C" {
00389 #endif
00390 
00391 int myprintf( const char* format, ... ) {
00392     extern MODSERIAL pc;
00393     string buff;
00394 
00395     va_list valist;
00396     buff.reserve(2048);
00397     va_start(valist, format);
00398     vsprintf(&buff[0],format,valist);
00399     pc.puts(buff.c_str());
00400     va_end(valist);
00401     return 0;
00402 }    
00403 
00404 #ifdef __cplusplus
00405 }
00406 #endif
00407 /**
00408  * The main loop of the HTTPS Hello World test
00409  */
00410 int main() {
00411     int ret;
00412     /* The default 9600 bps is too slow to print full TLS debug info and could
00413      * cause the other party to time out. */
00414 
00415     /* Inititalise with DHCP, connect, and start up the stack */
00416     WNCInterface eth_iface;
00417 
00418     pc.baud(115200);
00419     pc.printf(CRLF "Starting HTTPS File Download Example for TLS use WNC Data Module" CRLF);
00420     
00421     ret = eth_iface.init(NULL, &pc);                     
00422     pc.printf("WNC Module %s initialized (%02X)." CRLF, ret?"IS":"IS NOT", ret);
00423     if( !ret ) {
00424         pc.printf(" - - - - - - - ALL DONE - - - - - - - " CRLF);
00425         while(1);
00426     }
00427         
00428     eth_iface.connect();
00429     pc.printf("IP Address: %s " CRLF CRLF, eth_iface.getIPAddress());    
00430 
00431     HelloHTTPS *hello = new HelloHTTPS(HTTPS_SERVER_NAME, HTTPS_SERVER_PORT, &eth_iface);
00432     hello->startTest(HTTPS_PATH);
00433     pc.printf("  >>> DONE  <<<\r\n");
00434     delete hello;
00435 }