Publisher for IBM Quickstart and Watson IoT cloud.

Dependencies:   MQTT NDefLib X_NUCLEO_IKS01A2 X_NUCLEO_NFC01A1

Fork of Cloud_IBM_MbedOS by ST Expansion SW Team

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MQTTNetwork.h Source File

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_