refactored a bit, added code debugging

This commit is contained in:
Noah Laptop 2019-02-27 21:26:54 -08:00
parent 797a3cdf94
commit e7fdbfc00e
4 changed files with 113 additions and 42 deletions

View file

@ -89,16 +89,18 @@ public:
* is going to exists past the inital creation of the SSLClient. * is going to exists past the inital creation of the SSLClient.
* *
* @pre The client class must be able to access the internet, as 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 * @param trust_anchors Trust anchors used in the verification
* of the SSL server certificate, generated using the `brssl` command * of the SSL server certificate, generated using the `brssl` command
* line utility. For more information see the samples or bearssl.org * line utility. For more information see the samples or bearssl.org
* @param trust_anchors_num The number of trust anchors stored * @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 * @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) 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, debug) : SSLClientImpl(NULL, trust_anchors, trust_anchors_num, analog_pin, debug)
, m_client(client) , m_client(client)
{ {
// since we are copying the client in the ctor, we have to set // since we are copying the client in the ctor, we have to set

View file

@ -21,17 +21,19 @@
#include "SSLClient.h" #include "SSLClient.h"
/** see SSLClientImpl.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_client(client)
, m_trust_anchors(trust_anchors) , m_trust_anchors(trust_anchors)
, m_trust_anchors_num(trust_anchors_num) , m_trust_anchors_num(trust_anchors_num)
, m_analog_pin(analog_pin)
, m_debug(debug) , m_debug(debug)
, m_write_idx(0) { , m_write_idx(0) {
// zero the iobuf just in case it's still garbage // zero the iobuf just in case it's still garbage
memset(m_iobuf, 0, sizeof m_iobuf); memset(m_iobuf, 0, sizeof m_iobuf);
// initlalize the various bearssl libraries so they're ready to go when we connect // 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 // check if the buffer size is half or full duplex
constexpr auto duplex = sizeof m_iobuf <= BR_SSL_BUFSIZE_MONO ? 0 : 1; 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); 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, // first we need our hidden client member to negotiate the socket for us,
// since most times socket functionality is implemented in hardeware. // since most times socket functionality is implemented in hardeware.
if (!m_client->connect(ip, port)) { 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); setWriteError(SSL_CLIENT_CONNECT_FAIL);
return 0; return 0;
} }
// reset the client context, and look for previous sessions m_print("Base ethernet client connected!");
br_ssl_client_reset(&m_sslctx, NULL, 1); return m_start_ssl();
// 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;
} }
/* see SSLClientImpl.h*/ /* 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, // first we need our hidden client member to negotiate the socket for us,
// since most times socket functionality is implemented in hardeware. // since most times socket functionality is implemented in hardeware.
if (!m_client->connect(host, port)) { 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); setWriteError(SSL_CLIENT_CONNECT_FAIL);
return 0; return 0;
} }
// reset the client context, and look for previous sessions m_print("Base ethernet client connected!");
br_ssl_client_reset(&m_sslctx, host, 1); return m_start_ssl(host);
// 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;
} }
/** see SSLClientImpl.h*/ /** see SSLClientImpl.h*/
@ -235,10 +213,59 @@ uint8_t SSLClientImpl::connected() {
return c_con && br_con && wr_ok; 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<uint8_t>(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*/ /** see SSLClientImpl.h*/
int SSLClientImpl::m_run_until(const unsigned target) { int SSLClientImpl::m_run_until(const unsigned target) {
unsigned lastState = 0;
size_t lastLen = 0;
for (;;) { for (;;) {
// error check
if (!connected()) {
m_print("Error: tried to run_until when the engine is closed");
return -1;
}
unsigned state = m_update_engine(); 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 we reached our target, then we are finished.
*/ */
@ -260,6 +287,7 @@ int SSLClientImpl::m_run_until(const unsigned target) {
m_write_idx = 0; m_write_idx = 0;
m_print("Warn: discarded unread data to favor a write operation"); m_print("Warn: discarded unread data to favor a write operation");
br_ssl_engine_recvapp_ack(&m_sslctx.eng, len); br_ssl_engine_recvapp_ack(&m_sslctx.eng, len);
continue;
} }
else { else {
m_print("Error: ssl engine state is RECVAPP, however the buffer was null!"); 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. * record.
*/ */
if (state & BR_SSL_SENDAPP && target & BR_SSL_RECVAPP) br_ssl_engine_flush(&m_sslctx.eng, 0); 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; size_t len;
unsigned char * buf = br_ssl_engine_recvrec_buf(&m_sslctx.eng, &len); unsigned char * buf = br_ssl_engine_recvrec_buf(&m_sslctx.eng, &len);
// do we have the record you're looking for? // 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! // I suppose so!
int rlen = m_client->readBytes((char *)buf, len); int rlen = m_client->read(buf, len);
if (rlen < 0) { if (rlen <= 0) {
m_print("Error reading bytes from m_client"); m_print("Error reading bytes from m_client");
setWriteError(SSL_BR_WRITE_ERROR); setWriteError(SSL_BR_WRITE_ERROR);
return 0; return 0;
@ -382,7 +427,11 @@ unsigned SSLClientImpl::m_update_engine() {
continue; continue;
} }
// guess not, tell the state we're waiting still // 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 // 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 // in which case we return

View file

@ -33,7 +33,8 @@ public:
* @brief initializes SSL contexts for bearSSL * @brief initializes SSL contexts for bearSSL
* *
* @pre The client class must be able to access the internet, as 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.
* *
* @post set_client must be called immediatly after to set the client class * @post set_client must be called immediatly after to set the client class
* pointer. * pointer.
@ -42,9 +43,10 @@ public:
* of the SSL server certificate, generated using the `brssl` command * of the SSL server certificate, generated using the `brssl` command
* line utility. For more information see the samples or bearssl.org * line utility. For more information see the samples or bearssl.org
* @param trust_anchors_num The number of trust anchors stored * @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 * @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 */ /** Dtor is implicit since unique_ptr handles it fine */
/** functions specific to the EthernetClient which I'll have to override */ /** functions specific to the EthernetClient which I'll have to override */
@ -128,6 +130,22 @@ private:
Serial.println(str); 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 */ /** run the bearssl engine until a certain state */
int m_run_until(const unsigned target); int m_run_until(const unsigned target);
/** proxy for availble that returns the state */ /** proxy for availble that returns the state */
@ -138,6 +156,8 @@ private:
// should not be computed at runtime // should not be computed at runtime
const br_x509_trust_anchor *m_trust_anchors; const br_x509_trust_anchor *m_trust_anchors;
const size_t m_trust_anchors_num; 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 // store whether to enable debug logging
const bool m_debug; const bool m_debug;
// store the context values required for SSL // store the context values required for SSL