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!
main.cpp@59:209e439ae9dd, 2018-01-31 (annotated)
- Committer:
- mbed_official
- Date:
- Wed Jan 31 14:30:14 2018 +0000
- Revision:
- 59:209e439ae9dd
- Parent:
- 50:b6870173bcac
- Child:
- 66:ce8709d9912c
Merge pull request #144 from cmonr/master
All test cases pass it at least one CI run. Updating mbed-os to mbed-os-5.7.4
.
Commit copied from https://github.com/ARMmbed/mbed-os-example-tls
Who changed what in which revision?
User | Revision | Line number | New 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 | } |