Publisher for IBM Quickstart and Watson IoT cloud.
Dependencies: MQTT NDefLib X_NUCLEO_IKS01A2 X_NUCLEO_NFC01A1
Fork of Cloud_IBM_MbedOS by
MQTTNetwork.h
00001 #ifndef _MQTTNETWORK_H_ 00002 #define _MQTTNETWORK_H_ 00003 00004 #include "NetworkInterface.h" 00005 #include "mbedtls/platform.h" 00006 #include "mbedtls/ssl.h" 00007 #include "mbedtls/entropy.h" 00008 #include "mbedtls/ctr_drbg.h" 00009 #include "mbedtls/error.h" 00010 00011 /* Change to a number between 1 and 4 to debug the TLS connection */ 00012 #define DEBUG_LEVEL 0 00013 00014 #if DEBUG_LEVEL > 0 00015 #include "mbedtls/debug.h" 00016 #endif 00017 00018 #define TLS_OFF 0 00019 #define TLS_ON 1 00020 00021 /* personalization string for the drbg */ 00022 const char *DRBG_PERS = "mbed TLS Publisher for IBM Watson IoT"; 00023 00024 /* List of trusted root CA certificates 00025 * currently only GlobalSign, the CA for os.mbed.com 00026 * 00027 * To add more than one root, just concatenate them. 00028 */ 00029 mbedtls_entropy_context _entropy; 00030 mbedtls_ctr_drbg_context _ctr_drbg; 00031 mbedtls_x509_crt _cacert; 00032 mbedtls_ssl_context _ssl; 00033 mbedtls_ssl_config _ssl_conf; 00034 00035 class MQTTNetwork { 00036 public: 00037 MQTTNetwork(NetworkInterface *net_iface) : _network(net_iface) { 00038 _tcpsocket = new TCPSocket(); 00039 _tcpsocket->set_blocking(false); 00040 _is_tcpsocket_connected = 0; 00041 } 00042 00043 ~MQTTNetwork() { 00044 if (_is_tcpsocket_connected && _tls) { 00045 mbedtls_ssl_session_reset( &_ssl ); 00046 mbedtls_entropy_free(&_entropy); 00047 mbedtls_ctr_drbg_free(&_ctr_drbg); 00048 mbedtls_x509_crt_free(&_cacert); 00049 mbedtls_ssl_free(&_ssl); 00050 mbedtls_ssl_config_free(&_ssl_conf); 00051 } 00052 _tcpsocket->close(); 00053 delete _tcpsocket; 00054 } 00055 00056 int read(unsigned char* buffer, int len, int timeout) { 00057 size_t _bpos = 0; int offset = 0; int ret = 0; 00058 if (_tls) { 00059 //_tcpsocket->set_timeout(timeout); 00060 /* Read data out of the socket */ 00061 offset = 0; 00062 Countdown timer; 00063 timer.countdown_ms(timeout); 00064 00065 do { 00066 ret = mbedtls_ssl_read(&_ssl, buffer + offset, 00067 len - offset ); 00068 if (ret > 0) offset += ret; 00069 if (offset == len) return offset; 00070 if (timer.expired()) return 0; 00071 } while (ret == MBEDTLS_ERR_SSL_WANT_READ || 00072 ret == MBEDTLS_ERR_SSL_WANT_WRITE || ret == 0 ); 00073 if (ret == MBEDTLS_ERR_SSL_CLIENT_RECONNECT) { 00074 print_mbedtls_error("MBEDTLS_ERR_SSL_CLIENT_RECONNECT\n\r", ret); 00075 // int mbedtls_ssl_session_reset( mbedtls_ssl_context *ssl ); 00076 _tcpsocket->close(); 00077 _is_tcpsocket_connected = 0; 00078 return ret; 00079 } 00080 00081 if (ret < 0) { 00082 print_mbedtls_error("mbedtls_ssl_read", ret); 00083 _tcpsocket->close(); 00084 _is_tcpsocket_connected = 0; 00085 return ret; 00086 } 00087 return ret; 00088 } else { 00089 _tcpsocket->set_blocking(true); 00090 _tcpsocket->set_timeout(timeout); 00091 return _tcpsocket->recv(buffer, len); 00092 } 00093 } 00094 00095 00096 int write(unsigned char* buffer, int len, int timeout) { 00097 00098 size_t _bpos = len; 00099 int offset = 0; int ret = 0; 00100 if (_tls) { 00101 do { 00102 ret = mbedtls_ssl_write(&_ssl, 00103 (const unsigned char *) buffer + offset, 00104 _bpos - offset); 00105 if (ret > 0) 00106 offset += ret; 00107 } while (offset < _bpos && (ret > 0 || ret == MBEDTLS_ERR_SSL_WANT_READ || 00108 ret == MBEDTLS_ERR_SSL_WANT_WRITE)); 00109 if (ret < 0) { 00110 print_mbedtls_error("mbedtls_ssl_write", ret); 00111 _tcpsocket->close(); 00112 _is_tcpsocket_connected = 0; 00113 return ret; 00114 } 00115 return ret; 00116 } else { 00117 _tcpsocket->set_blocking(true); 00118 _tcpsocket->set_timeout(timeout); 00119 return _tcpsocket->send(buffer, len); 00120 } 00121 } 00122 00123 int connect(const char* hostname, int port, unsigned int tls=TLS_OFF, const char * cert=NULL, unsigned int sizeof_cert=0) { 00124 _tls = tls; 00125 if (tls == TLS_ON) { printf ("--->TLS is ON\n\r"); assert (cert); }; 00126 if (tls == TLS_ON) { 00127 mbedtls_entropy_init(&_entropy); 00128 mbedtls_ctr_drbg_init(&_ctr_drbg); 00129 mbedtls_x509_crt_init(&_cacert); 00130 mbedtls_ssl_init(&_ssl); 00131 mbedtls_ssl_config_init(&_ssl_conf); 00132 /* 00133 * Initialize TLS-related stuf. 00134 */ 00135 int ret = 0; 00136 if ((ret = mbedtls_ctr_drbg_seed(&_ctr_drbg, mbedtls_entropy_func, &_entropy, 00137 (const unsigned char *) DRBG_PERS, 00138 sizeof (DRBG_PERS))) != 0) { 00139 print_mbedtls_error("mbedtls_crt_drbg_init", ret); 00140 return ret; 00141 } 00142 if ((ret = mbedtls_x509_crt_parse(&_cacert, (const unsigned char *) cert, 00143 sizeof_cert)) != 0) { 00144 print_mbedtls_error("mbedtls_x509_crt_parse", ret); 00145 return ret; 00146 } 00147 if ((ret = mbedtls_ssl_config_defaults(&_ssl_conf, 00148 MBEDTLS_SSL_IS_CLIENT, 00149 MBEDTLS_SSL_TRANSPORT_STREAM, 00150 MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { 00151 print_mbedtls_error("mbedtls_ssl_config_defaults", ret); 00152 return ret; 00153 } 00154 mbedtls_ssl_conf_ca_chain(&_ssl_conf, &_cacert, NULL); 00155 mbedtls_ssl_conf_rng(&_ssl_conf, mbedtls_ctr_drbg_random, &_ctr_drbg); 00156 /* It is possible to disable authentication by passing 00157 * MBEDTLS_SSL_VERIFY_NONE in the call to mbedtls_ssl_conf_authmode() 00158 */ 00159 mbedtls_ssl_conf_authmode(&_ssl_conf, MBEDTLS_SSL_VERIFY_REQUIRED); 00160 #if DEBUG_LEVEL > 0 00161 mbedtls_ssl_conf_verify(&_ssl_conf, my_verify, NULL); 00162 mbedtls_ssl_conf_dbg(&_ssl_conf, my_debug, NULL); 00163 mbedtls_debug_set_threshold(DEBUG_LEVEL); 00164 #endif 00165 if ((ret = mbedtls_ssl_setup(&_ssl, &_ssl_conf)) != 0) { 00166 print_mbedtls_error("mbedtls_ssl_setup", ret); 00167 return ret; 00168 } 00169 mbedtls_ssl_set_hostname(&_ssl, hostname); 00170 00171 mbedtls_ssl_set_bio(&_ssl, static_cast<void *>(_tcpsocket), ssl_send, ssl_recv, NULL ); 00172 /* Connect to the server */ 00173 _tcpsocket->open(_network); 00174 mbedtls_printf("Connecting with %s port: %d\n", hostname, port); 00175 ret = _tcpsocket->connect(hostname, port); 00176 if (ret != NSAPI_ERROR_OK) { 00177 mbedtls_printf("Failed to connect\n"); 00178 printf("MBED: Socket Error: %d\n", ret); 00179 _tcpsocket->close(); 00180 return ret; 00181 } 00182 printf ("--->TCP Connected\n\r"); 00183 _is_tcpsocket_connected = 1; 00184 00185 /* Start the handshake, the rest will be done in onReceive() */ 00186 mbedtls_printf("Starting the TLS handshake...\n"); 00187 do { 00188 ret = mbedtls_ssl_handshake(&_ssl); 00189 } while (ret != 0 && (ret == MBEDTLS_ERR_SSL_WANT_READ || 00190 ret == MBEDTLS_ERR_SSL_WANT_WRITE)); 00191 if (ret < 0) { 00192 print_mbedtls_error("mbedtls_ssl_handshake", ret); 00193 _tcpsocket->close(); 00194 return ret; 00195 } 00196 /* const uint32_t buf_size = 1024; 00197 char *buf = new char[buf_size]; 00198 mbedtls_x509_crt_info(buf, buf_size, "\r ", 00199 mbedtls_ssl_get_peer_cert(&_ssl)); 00200 mbedtls_printf("Server certificate:\n%s", buf); 00201 00202 uint32_t flags = mbedtls_ssl_get_verify_result(&_ssl); 00203 if( flags != 0 ) 00204 { 00205 mbedtls_x509_crt_verify_info(buf, buf_size, "\r ! ", flags); 00206 printf("Certificate verification failed:\n%s\n", buf); 00207 } 00208 else 00209 printf("Certificate verification passed\n\n"); 00210 */ 00211 _is_tcpsocket_connected = 1; 00212 return ret; 00213 00214 } else { // tls off 00215 printf ("--->TLS is OFF\n\r"); 00216 _tcpsocket->open(_network); 00217 int ret = _tcpsocket->connect(hostname, port); 00218 if (ret != NSAPI_ERROR_OK) { 00219 mbedtls_printf("Failed to connect\n"); 00220 printf("MBED: Socket Error: %d\n", ret); 00221 _tcpsocket->close(); 00222 return ret; 00223 } 00224 printf ("--->TCP Connected\n\r"); 00225 _is_tcpsocket_connected = 1; 00226 return ret; 00227 } 00228 } 00229 00230 int disconnect() { 00231 if (_is_tcpsocket_connected && _tls == TLS_ON) { 00232 mbedtls_ssl_session_reset( &_ssl ); 00233 mbedtls_entropy_free(&_entropy); 00234 mbedtls_ctr_drbg_free(&_ctr_drbg); 00235 mbedtls_x509_crt_free(&_cacert); 00236 mbedtls_ssl_free(&_ssl); 00237 mbedtls_ssl_config_free(&_ssl_conf); 00238 } 00239 _is_tcpsocket_connected = 0; 00240 return _tcpsocket->close(); 00241 } 00242 00243 bool isConnected () { return _is_tcpsocket_connected; } 00244 00245 private: 00246 NetworkInterface* _network; 00247 unsigned int _is_tcpsocket_connected; 00248 00249 protected: 00250 /** 00251 * Helper for pretty-printing mbed TLS error codes 00252 */ 00253 static void print_mbedtls_error(const char *name, int err) { 00254 char buf[128]; 00255 mbedtls_strerror(err, buf, sizeof (buf)); 00256 mbedtls_printf("%s() failed: -0x%04x (%d): %s\n", name, -err, err, buf); 00257 } 00258 00259 #if DEBUG_LEVEL > 0 00260 /** 00261 * Debug callback for Mbed TLS 00262 * Just prints on the USB serial port 00263 */ 00264 static void my_debug(void *ctx, int level, const char *file, int line, 00265 const char *str) 00266 { 00267 const char *p, *basename; 00268 (void) ctx; 00269 00270 /* Extract basename from file */ 00271 for(p = basename = file; *p != '\0'; p++) { 00272 if(*p == '/' || *p == '\\') { 00273 basename = p + 1; 00274 } 00275 } 00276 00277 mbedtls_printf("%s:%04d: |%d| %s", basename, line, level, str); 00278 } 00279 00280 /** 00281 * Certificate verification callback for Mbed TLS 00282 * Here we only use it to display information on each cert in the chain 00283 */ 00284 static int my_verify(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags) 00285 { 00286 const uint32_t buf_size = 1024; 00287 char *buf = new char[buf_size]; 00288 (void) data; 00289 00290 mbedtls_printf("\nVerifying certificate at depth %d:\n", depth); 00291 mbedtls_x509_crt_info(buf, buf_size - 1, " ", crt); 00292 mbedtls_printf("%s", buf); 00293 00294 if (*flags == 0) 00295 mbedtls_printf("No verification issue for this certificate\n"); 00296 else 00297 { 00298 mbedtls_x509_crt_verify_info(buf, buf_size, " ! ", *flags); 00299 mbedtls_printf("%s\n", buf); 00300 } 00301 00302 delete[] buf; 00303 return 0; 00304 } 00305 #endif 00306 00307 /** 00308 * Receive callback for Mbed TLS 00309 */ 00310 static int ssl_recv(void *ctx, unsigned char *buf, size_t len) { 00311 int recv = -1; 00312 TCPSocket *socket = static_cast<TCPSocket *>(ctx); 00313 recv = socket->recv(buf, len); 00314 00315 if(NSAPI_ERROR_WOULD_BLOCK == recv){ 00316 return MBEDTLS_ERR_SSL_WANT_READ; 00317 }else if(recv < 0){ 00318 mbedtls_printf("Socket recv error %d\n", recv); 00319 return -1; 00320 }else{ 00321 return recv; 00322 } 00323 } 00324 00325 /** 00326 * Send callback for Mbed TLS 00327 */ 00328 static int ssl_send(void *ctx, const unsigned char *buf, size_t len) { 00329 int size = -1; 00330 TCPSocket *socket = static_cast<TCPSocket *>(ctx); 00331 size = socket->send(buf, len); 00332 00333 if(NSAPI_ERROR_WOULD_BLOCK == size){ 00334 return MBEDTLS_ERR_SSL_WANT_WRITE; 00335 }else if(size < 0){ 00336 mbedtls_printf("Socket send error %d\n", size); 00337 return -1; 00338 }else{ 00339 return size; 00340 } 00341 } 00342 00343 TCPSocket* _tcpsocket; 00344 volatile bool _disconnected; 00345 unsigned int _tls; 00346 }; 00347 00348 00349 #endif // _MQTTNETWORK_H_
Generated on Wed Jul 13 2022 18:42:12 by 1.7.2