Fork of the working HTTPClient adaptation using CyaSSL. This version adds a derivation of HTTPText called HTTPJson to emit JSON text properly. Additionally, the URL parser has defines that permit longer URLs to be utilized.

Dependencies:   mbedTLSLibrary

Dependents:   SalesforceInterface df-2014-heroku-thermostat-k64f SalesforceInterface

Fork of HTTPClient by wolf SSL

This is a fork of the working HTTPS/SSL library that contains two extensions:

- HTTPJson - a derivation of HTTPText for emitting JSON strings specifically. No JSON parsing/checking is accomplished - HTTPJson simply sets the right Content-Type for HTTP(S).

- Expanded internal buffers for longer URLs. This is set in HTTPClient.cpp and is tunable.

Files at this revision

API Documentation at this revision

Comitter:
ansond
Date:
Thu Aug 20 18:55:41 2015 +0000
Parent:
50:a18a06b000f3
Child:
52:cea1021a822d
Commit message:
initial port of HTTPS library to make use of the mbedTLS library...

Changed in this revision

CyaSSL.lib Show diff for this revision Revisions of this file
HTTPClient.cpp Show annotated file Show diff for this revision Revisions of this file
HTTPClient.h Show annotated file Show diff for this revision Revisions of this file
mbedTLSLibrary.lib Show annotated file Show diff for this revision Revisions of this file
--- a/CyaSSL.lib	Tue Jun 09 16:26:02 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-http://mbed.org/users/wolfSSL/code/CyaSSL/#64d4f7cb83d5
--- a/HTTPClient.cpp	Tue Jun 09 16:26:02 2015 +0000
+++ b/HTTPClient.cpp	Thu Aug 20 18:55:41 2015 +0000
@@ -46,15 +46,8 @@
 
 #include <cstring>
 
-#include  <../CyaSSL/cyassl/ctaocrypt/settings.h>
-#include <../CyaSSL/cyassl/ctaocrypt/types.h>
-#include <../CyaSSL/cyassl/internal.h>
-#include <../CyaSSL/cyassl/ssl.h>
-
 #include "HTTPClient.h"
 
-
-
 // ************ should be a better way to adjust for platform limitations 
 
 #if defined (TARGET_K64F)
@@ -68,6 +61,7 @@
     #define MAX_HEADER_KEY_LENGTH   40
     #define HEADER_SCANF_FORMAT     "%40[^:]: %4096[^\r\n]" /* must align with BIG_MEMORY_CHUNK */ 
     #define REDIRECT_SCANF_FORMAT   "%40[^:]: %4096[^\r\n]" /* must align with BIG_MEMORY_CHUNK */
+    #define RECV_RETRY              3
 #else
     // default smaller buffers
     #define CHUNK_SIZE              256
@@ -78,6 +72,7 @@
     #define MAX_HEADER_KEY_LENGTH   40
     #define HEADER_SCANF_FORMAT     "%40[^:]: %40[^\r\n]"   /* must align with MAX_HEADER_VALUE_LENGTH */ 
     #define REDIRECT_SCANF_FORMAT   "%40[^:]: %128[^\r\n]"  /* must align with MAX_URL_PATH_LENGTH */
+    #define RECV_RETRY              3
 #endif
 
 // ************ should be a better way to adjust for platform limitations
@@ -105,40 +100,101 @@
     }
     out[i] = '\0' ;
 }
-int SocketReceive(CYASSL* ssl, char *buf, int sz, void *ctx)
+
+static int SocketReceive(void* ssl, unsigned char *buf, size_t sz)
 {
-    int n ;
-    int i ;
-#define RECV_RETRY 3
+    int n = 0;
+    int i = 0;
 
     for(i=0; i<RECV_RETRY; i++) {
-        n =  m_sock_p->receive(buf, sz) ;
-        if(n >= 0)return n  ;
-        Thread::wait(200) ;
+        n = m_sock_p->receive((char *)buf,(int)sz) ;
+        if (n >= 0) return n;
     }
-    ERR("SocketReceive:%d/%d\n", n, sz)  ;
-    return n ;
+    ERR("SocketReceive: receive failed. received: %d bytes. tried to receive: %d bytes\n", n, sz)  ;
+    return n;
 }
-int SocketSend(CYASSL* ssl, char *buf, int sz, void *ctx)
+
+static int SocketSend(void* ssl, const unsigned char *buf, size_t sz)
 {
-    int n ;
-    
-    Thread::wait(100) ;
-    n =  m_sock_p->send(buf, sz);
-    if(n > 0) {
-        Thread::wait(300) ;
-        return n ;
-    } else  ERR("SocketSend:%d/%d\n", n, sz);
-    return n ;
+    int n = 0;
+    n = m_sock_p->send((char *)buf,(int)sz);
+    if(n > 0) return n;
+    ERR("SocketSend: send failed. sent: %d bytes. tried to send: %d bytes\n", n, sz);
+    return n;
+}
+
+short ssl_socket_read(ssl_context *ssl, char *receiveBuffer, unsigned int receiveBufferSize, unsigned int timeoutMilliseconds) {
+    int n = ssl_read(ssl,(unsigned char *)receiveBuffer, (size_t)receiveBufferSize);
+    if (n <= 0) {
+        ERR("ssl_socket_read failed\r\n");
+        return -1;
+    }
+    DBG("ssl_socket_read: read %d bytes...",n);
+    return n;
+}
+
+short ssl_socket_write(ssl_context *ssl, const char *sendBuffer, unsigned int sendBufferSize) {
+    sendBufferSize = strlen(sendBuffer);
+    int n = ssl_write(ssl,(const unsigned char *)sendBuffer,(size_t)sendBufferSize);
+    if (n != sendBufferSize) {
+        ERR("ssl_socket_write failed written=%d\r\n",n);
+        return -1;
+    }
+    DBG("ssl_socket_write: sent %d bytes...",sendBufferSize);
+    return sendBufferSize;
 }
 
-HTTPClient::HTTPClient() :
-    m_basicAuthUser(NULL), m_basicAuthPassword(NULL), m_httpResponseCode(0), m_oauthToken(NULL)
+void HTTPClient::set_ssl_version() {
+    // set the SSL version to be used
+    ssl_set_max_version(&this->ssl,SSL_MAX_MAJOR_VERSION,SSL_MAX_MINOR_VERSION);
+    if (this->SSLver == 0) {
+        // use v3
+        ssl_set_min_version(&this->ssl,SSL_MIN_MAJOR_VERSION,SSL_MIN_MINOR_VERSION);
+    }
+    if (this->SSLver == 1) {
+        // use v1
+        ssl_set_min_version(&this->ssl,SSL_MIN_MAJOR_VERSION,SSL_MINOR_VERSION_1);
+    }
+    if (this->SSLver == 2) {
+        // use v1.1
+        ssl_set_min_version(&this->ssl,SSL_MIN_MAJOR_VERSION,SSL_MINOR_VERSION_2);
+    }
+    if (this->SSLver == 3) {
+        // use v1.2
+        ssl_set_min_version(&this->ssl,SSL_MIN_MAJOR_VERSION,SSL_MINOR_VERSION_3);
+    } 
+}
+
+void HTTPClient::ssl_setup(const unsigned char *tag) {
+    entropy_init(&this->entropy);
+    ctr_drbg_init(&this->ctr_drbg,entropy_func,&this->entropy,tag,strlen((const char *)tag));
+    memset(&this->ssl,0,sizeof(ssl_context));
+    this->ssl_connected = false;
+}
+
+short HTTPClient::ssl_connect() {
+    short status = 0;
+    if (this->ssl_connected == false) {
+        this->ssl_setup("mbed_https_lib");              // debug tag could be taken from constructor parameter... fix me...
+        short status = ssl_init(&this->ssl);
+        if (status == 0) {
+            ssl_set_endpoint(&this->ssl,SSL_IS_CLIENT);
+            this->set_ssl_version();
+            ssl_set_rng(&this->ssl, ctr_drbg_random, &this->ctr_drbg);
+            ssl_set_authmode(&this->ssl,SSL_VERIFY_NONE);                                   // FIX ME:                             
+            ssl_set_bio(&this->ssl,SocketReceive,(void *)NULL,SocketSend,(void *)NULL);
+            this->ssl_connected = true;
+        }
+        DBG("ssl_connect: status=%d\r\n",status);
+    }
+    else {
+        DBG("ssl_connect: already connected (OK) status=%d\r\n",status);
+    }
+    return status;
+}
+
+HTTPClient::HTTPClient() : m_basicAuthUser(NULL), m_basicAuthPassword(NULL), m_httpResponseCode(0), m_oauthToken(NULL)
 {
-    // To DEBUG the underlying SSL - uncomment this...
-    //CyaSSL_Debugging_ON();
-    ctx = 0 ;
-    ssl = 0 ;
     SSLver = 3 ; 
     m_basicAuthUser = NULL ;
     m_basicAuthPassword = NULL;
@@ -250,7 +306,7 @@
 #define CHECK_CONN_ERR(ret) \
   do{ \
     if(ret) { \
-      cyassl_free() ;\
+      ssl_cleanup() ;\
       m_sock.close(); \
       ERR("Connection error (%d)", ret); \
       return HTTP_CONN; \
@@ -259,28 +315,22 @@
 
 #define PRTCL_ERR() \
   do{ \
-    cyassl_free() ;\
+    ssl_cleanup() ;\
     m_sock.close(); \
     ERR("Protocol error"); \
     return HTTP_PRTCL; \
   } while(0)
 
-void HTTPClient::cyassl_free(void)
+void HTTPClient::ssl_cleanup(void)
 {
-    if(ssl) {
-        CyaSSL_free(ssl) ;
-        ssl = NULL ;
-    }
-    if(ctx) {
-        CyaSSL_CTX_free(ctx) ;
-        ctx = NULL ;
-    }
-    CyaSSL_Cleanup() ;
+    ssl_free( &this->ssl );
+    ctr_drbg_free( &this->ctr_drbg );
+    entropy_free( &this->entropy );
+    this->ssl_connected = false;
 } 
 
 HTTPResult HTTPClient::connect(const char* url, HTTP_METH method, IHTTPDataOut* pDataOut, IHTTPDataIn* pDataIn, int timeout) //Execute request
 {
-    CYASSL_METHOD * SSLmethod = NULL;
     m_httpResponseCode = 0; //Invalidate code
     m_timeout = timeout;
     redirect = 0 ;
@@ -335,45 +385,15 @@
     }
 
     if(port == HTTPS_PORT) {
-
         /* Start SSL connect */
-        DBG("SSLver=%d", SSLver) ;
-        if(ctx == NULL) {
-            switch(SSLver) {
-            case 0 : SSLmethod = CyaSSLv3_client_method() ; break ;
-            case 1 : SSLmethod = CyaTLSv1_client_method() ; break ;
-            case 2 : SSLmethod = CyaTLSv1_1_client_method() ; break ;           
-            case 3 : SSLmethod = CyaTLSv1_2_client_method() ; break ;      
-            }
-            ctx = CyaSSL_CTX_new((CYASSL_METHOD *)SSLmethod);
-            if (ctx == NULL) {
-                ERR("unable to get ctx");
-                return HTTP_CONN;
-            }
-            CyaSSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, 0);
-            CyaSSL_SetIORecv(ctx, SocketReceive) ;
-            CyaSSL_SetIOSend(ctx, SocketSend) ;
-        }
-        if (ssl == NULL) {
-            ssl = CyaSSL_new(ctx);
-            if (ssl == NULL) {
-                ERR("unable to get SSL object");
-                cyassl_free() ;
-                return HTTP_CONN;
-            }
-        }
-        
-        DBG("ctx=%x, ssl=%x, ssl->ctx->CBIORecv, CBIOSend=%x, %x\n",ctx, ssl, SocketReceive, SocketSend ) ;
-        int result = CyaSSL_connect(ssl); 
-        if (result != SSL_SUCCESS) {
-            ERR("SSL_connect failed");
-            int err = CyaSSL_get_error(ssl, result);
-            char errorString[80];
-            CyaSSL_ERR_error_string(err, errorString);
-            ERR("SSL Error: %s (err=%d,status=%d)",errorString,err,result);
-            cyassl_free() ;
+        DBG("SSLver=%d", SSLver);
+        short ssl_connect_status = this->ssl_connect();
+        if (ssl_connect_status != 0) {
+            ERR("SSL connection failure: %d\r\n",ssl_connect_status);
+            ssl_cleanup();
             return HTTP_CONN;
         }
+        DBG("SSL connection succeeded...\r\n");
     } /* SSL connect complete */
 
     //Send request
@@ -668,7 +688,7 @@
         }
 
     }
-    cyassl_free() ;
+    ssl_cleanup() ;
     m_sock.close();
     DBG("Completed HTTP transaction");
     if(redirect)return HTTP_REDIRECT ;
@@ -688,15 +708,15 @@
     int ret;
 
     if(port == HTTPS_PORT) {
-        DBG("Enter CyaSSL_read") ;
+        DBG("Enter ssl_socket_read") ;
 
         m_sock.set_blocking(false, m_timeout);
-        readLen = CyaSSL_read(ssl, buf, maxLen);
+        readLen = ssl_socket_read(&this->ssl, buf, maxLen, m_timeout);
         if (readLen > 0) {
             buf[readLen] = 0;
-            DBG("CyaSSL_read:%s\n", buf);
+            DBG("ssl_socket_read:%s\n", buf);
         } else {
-            ERR("CyaSSL_read, ret = %d", readLen) ;
+            ERR("ssl_socket_read, ret = %d", readLen) ;
             return HTTP_ERROR ;
         }
         DBG("Read %d bytes", readLen);
@@ -789,12 +809,13 @@
     }
 
     if(port == HTTPS_PORT) {
-        DBG("Enter CyaSSL_write") ;
-        if (CyaSSL_write(ssl, buf, len) != len) {
-            ERR("SSL_write failed");
+        DBG("Enter ssl_socket_write");
+        int write_len = ssl_socket_write(&this->ssl, buf, len);
+        if (write_len != len) {
+            ERR("ssl_socket_write failed: wrote: %d bytes, expected to write %d bytes\r\n",write_len,len);
             return HTTP_ERROR ;
         }
-        DBG("Written %d bytes", writtenLen);
+        DBG("ssl_socket_write: sent %d bytes", writtenLen);
         return HTTP_OK;
     }
     m_sock.set_blocking(false, m_timeout);
--- a/HTTPClient.h	Tue Jun 09 16:26:02 2015 +0000
+++ b/HTTPClient.h	Thu Aug 20 18:55:41 2015 +0000
@@ -32,6 +32,11 @@
 #include "mbed.h"
 #include "TCPSocketConnection.h"
 
+#include "polarssl/ssl.h"
+#include "polarssl/net.h"
+#include "polarssl/entropy.h"
+#include "polarssl/ctr_drbg.h"
+
 ///HTTP client results
 enum HTTPResult {
     HTTP_PROCESSING, ///<Processing
@@ -59,8 +64,6 @@
     ///Instantiate the HTTP client
     HTTPClient();
     ~HTTPClient();
-    
-    
 
     /**
     Provides a OAUTH2 authentification feature 
@@ -150,18 +153,22 @@
     HTTPResult send(char* buf, size_t len = 0); //0 on success, err code on failure
     HTTPResult flush(void); //0 on success, err code on failure
     HTTPResult parseURL(const char* url, char* scheme, size_t maxSchemeLen, char* host, size_t maxHostLen, uint16_t* port, char* path, size_t maxPathLen); //Parse URL
-    void cyassl_free(void) ;
     HTTPResult bAuth(void) ;
     HTTPResult tokenAuth(void) ;
     HTTPResult readHeader(void) ;
     
+    // SSL internal methods...
+    void ssl_cleanup(void) ;
+    void ssl_setup(const unsigned char *tag);
+    short ssl_connect();
+    void set_ssl_version();
+    
     //Parameters
-
     int m_timeout;
     const char* m_basicAuthUser;
     const char* m_basicAuthPassword;
+    int m_httpResponseCode;
     const char* m_oauthToken;
-    int m_httpResponseCode;
 
     TCPSocketConnection m_sock;
     
@@ -170,11 +177,13 @@
     int    redirect_url_size ;
     int    redirect ;
     
-    /* for CyaSSL */
-    int    SSLver ;
-    uint16_t port;
-    struct CYASSL_CTX* ctx ;
-    struct CYASSL    * ssl ;
+    // mbedTLS Support
+    int                     SSLver;
+    uint16_t                port;
+    entropy_context         entropy;
+    ctr_drbg_context        ctr_drbg;
+    ssl_context             ssl;
+    bool                    ssl_connected;
 };
 
 //Including data containers here for more convenience
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbedTLSLibrary.lib	Thu Aug 20 18:55:41 2015 +0000
@@ -0,0 +1,1 @@
+http://developer.mbed.org/users/ansond/code/mbedTLSLibrary/#137634ff4186