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:
Janos Follath
Date:
Wed Jul 27 14:34:24 2016 +0100
Revision:
0:fc70c47eecb4
Child:
9:1ac74f2d7bda
Update example home repo at The canonical source for this example lives at 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
Janos Follath 0:fc70c47eecb4 270 char buf[1024];
Janos Follath 0:fc70c47eecb4 271 mbedtls_x509_crt_info(buf, sizeof(buf), "\r ",
Janos Follath 0:fc70c47eecb4 272 mbedtls_ssl_get_peer_cert(&_ssl));
Janos Follath 0:fc70c47eecb4 273 mbedtls_printf("Server certificate:\r\n%s\r", buf);
Janos Follath 0:fc70c47eecb4 274
Janos Follath 0:fc70c47eecb4 275 #if defined(UNSAFE)
Janos Follath 0:fc70c47eecb4 276 uint32_t flags = mbedtls_ssl_get_verify_result(&_ssl);
Janos Follath 0:fc70c47eecb4 277 if( flags != 0 )
Janos Follath 0:fc70c47eecb4 278 {
Janos Follath 0:fc70c47eecb4 279 mbedtls_x509_crt_verify_info(buf, sizeof (buf), "\r ! ", flags);
Janos Follath 0:fc70c47eecb4 280 printf("Certificate verification failed:\r\n%s\r\r\n", buf);
Janos Follath 0:fc70c47eecb4 281 }
Janos Follath 0:fc70c47eecb4 282 else
Janos Follath 0:fc70c47eecb4 283 #endif
Janos Follath 0:fc70c47eecb4 284 printf("Certificate verification passed\r\n\r\n");
Janos Follath 0:fc70c47eecb4 285
Janos Follath 0:fc70c47eecb4 286
Janos Follath 0:fc70c47eecb4 287 /* Read data out of the socket */
Janos Follath 0:fc70c47eecb4 288 ret = mbedtls_ssl_read(&_ssl, (unsigned char *) _buffer, sizeof(_buffer));
Janos Follath 0:fc70c47eecb4 289 if (ret < 0) {
Janos Follath 0:fc70c47eecb4 290 if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
Janos Follath 0:fc70c47eecb4 291 print_mbedtls_error("mbedtls_ssl_read", ret);
Janos Follath 0:fc70c47eecb4 292 onError(_tcpsocket, -1 );
Janos Follath 0:fc70c47eecb4 293 }
Janos Follath 0:fc70c47eecb4 294 return;
Janos Follath 0:fc70c47eecb4 295 }
Janos Follath 0:fc70c47eecb4 296 _bpos = static_cast<size_t>(ret);
Janos Follath 0:fc70c47eecb4 297
Janos Follath 0:fc70c47eecb4 298 _buffer[_bpos] = 0;
Janos Follath 0:fc70c47eecb4 299
Janos Follath 0:fc70c47eecb4 300 /* Check each of the flags */
Janos Follath 0:fc70c47eecb4 301 _got200 = _got200 || strstr(_buffer, HTTPS_OK_STR) != NULL;
Janos Follath 0:fc70c47eecb4 302 _gothello = _gothello || strstr(_buffer, HTTPS_HELLO_STR) != NULL;
Janos Follath 0:fc70c47eecb4 303
Janos Follath 0:fc70c47eecb4 304 /* Print status messages */
Janos Follath 0:fc70c47eecb4 305 mbedtls_printf("HTTPS: Received %d chars from server\r\n", _bpos);
Janos Follath 0:fc70c47eecb4 306 mbedtls_printf("HTTPS: Received 200 OK status ... %s\r\n", _got200 ? "[OK]" : "[FAIL]");
Janos Follath 0:fc70c47eecb4 307 mbedtls_printf("HTTPS: Received '%s' status ... %s\r\n", HTTPS_HELLO_STR, _gothello ? "[OK]" : "[FAIL]");
Janos Follath 0:fc70c47eecb4 308 mbedtls_printf("HTTPS: Received message:\r\n\r\n");
Janos Follath 0:fc70c47eecb4 309 mbedtls_printf("%s", _buffer);
Janos Follath 0:fc70c47eecb4 310 _error = !(_got200 && _gothello);
Janos Follath 0:fc70c47eecb4 311
Janos Follath 0:fc70c47eecb4 312 _tcpsocket->close();
Janos Follath 0:fc70c47eecb4 313 }
Janos Follath 0:fc70c47eecb4 314 /**
Janos Follath 0:fc70c47eecb4 315 * Check if the test has completed.
Janos Follath 0:fc70c47eecb4 316 * @return Returns true if done, false otherwise.
Janos Follath 0:fc70c47eecb4 317 */
Janos Follath 0:fc70c47eecb4 318 bool done() {
Janos Follath 0:fc70c47eecb4 319 return _error || (_got200 && _gothello);
Janos Follath 0:fc70c47eecb4 320 }
Janos Follath 0:fc70c47eecb4 321 /**
Janos Follath 0:fc70c47eecb4 322 * Check if there was an error
Janos Follath 0:fc70c47eecb4 323 * @return Returns true if there was an error, false otherwise.
Janos Follath 0:fc70c47eecb4 324 */
Janos Follath 0:fc70c47eecb4 325 bool error() {
Janos Follath 0:fc70c47eecb4 326 return _error;
Janos Follath 0:fc70c47eecb4 327 }
Janos Follath 0:fc70c47eecb4 328 /**
Janos Follath 0:fc70c47eecb4 329 * Closes the TCP socket
Janos Follath 0:fc70c47eecb4 330 */
Janos Follath 0:fc70c47eecb4 331 void close() {
Janos Follath 0:fc70c47eecb4 332 _tcpsocket->close();
Janos Follath 0:fc70c47eecb4 333 while (!_disconnected)
Janos Follath 0:fc70c47eecb4 334 __WFI();
Janos Follath 0:fc70c47eecb4 335 }
Janos Follath 0:fc70c47eecb4 336 protected:
Janos Follath 0:fc70c47eecb4 337 /**
Janos Follath 0:fc70c47eecb4 338 * Helper for pretty-printing mbed TLS error codes
Janos Follath 0:fc70c47eecb4 339 */
Janos Follath 0:fc70c47eecb4 340 static void print_mbedtls_error(const char *name, int err) {
Janos Follath 0:fc70c47eecb4 341 char buf[128];
Janos Follath 0:fc70c47eecb4 342 mbedtls_strerror(err, buf, sizeof (buf));
Janos Follath 0:fc70c47eecb4 343 mbedtls_printf("%s() failed: -0x%04x (%d): %s\r\n", name, -err, err, buf);
Janos Follath 0:fc70c47eecb4 344 }
Janos Follath 0:fc70c47eecb4 345
Janos Follath 0:fc70c47eecb4 346 #if DEBUG_LEVEL > 0
Janos Follath 0:fc70c47eecb4 347 /**
Janos Follath 0:fc70c47eecb4 348 * Debug callback for mbed TLS
Janos Follath 0:fc70c47eecb4 349 * Just prints on the USB serial port
Janos Follath 0:fc70c47eecb4 350 */
Janos Follath 0:fc70c47eecb4 351 static void my_debug(void *ctx, int level, const char *file, int line,
Janos Follath 0:fc70c47eecb4 352 const char *str)
Janos Follath 0:fc70c47eecb4 353 {
Janos Follath 0:fc70c47eecb4 354 const char *p, *basename;
Janos Follath 0:fc70c47eecb4 355 (void) ctx;
Janos Follath 0:fc70c47eecb4 356
Janos Follath 0:fc70c47eecb4 357 /* Extract basename from file */
Janos Follath 0:fc70c47eecb4 358 for(p = basename = file; *p != '\0'; p++) {
Janos Follath 0:fc70c47eecb4 359 if(*p == '/' || *p == '\\') {
Janos Follath 0:fc70c47eecb4 360 basename = p + 1;
Janos Follath 0:fc70c47eecb4 361 }
Janos Follath 0:fc70c47eecb4 362 }
Janos Follath 0:fc70c47eecb4 363
Janos Follath 0:fc70c47eecb4 364 mbedtls_printf("%s:%04d: |%d| %s", basename, line, level, str);
Janos Follath 0:fc70c47eecb4 365 }
Janos Follath 0:fc70c47eecb4 366
Janos Follath 0:fc70c47eecb4 367 /**
Janos Follath 0:fc70c47eecb4 368 * Certificate verification callback for mbed TLS
Janos Follath 0:fc70c47eecb4 369 * Here we only use it to display information on each cert in the chain
Janos Follath 0:fc70c47eecb4 370 */
Janos Follath 0:fc70c47eecb4 371 static int my_verify(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags)
Janos Follath 0:fc70c47eecb4 372 {
Janos Follath 0:fc70c47eecb4 373 char buf[1024];
Janos Follath 0:fc70c47eecb4 374 (void) data;
Janos Follath 0:fc70c47eecb4 375
Janos Follath 0:fc70c47eecb4 376 mbedtls_printf("\nVerifying certificate at depth %d:\n", depth);
Janos Follath 0:fc70c47eecb4 377 mbedtls_x509_crt_info(buf, sizeof (buf) - 1, " ", crt);
Janos Follath 0:fc70c47eecb4 378 mbedtls_printf("%s", buf);
Janos Follath 0:fc70c47eecb4 379
Janos Follath 0:fc70c47eecb4 380 if (*flags == 0)
Janos Follath 0:fc70c47eecb4 381 mbedtls_printf("No verification issue for this certificate\n");
Janos Follath 0:fc70c47eecb4 382 else
Janos Follath 0:fc70c47eecb4 383 {
Janos Follath 0:fc70c47eecb4 384 mbedtls_x509_crt_verify_info(buf, sizeof (buf), " ! ", *flags);
Janos Follath 0:fc70c47eecb4 385 mbedtls_printf("%s\n", buf);
Janos Follath 0:fc70c47eecb4 386 }
Janos Follath 0:fc70c47eecb4 387
Janos Follath 0:fc70c47eecb4 388 return 0;
Janos Follath 0:fc70c47eecb4 389 }
Janos Follath 0:fc70c47eecb4 390 #endif
Janos Follath 0:fc70c47eecb4 391
Janos Follath 0:fc70c47eecb4 392 /**
Janos Follath 0:fc70c47eecb4 393 * Receive callback for mbed TLS
Janos Follath 0:fc70c47eecb4 394 */
Janos Follath 0:fc70c47eecb4 395 static int ssl_recv(void *ctx, unsigned char *buf, size_t len) {
Janos Follath 0:fc70c47eecb4 396 int recv = -1;
Janos Follath 0:fc70c47eecb4 397 TCPSocket *socket = static_cast<TCPSocket *>(ctx);
Janos Follath 0:fc70c47eecb4 398 recv = socket->recv(buf, len);
Janos Follath 0:fc70c47eecb4 399
Janos Follath 0:fc70c47eecb4 400 if(NSAPI_ERROR_WOULD_BLOCK == recv){
Janos Follath 0:fc70c47eecb4 401 return MBEDTLS_ERR_SSL_WANT_READ;
Janos Follath 0:fc70c47eecb4 402 }else if(recv < 0){
Janos Follath 0:fc70c47eecb4 403 return -1;
Janos Follath 0:fc70c47eecb4 404 }else{
Janos Follath 0:fc70c47eecb4 405 return recv;
Janos Follath 0:fc70c47eecb4 406 }
Janos Follath 0:fc70c47eecb4 407 }
Janos Follath 0:fc70c47eecb4 408
Janos Follath 0:fc70c47eecb4 409 /**
Janos Follath 0:fc70c47eecb4 410 * Send callback for mbed TLS
Janos Follath 0:fc70c47eecb4 411 */
Janos Follath 0:fc70c47eecb4 412 static int ssl_send(void *ctx, const unsigned char *buf, size_t len) {
Janos Follath 0:fc70c47eecb4 413 int size = -1;
Janos Follath 0:fc70c47eecb4 414 TCPSocket *socket = static_cast<TCPSocket *>(ctx);
Janos Follath 0:fc70c47eecb4 415 size = socket->send(buf, len);
Janos Follath 0:fc70c47eecb4 416
Janos Follath 0:fc70c47eecb4 417 if(NSAPI_ERROR_WOULD_BLOCK == size){
Janos Follath 0:fc70c47eecb4 418 return len;
Janos Follath 0:fc70c47eecb4 419 }else if(size < 0){
Janos Follath 0:fc70c47eecb4 420 return -1;
Janos Follath 0:fc70c47eecb4 421 }else{
Janos Follath 0:fc70c47eecb4 422 return size;
Janos Follath 0:fc70c47eecb4 423 }
Janos Follath 0:fc70c47eecb4 424 }
Janos Follath 0:fc70c47eecb4 425
Janos Follath 0:fc70c47eecb4 426 void onError(TCPSocket *s, int error) {
Janos Follath 0:fc70c47eecb4 427 printf("MBED: Socket Error: %d\r\n", error);
Janos Follath 0:fc70c47eecb4 428 s->close();
Janos Follath 0:fc70c47eecb4 429 _error = true;
Janos Follath 0:fc70c47eecb4 430 }
Janos Follath 0:fc70c47eecb4 431
Janos Follath 0:fc70c47eecb4 432 protected:
Janos Follath 0:fc70c47eecb4 433 TCPSocket* _tcpsocket;
Janos Follath 0:fc70c47eecb4 434
Janos Follath 0:fc70c47eecb4 435 const char *_domain; /**< The domain name of the HTTPS server */
Janos Follath 0:fc70c47eecb4 436 const uint16_t _port; /**< The HTTPS server port */
Janos Follath 0:fc70c47eecb4 437 char _buffer[RECV_BUFFER_SIZE]; /**< The response buffer */
Janos Follath 0:fc70c47eecb4 438 size_t _bpos; /**< The current offset in the response buffer */
Janos Follath 0:fc70c47eecb4 439 volatile bool _got200; /**< Status flag for HTTPS 200 */
Janos Follath 0:fc70c47eecb4 440 volatile bool _gothello; /**< Status flag for finding the test string */
Janos Follath 0:fc70c47eecb4 441 volatile bool _error; /**< Status flag for an error */
Janos Follath 0:fc70c47eecb4 442 volatile bool _disconnected;
Janos Follath 0:fc70c47eecb4 443 volatile bool _request_sent;
Janos Follath 0:fc70c47eecb4 444
Janos Follath 0:fc70c47eecb4 445 mbedtls_entropy_context _entropy;
Janos Follath 0:fc70c47eecb4 446 mbedtls_ctr_drbg_context _ctr_drbg;
Janos Follath 0:fc70c47eecb4 447 mbedtls_x509_crt _cacert;
Janos Follath 0:fc70c47eecb4 448 mbedtls_ssl_context _ssl;
Janos Follath 0:fc70c47eecb4 449 mbedtls_ssl_config _ssl_conf;
Janos Follath 0:fc70c47eecb4 450 };
Janos Follath 0:fc70c47eecb4 451
Janos Follath 0:fc70c47eecb4 452 /**
Janos Follath 0:fc70c47eecb4 453 * The main loop of the HTTPS Hello World test
Janos Follath 0:fc70c47eecb4 454 */
Janos Follath 0:fc70c47eecb4 455 int main() {
Janos Follath 0:fc70c47eecb4 456 /* The default 9600 bps is too slow to print full TLS debug info and could
Janos Follath 0:fc70c47eecb4 457 * cause the other party to time out. */
Janos Follath 0:fc70c47eecb4 458
Janos Follath 0:fc70c47eecb4 459 /* Inititalise with DHCP, connect, and start up the stack */
Janos Follath 0:fc70c47eecb4 460 EthernetInterface eth_iface;
Janos Follath 0:fc70c47eecb4 461 eth_iface.connect();
Janos Follath 0:fc70c47eecb4 462 mbedtls_printf("Using Ethernet LWIP\r\n");
Janos Follath 0:fc70c47eecb4 463 const char *ip_addr = eth_iface.get_ip_address();
Janos Follath 0:fc70c47eecb4 464 if (ip_addr) {
Janos Follath 0:fc70c47eecb4 465 mbedtls_printf("Client IP Address is %s\r\n", ip_addr);
Janos Follath 0:fc70c47eecb4 466 } else {
Janos Follath 0:fc70c47eecb4 467 mbedtls_printf("No Client IP Address\r\n");
Janos Follath 0:fc70c47eecb4 468 }
Janos Follath 0:fc70c47eecb4 469
Janos Follath 0:fc70c47eecb4 470 HelloHTTPS hello(HTTPS_SERVER_NAME, HTTPS_SERVER_PORT, &eth_iface);
Janos Follath 0:fc70c47eecb4 471 hello.startTest(HTTPS_PATH);
Janos Follath 0:fc70c47eecb4 472 }