Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: WNCInterface mbed-rtos mbed
main.cpp
00001 /* 00002 * Hello world example of a TLS client: fetch an HTTPS page 00003 * 00004 * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved 00005 * SPDX-License-Identifier: Apache-2.0 00006 * 00007 * Licensed under the Apache License, Version 2.0 (the "License"); you may 00008 * not use this file except in compliance with the License. 00009 * You may obtain a copy of the License at 00010 * 00011 * http://www.apache.org/licenses/LICENSE-2.0 00012 * 00013 * Unless required by applicable law or agreed to in writing, software 00014 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 00015 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00016 * See the License for the specific language governing permissions and 00017 * limitations under the License. 00018 * 00019 * This file is part of mbed TLS (https://tls.mbed.org) 00020 */ 00021 00022 /** \file main.cpp 00023 * \brief An example TLS Client application 00024 * This application sends an HTTPS request to developer.mbed.org and searches for a string in 00025 * the result. 00026 * 00027 * This example is implemented as a logic class (HelloHTTPS) wrapping a TCP socket. 00028 * The logic class handles all events, leaving the main loop to just check if the process 00029 * has finished. 00030 */ 00031 00032 /* Change to a number between 1 and 4 to debug the TLS connection */ 00033 #define DEBUG_LEVEL 0 00034 00035 #include "mbed.h" 00036 //#include "NetworkStack.h" 00037 00038 #include "WNCInterface.h" 00039 #include "TCPSocketConnection.h" 00040 00041 #include "mbedtls/platform.h" 00042 #include "mbedtls/ssl.h" 00043 #include "mbedtls/entropy.h" 00044 #include "mbedtls/ctr_drbg.h" 00045 #include "mbedtls/error.h" 00046 00047 #define CRLF "\r\n" 00048 00049 #if DEBUG_LEVEL > 0 00050 #include "mbedtls/debug.h" 00051 #endif 00052 00053 namespace { 00054 00055 const char *HTTPS_SERVER_NAME = "developer.mbed.org"; 00056 const int HTTPS_SERVER_PORT = 443; 00057 const int RECV_BUFFER_SIZE = 600; 00058 00059 const char HTTPS_PATH[] = "/media/uploads/mbed_official/hello.txt"; 00060 //const size_t HTTPS_PATH_LEN = sizeof(HTTPS_PATH) - 1; 00061 00062 /* Test related data */ 00063 const char *HTTPS_OK_STR = "200 OK"; 00064 const char *HTTPS_HELLO_STR = "Hello world!"; 00065 00066 /* personalization string for the drbg */ 00067 const char *DRBG_PERS = "mbed TLS helloword client"; 00068 00069 /* List of trusted root CA certificates 00070 * currently only GlobalSign, the CA for developer.mbed.org 00071 * 00072 * To add more than one root, just concatenate them. 00073 */ 00074 const char SSL_CA_PEM[] = "-----BEGIN CERTIFICATE-----\n" 00075 "MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG\n" 00076 "A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv\n" 00077 "b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw\n" 00078 "MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i\n" 00079 "YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT\n" 00080 "aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ\n" 00081 "jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp\n" 00082 "xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp\n" 00083 "1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG\n" 00084 "snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ\n" 00085 "U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8\n" 00086 "9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E\n" 00087 "BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B\n" 00088 "AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz\n" 00089 "yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE\n" 00090 "38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP\n" 00091 "AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad\n" 00092 "DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME\n" 00093 "HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==\n" 00094 "-----END CERTIFICATE-----\n"; 00095 00096 } 00097 00098 /** 00099 * \brief HelloHTTPS implements the logic for fetching a file from a webserver 00100 * using a TCP socket and parsing the result. 00101 */ 00102 class HelloHTTPS { 00103 public: 00104 /** 00105 * HelloHTTPS Constructor 00106 * Initializes the TCP socket, sets up event handlers and flags. 00107 * 00108 * @param[in] domain The domain name to fetch from 00109 * @param[in] port The port of the HTTPS server 00110 */ 00111 HelloHTTPS(const char * domain, const uint16_t port, WNCInterface *net_iface) : 00112 _domain(domain), _port(port) 00113 { 00114 00115 _error = false; 00116 _gothello = false; 00117 _got200 = false; 00118 _bpos = 0; 00119 _request_sent = 0; 00120 _tcpsocket = new TCPSocketConnection; 00121 00122 mbedtls_entropy_init(&_entropy); 00123 mbedtls_ctr_drbg_init(&_ctr_drbg); 00124 mbedtls_x509_crt_init(&_cacert); 00125 mbedtls_ssl_init(&_ssl); 00126 mbedtls_ssl_config_init(&_ssl_conf); 00127 } 00128 /** 00129 * HelloHTTPS Desctructor 00130 */ 00131 ~HelloHTTPS() { 00132 mbedtls_entropy_free(&_entropy); 00133 mbedtls_ctr_drbg_free(&_ctr_drbg); 00134 mbedtls_x509_crt_free(&_cacert); 00135 mbedtls_ssl_free(&_ssl); 00136 mbedtls_ssl_config_free(&_ssl_conf); 00137 } 00138 /** 00139 * Start the test. 00140 * 00141 * Starts by clearing test flags, then resolves the address with DNS. 00142 * 00143 * @param[in] path The path of the file to fetch from the HTTPS server 00144 * @return SOCKET_ERROR_NONE on success, or an error code on failure 00145 */ 00146 void startTest(const char *path) { 00147 /* Initialize the flags */ 00148 _got200 = false; 00149 _gothello = false; 00150 _error = false; 00151 _disconnected = false; 00152 _request_sent = false; 00153 /* Fill the request buffer */ 00154 _bpos = snprintf(_buffer, sizeof(_buffer) - 1, "GET %s HTTP/1.1\nHost: %s\n\n", path, HTTPS_SERVER_NAME); 00155 00156 /* 00157 * Initialize TLS-related stuf. 00158 */ 00159 int ret; 00160 if ((ret = mbedtls_ctr_drbg_seed(&_ctr_drbg, mbedtls_entropy_func, &_entropy, 00161 (const unsigned char *) DRBG_PERS, 00162 sizeof (DRBG_PERS))) != 0) { 00163 print_mbedtls_error("mbedtls_crt_drbg_init", ret); 00164 _error = true; 00165 return; 00166 } 00167 00168 if ((ret = mbedtls_x509_crt_parse(&_cacert, (const unsigned char *) SSL_CA_PEM, 00169 sizeof (SSL_CA_PEM))) != 0) { 00170 print_mbedtls_error("mbedtls_x509_crt_parse", ret); 00171 _error = true; 00172 return; 00173 } 00174 00175 if ((ret = mbedtls_ssl_config_defaults(&_ssl_conf, 00176 MBEDTLS_SSL_IS_CLIENT, 00177 MBEDTLS_SSL_TRANSPORT_STREAM, 00178 MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { 00179 print_mbedtls_error("mbedtls_ssl_config_defaults", ret); 00180 _error = true; 00181 return; 00182 } 00183 00184 mbedtls_ssl_conf_ca_chain(&_ssl_conf, &_cacert, NULL); 00185 mbedtls_ssl_conf_rng(&_ssl_conf, mbedtls_ctr_drbg_random, &_ctr_drbg); 00186 00187 /* It is possible to disable authentication by passing 00188 * MBEDTLS_SSL_VERIFY_NONE in the call to mbedtls_ssl_conf_authmode() 00189 */ 00190 mbedtls_ssl_conf_authmode(&_ssl_conf, MBEDTLS_SSL_VERIFY_REQUIRED); 00191 00192 #if DEBUG_LEVEL > 0 00193 mbedtls_ssl_conf_verify(&_ssl_conf, my_verify, NULL); 00194 mbedtls_ssl_conf_dbg(&_ssl_conf, my_debug, NULL); 00195 mbedtls_debug_set_threshold(DEBUG_LEVEL); 00196 #endif 00197 00198 if ((ret = mbedtls_ssl_setup(&_ssl, &_ssl_conf)) != 0) { 00199 print_mbedtls_error("mbedtls_ssl_setup", ret); 00200 _error = true; 00201 return; 00202 } 00203 00204 mbedtls_ssl_set_hostname(&_ssl, HTTPS_SERVER_NAME); 00205 00206 mbedtls_ssl_set_bio(&_ssl, static_cast<void *>(_tcpsocket), 00207 ssl_send, ssl_recv, NULL ); 00208 00209 00210 /* Connect to the server */ 00211 mbedtls_printf("Connecting with %s\r\n", _domain); 00212 ret = _tcpsocket->connect(_domain, _port); 00213 _tcpsocket->set_blocking (false,1500); 00214 00215 /* Start the handshake, the rest will be done in onReceive() */ 00216 mbedtls_printf("Starting the TLS handshake...\r\n"); 00217 ret = mbedtls_ssl_handshake(&_ssl); 00218 if (ret < 0) { 00219 if (ret != MBEDTLS_ERR_SSL_WANT_READ && 00220 ret != MBEDTLS_ERR_SSL_WANT_WRITE) { 00221 print_mbedtls_error("mbedtls_ssl_handshake", ret); 00222 onError(_tcpsocket, -1 ); 00223 } 00224 return; 00225 } 00226 00227 ret = mbedtls_ssl_write(&_ssl, (const unsigned char *) _buffer, _bpos); 00228 if (ret < 0) { 00229 if (ret != MBEDTLS_ERR_SSL_WANT_READ && 00230 ret != MBEDTLS_ERR_SSL_WANT_WRITE) { 00231 print_mbedtls_error("mbedtls_ssl_write", ret); 00232 onError(_tcpsocket, -1 ); 00233 } 00234 return; 00235 } 00236 00237 /* It also means the handshake is done, time to print info */ 00238 mbedtls_printf("TLS connection to %s established\r\n", HTTPS_SERVER_NAME); 00239 00240 const uint32_t buf_size = 1024; 00241 char *buf = new char[buf_size]; 00242 mbedtls_x509_crt_info(buf, buf_size, "\r ", 00243 mbedtls_ssl_get_peer_cert(&_ssl)); 00244 mbedtls_printf("Server certificate:\r\n%s\r", buf); 00245 00246 uint32_t flags = mbedtls_ssl_get_verify_result(&_ssl); 00247 if( flags != 0 ) 00248 { 00249 mbedtls_x509_crt_verify_info(buf, buf_size, "\r ! ", flags); 00250 mbedtls_printf("Certificate verification failed:\r\n%s\r\r\n", buf); 00251 } 00252 else 00253 mbedtls_printf("Certificate verification passed\r\n\r\n"); 00254 00255 00256 /* Read data out of the socket */ 00257 ret = mbedtls_ssl_read(&_ssl, (unsigned char *) _buffer, sizeof(_buffer)); 00258 if (ret < 0) { 00259 if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { 00260 print_mbedtls_error("mbedtls_ssl_read", ret); 00261 onError(_tcpsocket, -1 ); 00262 } 00263 delete[] buf; 00264 return; 00265 } 00266 _bpos = static_cast<size_t>(ret); 00267 00268 _buffer[_bpos] = 0; 00269 00270 /* Check each of the flags */ 00271 _got200 = _got200 || strstr(_buffer, HTTPS_OK_STR) != NULL; 00272 _gothello = _gothello || strstr(_buffer, HTTPS_HELLO_STR) != NULL; 00273 00274 /* Print status messages */ 00275 mbedtls_printf("HTTPS: Received %d chars from server\r\n", _bpos); 00276 mbedtls_printf("HTTPS: Received 200 OK status ... %s\r\n", _got200 ? "[OK]" : "[FAIL]"); 00277 mbedtls_printf("HTTPS: Received '%s' status ... %s\r\n", HTTPS_HELLO_STR, _gothello ? "[OK]" : "[FAIL]"); 00278 mbedtls_printf("HTTPS: Received message:\r\n\r\n"); 00279 mbedtls_printf("%s", _buffer); 00280 _error = !(_got200 && _gothello); 00281 00282 _tcpsocket->close(); 00283 delete[] buf; 00284 } 00285 protected: 00286 /** 00287 * Helper for pretty-printing mbed TLS error codes 00288 */ 00289 static void print_mbedtls_error(const char *name, int err) { 00290 char buf[128]; 00291 mbedtls_strerror(err, buf, sizeof (buf)); 00292 mbedtls_printf("%s() failed: -0x%04x (%d): %s\r\n", name, -err, err, buf); 00293 } 00294 00295 #if DEBUG_LEVEL > 0 00296 /** 00297 * Debug callback for mbed TLS 00298 * Just prints on the USB serial port 00299 */ 00300 static void my_debug(void *ctx, int level, const char *file, int line, 00301 const char *str) 00302 { 00303 const char *p, *basename; 00304 (void) ctx; 00305 00306 /* Extract basename from file */ 00307 for(p = basename = file; *p != '\0'; p++) { 00308 if(*p == '/' || *p == '\\') { 00309 basename = p + 1; 00310 } 00311 } 00312 00313 mbedtls_printf("%s:%04d: |%d| %s", basename, line, level, str); 00314 } 00315 00316 /** 00317 * Certificate verification callback for mbed TLS 00318 * Here we only use it to display information on each cert in the chain 00319 */ 00320 static int my_verify(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags) 00321 { 00322 const uint32_t buf_size = 1024; 00323 char *buf = new char[buf_size]; 00324 (void) data; 00325 00326 mbedtls_printf("\nVerifying certificate at depth %d:\n", depth); 00327 mbedtls_x509_crt_info(buf, buf_size - 1, " ", crt); 00328 mbedtls_printf("%s", buf); 00329 00330 if (*flags == 0) 00331 mbedtls_printf("No verification issue for this certificate\n"); 00332 else 00333 { 00334 mbedtls_x509_crt_verify_info(buf, buf_size, " ! ", *flags); 00335 mbedtls_printf("%s\n", buf); 00336 } 00337 00338 delete[] buf; 00339 return 0; 00340 } 00341 #endif 00342 00343 /** 00344 * Receive callback for mbed TLS 00345 */ 00346 static int ssl_recv(void *ctx, unsigned char *buf, size_t len) { 00347 TCPSocketConnection *socket = static_cast<TCPSocketConnection *>(ctx); 00348 return (int)socket->receive((char*)buf, len); 00349 } 00350 00351 /** 00352 * Send callback for mbed TLS 00353 */ 00354 static int ssl_send(void *ctx, const unsigned char *buf, size_t len) { 00355 TCPSocketConnection *socket = static_cast<TCPSocketConnection *>(ctx); 00356 return socket->send((char*)buf, len); 00357 } 00358 00359 void onError(TCPSocketConnection *s, int error) { 00360 mbedtls_printf("MBED: Socket Error: %d\r\n", error); 00361 s->close(); 00362 _error = true; 00363 } 00364 00365 protected: 00366 TCPSocketConnection* _tcpsocket; 00367 00368 const char *_domain; /**< The domain name of the HTTPS server */ 00369 const uint16_t _port; /**< The HTTPS server port */ 00370 char _buffer[RECV_BUFFER_SIZE]; /**< The response buffer */ 00371 size_t _bpos; /**< The current offset in the response buffer */ 00372 volatile bool _got200; /**< Status flag for HTTPS 200 */ 00373 volatile bool _gothello; /**< Status flag for finding the test string */ 00374 volatile bool _error; /**< Status flag for an error */ 00375 volatile bool _disconnected; 00376 volatile bool _request_sent; 00377 00378 mbedtls_entropy_context _entropy; 00379 mbedtls_ctr_drbg_context _ctr_drbg; 00380 mbedtls_x509_crt _cacert; 00381 mbedtls_ssl_context _ssl; 00382 mbedtls_ssl_config _ssl_conf; 00383 }; 00384 00385 MODSERIAL pc(USBTX,USBRX,256,256); 00386 00387 #ifdef __cplusplus 00388 extern "C" { 00389 #endif 00390 00391 int myprintf( const char* format, ... ) { 00392 extern MODSERIAL pc; 00393 string buff; 00394 00395 va_list valist; 00396 buff.reserve(2048); 00397 va_start(valist, format); 00398 vsprintf(&buff[0],format,valist); 00399 pc.puts(buff.c_str()); 00400 va_end(valist); 00401 return 0; 00402 } 00403 00404 #ifdef __cplusplus 00405 } 00406 #endif 00407 /** 00408 * The main loop of the HTTPS Hello World test 00409 */ 00410 int main() { 00411 int ret; 00412 /* The default 9600 bps is too slow to print full TLS debug info and could 00413 * cause the other party to time out. */ 00414 00415 /* Inititalise with DHCP, connect, and start up the stack */ 00416 WNCInterface eth_iface; 00417 00418 pc.baud(115200); 00419 pc.printf(CRLF "Starting HTTPS File Download Example for TLS use WNC Data Module" CRLF); 00420 00421 ret = eth_iface.init(NULL, &pc); 00422 pc.printf("WNC Module %s initialized (%02X)." CRLF, ret?"IS":"IS NOT", ret); 00423 if( !ret ) { 00424 pc.printf(" - - - - - - - ALL DONE - - - - - - - " CRLF); 00425 while(1); 00426 } 00427 00428 eth_iface.connect(); 00429 pc.printf("IP Address: %s " CRLF CRLF, eth_iface.getIPAddress()); 00430 00431 HelloHTTPS *hello = new HelloHTTPS(HTTPS_SERVER_NAME, HTTPS_SERVER_PORT, ð_iface); 00432 hello->startTest(HTTPS_PATH); 00433 pc.printf(" >>> DONE <<<\r\n"); 00434 delete hello; 00435 }
Generated on Wed Jul 13 2022 02:01:01 by
1.7.2