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:
Thu Nov 09 09:15:40 2017 +0000
Revision:
50:b6870173bcac
Parent:
47:c84bc63913c6
Child:
66:ce8709d9912c
Change Arm trademarks in the examples' source files

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