From e7fdbfc00e62eb51b13ec9ea68a15cef03ee4c48 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Wed, 27 Feb 2019 21:26:54 -0800 Subject: [PATCH] refactored a bit, added code debugging --- src/SSLClient.h | 8 +- src/SSLClientImpl.cpp | 123 +++++++++++++++++-------- src/SSLClientImpl.h | 24 ++++- src/{bearssl => }/TLS12_only_profile.c | 0 4 files changed, 113 insertions(+), 42 deletions(-) rename src/{bearssl => }/TLS12_only_profile.c (100%) diff --git a/src/SSLClient.h b/src/SSLClient.h index 176e51d..1ce3647 100644 --- a/src/SSLClient.h +++ b/src/SSLClient.h @@ -89,16 +89,18 @@ public: * is going to exists past the inital creation of the SSLClient. * * @pre The client class must be able to access the internet, as SSLClient - * cannot manage this for you. + * cannot manage this for you. Additionally it is recommended that the analog_pin + * be set to input. * * @param trust_anchors Trust anchors used in the verification * of the SSL server certificate, generated using the `brssl` command * line utility. For more information see the samples or bearssl.org * @param trust_anchors_num The number of trust anchors stored + * @param analog_pin An analog pin to pull random bytes from, used in seeding the RNG * @param debug whether to enable or disable debug logging, must be constexpr */ - SSLClient(const C& client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const bool debug = true) - : SSLClientImpl(NULL, trust_anchors, trust_anchors_num, debug) + explicit SSLClient(const C& client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const bool debug = true) + : SSLClientImpl(NULL, trust_anchors, trust_anchors_num, analog_pin, debug) , m_client(client) { // since we are copying the client in the ctor, we have to set diff --git a/src/SSLClientImpl.cpp b/src/SSLClientImpl.cpp index f28ed75..6156a0e 100644 --- a/src/SSLClientImpl.cpp +++ b/src/SSLClientImpl.cpp @@ -21,17 +21,19 @@ #include "SSLClient.h" /** see SSLClientImpl.h */ -SSLClientImpl::SSLClientImpl(Client* client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const bool debug) +SSLClientImpl::SSLClientImpl(Client* client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const bool debug) : m_client(client) , m_trust_anchors(trust_anchors) , m_trust_anchors_num(trust_anchors_num) + , m_analog_pin(analog_pin) , m_debug(debug) , m_write_idx(0) { // zero the iobuf just in case it's still garbage memset(m_iobuf, 0, sizeof m_iobuf); // initlalize the various bearssl libraries so they're ready to go when we connect - br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num); + // br_client_init_TLS12_only(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num); + br_ssl_client_init_full(&m_sslctx, &m_x509ctx, m_trust_anchors, m_trust_anchors_num); // check if the buffer size is half or full duplex constexpr auto duplex = sizeof m_iobuf <= BR_SSL_BUFSIZE_MONO ? 0 : 1; br_ssl_engine_set_buffer(&m_sslctx.eng, m_iobuf, sizeof m_iobuf, duplex); @@ -46,24 +48,12 @@ int SSLClientImpl::connect(IPAddress ip, uint16_t port) { // first we need our hidden client member to negotiate the socket for us, // since most times socket functionality is implemented in hardeware. if (!m_client->connect(ip, port)) { - m_print("Failed to connect using m_client"); + m_print("Error: Failed to connect using m_client"); setWriteError(SSL_CLIENT_CONNECT_FAIL); return 0; } - // reset the client context, and look for previous sessions - br_ssl_client_reset(&m_sslctx, NULL, 1); - // initlalize the SSL socket over the network - // normally this would happen in br_sslio_write, but I think it makes - // a little more structural sense to put it here - if (m_run_until(BR_SSL_SENDAPP) < 0) { - m_print("Failed to initlalize the SSL layer"); - setWriteError(SSL_BR_CONNECT_FAIL); - return 0; - } - // all good to go! the SSL socket should be up and running - m_print("SSL Initialized"); - setWriteError(SSL_OK); - return 1; + m_print("Base ethernet client connected!"); + return m_start_ssl(); } /* see SSLClientImpl.h*/ @@ -73,24 +63,12 @@ int SSLClientImpl::connect(const char *host, uint16_t port) { // first we need our hidden client member to negotiate the socket for us, // since most times socket functionality is implemented in hardeware. if (!m_client->connect(host, port)) { - m_print("Failed to connect using m_client"); + m_print("Error: Failed to connect using m_client"); setWriteError(SSL_CLIENT_CONNECT_FAIL); return 0; } - // reset the client context, and look for previous sessions - br_ssl_client_reset(&m_sslctx, host, 1); - // initlalize the SSL socket over the network - // normally this would happen in br_sslio_write, but I think it makes - // a little more structural sense to put it here - if (m_run_until(BR_SSL_SENDAPP) < 0) { - m_print("Failed to initlalize the SSL layer"); - setWriteError(SSL_BR_CONNECT_FAIL); - return 0; - } - // all good to go! the SSL socket should be up and running - m_print("SSL Initialized"); - setWriteError(SSL_OK); - return 1; + m_print("Base ethernet client connected!"); + return m_start_ssl(host); } /** see SSLClientImpl.h*/ @@ -235,11 +213,60 @@ uint8_t SSLClientImpl::connected() { return c_con && br_con && wr_ok; } +/** see SSLClientImpl.h */ +int SSLClientImpl::m_start_ssl(const char* host) { + // get some random data by reading the analog pin we've been handed + // we want 128 bits to be safe, as recommended by the bearssl docs + uint8_t rng_seeds[16]; + // take the bottom 8 bits of the analog read + for (uint8_t i = 0; i < sizeof rng_seeds; i++) rng_seeds[i] = static_cast(analogRead(m_analog_pin)); + br_ssl_engine_inject_entropy(&m_sslctx.eng, rng_seeds, sizeof rng_seeds); + // reset the client context, and look for previous sessions + auto ret = br_ssl_client_reset(&m_sslctx, host, 1); + if (!ret) { + m_print("Error: reset failed"); + m_print(br_ssl_engine_last_error(&m_sslctx.eng)); + } + // initlalize the SSL socket over the network + // normally this would happen in br_sslio_write, but I think it makes + // a little more structural sense to put it here + if (m_run_until(BR_SSL_SENDAPP) < 0) { + m_print("Error: Failed to initlalize the SSL layer"); + setWriteError(SSL_BR_CONNECT_FAIL); + return 0; + } + // all good to go! the SSL socket should be up and running + m_print("SSL Initialized"); + setWriteError(SSL_OK); + return 1; +} + /** see SSLClientImpl.h*/ int SSLClientImpl::m_run_until(const unsigned target) { + unsigned lastState = 0; + size_t lastLen = 0; for (;;) { + // error check + if (!connected()) { + m_print("Error: tried to run_until when the engine is closed"); + return -1; + } unsigned state = m_update_engine(); - /* + // debug + if (state != lastState) { + lastState = state; + m_print("m_run stuck:"); + printState(state); + } + if (state & BR_SSL_RECVREC) { + size_t len; + unsigned char * buf = br_ssl_engine_recvrec_buf(&m_sslctx.eng, &len); + if (lastLen != len) { + m_print("Expected bytes count: "); + m_print(lastLen = len); + } + } + /* * If we reached our target, then we are finished. */ if (state & target) return 0; @@ -260,6 +287,7 @@ int SSLClientImpl::m_run_until(const unsigned target) { m_write_idx = 0; m_print("Warn: discarded unread data to favor a write operation"); br_ssl_engine_recvapp_ack(&m_sslctx.eng, len); + continue; } else { m_print("Error: ssl engine state is RECVAPP, however the buffer was null!"); @@ -276,6 +304,9 @@ int SSLClientImpl::m_run_until(const unsigned target) { * record. */ if (state & BR_SSL_SENDAPP && target & BR_SSL_RECVAPP) br_ssl_engine_flush(&m_sslctx.eng, 0); + + // debug delay + delay(500); } } @@ -368,10 +399,24 @@ unsigned SSLClientImpl::m_update_engine() { size_t len; unsigned char * buf = br_ssl_engine_recvrec_buf(&m_sslctx.eng, &len); // do we have the record you're looking for? - if (m_client->available() >= len) { + const auto avail = m_client->available(); + if (avail >= len) { + m_print("Read bytes from client: "); + m_print(avail); + m_print(len); + /* + unsigned char debug[avail]; + m_client->read(debug, avail); + for (size_t i = 0; i < avail; i++) { + Serial.print("0x"); + Serial.print(debug[i], HEX); + Serial.print(", "); + } + while(true) {} + */ // I suppose so! - int rlen = m_client->readBytes((char *)buf, len); - if (rlen < 0) { + int rlen = m_client->read(buf, len); + if (rlen <= 0) { m_print("Error reading bytes from m_client"); setWriteError(SSL_BR_WRITE_ERROR); return 0; @@ -382,7 +427,11 @@ unsigned SSLClientImpl::m_update_engine() { continue; } // guess not, tell the state we're waiting still - else return state; + else { + m_print("Bytes avail: "); + m_print(avail); + return state; + } } // if it's not any of the above states, then it must be waiting to send or recieve app data // in which case we return diff --git a/src/SSLClientImpl.h b/src/SSLClientImpl.h index 0bde340..21fe88f 100644 --- a/src/SSLClientImpl.h +++ b/src/SSLClientImpl.h @@ -33,7 +33,8 @@ public: * @brief initializes SSL contexts for bearSSL * * @pre The client class must be able to access the internet, as SSLClient - * cannot manage this for you. + * cannot manage this for you. Additionally it is recommended that the analog_pin + * be set to input. * * @post set_client must be called immediatly after to set the client class * pointer. @@ -42,9 +43,10 @@ public: * of the SSL server certificate, generated using the `brssl` command * line utility. For more information see the samples or bearssl.org * @param trust_anchors_num The number of trust anchors stored + * @param analog_pin An analog pin to pull random bytes from, used in seeding the RNG * @param debug whether to enable or disable debug logging, must be constexpr */ - explicit SSLClientImpl(Client* client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const bool debug = true); + explicit SSLClientImpl(Client* client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const int analog_pin, const bool debug = true); /** Dtor is implicit since unique_ptr handles it fine */ /** functions specific to the EthernetClient which I'll have to override */ @@ -128,6 +130,22 @@ private: Serial.println(str); } } + + void printState(unsigned state) const { + if(m_debug) { + m_print("State: "); + if(state == 0) m_print(" Invalid"); + else if (state & BR_SSL_CLOSED) m_print(" Connection closed"); + else { + if (state & BR_SSL_SENDREC) m_print(" SENDREC"); + if (state & BR_SSL_RECVREC) m_print(" RECVREC"); + if (state & BR_SSL_SENDAPP) m_print(" SENDAPP"); + if (state & BR_SSL_RECVAPP) m_print(" RECVAPP"); + } + } + } + /** start the ssl engine on the connected client */ + int m_start_ssl(const char* host = NULL); /** run the bearssl engine until a certain state */ int m_run_until(const unsigned target); /** proxy for availble that returns the state */ @@ -138,6 +156,8 @@ private: // should not be computed at runtime const br_x509_trust_anchor *m_trust_anchors; const size_t m_trust_anchors_num; + // store the pin to fetch an RNG see from + const int m_analog_pin; // store whether to enable debug logging const bool m_debug; // store the context values required for SSL diff --git a/src/bearssl/TLS12_only_profile.c b/src/TLS12_only_profile.c similarity index 100% rename from src/bearssl/TLS12_only_profile.c rename to src/TLS12_only_profile.c