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:
Wed Sep 20 12:17:15 2017 +0100
Revision:
42:5236ebc3d12a
Parent:
33:34783d5deafd
Child:
47:c84bc63913c6
Merge pull request #117 from andresag01/change-mbed-server-address

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