refactored a bit, added code debugging
This commit is contained in:
parent
797a3cdf94
commit
e7fdbfc00e
4 changed files with 113 additions and 42 deletions
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue