Hello world example of a TLS client: fetch an HTTPS page. The canonical source for this example lives at https://github.com/ARMmbed/mbed-os-example-tls

HTTPS File Download Example for TLS Client on mbed OS

This application downloads a file from an HTTPS server (developer.mbed.org) and looks for a specific string in that file.

Getting started

Building with mbed CLI

If you'd like to use mbed CLI to build this, then you should set up your environment if you have not done so already. For instructions, refer to the main readme. The instructions here relate to using the developer.mbed.org Online Compiler

Import the program in to the Online Compiler, select your board from the drop down in the top right hand corner and then compile the application. Once it has built, you can drag and drop the binary onto your device.

Required hardware

This example also requires an Ethernet cable an connection to the internet additional to the hardware requirements in the main readme.

Monitoring the application

NOTE: Make sure that the Ethernet cable is plugged in correctly before running the application.

The output in the terminal window should be similar to this:

terminal output

Using Ethernet LWIP
Client IP Address is 10.2.203.43
Connecting with developer.mbed.org
Starting the TLS handshake...
TLS connection to developer.mbed.org established
Server certificate:
    cert. version     : 3
    serial number     : 11:21:B8:47:9B:21:6C:B1:C6:AF:BC:5D:0C:19:52:DC:D7:C3
    issuer name       : C=BE, O=GlobalSign nv-sa, CN=GlobalSign Organization Validation CA - SHA256 - G2
    subject name      : C=GB, ST=Cambridgeshire, L=Cambridge, O=ARM Ltd, CN=*.mbed.com
    issued  on        : 2016-03-03 12:26:08
    expires on        : 2017-04-05 10:31:02
    signed using      : RSA with SHA-256
    RSA key size      : 2048 bits
    basic constraints : CA=false
    subject alt name  : *.mbed.com, mbed.org, *.mbed.org, mbed.com
    key usage         : Digital Signature, Key Encipherment
    ext key usage     : TLS Web Server Authentication, TLS Web Client Authentication
Certificate verification passed

HTTPS: Received 439 chars from server
HTTPS: Received 200 OK status ... [OK]
HTTPS: Received 'Hello world!' status ... [OK]
HTTPS: Received message:

HTTP/1.1 200 OK
Server: nginx/1.7.10
Date: Wed, 20 Jul 2016 10:00:35 GMT
Content-Type: text/plain
Content-Length: 14
Connection: keep-alive
Last-Modified: Fri, 27 Jul 2012 13:30:34 GMT
Accept-Ranges: bytes
Cache-Control: max-age=36000
Expires: Wed, 20 Jul 2016 20:00:35 GMT
X-Upstream-L3: 172.17.0.3:80
X-Upstream-L2: developer-sjc-indigo-1-nginx
Strict-Transport-Security: max-age=31536000; includeSubdomains

Hello world!

Debugging the TLS connection

To print out more debug information about the TLS connection, edit the file `main.cpp` and change the definition of `DEBUG_LEVEL` (near the top of the file) from 0 to a positive number:

  • Level 1 only prints non-zero return codes from SSL functions and information about the full certificate chain being verified.
  • Level 2 prints more information about internal state updates.
  • Level 3 is intermediate.
  • Level 4 (the maximum) includes full binary dumps of the packets.

The TLS connection can fail with an error similar to:

error message

    mbedtls_ssl_write() failed: -0x2700 (-9984): X509 - Certificate verification failed, e.g. CRL, CA or signature check failed
    Failed to fetch /media/uploads/mbed_official/hello.txt from developer.mbed.org:443

This probably means you need to update the contents of the SSL_CA_PEM constant (this can happen if you modify HTTPS_SERVER_NAME, or when developer.mbed.org switches to a new CA when updating its certificate).

Another possible reason for this error is a proxy providing a different certificate. Proxies can be used in some network configurations or for performing man-in-the-middle attacks. If you choose to ignore this error and proceed with the connection anyway, you can change the definition of UNSAFE near the top of the file from 0 to 1.

Warning: this removes all security against a possible active attacker, so use at your own risk or for debugging only!

Committer:
mbed_official
Date:
Tue Sep 06 16:30:30 2016 +0100
Revision:
9:1ac74f2d7bda
Parent:
0:fc70c47eecb4
Child:
12:1ae41c231014
Reduce example stack usage

Dynamically allocate buffers that would normally be declared on the
stack. This reduces the maximum stack depth by ~2k.


Commit copied from https://github.com/ARMmbed/mbed-os-example-tls

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Janos Follath 0:fc70c47eecb4 1 /*
Janos Follath 0:fc70c47eecb4 2 * Hello world example of a TLS client: fetch an HTTPS page
Janos Follath 0:fc70c47eecb4 3 *
Janos Follath 0:fc70c47eecb4 4 * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved
Janos Follath 0:fc70c47eecb4 5 * SPDX-License-Identifier: Apache-2.0
Janos Follath 0:fc70c47eecb4 6 *
Janos Follath 0:fc70c47eecb4 7 * Licensed under the Apache License, Version 2.0 (the "License"); you may
Janos Follath 0:fc70c47eecb4 8 * not use this file except in compliance with the License.
Janos Follath 0:fc70c47eecb4 9 * You may obtain a copy of the License at
Janos Follath 0:fc70c47eecb4 10 *
Janos Follath 0:fc70c47eecb4 11 * http://www.apache.org/licenses/LICENSE-2.0
Janos Follath 0:fc70c47eecb4 12 *
Janos Follath 0:fc70c47eecb4 13 * Unless required by applicable law or agreed to in writing, software
Janos Follath 0:fc70c47eecb4 14 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
Janos Follath 0:fc70c47eecb4 15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Janos Follath 0:fc70c47eecb4 16 * See the License for the specific language governing permissions and
Janos Follath 0:fc70c47eecb4 17 * limitations under the License.
Janos Follath 0:fc70c47eecb4 18 *
Janos Follath 0:fc70c47eecb4 19 * This file is part of mbed TLS (https://tls.mbed.org)
Janos Follath 0:fc70c47eecb4 20 */
Janos Follath 0:fc70c47eecb4 21
Janos Follath 0:fc70c47eecb4 22 /** \file main.cpp
Janos Follath 0:fc70c47eecb4 23 * \brief An example TLS Client application
Janos Follath 0:fc70c47eecb4 24 * This application sends an HTTPS request to developer.mbed.org and searches for a string in
Janos Follath 0:fc70c47eecb4 25 * the result.
Janos Follath 0:fc70c47eecb4 26 *
Janos Follath 0:fc70c47eecb4 27 * This example is implemented as a logic class (HelloHTTPS) wrapping a TCP socket.
Janos Follath 0:fc70c47eecb4 28 * The logic class handles all events, leaving the main loop to just check if the process
Janos Follath 0:fc70c47eecb4 29 * has finished.
Janos Follath 0:fc70c47eecb4 30 */
Janos Follath 0:fc70c47eecb4 31
Janos Follath 0:fc70c47eecb4 32 /* Change to a number between 1 and 4 to debug the TLS connection */
Janos Follath 0:fc70c47eecb4 33 #define DEBUG_LEVEL 0
Janos Follath 0:fc70c47eecb4 34
Janos Follath 0:fc70c47eecb4 35 /* Change to 1 to skip certificate verification (UNSAFE, for debug only!) */
Janos Follath 0:fc70c47eecb4 36 #define UNSAFE 0
Janos Follath 0:fc70c47eecb4 37
Janos Follath 0:fc70c47eecb4 38 #include "mbed.h"
Janos Follath 0:fc70c47eecb4 39 #include "NetworkStack.h"
Janos Follath 0:fc70c47eecb4 40
Janos Follath 0:fc70c47eecb4 41 #include "EthernetInterface.h"
Janos Follath 0:fc70c47eecb4 42 #include "TCPSocket.h"
Janos Follath 0:fc70c47eecb4 43
Janos Follath 0:fc70c47eecb4 44 #include "mbedtls/platform.h"
Janos Follath 0:fc70c47eecb4 45 #include "mbedtls/ssl.h"
Janos Follath 0:fc70c47eecb4 46 #include "mbedtls/entropy.h"
Janos Follath 0:fc70c47eecb4 47 #include "mbedtls/ctr_drbg.h"
Janos Follath 0:fc70c47eecb4 48 #include "mbedtls/error.h"
Janos Follath 0:fc70c47eecb4 49 #if DEBUG_LEVEL > 0
Janos Follath 0:fc70c47eecb4 50 #include "mbedtls/debug.h"
Janos Follath 0:fc70c47eecb4 51 #endif
Janos Follath 0:fc70c47eecb4 52
Janos Follath 0:fc70c47eecb4 53 namespace {
Janos Follath 0:fc70c47eecb4 54
Janos Follath 0:fc70c47eecb4 55 const char *HTTPS_SERVER_NAME = "developer.mbed.org";
Janos Follath 0:fc70c47eecb4 56 const int HTTPS_SERVER_PORT = 443;
Janos Follath 0:fc70c47eecb4 57 const int RECV_BUFFER_SIZE = 600;
Janos Follath 0:fc70c47eecb4 58
Janos Follath 0:fc70c47eecb4 59 const char HTTPS_PATH[] = "/media/uploads/mbed_official/hello.txt";
Janos Follath 0:fc70c47eecb4 60 const size_t HTTPS_PATH_LEN = sizeof(HTTPS_PATH) - 1;
Janos Follath 0:fc70c47eecb4 61
Janos Follath 0:fc70c47eecb4 62 /* Test related data */
Janos Follath 0:fc70c47eecb4 63 const char *HTTPS_OK_STR = "200 OK";
Janos Follath 0:fc70c47eecb4 64 const char *HTTPS_HELLO_STR = "Hello world!";
Janos Follath 0:fc70c47eecb4 65
Janos Follath 0:fc70c47eecb4 66 /* personalization string for the drbg */
Janos Follath 0:fc70c47eecb4 67 const char *DRBG_PERS = "mbed TLS helloword client";
Janos Follath 0:fc70c47eecb4 68
Janos Follath 0:fc70c47eecb4 69 /* List of trusted root CA certificates
Janos Follath 0:fc70c47eecb4 70 * currently only GlobalSign, the CA for developer.mbed.org
Janos Follath 0:fc70c47eecb4 71 *
Janos Follath 0:fc70c47eecb4 72 * To add more than one root, just concatenate them.
Janos Follath 0:fc70c47eecb4 73 */
Janos Follath 0:fc70c47eecb4 74 const char SSL_CA_PEM[] =
Janos Follath 0:fc70c47eecb4 75 /* GlobalSign Root certificate */
Janos Follath 0:fc70c47eecb4 76 "-----BEGIN CERTIFICATE-----\n"
Janos Follath 0:fc70c47eecb4 77 "MIIEaTCCA1GgAwIBAgILBAAAAAABRE7wQkcwDQYJKoZIhvcNAQELBQAwVzELMAkG\n"
Janos Follath 0:fc70c47eecb4 78 "A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv\n"
Janos Follath 0:fc70c47eecb4 79 "b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw0xNDAyMjAxMDAw\n"
Janos Follath 0:fc70c47eecb4 80 "MDBaFw0yNDAyMjAxMDAwMDBaMGYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i\n"
Janos Follath 0:fc70c47eecb4 81 "YWxTaWduIG52LXNhMTwwOgYDVQQDEzNHbG9iYWxTaWduIE9yZ2FuaXphdGlvbiBW\n"
Janos Follath 0:fc70c47eecb4 82 "YWxpZGF0aW9uIENBIC0gU0hBMjU2IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IB\n"
Janos Follath 0:fc70c47eecb4 83 "DwAwggEKAoIBAQDHDmw/I5N/zHClnSDDDlM/fsBOwphJykfVI+8DNIV0yKMCLkZc\n"
Janos Follath 0:fc70c47eecb4 84 "C33JiJ1Pi/D4nGyMVTXbv/Kz6vvjVudKRtkTIso21ZvBqOOWQ5PyDLzm+ebomchj\n"
Janos Follath 0:fc70c47eecb4 85 "SHh/VzZpGhkdWtHUfcKc1H/hgBKueuqI6lfYygoKOhJJomIZeg0k9zfrtHOSewUj\n"
Janos Follath 0:fc70c47eecb4 86 "mxK1zusp36QUArkBpdSmnENkiN74fv7j9R7l/tyjqORmMdlMJekYuYlZCa7pnRxt\n"
Janos Follath 0:fc70c47eecb4 87 "Nw9KHjUgKOKv1CGLAcRFrW4rY6uSa2EKTSDtc7p8zv4WtdufgPDWi2zZCHlKT3hl\n"
Janos Follath 0:fc70c47eecb4 88 "2pK8vjX5s8T5J4BO/5ZS5gIg4Qdz6V0rvbLxAgMBAAGjggElMIIBITAOBgNVHQ8B\n"
Janos Follath 0:fc70c47eecb4 89 "Af8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUlt5h8b0cFilT\n"
Janos Follath 0:fc70c47eecb4 90 "HMDMfTuDAEDmGnwwRwYDVR0gBEAwPjA8BgRVHSAAMDQwMgYIKwYBBQUHAgEWJmh0\n"
Janos Follath 0:fc70c47eecb4 91 "dHBzOi8vd3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMDMGA1UdHwQsMCow\n"
Janos Follath 0:fc70c47eecb4 92 "KKAmoCSGImh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5uZXQvcm9vdC5jcmwwPQYIKwYB\n"
Janos Follath 0:fc70c47eecb4 93 "BQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwOi8vb2NzcC5nbG9iYWxzaWduLmNv\n"
Janos Follath 0:fc70c47eecb4 94 "bS9yb290cjEwHwYDVR0jBBgwFoAUYHtmGkUNl8qJUC99BM00qP/8/UswDQYJKoZI\n"
Janos Follath 0:fc70c47eecb4 95 "hvcNAQELBQADggEBAEYq7l69rgFgNzERhnF0tkZJyBAW/i9iIxerH4f4gu3K3w4s\n"
Janos Follath 0:fc70c47eecb4 96 "32R1juUYcqeMOovJrKV3UPfvnqTgoI8UV6MqX+x+bRDmuo2wCId2Dkyy2VG7EQLy\n"
Janos Follath 0:fc70c47eecb4 97 "XN0cvfNVlg/UBsD84iOKJHDTu/B5GqdhcIOKrwbFINihY9Bsrk8y1658GEV1BSl3\n"
Janos Follath 0:fc70c47eecb4 98 "30JAZGSGvip2CTFvHST0mdCF/vIhCPnG9vHQWe3WVjwIKANnuvD58ZAWR65n5ryA\n"
Janos Follath 0:fc70c47eecb4 99 "SOlCdjSXVWkkDoPWoC209fN5ikkodBpBocLTJIg1MGCUF7ThBCIxPTsvFwayuJ2G\n"
Janos Follath 0:fc70c47eecb4 100 "K1pp74P1S8SqtCr4fKGxhZSM9AyHDPSsQPhZSZg=\n"
Janos Follath 0:fc70c47eecb4 101 "-----END CERTIFICATE-----\n";
Janos Follath 0:fc70c47eecb4 102
Janos Follath 0:fc70c47eecb4 103 #if OLD_CERTIFICATE
Janos Follath 0:fc70c47eecb4 104 /* GlobalSign Root R1 SHA1/RSA/2048
Janos Follath 0:fc70c47eecb4 105 * Serial no. 04 00 00 00 00 01 15 4b 5a c3 94 */
Janos Follath 0:fc70c47eecb4 106 "-----BEGIN CERTIFICATE-----\n"
Janos Follath 0:fc70c47eecb4 107 "MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG\n"
Janos Follath 0:fc70c47eecb4 108 "A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv\n"
Janos Follath 0:fc70c47eecb4 109 "b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw\n"
Janos Follath 0:fc70c47eecb4 110 "MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i\n"
Janos Follath 0:fc70c47eecb4 111 "YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT\n"
Janos Follath 0:fc70c47eecb4 112 "aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ\n"
Janos Follath 0:fc70c47eecb4 113 "jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp\n"
Janos Follath 0:fc70c47eecb4 114 "xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp\n"
Janos Follath 0:fc70c47eecb4 115 "1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG\n"
Janos Follath 0:fc70c47eecb4 116 "snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ\n"
Janos Follath 0:fc70c47eecb4 117 "U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8\n"
Janos Follath 0:fc70c47eecb4 118 "9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E\n"
Janos Follath 0:fc70c47eecb4 119 "BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B\n"
Janos Follath 0:fc70c47eecb4 120 "AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz\n"
Janos Follath 0:fc70c47eecb4 121 "yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE\n"
Janos Follath 0:fc70c47eecb4 122 "38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP\n"
Janos Follath 0:fc70c47eecb4 123 "AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad\n"
Janos Follath 0:fc70c47eecb4 124 "DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME\n"
Janos Follath 0:fc70c47eecb4 125 "HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==\n"
Janos Follath 0:fc70c47eecb4 126 "-----END CERTIFICATE-----\n";
Janos Follath 0:fc70c47eecb4 127 #endif
Janos Follath 0:fc70c47eecb4 128 }
Janos Follath 0:fc70c47eecb4 129
Janos Follath 0:fc70c47eecb4 130 /**
Janos Follath 0:fc70c47eecb4 131 * \brief HelloHTTPS implements the logic for fetching a file from a webserver
Janos Follath 0:fc70c47eecb4 132 * using a TCP socket and parsing the result.
Janos Follath 0:fc70c47eecb4 133 */
Janos Follath 0:fc70c47eecb4 134 class HelloHTTPS {
Janos Follath 0:fc70c47eecb4 135 public:
Janos Follath 0:fc70c47eecb4 136 /**
Janos Follath 0:fc70c47eecb4 137 * HelloHTTPS Constructor
Janos Follath 0:fc70c47eecb4 138 * Initializes the TCP socket, sets up event handlers and flags.
Janos Follath 0:fc70c47eecb4 139 *
Janos Follath 0:fc70c47eecb4 140 * @param[in] domain The domain name to fetch from
Janos Follath 0:fc70c47eecb4 141 * @param[in] port The port of the HTTPS server
Janos Follath 0:fc70c47eecb4 142 */
Janos Follath 0:fc70c47eecb4 143 HelloHTTPS(const char * domain, const uint16_t port, NetworkInterface *net_iface) :
Janos Follath 0:fc70c47eecb4 144 _domain(domain), _port(port)
Janos Follath 0:fc70c47eecb4 145 {
Janos Follath 0:fc70c47eecb4 146
Janos Follath 0:fc70c47eecb4 147 _error = false;
Janos Follath 0:fc70c47eecb4 148 _gothello = false;
Janos Follath 0:fc70c47eecb4 149 _got200 = false;
Janos Follath 0:fc70c47eecb4 150 _bpos = 0;
Janos Follath 0:fc70c47eecb4 151 _request_sent = 0;
Janos Follath 0:fc70c47eecb4 152 _tcpsocket = new TCPSocket(net_iface);
Janos Follath 0:fc70c47eecb4 153
Janos Follath 0:fc70c47eecb4 154 mbedtls_entropy_init(&_entropy);
Janos Follath 0:fc70c47eecb4 155 mbedtls_ctr_drbg_init(&_ctr_drbg);
Janos Follath 0:fc70c47eecb4 156 mbedtls_x509_crt_init(&_cacert);
Janos Follath 0:fc70c47eecb4 157 mbedtls_ssl_init(&_ssl);
Janos Follath 0:fc70c47eecb4 158 mbedtls_ssl_config_init(&_ssl_conf);
Janos Follath 0:fc70c47eecb4 159 }
Janos Follath 0:fc70c47eecb4 160 /**
Janos Follath 0:fc70c47eecb4 161 * HelloHTTPS Desctructor
Janos Follath 0:fc70c47eecb4 162 */
Janos Follath 0:fc70c47eecb4 163 ~HelloHTTPS() {
Janos Follath 0:fc70c47eecb4 164 mbedtls_entropy_free(&_entropy);
Janos Follath 0:fc70c47eecb4 165 mbedtls_ctr_drbg_free(&_ctr_drbg);
Janos Follath 0:fc70c47eecb4 166 mbedtls_x509_crt_free(&_cacert);
Janos Follath 0:fc70c47eecb4 167 mbedtls_ssl_free(&_ssl);
Janos Follath 0:fc70c47eecb4 168 mbedtls_ssl_config_free(&_ssl_conf);
Janos Follath 0:fc70c47eecb4 169 }
Janos Follath 0:fc70c47eecb4 170 /**
Janos Follath 0:fc70c47eecb4 171 * Start the test.
Janos Follath 0:fc70c47eecb4 172 *
Janos Follath 0:fc70c47eecb4 173 * Starts by clearing test flags, then resolves the address with DNS.
Janos Follath 0:fc70c47eecb4 174 *
Janos Follath 0:fc70c47eecb4 175 * @param[in] path The path of the file to fetch from the HTTPS server
Janos Follath 0:fc70c47eecb4 176 * @return SOCKET_ERROR_NONE on success, or an error code on failure
Janos Follath 0:fc70c47eecb4 177 */
Janos Follath 0:fc70c47eecb4 178 void startTest(const char *path) {
Janos Follath 0:fc70c47eecb4 179 /* Initialize the flags */
Janos Follath 0:fc70c47eecb4 180 _got200 = false;
Janos Follath 0:fc70c47eecb4 181 _gothello = false;
Janos Follath 0:fc70c47eecb4 182 _error = false;
Janos Follath 0:fc70c47eecb4 183 _disconnected = false;
Janos Follath 0:fc70c47eecb4 184 _request_sent = false;
Janos Follath 0:fc70c47eecb4 185 /* Fill the request buffer */
Janos Follath 0:fc70c47eecb4 186 _bpos = snprintf(_buffer, sizeof(_buffer) - 1, "GET %s HTTP/1.1\nHost: %s\n\n", path, HTTPS_SERVER_NAME);
Janos Follath 0:fc70c47eecb4 187
Janos Follath 0:fc70c47eecb4 188 /*
Janos Follath 0:fc70c47eecb4 189 * Initialize TLS-related stuf.
Janos Follath 0:fc70c47eecb4 190 */
Janos Follath 0:fc70c47eecb4 191 int ret;
Janos Follath 0:fc70c47eecb4 192 if ((ret = mbedtls_ctr_drbg_seed(&_ctr_drbg, mbedtls_entropy_func, &_entropy,
Janos Follath 0:fc70c47eecb4 193 (const unsigned char *) DRBG_PERS,
Janos Follath 0:fc70c47eecb4 194 sizeof (DRBG_PERS))) != 0) {
Janos Follath 0:fc70c47eecb4 195 print_mbedtls_error("mbedtls_crt_drbg_init", ret);
Janos Follath 0:fc70c47eecb4 196 _error = true;
Janos Follath 0:fc70c47eecb4 197 return;
Janos Follath 0:fc70c47eecb4 198 }
Janos Follath 0:fc70c47eecb4 199
Janos Follath 0:fc70c47eecb4 200 if ((ret = mbedtls_x509_crt_parse(&_cacert, (const unsigned char *) SSL_CA_PEM,
Janos Follath 0:fc70c47eecb4 201 sizeof (SSL_CA_PEM))) != 0) {
Janos Follath 0:fc70c47eecb4 202 print_mbedtls_error("mbedtls_x509_crt_parse", ret);
Janos Follath 0:fc70c47eecb4 203 _error = true;
Janos Follath 0:fc70c47eecb4 204 return;
Janos Follath 0:fc70c47eecb4 205 }
Janos Follath 0:fc70c47eecb4 206
Janos Follath 0:fc70c47eecb4 207 if ((ret = mbedtls_ssl_config_defaults(&_ssl_conf,
Janos Follath 0:fc70c47eecb4 208 MBEDTLS_SSL_IS_CLIENT,
Janos Follath 0:fc70c47eecb4 209 MBEDTLS_SSL_TRANSPORT_STREAM,
Janos Follath 0:fc70c47eecb4 210 MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
Janos Follath 0:fc70c47eecb4 211 print_mbedtls_error("mbedtls_ssl_config_defaults", ret);
Janos Follath 0:fc70c47eecb4 212 _error = true;
Janos Follath 0:fc70c47eecb4 213 return;
Janos Follath 0:fc70c47eecb4 214 }
Janos Follath 0:fc70c47eecb4 215
Janos Follath 0:fc70c47eecb4 216 mbedtls_ssl_conf_ca_chain(&_ssl_conf, &_cacert, NULL);
Janos Follath 0:fc70c47eecb4 217 mbedtls_ssl_conf_rng(&_ssl_conf, mbedtls_ctr_drbg_random, &_ctr_drbg);
Janos Follath 0:fc70c47eecb4 218
Janos Follath 0:fc70c47eecb4 219 #if UNSAFE
Janos Follath 0:fc70c47eecb4 220 mbedtls_ssl_conf_authmode(&_ssl_conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
Janos Follath 0:fc70c47eecb4 221 #endif
Janos Follath 0:fc70c47eecb4 222
Janos Follath 0:fc70c47eecb4 223 #if DEBUG_LEVEL > 0
Janos Follath 0:fc70c47eecb4 224 mbedtls_ssl_conf_verify(&_ssl_conf, my_verify, NULL);
Janos Follath 0:fc70c47eecb4 225 mbedtls_ssl_conf_dbg(&_ssl_conf, my_debug, NULL);
Janos Follath 0:fc70c47eecb4 226 mbedtls_debug_set_threshold(DEBUG_LEVEL);
Janos Follath 0:fc70c47eecb4 227 #endif
Janos Follath 0:fc70c47eecb4 228
Janos Follath 0:fc70c47eecb4 229 if ((ret = mbedtls_ssl_setup(&_ssl, &_ssl_conf)) != 0) {
Janos Follath 0:fc70c47eecb4 230 print_mbedtls_error("mbedtls_ssl_setup", ret);
Janos Follath 0:fc70c47eecb4 231 _error = true;
Janos Follath 0:fc70c47eecb4 232 return;
Janos Follath 0:fc70c47eecb4 233 }
Janos Follath 0:fc70c47eecb4 234
Janos Follath 0:fc70c47eecb4 235 mbedtls_ssl_set_hostname(&_ssl, HTTPS_SERVER_NAME);
Janos Follath 0:fc70c47eecb4 236
Janos Follath 0:fc70c47eecb4 237 mbedtls_ssl_set_bio(&_ssl, static_cast<void *>(_tcpsocket),
Janos Follath 0:fc70c47eecb4 238 ssl_send, ssl_recv, NULL );
Janos Follath 0:fc70c47eecb4 239
Janos Follath 0:fc70c47eecb4 240
Janos Follath 0:fc70c47eecb4 241 /* Connect to the server */
Janos Follath 0:fc70c47eecb4 242 mbedtls_printf("Connecting with %s\r\n", _domain);
Janos Follath 0:fc70c47eecb4 243 _tcpsocket->connect( _domain, _port );
Janos Follath 0:fc70c47eecb4 244
Janos Follath 0:fc70c47eecb4 245 /* Start the handshake, the rest will be done in onReceive() */
Janos Follath 0:fc70c47eecb4 246 mbedtls_printf("Starting the TLS handshake...\r\n");
Janos Follath 0:fc70c47eecb4 247 ret = mbedtls_ssl_handshake(&_ssl);
Janos Follath 0:fc70c47eecb4 248 if (ret < 0) {
Janos Follath 0:fc70c47eecb4 249 if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
Janos Follath 0:fc70c47eecb4 250 ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
Janos Follath 0:fc70c47eecb4 251 print_mbedtls_error("mbedtls_ssl_handshake", ret);
Janos Follath 0:fc70c47eecb4 252 onError(_tcpsocket, -1 );
Janos Follath 0:fc70c47eecb4 253 }
Janos Follath 0:fc70c47eecb4 254 return;
Janos Follath 0:fc70c47eecb4 255 }
Janos Follath 0:fc70c47eecb4 256
Janos Follath 0:fc70c47eecb4 257 ret = mbedtls_ssl_write(&_ssl, (const unsigned char *) _buffer, _bpos);
Janos Follath 0:fc70c47eecb4 258 if (ret < 0) {
Janos Follath 0:fc70c47eecb4 259 if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
Janos Follath 0:fc70c47eecb4 260 ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
Janos Follath 0:fc70c47eecb4 261 print_mbedtls_error("mbedtls_ssl_write", ret);
Janos Follath 0:fc70c47eecb4 262 onError(_tcpsocket, -1 );
Janos Follath 0:fc70c47eecb4 263 }
Janos Follath 0:fc70c47eecb4 264 return;
Janos Follath 0:fc70c47eecb4 265 }
Janos Follath 0:fc70c47eecb4 266
Janos Follath 0:fc70c47eecb4 267 /* It also means the handshake is done, time to print info */
Janos Follath 0:fc70c47eecb4 268 printf("TLS connection to %s established\r\n", HTTPS_SERVER_NAME);
Janos Follath 0:fc70c47eecb4 269
mbed_official 9:1ac74f2d7bda 270 const uint32_t buf_size = 1024;
mbed_official 9:1ac74f2d7bda 271 char *buf = new char[buf_size];
mbed_official 9:1ac74f2d7bda 272 mbedtls_x509_crt_info(buf, buf_size, "\r ",
Janos Follath 0:fc70c47eecb4 273 mbedtls_ssl_get_peer_cert(&_ssl));
Janos Follath 0:fc70c47eecb4 274 mbedtls_printf("Server certificate:\r\n%s\r", buf);
Janos Follath 0:fc70c47eecb4 275
Janos Follath 0:fc70c47eecb4 276 #if defined(UNSAFE)
Janos Follath 0:fc70c47eecb4 277 uint32_t flags = mbedtls_ssl_get_verify_result(&_ssl);
Janos Follath 0:fc70c47eecb4 278 if( flags != 0 )
Janos Follath 0:fc70c47eecb4 279 {
mbed_official 9:1ac74f2d7bda 280 mbedtls_x509_crt_verify_info(buf, buf_size, "\r ! ", flags);
Janos Follath 0:fc70c47eecb4 281 printf("Certificate verification failed:\r\n%s\r\r\n", buf);
Janos Follath 0:fc70c47eecb4 282 }
Janos Follath 0:fc70c47eecb4 283 else
Janos Follath 0:fc70c47eecb4 284 #endif
Janos Follath 0:fc70c47eecb4 285 printf("Certificate verification passed\r\n\r\n");
Janos Follath 0:fc70c47eecb4 286
Janos Follath 0:fc70c47eecb4 287
Janos Follath 0:fc70c47eecb4 288 /* Read data out of the socket */
Janos Follath 0:fc70c47eecb4 289 ret = mbedtls_ssl_read(&_ssl, (unsigned char *) _buffer, sizeof(_buffer));
Janos Follath 0:fc70c47eecb4 290 if (ret < 0) {
Janos Follath 0:fc70c47eecb4 291 if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
Janos Follath 0:fc70c47eecb4 292 print_mbedtls_error("mbedtls_ssl_read", ret);
Janos Follath 0:fc70c47eecb4 293 onError(_tcpsocket, -1 );
Janos Follath 0:fc70c47eecb4 294 }
mbed_official 9:1ac74f2d7bda 295 delete[] buf;
Janos Follath 0:fc70c47eecb4 296 return;
Janos Follath 0:fc70c47eecb4 297 }
Janos Follath 0:fc70c47eecb4 298 _bpos = static_cast<size_t>(ret);
Janos Follath 0:fc70c47eecb4 299
Janos Follath 0:fc70c47eecb4 300 _buffer[_bpos] = 0;
Janos Follath 0:fc70c47eecb4 301
Janos Follath 0:fc70c47eecb4 302 /* Check each of the flags */
Janos Follath 0:fc70c47eecb4 303 _got200 = _got200 || strstr(_buffer, HTTPS_OK_STR) != NULL;
Janos Follath 0:fc70c47eecb4 304 _gothello = _gothello || strstr(_buffer, HTTPS_HELLO_STR) != NULL;
Janos Follath 0:fc70c47eecb4 305
Janos Follath 0:fc70c47eecb4 306 /* Print status messages */
Janos Follath 0:fc70c47eecb4 307 mbedtls_printf("HTTPS: Received %d chars from server\r\n", _bpos);
Janos Follath 0:fc70c47eecb4 308 mbedtls_printf("HTTPS: Received 200 OK status ... %s\r\n", _got200 ? "[OK]" : "[FAIL]");
Janos Follath 0:fc70c47eecb4 309 mbedtls_printf("HTTPS: Received '%s' status ... %s\r\n", HTTPS_HELLO_STR, _gothello ? "[OK]" : "[FAIL]");
Janos Follath 0:fc70c47eecb4 310 mbedtls_printf("HTTPS: Received message:\r\n\r\n");
Janos Follath 0:fc70c47eecb4 311 mbedtls_printf("%s", _buffer);
Janos Follath 0:fc70c47eecb4 312 _error = !(_got200 && _gothello);
Janos Follath 0:fc70c47eecb4 313
Janos Follath 0:fc70c47eecb4 314 _tcpsocket->close();
mbed_official 9:1ac74f2d7bda 315 delete[] buf;
Janos Follath 0:fc70c47eecb4 316 }
Janos Follath 0:fc70c47eecb4 317 /**
Janos Follath 0:fc70c47eecb4 318 * Check if the test has completed.
Janos Follath 0:fc70c47eecb4 319 * @return Returns true if done, false otherwise.
Janos Follath 0:fc70c47eecb4 320 */
Janos Follath 0:fc70c47eecb4 321 bool done() {
Janos Follath 0:fc70c47eecb4 322 return _error || (_got200 && _gothello);
Janos Follath 0:fc70c47eecb4 323 }
Janos Follath 0:fc70c47eecb4 324 /**
Janos Follath 0:fc70c47eecb4 325 * Check if there was an error
Janos Follath 0:fc70c47eecb4 326 * @return Returns true if there was an error, false otherwise.
Janos Follath 0:fc70c47eecb4 327 */
Janos Follath 0:fc70c47eecb4 328 bool error() {
Janos Follath 0:fc70c47eecb4 329 return _error;
Janos Follath 0:fc70c47eecb4 330 }
Janos Follath 0:fc70c47eecb4 331 /**
Janos Follath 0:fc70c47eecb4 332 * Closes the TCP socket
Janos Follath 0:fc70c47eecb4 333 */
Janos Follath 0:fc70c47eecb4 334 void close() {
Janos Follath 0:fc70c47eecb4 335 _tcpsocket->close();
Janos Follath 0:fc70c47eecb4 336 while (!_disconnected)
Janos Follath 0:fc70c47eecb4 337 __WFI();
Janos Follath 0:fc70c47eecb4 338 }
Janos Follath 0:fc70c47eecb4 339 protected:
Janos Follath 0:fc70c47eecb4 340 /**
Janos Follath 0:fc70c47eecb4 341 * Helper for pretty-printing mbed TLS error codes
Janos Follath 0:fc70c47eecb4 342 */
Janos Follath 0:fc70c47eecb4 343 static void print_mbedtls_error(const char *name, int err) {
Janos Follath 0:fc70c47eecb4 344 char buf[128];
Janos Follath 0:fc70c47eecb4 345 mbedtls_strerror(err, buf, sizeof (buf));
Janos Follath 0:fc70c47eecb4 346 mbedtls_printf("%s() failed: -0x%04x (%d): %s\r\n", name, -err, err, buf);
Janos Follath 0:fc70c47eecb4 347 }
Janos Follath 0:fc70c47eecb4 348
Janos Follath 0:fc70c47eecb4 349 #if DEBUG_LEVEL > 0
Janos Follath 0:fc70c47eecb4 350 /**
Janos Follath 0:fc70c47eecb4 351 * Debug callback for mbed TLS
Janos Follath 0:fc70c47eecb4 352 * Just prints on the USB serial port
Janos Follath 0:fc70c47eecb4 353 */
Janos Follath 0:fc70c47eecb4 354 static void my_debug(void *ctx, int level, const char *file, int line,
Janos Follath 0:fc70c47eecb4 355 const char *str)
Janos Follath 0:fc70c47eecb4 356 {
Janos Follath 0:fc70c47eecb4 357 const char *p, *basename;
Janos Follath 0:fc70c47eecb4 358 (void) ctx;
Janos Follath 0:fc70c47eecb4 359
Janos Follath 0:fc70c47eecb4 360 /* Extract basename from file */
Janos Follath 0:fc70c47eecb4 361 for(p = basename = file; *p != '\0'; p++) {
Janos Follath 0:fc70c47eecb4 362 if(*p == '/' || *p == '\\') {
Janos Follath 0:fc70c47eecb4 363 basename = p + 1;
Janos Follath 0:fc70c47eecb4 364 }
Janos Follath 0:fc70c47eecb4 365 }
Janos Follath 0:fc70c47eecb4 366
Janos Follath 0:fc70c47eecb4 367 mbedtls_printf("%s:%04d: |%d| %s", basename, line, level, str);
Janos Follath 0:fc70c47eecb4 368 }
Janos Follath 0:fc70c47eecb4 369
Janos Follath 0:fc70c47eecb4 370 /**
Janos Follath 0:fc70c47eecb4 371 * Certificate verification callback for mbed TLS
Janos Follath 0:fc70c47eecb4 372 * Here we only use it to display information on each cert in the chain
Janos Follath 0:fc70c47eecb4 373 */
Janos Follath 0:fc70c47eecb4 374 static int my_verify(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags)
Janos Follath 0:fc70c47eecb4 375 {
mbed_official 9:1ac74f2d7bda 376 const uint32_t buf_size = 1024;
mbed_official 9:1ac74f2d7bda 377 char *buf = new char[buf_size];
Janos Follath 0:fc70c47eecb4 378 (void) data;
Janos Follath 0:fc70c47eecb4 379
Janos Follath 0:fc70c47eecb4 380 mbedtls_printf("\nVerifying certificate at depth %d:\n", depth);
mbed_official 9:1ac74f2d7bda 381 mbedtls_x509_crt_info(buf, buf_size - 1, " ", crt);
Janos Follath 0:fc70c47eecb4 382 mbedtls_printf("%s", buf);
Janos Follath 0:fc70c47eecb4 383
Janos Follath 0:fc70c47eecb4 384 if (*flags == 0)
Janos Follath 0:fc70c47eecb4 385 mbedtls_printf("No verification issue for this certificate\n");
Janos Follath 0:fc70c47eecb4 386 else
Janos Follath 0:fc70c47eecb4 387 {
mbed_official 9:1ac74f2d7bda 388 mbedtls_x509_crt_verify_info(buf, buf_size, " ! ", *flags);
Janos Follath 0:fc70c47eecb4 389 mbedtls_printf("%s\n", buf);
Janos Follath 0:fc70c47eecb4 390 }
Janos Follath 0:fc70c47eecb4 391
mbed_official 9:1ac74f2d7bda 392 delete[] buf;
Janos Follath 0:fc70c47eecb4 393 return 0;
Janos Follath 0:fc70c47eecb4 394 }
Janos Follath 0:fc70c47eecb4 395 #endif
Janos Follath 0:fc70c47eecb4 396
Janos Follath 0:fc70c47eecb4 397 /**
Janos Follath 0:fc70c47eecb4 398 * Receive callback for mbed TLS
Janos Follath 0:fc70c47eecb4 399 */
Janos Follath 0:fc70c47eecb4 400 static int ssl_recv(void *ctx, unsigned char *buf, size_t len) {
Janos Follath 0:fc70c47eecb4 401 int recv = -1;
Janos Follath 0:fc70c47eecb4 402 TCPSocket *socket = static_cast<TCPSocket *>(ctx);
Janos Follath 0:fc70c47eecb4 403 recv = socket->recv(buf, len);
Janos Follath 0:fc70c47eecb4 404
Janos Follath 0:fc70c47eecb4 405 if(NSAPI_ERROR_WOULD_BLOCK == recv){
Janos Follath 0:fc70c47eecb4 406 return MBEDTLS_ERR_SSL_WANT_READ;
Janos Follath 0:fc70c47eecb4 407 }else if(recv < 0){
Janos Follath 0:fc70c47eecb4 408 return -1;
Janos Follath 0:fc70c47eecb4 409 }else{
Janos Follath 0:fc70c47eecb4 410 return recv;
Janos Follath 0:fc70c47eecb4 411 }
Janos Follath 0:fc70c47eecb4 412 }
Janos Follath 0:fc70c47eecb4 413
Janos Follath 0:fc70c47eecb4 414 /**
Janos Follath 0:fc70c47eecb4 415 * Send callback for mbed TLS
Janos Follath 0:fc70c47eecb4 416 */
Janos Follath 0:fc70c47eecb4 417 static int ssl_send(void *ctx, const unsigned char *buf, size_t len) {
Janos Follath 0:fc70c47eecb4 418 int size = -1;
Janos Follath 0:fc70c47eecb4 419 TCPSocket *socket = static_cast<TCPSocket *>(ctx);
Janos Follath 0:fc70c47eecb4 420 size = socket->send(buf, len);
Janos Follath 0:fc70c47eecb4 421
Janos Follath 0:fc70c47eecb4 422 if(NSAPI_ERROR_WOULD_BLOCK == size){
Janos Follath 0:fc70c47eecb4 423 return len;
Janos Follath 0:fc70c47eecb4 424 }else if(size < 0){
Janos Follath 0:fc70c47eecb4 425 return -1;
Janos Follath 0:fc70c47eecb4 426 }else{
Janos Follath 0:fc70c47eecb4 427 return size;
Janos Follath 0:fc70c47eecb4 428 }
Janos Follath 0:fc70c47eecb4 429 }
Janos Follath 0:fc70c47eecb4 430
Janos Follath 0:fc70c47eecb4 431 void onError(TCPSocket *s, int error) {
Janos Follath 0:fc70c47eecb4 432 printf("MBED: Socket Error: %d\r\n", error);
Janos Follath 0:fc70c47eecb4 433 s->close();
Janos Follath 0:fc70c47eecb4 434 _error = true;
Janos Follath 0:fc70c47eecb4 435 }
Janos Follath 0:fc70c47eecb4 436
Janos Follath 0:fc70c47eecb4 437 protected:
Janos Follath 0:fc70c47eecb4 438 TCPSocket* _tcpsocket;
Janos Follath 0:fc70c47eecb4 439
Janos Follath 0:fc70c47eecb4 440 const char *_domain; /**< The domain name of the HTTPS server */
Janos Follath 0:fc70c47eecb4 441 const uint16_t _port; /**< The HTTPS server port */
Janos Follath 0:fc70c47eecb4 442 char _buffer[RECV_BUFFER_SIZE]; /**< The response buffer */
Janos Follath 0:fc70c47eecb4 443 size_t _bpos; /**< The current offset in the response buffer */
Janos Follath 0:fc70c47eecb4 444 volatile bool _got200; /**< Status flag for HTTPS 200 */
Janos Follath 0:fc70c47eecb4 445 volatile bool _gothello; /**< Status flag for finding the test string */
Janos Follath 0:fc70c47eecb4 446 volatile bool _error; /**< Status flag for an error */
Janos Follath 0:fc70c47eecb4 447 volatile bool _disconnected;
Janos Follath 0:fc70c47eecb4 448 volatile bool _request_sent;
Janos Follath 0:fc70c47eecb4 449
Janos Follath 0:fc70c47eecb4 450 mbedtls_entropy_context _entropy;
Janos Follath 0:fc70c47eecb4 451 mbedtls_ctr_drbg_context _ctr_drbg;
Janos Follath 0:fc70c47eecb4 452 mbedtls_x509_crt _cacert;
Janos Follath 0:fc70c47eecb4 453 mbedtls_ssl_context _ssl;
Janos Follath 0:fc70c47eecb4 454 mbedtls_ssl_config _ssl_conf;
Janos Follath 0:fc70c47eecb4 455 };
Janos Follath 0:fc70c47eecb4 456
Janos Follath 0:fc70c47eecb4 457 /**
Janos Follath 0:fc70c47eecb4 458 * The main loop of the HTTPS Hello World test
Janos Follath 0:fc70c47eecb4 459 */
Janos Follath 0:fc70c47eecb4 460 int main() {
Janos Follath 0:fc70c47eecb4 461 /* The default 9600 bps is too slow to print full TLS debug info and could
Janos Follath 0:fc70c47eecb4 462 * cause the other party to time out. */
Janos Follath 0:fc70c47eecb4 463
Janos Follath 0:fc70c47eecb4 464 /* Inititalise with DHCP, connect, and start up the stack */
Janos Follath 0:fc70c47eecb4 465 EthernetInterface eth_iface;
Janos Follath 0:fc70c47eecb4 466 eth_iface.connect();
Janos Follath 0:fc70c47eecb4 467 mbedtls_printf("Using Ethernet LWIP\r\n");
Janos Follath 0:fc70c47eecb4 468 const char *ip_addr = eth_iface.get_ip_address();
Janos Follath 0:fc70c47eecb4 469 if (ip_addr) {
Janos Follath 0:fc70c47eecb4 470 mbedtls_printf("Client IP Address is %s\r\n", ip_addr);
Janos Follath 0:fc70c47eecb4 471 } else {
Janos Follath 0:fc70c47eecb4 472 mbedtls_printf("No Client IP Address\r\n");
Janos Follath 0:fc70c47eecb4 473 }
Janos Follath 0:fc70c47eecb4 474
mbed_official 9:1ac74f2d7bda 475 HelloHTTPS *hello = new HelloHTTPS(HTTPS_SERVER_NAME, HTTPS_SERVER_PORT, &eth_iface);
mbed_official 9:1ac74f2d7bda 476 hello->startTest(HTTPS_PATH);
mbed_official 9:1ac74f2d7bda 477 delete hello;
Janos Follath 0:fc70c47eecb4 478 }