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.
Dependents: SalesforceInterface df-2014-heroku-thermostat-k64f SalesforceInterface
Fork of HTTPClient by
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.
Revision 51:3bdf57f7fd60, committed 2015-08-20
- 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
--- 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