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:
Fri Oct 21 16:00:20 2016 +0100
Revision:
12:1ae41c231014
Parent:
9:1ac74f2d7bda
Child:
33:34783d5deafd
Updating mbed-os to mbed-os-5.2.0-rc4


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)
mbed_official 12:1ae41c231014 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 #include "mbed.h"
Janos Follath 0:fc70c47eecb4 36 #include "NetworkStack.h"
Janos Follath 0:fc70c47eecb4 37
Janos Follath 0:fc70c47eecb4 38 #include "EthernetInterface.h"
Janos Follath 0:fc70c47eecb4 39 #include "TCPSocket.h"
Janos Follath 0:fc70c47eecb4 40
Janos Follath 0:fc70c47eecb4 41 #include "mbedtls/platform.h"
Janos Follath 0:fc70c47eecb4 42 #include "mbedtls/ssl.h"
Janos Follath 0:fc70c47eecb4 43 #include "mbedtls/entropy.h"
Janos Follath 0:fc70c47eecb4 44 #include "mbedtls/ctr_drbg.h"
Janos Follath 0:fc70c47eecb4 45 #include "mbedtls/error.h"
mbed_official 12:1ae41c231014 46
Janos Follath 0:fc70c47eecb4 47 #if DEBUG_LEVEL > 0
Janos Follath 0:fc70c47eecb4 48 #include "mbedtls/debug.h"
Janos Follath 0:fc70c47eecb4 49 #endif
Janos Follath 0:fc70c47eecb4 50
Janos Follath 0:fc70c47eecb4 51 namespace {
Janos Follath 0:fc70c47eecb4 52
Janos Follath 0:fc70c47eecb4 53 const char *HTTPS_SERVER_NAME = "developer.mbed.org";
Janos Follath 0:fc70c47eecb4 54 const int HTTPS_SERVER_PORT = 443;
Janos Follath 0:fc70c47eecb4 55 const int RECV_BUFFER_SIZE = 600;
Janos Follath 0:fc70c47eecb4 56
Janos Follath 0:fc70c47eecb4 57 const char HTTPS_PATH[] = "/media/uploads/mbed_official/hello.txt";
Janos Follath 0:fc70c47eecb4 58 const size_t HTTPS_PATH_LEN = sizeof(HTTPS_PATH) - 1;
Janos Follath 0:fc70c47eecb4 59
Janos Follath 0:fc70c47eecb4 60 /* Test related data */
Janos Follath 0:fc70c47eecb4 61 const char *HTTPS_OK_STR = "200 OK";
Janos Follath 0:fc70c47eecb4 62 const char *HTTPS_HELLO_STR = "Hello world!";
Janos Follath 0:fc70c47eecb4 63
Janos Follath 0:fc70c47eecb4 64 /* personalization string for the drbg */
Janos Follath 0:fc70c47eecb4 65 const char *DRBG_PERS = "mbed TLS helloword client";
Janos Follath 0:fc70c47eecb4 66
Janos Follath 0:fc70c47eecb4 67 /* List of trusted root CA certificates
Janos Follath 0:fc70c47eecb4 68 * currently only GlobalSign, the CA for developer.mbed.org
Janos Follath 0:fc70c47eecb4 69 *
Janos Follath 0:fc70c47eecb4 70 * To add more than one root, just concatenate them.
Janos Follath 0:fc70c47eecb4 71 */
mbed_official 12:1ae41c231014 72 const char SSL_CA_PEM[] = "-----BEGIN CERTIFICATE-----\n"
mbed_official 12:1ae41c231014 73 "MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG\n"
mbed_official 12:1ae41c231014 74 "A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv\n"
mbed_official 12:1ae41c231014 75 "b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw\n"
mbed_official 12:1ae41c231014 76 "MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i\n"
mbed_official 12:1ae41c231014 77 "YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT\n"
mbed_official 12:1ae41c231014 78 "aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ\n"
mbed_official 12:1ae41c231014 79 "jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp\n"
mbed_official 12:1ae41c231014 80 "xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp\n"
mbed_official 12:1ae41c231014 81 "1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG\n"
mbed_official 12:1ae41c231014 82 "snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ\n"
mbed_official 12:1ae41c231014 83 "U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8\n"
mbed_official 12:1ae41c231014 84 "9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E\n"
mbed_official 12:1ae41c231014 85 "BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B\n"
mbed_official 12:1ae41c231014 86 "AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz\n"
mbed_official 12:1ae41c231014 87 "yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE\n"
mbed_official 12:1ae41c231014 88 "38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP\n"
mbed_official 12:1ae41c231014 89 "AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad\n"
mbed_official 12:1ae41c231014 90 "DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME\n"
mbed_official 12:1ae41c231014 91 "HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==\n"
mbed_official 12:1ae41c231014 92 "-----END CERTIFICATE-----\n";
Janos Follath 0:fc70c47eecb4 93
Janos Follath 0:fc70c47eecb4 94 }
Janos Follath 0:fc70c47eecb4 95
Janos Follath 0:fc70c47eecb4 96 /**
Janos Follath 0:fc70c47eecb4 97 * \brief HelloHTTPS implements the logic for fetching a file from a webserver
Janos Follath 0:fc70c47eecb4 98 * using a TCP socket and parsing the result.
Janos Follath 0:fc70c47eecb4 99 */
Janos Follath 0:fc70c47eecb4 100 class HelloHTTPS {
Janos Follath 0:fc70c47eecb4 101 public:
Janos Follath 0:fc70c47eecb4 102 /**
Janos Follath 0:fc70c47eecb4 103 * HelloHTTPS Constructor
Janos Follath 0:fc70c47eecb4 104 * Initializes the TCP socket, sets up event handlers and flags.
Janos Follath 0:fc70c47eecb4 105 *
Janos Follath 0:fc70c47eecb4 106 * @param[in] domain The domain name to fetch from
Janos Follath 0:fc70c47eecb4 107 * @param[in] port The port of the HTTPS server
Janos Follath 0:fc70c47eecb4 108 */
Janos Follath 0:fc70c47eecb4 109 HelloHTTPS(const char * domain, const uint16_t port, NetworkInterface *net_iface) :
Janos Follath 0:fc70c47eecb4 110 _domain(domain), _port(port)
Janos Follath 0:fc70c47eecb4 111 {
Janos Follath 0:fc70c47eecb4 112
Janos Follath 0:fc70c47eecb4 113 _error = false;
Janos Follath 0:fc70c47eecb4 114 _gothello = false;
Janos Follath 0:fc70c47eecb4 115 _got200 = false;
Janos Follath 0:fc70c47eecb4 116 _bpos = 0;
Janos Follath 0:fc70c47eecb4 117 _request_sent = 0;
Janos Follath 0:fc70c47eecb4 118 _tcpsocket = new TCPSocket(net_iface);
Janos Follath 0:fc70c47eecb4 119
Janos Follath 0:fc70c47eecb4 120 mbedtls_entropy_init(&_entropy);
Janos Follath 0:fc70c47eecb4 121 mbedtls_ctr_drbg_init(&_ctr_drbg);
Janos Follath 0:fc70c47eecb4 122 mbedtls_x509_crt_init(&_cacert);
Janos Follath 0:fc70c47eecb4 123 mbedtls_ssl_init(&_ssl);
Janos Follath 0:fc70c47eecb4 124 mbedtls_ssl_config_init(&_ssl_conf);
Janos Follath 0:fc70c47eecb4 125 }
Janos Follath 0:fc70c47eecb4 126 /**
Janos Follath 0:fc70c47eecb4 127 * HelloHTTPS Desctructor
Janos Follath 0:fc70c47eecb4 128 */
Janos Follath 0:fc70c47eecb4 129 ~HelloHTTPS() {
Janos Follath 0:fc70c47eecb4 130 mbedtls_entropy_free(&_entropy);
Janos Follath 0:fc70c47eecb4 131 mbedtls_ctr_drbg_free(&_ctr_drbg);
Janos Follath 0:fc70c47eecb4 132 mbedtls_x509_crt_free(&_cacert);
Janos Follath 0:fc70c47eecb4 133 mbedtls_ssl_free(&_ssl);
Janos Follath 0:fc70c47eecb4 134 mbedtls_ssl_config_free(&_ssl_conf);
Janos Follath 0:fc70c47eecb4 135 }
Janos Follath 0:fc70c47eecb4 136 /**
Janos Follath 0:fc70c47eecb4 137 * Start the test.
Janos Follath 0:fc70c47eecb4 138 *
Janos Follath 0:fc70c47eecb4 139 * Starts by clearing test flags, then resolves the address with DNS.
Janos Follath 0:fc70c47eecb4 140 *
Janos Follath 0:fc70c47eecb4 141 * @param[in] path The path of the file to fetch from the HTTPS server
Janos Follath 0:fc70c47eecb4 142 * @return SOCKET_ERROR_NONE on success, or an error code on failure
Janos Follath 0:fc70c47eecb4 143 */
Janos Follath 0:fc70c47eecb4 144 void startTest(const char *path) {
Janos Follath 0:fc70c47eecb4 145 /* Initialize the flags */
Janos Follath 0:fc70c47eecb4 146 _got200 = false;
Janos Follath 0:fc70c47eecb4 147 _gothello = false;
Janos Follath 0:fc70c47eecb4 148 _error = false;
Janos Follath 0:fc70c47eecb4 149 _disconnected = false;
Janos Follath 0:fc70c47eecb4 150 _request_sent = false;
Janos Follath 0:fc70c47eecb4 151 /* Fill the request buffer */
Janos Follath 0:fc70c47eecb4 152 _bpos = snprintf(_buffer, sizeof(_buffer) - 1, "GET %s HTTP/1.1\nHost: %s\n\n", path, HTTPS_SERVER_NAME);
Janos Follath 0:fc70c47eecb4 153
Janos Follath 0:fc70c47eecb4 154 /*
Janos Follath 0:fc70c47eecb4 155 * Initialize TLS-related stuf.
Janos Follath 0:fc70c47eecb4 156 */
Janos Follath 0:fc70c47eecb4 157 int ret;
Janos Follath 0:fc70c47eecb4 158 if ((ret = mbedtls_ctr_drbg_seed(&_ctr_drbg, mbedtls_entropy_func, &_entropy,
Janos Follath 0:fc70c47eecb4 159 (const unsigned char *) DRBG_PERS,
Janos Follath 0:fc70c47eecb4 160 sizeof (DRBG_PERS))) != 0) {
Janos Follath 0:fc70c47eecb4 161 print_mbedtls_error("mbedtls_crt_drbg_init", ret);
Janos Follath 0:fc70c47eecb4 162 _error = true;
Janos Follath 0:fc70c47eecb4 163 return;
Janos Follath 0:fc70c47eecb4 164 }
Janos Follath 0:fc70c47eecb4 165
Janos Follath 0:fc70c47eecb4 166 if ((ret = mbedtls_x509_crt_parse(&_cacert, (const unsigned char *) SSL_CA_PEM,
Janos Follath 0:fc70c47eecb4 167 sizeof (SSL_CA_PEM))) != 0) {
Janos Follath 0:fc70c47eecb4 168 print_mbedtls_error("mbedtls_x509_crt_parse", ret);
Janos Follath 0:fc70c47eecb4 169 _error = true;
Janos Follath 0:fc70c47eecb4 170 return;
Janos Follath 0:fc70c47eecb4 171 }
Janos Follath 0:fc70c47eecb4 172
Janos Follath 0:fc70c47eecb4 173 if ((ret = mbedtls_ssl_config_defaults(&_ssl_conf,
Janos Follath 0:fc70c47eecb4 174 MBEDTLS_SSL_IS_CLIENT,
Janos Follath 0:fc70c47eecb4 175 MBEDTLS_SSL_TRANSPORT_STREAM,
Janos Follath 0:fc70c47eecb4 176 MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
Janos Follath 0:fc70c47eecb4 177 print_mbedtls_error("mbedtls_ssl_config_defaults", ret);
Janos Follath 0:fc70c47eecb4 178 _error = true;
Janos Follath 0:fc70c47eecb4 179 return;
Janos Follath 0:fc70c47eecb4 180 }
Janos Follath 0:fc70c47eecb4 181
Janos Follath 0:fc70c47eecb4 182 mbedtls_ssl_conf_ca_chain(&_ssl_conf, &_cacert, NULL);
Janos Follath 0:fc70c47eecb4 183 mbedtls_ssl_conf_rng(&_ssl_conf, mbedtls_ctr_drbg_random, &_ctr_drbg);
Janos Follath 0:fc70c47eecb4 184
mbed_official 12:1ae41c231014 185 /* It is possible to disable authentication by passing
mbed_official 12:1ae41c231014 186 * MBEDTLS_SSL_VERIFY_NONE in the call to mbedtls_ssl_conf_authmode()
mbed_official 12:1ae41c231014 187 */
mbed_official 12:1ae41c231014 188 mbedtls_ssl_conf_authmode(&_ssl_conf, MBEDTLS_SSL_VERIFY_REQUIRED);
Janos Follath 0:fc70c47eecb4 189
Janos Follath 0:fc70c47eecb4 190 #if DEBUG_LEVEL > 0
Janos Follath 0:fc70c47eecb4 191 mbedtls_ssl_conf_verify(&_ssl_conf, my_verify, NULL);
Janos Follath 0:fc70c47eecb4 192 mbedtls_ssl_conf_dbg(&_ssl_conf, my_debug, NULL);
Janos Follath 0:fc70c47eecb4 193 mbedtls_debug_set_threshold(DEBUG_LEVEL);
Janos Follath 0:fc70c47eecb4 194 #endif
Janos Follath 0:fc70c47eecb4 195
Janos Follath 0:fc70c47eecb4 196 if ((ret = mbedtls_ssl_setup(&_ssl, &_ssl_conf)) != 0) {
Janos Follath 0:fc70c47eecb4 197 print_mbedtls_error("mbedtls_ssl_setup", ret);
Janos Follath 0:fc70c47eecb4 198 _error = true;
Janos Follath 0:fc70c47eecb4 199 return;
Janos Follath 0:fc70c47eecb4 200 }
Janos Follath 0:fc70c47eecb4 201
Janos Follath 0:fc70c47eecb4 202 mbedtls_ssl_set_hostname(&_ssl, HTTPS_SERVER_NAME);
Janos Follath 0:fc70c47eecb4 203
Janos Follath 0:fc70c47eecb4 204 mbedtls_ssl_set_bio(&_ssl, static_cast<void *>(_tcpsocket),
Janos Follath 0:fc70c47eecb4 205 ssl_send, ssl_recv, NULL );
Janos Follath 0:fc70c47eecb4 206
Janos Follath 0:fc70c47eecb4 207
Janos Follath 0:fc70c47eecb4 208 /* Connect to the server */
Janos Follath 0:fc70c47eecb4 209 mbedtls_printf("Connecting with %s\r\n", _domain);
mbed_official 12:1ae41c231014 210 ret = _tcpsocket->connect(_domain, _port);
mbed_official 12:1ae41c231014 211 if (ret != NSAPI_ERROR_OK) {
mbed_official 12:1ae41c231014 212 mbedtls_printf("Failed to connect\r\n");
mbed_official 12:1ae41c231014 213 onError(_tcpsocket, -1);
mbed_official 12:1ae41c231014 214 return;
mbed_official 12:1ae41c231014 215 }
Janos Follath 0:fc70c47eecb4 216
Janos Follath 0:fc70c47eecb4 217 /* Start the handshake, the rest will be done in onReceive() */
Janos Follath 0:fc70c47eecb4 218 mbedtls_printf("Starting the TLS handshake...\r\n");
Janos Follath 0:fc70c47eecb4 219 ret = mbedtls_ssl_handshake(&_ssl);
Janos Follath 0:fc70c47eecb4 220 if (ret < 0) {
Janos Follath 0:fc70c47eecb4 221 if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
Janos Follath 0:fc70c47eecb4 222 ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
Janos Follath 0:fc70c47eecb4 223 print_mbedtls_error("mbedtls_ssl_handshake", ret);
Janos Follath 0:fc70c47eecb4 224 onError(_tcpsocket, -1 );
Janos Follath 0:fc70c47eecb4 225 }
Janos Follath 0:fc70c47eecb4 226 return;
Janos Follath 0:fc70c47eecb4 227 }
Janos Follath 0:fc70c47eecb4 228
Janos Follath 0:fc70c47eecb4 229 ret = mbedtls_ssl_write(&_ssl, (const unsigned char *) _buffer, _bpos);
Janos Follath 0:fc70c47eecb4 230 if (ret < 0) {
Janos Follath 0:fc70c47eecb4 231 if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
Janos Follath 0:fc70c47eecb4 232 ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
Janos Follath 0:fc70c47eecb4 233 print_mbedtls_error("mbedtls_ssl_write", ret);
Janos Follath 0:fc70c47eecb4 234 onError(_tcpsocket, -1 );
Janos Follath 0:fc70c47eecb4 235 }
Janos Follath 0:fc70c47eecb4 236 return;
Janos Follath 0:fc70c47eecb4 237 }
Janos Follath 0:fc70c47eecb4 238
Janos Follath 0:fc70c47eecb4 239 /* It also means the handshake is done, time to print info */
Janos Follath 0:fc70c47eecb4 240 printf("TLS connection to %s established\r\n", HTTPS_SERVER_NAME);
Janos Follath 0:fc70c47eecb4 241
mbed_official 9:1ac74f2d7bda 242 const uint32_t buf_size = 1024;
mbed_official 9:1ac74f2d7bda 243 char *buf = new char[buf_size];
mbed_official 9:1ac74f2d7bda 244 mbedtls_x509_crt_info(buf, buf_size, "\r ",
Janos Follath 0:fc70c47eecb4 245 mbedtls_ssl_get_peer_cert(&_ssl));
Janos Follath 0:fc70c47eecb4 246 mbedtls_printf("Server certificate:\r\n%s\r", buf);
Janos Follath 0:fc70c47eecb4 247
Janos Follath 0:fc70c47eecb4 248 uint32_t flags = mbedtls_ssl_get_verify_result(&_ssl);
Janos Follath 0:fc70c47eecb4 249 if( flags != 0 )
Janos Follath 0:fc70c47eecb4 250 {
mbed_official 9:1ac74f2d7bda 251 mbedtls_x509_crt_verify_info(buf, buf_size, "\r ! ", flags);
Janos Follath 0:fc70c47eecb4 252 printf("Certificate verification failed:\r\n%s\r\r\n", buf);
Janos Follath 0:fc70c47eecb4 253 }
Janos Follath 0:fc70c47eecb4 254 else
Janos Follath 0:fc70c47eecb4 255 printf("Certificate verification passed\r\n\r\n");
Janos Follath 0:fc70c47eecb4 256
Janos Follath 0:fc70c47eecb4 257
Janos Follath 0:fc70c47eecb4 258 /* Read data out of the socket */
Janos Follath 0:fc70c47eecb4 259 ret = mbedtls_ssl_read(&_ssl, (unsigned char *) _buffer, sizeof(_buffer));
Janos Follath 0:fc70c47eecb4 260 if (ret < 0) {
Janos Follath 0:fc70c47eecb4 261 if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
Janos Follath 0:fc70c47eecb4 262 print_mbedtls_error("mbedtls_ssl_read", ret);
Janos Follath 0:fc70c47eecb4 263 onError(_tcpsocket, -1 );
Janos Follath 0:fc70c47eecb4 264 }
mbed_official 9:1ac74f2d7bda 265 delete[] buf;
Janos Follath 0:fc70c47eecb4 266 return;
Janos Follath 0:fc70c47eecb4 267 }
Janos Follath 0:fc70c47eecb4 268 _bpos = static_cast<size_t>(ret);
Janos Follath 0:fc70c47eecb4 269
Janos Follath 0:fc70c47eecb4 270 _buffer[_bpos] = 0;
Janos Follath 0:fc70c47eecb4 271
Janos Follath 0:fc70c47eecb4 272 /* Check each of the flags */
Janos Follath 0:fc70c47eecb4 273 _got200 = _got200 || strstr(_buffer, HTTPS_OK_STR) != NULL;
Janos Follath 0:fc70c47eecb4 274 _gothello = _gothello || strstr(_buffer, HTTPS_HELLO_STR) != NULL;
Janos Follath 0:fc70c47eecb4 275
Janos Follath 0:fc70c47eecb4 276 /* Print status messages */
Janos Follath 0:fc70c47eecb4 277 mbedtls_printf("HTTPS: Received %d chars from server\r\n", _bpos);
Janos Follath 0:fc70c47eecb4 278 mbedtls_printf("HTTPS: Received 200 OK status ... %s\r\n", _got200 ? "[OK]" : "[FAIL]");
Janos Follath 0:fc70c47eecb4 279 mbedtls_printf("HTTPS: Received '%s' status ... %s\r\n", HTTPS_HELLO_STR, _gothello ? "[OK]" : "[FAIL]");
Janos Follath 0:fc70c47eecb4 280 mbedtls_printf("HTTPS: Received message:\r\n\r\n");
Janos Follath 0:fc70c47eecb4 281 mbedtls_printf("%s", _buffer);
Janos Follath 0:fc70c47eecb4 282 _error = !(_got200 && _gothello);
Janos Follath 0:fc70c47eecb4 283
Janos Follath 0:fc70c47eecb4 284 _tcpsocket->close();
mbed_official 9:1ac74f2d7bda 285 delete[] buf;
Janos Follath 0:fc70c47eecb4 286 }
Janos Follath 0:fc70c47eecb4 287 /**
Janos Follath 0:fc70c47eecb4 288 * Check if the test has completed.
Janos Follath 0:fc70c47eecb4 289 * @return Returns true if done, false otherwise.
Janos Follath 0:fc70c47eecb4 290 */
Janos Follath 0:fc70c47eecb4 291 bool done() {
Janos Follath 0:fc70c47eecb4 292 return _error || (_got200 && _gothello);
Janos Follath 0:fc70c47eecb4 293 }
Janos Follath 0:fc70c47eecb4 294 /**
Janos Follath 0:fc70c47eecb4 295 * Check if there was an error
Janos Follath 0:fc70c47eecb4 296 * @return Returns true if there was an error, false otherwise.
Janos Follath 0:fc70c47eecb4 297 */
Janos Follath 0:fc70c47eecb4 298 bool error() {
Janos Follath 0:fc70c47eecb4 299 return _error;
Janos Follath 0:fc70c47eecb4 300 }
Janos Follath 0:fc70c47eecb4 301 /**
Janos Follath 0:fc70c47eecb4 302 * Closes the TCP socket
Janos Follath 0:fc70c47eecb4 303 */
Janos Follath 0:fc70c47eecb4 304 void close() {
Janos Follath 0:fc70c47eecb4 305 _tcpsocket->close();
Janos Follath 0:fc70c47eecb4 306 while (!_disconnected)
Janos Follath 0:fc70c47eecb4 307 __WFI();
Janos Follath 0:fc70c47eecb4 308 }
Janos Follath 0:fc70c47eecb4 309 protected:
Janos Follath 0:fc70c47eecb4 310 /**
Janos Follath 0:fc70c47eecb4 311 * Helper for pretty-printing mbed TLS error codes
Janos Follath 0:fc70c47eecb4 312 */
Janos Follath 0:fc70c47eecb4 313 static void print_mbedtls_error(const char *name, int err) {
Janos Follath 0:fc70c47eecb4 314 char buf[128];
Janos Follath 0:fc70c47eecb4 315 mbedtls_strerror(err, buf, sizeof (buf));
Janos Follath 0:fc70c47eecb4 316 mbedtls_printf("%s() failed: -0x%04x (%d): %s\r\n", name, -err, err, buf);
Janos Follath 0:fc70c47eecb4 317 }
Janos Follath 0:fc70c47eecb4 318
Janos Follath 0:fc70c47eecb4 319 #if DEBUG_LEVEL > 0
Janos Follath 0:fc70c47eecb4 320 /**
Janos Follath 0:fc70c47eecb4 321 * Debug callback for mbed TLS
Janos Follath 0:fc70c47eecb4 322 * Just prints on the USB serial port
Janos Follath 0:fc70c47eecb4 323 */
Janos Follath 0:fc70c47eecb4 324 static void my_debug(void *ctx, int level, const char *file, int line,
Janos Follath 0:fc70c47eecb4 325 const char *str)
Janos Follath 0:fc70c47eecb4 326 {
Janos Follath 0:fc70c47eecb4 327 const char *p, *basename;
Janos Follath 0:fc70c47eecb4 328 (void) ctx;
Janos Follath 0:fc70c47eecb4 329
Janos Follath 0:fc70c47eecb4 330 /* Extract basename from file */
Janos Follath 0:fc70c47eecb4 331 for(p = basename = file; *p != '\0'; p++) {
Janos Follath 0:fc70c47eecb4 332 if(*p == '/' || *p == '\\') {
Janos Follath 0:fc70c47eecb4 333 basename = p + 1;
Janos Follath 0:fc70c47eecb4 334 }
Janos Follath 0:fc70c47eecb4 335 }
Janos Follath 0:fc70c47eecb4 336
Janos Follath 0:fc70c47eecb4 337 mbedtls_printf("%s:%04d: |%d| %s", basename, line, level, str);
Janos Follath 0:fc70c47eecb4 338 }
Janos Follath 0:fc70c47eecb4 339
Janos Follath 0:fc70c47eecb4 340 /**
Janos Follath 0:fc70c47eecb4 341 * Certificate verification callback for mbed TLS
Janos Follath 0:fc70c47eecb4 342 * Here we only use it to display information on each cert in the chain
Janos Follath 0:fc70c47eecb4 343 */
Janos Follath 0:fc70c47eecb4 344 static int my_verify(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags)
Janos Follath 0:fc70c47eecb4 345 {
mbed_official 9:1ac74f2d7bda 346 const uint32_t buf_size = 1024;
mbed_official 9:1ac74f2d7bda 347 char *buf = new char[buf_size];
Janos Follath 0:fc70c47eecb4 348 (void) data;
Janos Follath 0:fc70c47eecb4 349
Janos Follath 0:fc70c47eecb4 350 mbedtls_printf("\nVerifying certificate at depth %d:\n", depth);
mbed_official 9:1ac74f2d7bda 351 mbedtls_x509_crt_info(buf, buf_size - 1, " ", crt);
Janos Follath 0:fc70c47eecb4 352 mbedtls_printf("%s", buf);
Janos Follath 0:fc70c47eecb4 353
Janos Follath 0:fc70c47eecb4 354 if (*flags == 0)
Janos Follath 0:fc70c47eecb4 355 mbedtls_printf("No verification issue for this certificate\n");
Janos Follath 0:fc70c47eecb4 356 else
Janos Follath 0:fc70c47eecb4 357 {
mbed_official 9:1ac74f2d7bda 358 mbedtls_x509_crt_verify_info(buf, buf_size, " ! ", *flags);
Janos Follath 0:fc70c47eecb4 359 mbedtls_printf("%s\n", buf);
Janos Follath 0:fc70c47eecb4 360 }
Janos Follath 0:fc70c47eecb4 361
mbed_official 9:1ac74f2d7bda 362 delete[] buf;
Janos Follath 0:fc70c47eecb4 363 return 0;
Janos Follath 0:fc70c47eecb4 364 }
Janos Follath 0:fc70c47eecb4 365 #endif
Janos Follath 0:fc70c47eecb4 366
Janos Follath 0:fc70c47eecb4 367 /**
Janos Follath 0:fc70c47eecb4 368 * Receive callback for mbed TLS
Janos Follath 0:fc70c47eecb4 369 */
Janos Follath 0:fc70c47eecb4 370 static int ssl_recv(void *ctx, unsigned char *buf, size_t len) {
Janos Follath 0:fc70c47eecb4 371 int recv = -1;
Janos Follath 0:fc70c47eecb4 372 TCPSocket *socket = static_cast<TCPSocket *>(ctx);
Janos Follath 0:fc70c47eecb4 373 recv = socket->recv(buf, len);
Janos Follath 0:fc70c47eecb4 374
Janos Follath 0:fc70c47eecb4 375 if(NSAPI_ERROR_WOULD_BLOCK == recv){
Janos Follath 0:fc70c47eecb4 376 return MBEDTLS_ERR_SSL_WANT_READ;
Janos Follath 0:fc70c47eecb4 377 }else if(recv < 0){
Janos Follath 0:fc70c47eecb4 378 return -1;
Janos Follath 0:fc70c47eecb4 379 }else{
Janos Follath 0:fc70c47eecb4 380 return recv;
Janos Follath 0:fc70c47eecb4 381 }
Janos Follath 0:fc70c47eecb4 382 }
Janos Follath 0:fc70c47eecb4 383
Janos Follath 0:fc70c47eecb4 384 /**
Janos Follath 0:fc70c47eecb4 385 * Send callback for mbed TLS
Janos Follath 0:fc70c47eecb4 386 */
Janos Follath 0:fc70c47eecb4 387 static int ssl_send(void *ctx, const unsigned char *buf, size_t len) {
Janos Follath 0:fc70c47eecb4 388 int size = -1;
Janos Follath 0:fc70c47eecb4 389 TCPSocket *socket = static_cast<TCPSocket *>(ctx);
Janos Follath 0:fc70c47eecb4 390 size = socket->send(buf, len);
Janos Follath 0:fc70c47eecb4 391
Janos Follath 0:fc70c47eecb4 392 if(NSAPI_ERROR_WOULD_BLOCK == size){
Janos Follath 0:fc70c47eecb4 393 return len;
Janos Follath 0:fc70c47eecb4 394 }else if(size < 0){
Janos Follath 0:fc70c47eecb4 395 return -1;
Janos Follath 0:fc70c47eecb4 396 }else{
Janos Follath 0:fc70c47eecb4 397 return size;
Janos Follath 0:fc70c47eecb4 398 }
Janos Follath 0:fc70c47eecb4 399 }
Janos Follath 0:fc70c47eecb4 400
Janos Follath 0:fc70c47eecb4 401 void onError(TCPSocket *s, int error) {
Janos Follath 0:fc70c47eecb4 402 printf("MBED: Socket Error: %d\r\n", error);
Janos Follath 0:fc70c47eecb4 403 s->close();
Janos Follath 0:fc70c47eecb4 404 _error = true;
Janos Follath 0:fc70c47eecb4 405 }
Janos Follath 0:fc70c47eecb4 406
Janos Follath 0:fc70c47eecb4 407 protected:
Janos Follath 0:fc70c47eecb4 408 TCPSocket* _tcpsocket;
Janos Follath 0:fc70c47eecb4 409
Janos Follath 0:fc70c47eecb4 410 const char *_domain; /**< The domain name of the HTTPS server */
Janos Follath 0:fc70c47eecb4 411 const uint16_t _port; /**< The HTTPS server port */
Janos Follath 0:fc70c47eecb4 412 char _buffer[RECV_BUFFER_SIZE]; /**< The response buffer */
Janos Follath 0:fc70c47eecb4 413 size_t _bpos; /**< The current offset in the response buffer */
Janos Follath 0:fc70c47eecb4 414 volatile bool _got200; /**< Status flag for HTTPS 200 */
Janos Follath 0:fc70c47eecb4 415 volatile bool _gothello; /**< Status flag for finding the test string */
Janos Follath 0:fc70c47eecb4 416 volatile bool _error; /**< Status flag for an error */
Janos Follath 0:fc70c47eecb4 417 volatile bool _disconnected;
Janos Follath 0:fc70c47eecb4 418 volatile bool _request_sent;
Janos Follath 0:fc70c47eecb4 419
Janos Follath 0:fc70c47eecb4 420 mbedtls_entropy_context _entropy;
Janos Follath 0:fc70c47eecb4 421 mbedtls_ctr_drbg_context _ctr_drbg;
Janos Follath 0:fc70c47eecb4 422 mbedtls_x509_crt _cacert;
Janos Follath 0:fc70c47eecb4 423 mbedtls_ssl_context _ssl;
Janos Follath 0:fc70c47eecb4 424 mbedtls_ssl_config _ssl_conf;
Janos Follath 0:fc70c47eecb4 425 };
Janos Follath 0:fc70c47eecb4 426
Janos Follath 0:fc70c47eecb4 427 /**
Janos Follath 0:fc70c47eecb4 428 * The main loop of the HTTPS Hello World test
Janos Follath 0:fc70c47eecb4 429 */
Janos Follath 0:fc70c47eecb4 430 int main() {
Janos Follath 0:fc70c47eecb4 431 /* The default 9600 bps is too slow to print full TLS debug info and could
Janos Follath 0:fc70c47eecb4 432 * cause the other party to time out. */
Janos Follath 0:fc70c47eecb4 433
Janos Follath 0:fc70c47eecb4 434 /* Inititalise with DHCP, connect, and start up the stack */
Janos Follath 0:fc70c47eecb4 435 EthernetInterface eth_iface;
Janos Follath 0:fc70c47eecb4 436 eth_iface.connect();
Janos Follath 0:fc70c47eecb4 437 mbedtls_printf("Using Ethernet LWIP\r\n");
Janos Follath 0:fc70c47eecb4 438 const char *ip_addr = eth_iface.get_ip_address();
Janos Follath 0:fc70c47eecb4 439 if (ip_addr) {
Janos Follath 0:fc70c47eecb4 440 mbedtls_printf("Client IP Address is %s\r\n", ip_addr);
Janos Follath 0:fc70c47eecb4 441 } else {
Janos Follath 0:fc70c47eecb4 442 mbedtls_printf("No Client IP Address\r\n");
Janos Follath 0:fc70c47eecb4 443 }
Janos Follath 0:fc70c47eecb4 444
mbed_official 9:1ac74f2d7bda 445 HelloHTTPS *hello = new HelloHTTPS(HTTPS_SERVER_NAME, HTTPS_SERVER_PORT, &eth_iface);
mbed_official 9:1ac74f2d7bda 446 hello->startTest(HTTPS_PATH);
mbed_official 9:1ac74f2d7bda 447 delete hello;
Janos Follath 0:fc70c47eecb4 448 }