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.
Fork of mbed-http by
tls_socket.h
00001 /* 00002 * PackageLicenseDeclared: Apache-2.0 00003 * Copyright (c) 2017 ARM Limited 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); 00006 * you may not use this file except in compliance with the License. 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, 00013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 00018 #ifndef _MBED_HTTPS_TLS_SOCKET_H_ 00019 #define _MBED_HTTPS_TLS_SOCKET_H_ 00020 00021 /* Change to a number between 1 and 4 to debug the TLS connection */ 00022 #define DEBUG_LEVEL 0 00023 00024 #include <string> 00025 #include <vector> 00026 #include <map> 00027 #include "http_parser.h" 00028 #include "http_response.h" 00029 #include "http_request_builder.h" 00030 #include "http_request_parser.h" 00031 #include "http_parsed_url.h" 00032 00033 #include "mbedtls/platform.h" 00034 #include "mbedtls/ssl.h" 00035 #include "mbedtls/entropy.h" 00036 #include "mbedtls/ctr_drbg.h" 00037 #include "mbedtls/error.h" 00038 00039 #if DEBUG_LEVEL > 0 00040 #include "mbedtls/debug.h" 00041 #endif 00042 00043 /** 00044 * \brief TLSSocket a wrapper around TCPSocket for interacting with TLS servers 00045 */ 00046 class TLSSocket { 00047 public: 00048 TLSSocket(NetworkInterface* net_iface, const char* hostname, uint16_t port, const char* ssl_ca_pem) { 00049 _tcpsocket = new TCPSocket(net_iface); 00050 _ssl_ca_pem = ssl_ca_pem; 00051 _is_connected = false; 00052 _debug = false; 00053 _hostname = hostname; 00054 _port = port; 00055 _error = 0; 00056 00057 DRBG_PERS = "mbed TLS helloword client"; 00058 00059 mbedtls_entropy_init(&_entropy); 00060 mbedtls_ctr_drbg_init(&_ctr_drbg); 00061 mbedtls_x509_crt_init(&_cacert); 00062 mbedtls_ssl_init(&_ssl); 00063 mbedtls_ssl_config_init(&_ssl_conf); 00064 } 00065 00066 ~TLSSocket() { 00067 mbedtls_entropy_free(&_entropy); 00068 mbedtls_ctr_drbg_free(&_ctr_drbg); 00069 mbedtls_x509_crt_free(&_cacert); 00070 mbedtls_ssl_free(&_ssl); 00071 mbedtls_ssl_config_free(&_ssl_conf); 00072 00073 if (_tcpsocket) { 00074 _tcpsocket->close(); 00075 delete _tcpsocket; 00076 } 00077 00078 // @todo: free DRBG_PERS ? 00079 } 00080 00081 nsapi_error_t connect() { 00082 /* Initialize the flags */ 00083 /* 00084 * Initialize TLS-related stuf. 00085 */ 00086 int ret; 00087 if ((ret = mbedtls_ctr_drbg_seed(&_ctr_drbg, mbedtls_entropy_func, &_entropy, 00088 (const unsigned char *) DRBG_PERS, 00089 sizeof (DRBG_PERS))) != 0) { 00090 print_mbedtls_error("mbedtls_crt_drbg_init", ret); 00091 _error = ret; 00092 return _error; 00093 } 00094 00095 if ((ret = mbedtls_x509_crt_parse(&_cacert, (const unsigned char *)_ssl_ca_pem, 00096 strlen(_ssl_ca_pem) + 1)) != 0) { 00097 print_mbedtls_error("mbedtls_x509_crt_parse", ret); 00098 _error = ret; 00099 return _error; 00100 } 00101 00102 if ((ret = mbedtls_ssl_config_defaults(&_ssl_conf, 00103 MBEDTLS_SSL_IS_CLIENT, 00104 MBEDTLS_SSL_TRANSPORT_STREAM, 00105 MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { 00106 print_mbedtls_error("mbedtls_ssl_config_defaults", ret); 00107 _error = ret; 00108 return _error; 00109 } 00110 00111 mbedtls_ssl_conf_ca_chain(&_ssl_conf, &_cacert, NULL); 00112 mbedtls_ssl_conf_rng(&_ssl_conf, mbedtls_ctr_drbg_random, &_ctr_drbg); 00113 00114 /* It is possible to disable authentication by passing 00115 * MBEDTLS_SSL_VERIFY_NONE in the call to mbedtls_ssl_conf_authmode() 00116 */ 00117 mbedtls_ssl_conf_authmode(&_ssl_conf, MBEDTLS_SSL_VERIFY_REQUIRED); 00118 00119 #if DEBUG_LEVEL > 0 00120 mbedtls_ssl_conf_verify(&_ssl_conf, my_verify, NULL); 00121 mbedtls_ssl_conf_dbg(&_ssl_conf, my_debug, NULL); 00122 mbedtls_debug_set_threshold(DEBUG_LEVEL); 00123 #endif 00124 00125 if ((ret = mbedtls_ssl_setup(&_ssl, &_ssl_conf)) != 0) { 00126 print_mbedtls_error("mbedtls_ssl_setup", ret); 00127 _error = ret; 00128 return _error; 00129 } 00130 00131 mbedtls_ssl_set_hostname(&_ssl, _hostname); 00132 00133 mbedtls_ssl_set_bio(&_ssl, static_cast<void *>(_tcpsocket), 00134 ssl_send, ssl_recv, NULL ); 00135 00136 /* Connect to the server */ 00137 if (_debug) mbedtls_printf("Connecting to %s:%d\r\n", _hostname, _port); 00138 ret = _tcpsocket->connect(_hostname, _port); 00139 if (ret != NSAPI_ERROR_OK) { 00140 if (_debug) mbedtls_printf("Failed to connect\r\n"); 00141 onError(_tcpsocket, -1); 00142 return _error; 00143 } 00144 00145 /* Start the handshake, the rest will be done in onReceive() */ 00146 if (_debug) mbedtls_printf("Starting the TLS handshake...\r\n"); 00147 ret = mbedtls_ssl_handshake(&_ssl); 00148 if (ret < 0) { 00149 if (ret != MBEDTLS_ERR_SSL_WANT_READ && 00150 ret != MBEDTLS_ERR_SSL_WANT_WRITE) { 00151 print_mbedtls_error("mbedtls_ssl_handshake", ret); 00152 onError(_tcpsocket, -1); 00153 } 00154 else { 00155 _error = ret; 00156 } 00157 return _error; 00158 } 00159 00160 /* It also means the handshake is done, time to print info */ 00161 if (_debug) mbedtls_printf("TLS connection to %s:%d established\r\n", _hostname, _port); 00162 00163 const uint32_t buf_size = 1024; 00164 char buf[buf_size] = { 0 }; 00165 mbedtls_x509_crt_info(buf, buf_size, "\r ", 00166 mbedtls_ssl_get_peer_cert(&_ssl)); 00167 if (_debug) mbedtls_printf("Server certificate:\r\n%s\r", buf); 00168 00169 uint32_t flags = mbedtls_ssl_get_verify_result(&_ssl); 00170 if( flags != 0 ) 00171 { 00172 mbedtls_x509_crt_verify_info(buf, buf_size, "\r ! ", flags); 00173 if (_debug) mbedtls_printf("Certificate verification failed:\r\n%s\r\r\n", buf); 00174 } 00175 else { 00176 if (_debug) mbedtls_printf("Certificate verification passed\r\n\r\n"); 00177 } 00178 00179 _is_connected = true; 00180 00181 return 0; 00182 } 00183 00184 bool connected() { 00185 return _is_connected; 00186 } 00187 00188 nsapi_error_t error() { 00189 return _error; 00190 } 00191 00192 TCPSocket* get_tcp_socket() { 00193 return _tcpsocket; 00194 } 00195 00196 mbedtls_ssl_context* get_ssl_context() { 00197 return &_ssl; 00198 } 00199 00200 /** 00201 * Set the debug flag. 00202 * 00203 * If this flag is set, debug information from mbed TLS will be logged to stdout. 00204 */ 00205 void set_debug(bool debug) { 00206 _debug = debug; 00207 } 00208 00209 protected: 00210 /** 00211 * Helper for pretty-printing mbed TLS error codes 00212 */ 00213 static void print_mbedtls_error(const char *name, int err) { 00214 char buf[128]; 00215 mbedtls_strerror(err, buf, sizeof (buf)); 00216 mbedtls_printf("%s() failed: -0x%04x (%d): %s\r\n", name, -err, err, buf); 00217 } 00218 00219 #if DEBUG_LEVEL > 0 00220 /** 00221 * Debug callback for mbed TLS 00222 * Just prints on the USB serial port 00223 */ 00224 static void my_debug(void *ctx, int level, const char *file, int line, 00225 const char *str) 00226 { 00227 const char *p, *basename; 00228 (void) ctx; 00229 00230 /* Extract basename from file */ 00231 for(p = basename = file; *p != '\0'; p++) { 00232 if(*p == '/' || *p == '\\') { 00233 basename = p + 1; 00234 } 00235 } 00236 00237 if (_debug) { 00238 mbedtls_printf("%s:%04d: |%d| %s", basename, line, level, str); 00239 } 00240 } 00241 00242 /** 00243 * Certificate verification callback for mbed TLS 00244 * Here we only use it to display information on each cert in the chain 00245 */ 00246 static int my_verify(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags) 00247 { 00248 const uint32_t buf_size = 1024; 00249 char *buf = new char[buf_size]; 00250 (void) data; 00251 00252 if (_debug) mbedtls_printf("\nVerifying certificate at depth %d:\n", depth); 00253 mbedtls_x509_crt_info(buf, buf_size - 1, " ", crt); 00254 if (_debug) mbedtls_printf("%s", buf); 00255 00256 if (*flags == 0) 00257 if (_debug) mbedtls_printf("No verification issue for this certificate\n"); 00258 else 00259 { 00260 mbedtls_x509_crt_verify_info(buf, buf_size, " ! ", *flags); 00261 if (_debug) mbedtls_printf("%s\n", buf); 00262 } 00263 00264 delete[] buf; 00265 return 0; 00266 } 00267 #endif 00268 00269 /** 00270 * Receive callback for mbed TLS 00271 */ 00272 static int ssl_recv(void *ctx, unsigned char *buf, size_t len) { 00273 int recv = -1; 00274 TCPSocket *socket = static_cast<TCPSocket *>(ctx); 00275 recv = socket->recv(buf, len); 00276 00277 if (NSAPI_ERROR_WOULD_BLOCK == recv) { 00278 return MBEDTLS_ERR_SSL_WANT_READ; 00279 } 00280 else if (recv < 0) { 00281 return -1; 00282 } 00283 else { 00284 return recv; 00285 } 00286 } 00287 00288 /** 00289 * Send callback for mbed TLS 00290 */ 00291 static int ssl_send(void *ctx, const unsigned char *buf, size_t len) { 00292 int size = -1; 00293 TCPSocket *socket = static_cast<TCPSocket *>(ctx); 00294 size = socket->send(buf, len); 00295 00296 if(NSAPI_ERROR_WOULD_BLOCK == size) { 00297 return len; 00298 } 00299 else if (size < 0){ 00300 return -1; 00301 } 00302 else { 00303 return size; 00304 } 00305 } 00306 00307 private: 00308 void onError(TCPSocket *s, int error) { 00309 s->close(); 00310 _error = error; 00311 } 00312 00313 TCPSocket* _tcpsocket; 00314 00315 const char* DRBG_PERS; 00316 const char* _ssl_ca_pem; 00317 const char* _hostname; 00318 uint16_t _port; 00319 00320 bool _debug; 00321 bool _is_connected; 00322 00323 nsapi_error_t _error; 00324 00325 mbedtls_entropy_context _entropy; 00326 mbedtls_ctr_drbg_context _ctr_drbg; 00327 mbedtls_x509_crt _cacert; 00328 mbedtls_ssl_context _ssl; 00329 mbedtls_ssl_config _ssl_conf; 00330 }; 00331 00332 #endif // _MBED_HTTPS_TLS_SOCKET_H_
Generated on Fri Jul 15 2022 18:07:13 by
1.7.2
