finished SSLCLient implementation, in process of fixing syntax errors and need to rigorously document
This commit is contained in:
parent
f4ea538dab
commit
0546070cbd
2 changed files with 226 additions and 59 deletions
|
@ -21,17 +21,28 @@
|
||||||
#include "SSLClient.h"
|
#include "SSLClient.h"
|
||||||
|
|
||||||
/** see SSLClient.h */
|
/** see SSLClient.h */
|
||||||
SSLClient::SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const bool debug) {
|
template<class C>
|
||||||
|
SSLClient<C>::SSLClient(const C &client, const br_x509_trust_anchor *trust_anchors, const size_t trust_anchors_num, const bool debug)
|
||||||
|
: m_client(client)
|
||||||
|
, m_trust_anchors(trust_anchors)
|
||||||
|
, m_trust_anchors_num(trust_anchors_num)
|
||||||
|
, 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
|
// 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);
|
||||||
// check if the buffer size is half or full duplex
|
// check if the buffer size is half or full duplex
|
||||||
constexpr auto duplex = sizeof iobuf <= BR_SSL_BUFSIZE_MONO ? 0 : 1;
|
constexpr auto duplex = sizeof iobuf <= BR_SSL_BUFSIZE_MONO ? 0 : 1;
|
||||||
br_ssl_engine_set_buffer(&m_sslctx, m_iobuf, sizeof m_iobuf, duplex);
|
br_ssl_engine_set_buffer(&m_sslctx, m_iobuf, sizeof m_iobuf, duplex);
|
||||||
br_sslio_init(&m_ioctx, &m_sslctx.eng, m_readraw, NULL, m_writeraw, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* see SSLClient.h */
|
/* see SSLClient.h */
|
||||||
virtual int SSLClient::connect(IPAddress ip, uint16_t port) {
|
template<class C>
|
||||||
|
int SSLClient<C>::connect(IPAddress ip, uint16_t port) {
|
||||||
|
// reset indexs for saftey
|
||||||
|
m_write_idx = 0;
|
||||||
// Warning for security
|
// Warning for security
|
||||||
m_print("Warning! Using a raw IP Address for an SSL connection bypasses some important verification steps\nYou should use a domain name (www.google.com) whenever possible.");
|
m_print("Warning! Using a raw IP Address for an SSL connection bypasses some important verification steps\nYou should use a domain name (www.google.com) whenever possible.");
|
||||||
// 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,
|
||||||
|
@ -46,7 +57,7 @@ virtual int SSLClient::connect(IPAddress ip, uint16_t port) {
|
||||||
// initlalize the SSL socket over the network
|
// initlalize the SSL socket over the network
|
||||||
// normally this would happen in br_sslio_write, but I think it makes
|
// normally this would happen in br_sslio_write, but I think it makes
|
||||||
// a little more structural sense to put it here
|
// a little more structural sense to put it here
|
||||||
if (m_run_until(ctx, BR_SSL_SENDAPP) < 0) {
|
if (m_run_until(BR_SSL_SENDAPP) < 0) {
|
||||||
m_print("Failed to initlalize the SSL layer");
|
m_print("Failed to initlalize the SSL layer");
|
||||||
setWriteError(SSL_BR_CONNECT_FAIL);
|
setWriteError(SSL_BR_CONNECT_FAIL);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -58,7 +69,10 @@ virtual int SSLClient::connect(IPAddress ip, uint16_t port) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* see SSLClient.h */
|
/* see SSLClient.h */
|
||||||
virtual int SSLClient::connect(const char *host, uint16_t port) {
|
template<class C>
|
||||||
|
int SSLClient<C>::connect(const char *host, uint16_t port) {
|
||||||
|
// reset indexs for saftey
|
||||||
|
m_write_idx = 0;
|
||||||
// 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 (!this->m_client.connect(host, port)) {
|
if (!this->m_client.connect(host, port)) {
|
||||||
|
@ -82,38 +96,62 @@ virtual int SSLClient::connect(const char *host, uint16_t port) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** see SSLClient.h TODO: fix */
|
/** see SSLClient.h */
|
||||||
virtual size_t SSLClient::write(const uint8_t *buf, size_t size) {
|
template<class C>
|
||||||
|
size_t SSLClient<C>::write(const uint8_t *buf, size_t size) {
|
||||||
// check if the socket is still open and such
|
// check if the socket is still open and such
|
||||||
if(!m_client.connected()) {
|
if(!m_client.connected()) {
|
||||||
m_print("Client is not connected! Perhaps something has happened?");
|
m_print("Client is not connected! Perhaps something has happened?");
|
||||||
|
br_ssl_engine_fail(m_sslctx->engine, BR_ERR_IO);
|
||||||
setWriteError(SSL_CLIENT_CONNECT_FAIL);
|
setWriteError(SSL_CLIENT_CONNECT_FAIL);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// write to the ssl socket using bearssl, and error check
|
// add to the bearssl io buffer, simply appending whatever we want to write
|
||||||
const auto status = br_sslio_write_all(&m_ioctx, buf, size);
|
size_t alen;
|
||||||
if (status != size) {
|
unsigned char *br_buf = br_ssl_engine_sendapp_buf(m_sslctx->engine, &alen);
|
||||||
if (status < 0) {
|
size_t cur_idx = 0;
|
||||||
m_print("Encountered a write error:");
|
// while there are still elements to write
|
||||||
if (m_client.getWriteError()) {
|
while (cur_idx < size) {
|
||||||
m_print("m_client write error");
|
// run until the ssl socket is ready to write, unless we've already written
|
||||||
setWriteError(SSL_CLIENT_WRTIE_ERROR);
|
// to the buffer in which we conclude it's already safe to write
|
||||||
}
|
if(m_write_idx == 0) {
|
||||||
else {
|
if (m_run_until(BR_SSL_SENDAPP) < 0) {
|
||||||
m_print("bearssl write error: ");
|
m_print("Error: could not run until sendapp");
|
||||||
m_print(err = br_ssl_engine_last_error(&m_sslctx.eng));
|
|
||||||
setWriteError(SSL_BR_WRITE_ERROR);
|
setWriteError(SSL_BR_WRITE_ERROR);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
// reset the buffer pointer
|
||||||
|
br_ssl_engine_sendapp_buf(m_sslctx->engine, &alen);
|
||||||
|
}
|
||||||
|
// sanity check
|
||||||
|
if(br_buf == NULL || alen == 0) {
|
||||||
|
m_print("Error: recieved null buffer or zero alen in write");
|
||||||
|
br_ssl_engine_fail(m_sslctx->engine, BR_ERR_IO);
|
||||||
|
setWriteError(SSL_BR_WRITE_ERROR);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
m_print("Warn: Wrote less than status! Something might be wrong");
|
// if we're about to fill the buffer, we need to send the data and then wait
|
||||||
|
// for another oppurtinity to send
|
||||||
|
const size_t cpamount = m_write_idx + (size - cur_idx) > alen ? alen : size - cur_idx;
|
||||||
|
memcpy(br_buf + m_write_idx, buf + cur_idx, cpamount);
|
||||||
|
// if we filled the buffer, reset m_write_idx
|
||||||
|
if (cpamount == alen) m_write_idx = 0;
|
||||||
|
// else increment
|
||||||
|
else m_write_idx += cpamount;
|
||||||
|
// increment the buffer pointer
|
||||||
|
cur_size += cpamount;
|
||||||
}
|
}
|
||||||
return status;
|
// works oky
|
||||||
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual int SSLClient::available() {
|
/** see SSLClient.h */
|
||||||
|
template<class C>
|
||||||
|
int SSLClient<C>::available() {
|
||||||
if (!m_client.connected()) {
|
if (!m_client.connected()) {
|
||||||
m_print("Cannot check available of disconnected client!");
|
m_print("Warn: Cannot check available of disconnected client");
|
||||||
|
br_ssl_engine_fail(m_sslctx->engine, BR_ERR_IO);
|
||||||
|
setWriteError(SSL_CLIENT_CONNECT_FAIL);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// run the SSL engine until we are waiting for either user input or a server response
|
// run the SSL engine until we are waiting for either user input or a server response
|
||||||
|
@ -121,14 +159,14 @@ virtual int SSLClient::available() {
|
||||||
if(state & BR_SSL_RECVAPP) {
|
if(state & BR_SSL_RECVAPP) {
|
||||||
// return how many received bytes we have
|
// return how many received bytes we have
|
||||||
size_t alen;
|
size_t alen;
|
||||||
br_ssl_engine_recvapp_buf(ctx->engine, &alen);
|
br_ssl_engine_recvapp_buf(m_sslctx->engine, &alen);
|
||||||
return (int)alen;
|
return (int)(alen);
|
||||||
}
|
}
|
||||||
else if (state == BR_SSL_CLOSED) m_print("Tried to check available when engine is closed!");
|
else if (state == BR_SSL_CLOSED) m_print("Error: Tried to check available when engine is closed");
|
||||||
// flush the buffer if it's stuck in the SENDAPP state
|
// flush the buffer if it's stuck in the SENDAPP state
|
||||||
else if (state & BR_SSL_SENDAPP) br_ssl_engine_flush(m_sslctx->engine, 0);
|
else if (state & BR_SSL_SENDAPP) br_ssl_engine_flush(m_sslctx->engine, 0);
|
||||||
else if (state == 0) {
|
else if (state == 0) {
|
||||||
m_print("SSL engine failed: ");
|
m_print("Error: SSL engine failed: ");
|
||||||
m_print(br_ssl_engine_last_error(&m_sslctx));
|
m_print(br_ssl_engine_last_error(&m_sslctx));
|
||||||
setWriteError(SSL_BR_WRITE_ERROR);
|
setWriteError(SSL_BR_WRITE_ERROR);
|
||||||
}
|
}
|
||||||
|
@ -136,7 +174,71 @@ virtual int SSLClient::available() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SSLClient::m_run_until(const unsigned target) {
|
/** see SSLClient.h */
|
||||||
|
template<class C>
|
||||||
|
int SSLClient<C>::read(uint8_t *buf, size_t size) {
|
||||||
|
// check that the engine is ready to read
|
||||||
|
else if (available()) {
|
||||||
|
// read the buffer, send the ack, and return the bytes read
|
||||||
|
size_t alen;
|
||||||
|
unsigned char* br_buf = br_ssl_engine_recvapp_buf(m_sslctx->engine, &alen);
|
||||||
|
const size_t read_amount = size > alen ? alen : size;
|
||||||
|
memcpy(buf, br_buf, read_amount);
|
||||||
|
// tell engine we read that many bytes
|
||||||
|
br_ssl_engine_sendapp_ack(m_sslctx->engine, read_amount);
|
||||||
|
// tell the user we read that many bytes
|
||||||
|
return read_amount;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** see SSLClient.h */
|
||||||
|
template<class C>
|
||||||
|
int SSLClient<C>::peek() {
|
||||||
|
// check that the engine is ready to read
|
||||||
|
if (available()) {
|
||||||
|
// read the buffer, send the ack, and return the bytes read
|
||||||
|
size_t alen;
|
||||||
|
uint8_t read_num;
|
||||||
|
read_num = br_ssl_engine_recvapp_buf(m_sslctx->engine, &alen)[0];
|
||||||
|
// tell the user we read that many bytes
|
||||||
|
return (int)read_num;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** see SSLClient.h */
|
||||||
|
template<class C>
|
||||||
|
void SSLClient<C>::flush() {
|
||||||
|
// trigger a flush, incase there's any leftover data
|
||||||
|
br_ssl_engine_flush(m_sslctx->engine, 0);
|
||||||
|
// run until application data is ready for pickup
|
||||||
|
if(m_run_until(BR_SSL_RECVAPP) < 0) m_print("Error: could not flush write buffer!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** see SSLClient.h */
|
||||||
|
template<class C>
|
||||||
|
void SSLClient<C>::stop() {
|
||||||
|
// tell the SSL connection to gracefully close
|
||||||
|
br_ssl_engine_close(m_sslctx->engine);
|
||||||
|
while (br_ssl_engine_current_state(m_sslctx->engine) != BR_SSL_CLOSED) {
|
||||||
|
/*
|
||||||
|
* Discard any incoming application data.
|
||||||
|
*/
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
m_run_until(BR_SSL_RECVAPP);
|
||||||
|
if (br_ssl_engine_recvapp_buf(m_sslctx->engine, &len) != NULL) {
|
||||||
|
br_ssl_engine_recvapp_ack(m_sslctx->engine, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// close the ethernet socket
|
||||||
|
m_client.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** see SSLClient.h */
|
||||||
|
template<class C>
|
||||||
|
int SSLClient<C>::m_run_until(const unsigned target) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
unsigned state = m_update_engine();
|
unsigned state = m_update_engine();
|
||||||
/*
|
/*
|
||||||
|
@ -150,9 +252,24 @@ int SSLClient::m_run_until(const unsigned target) {
|
||||||
* and that's not possible until the application data is
|
* and that's not possible until the application data is
|
||||||
* read. This may happen if using a shared in/out buffer,
|
* read. This may happen if using a shared in/out buffer,
|
||||||
* and the underlying protocol is not strictly half-duplex.
|
* and the underlying protocol is not strictly half-duplex.
|
||||||
* This is unrecoverable here, so we report an error.
|
* Normally this would be unrecoverable, however we can attempt
|
||||||
|
* to remedy the problem by telling the engine to discard
|
||||||
|
* the data.
|
||||||
*/
|
*/
|
||||||
if (state & BR_SSL_RECVAPP && target & BR_SSL_SENDAPP) return -1;
|
if (state & BR_SSL_RECVAPP && target & BR_SSL_SENDAPP) {
|
||||||
|
size_t len;
|
||||||
|
if (br_ssl_engine_recvapp_buf(m_sslctx->engine, &len) != NULL) {
|
||||||
|
m_write_idx = 0;
|
||||||
|
m_print("Warn: discarded unread data to favor a write operation");
|
||||||
|
br_ssl_engine_recvapp_ack(m_sslctx->engine, len);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_print("Error: ssl engine state is RECVAPP, however the buffer was null!");
|
||||||
|
br_ssl_engine_fail(m_sslctx->engine, BR_ERR_IO);
|
||||||
|
setWriteError(SSL_BR_WRITE_ERROR);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We can reach that point if the target RECVAPP, and
|
* We can reach that point if the target RECVAPP, and
|
||||||
|
@ -165,6 +282,8 @@ int SSLClient::m_run_until(const unsigned target) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** see SSLClient.h */
|
||||||
|
template<class C>
|
||||||
unsigned SSLClient::m_update_engine() {
|
unsigned SSLClient::m_update_engine() {
|
||||||
for(;;) {
|
for(;;) {
|
||||||
// get the state
|
// get the state
|
||||||
|
@ -179,9 +298,10 @@ unsigned SSLClient::m_update_engine() {
|
||||||
size_t len;
|
size_t len;
|
||||||
int wlen;
|
int wlen;
|
||||||
|
|
||||||
buf = br_ssl_engine_sendrec_buf(ctx->engine, &len);
|
buf = br_ssl_engine_sendrec_buf(m_sslctx->engine, &len);
|
||||||
wlen = m_client.write(buf, len);
|
wlen = m_client.write(buf, len);
|
||||||
if (wlen < 0) {
|
if (wlen < 0) {
|
||||||
|
m_print("Error writing to m_client");
|
||||||
/*
|
/*
|
||||||
* If we received a close_notify and we
|
* If we received a close_notify and we
|
||||||
* still send something, then we have our
|
* still send something, then we have our
|
||||||
|
@ -189,19 +309,64 @@ unsigned SSLClient::m_update_engine() {
|
||||||
* the peer is allowed by RFC 5246 not to
|
* the peer is allowed by RFC 5246 not to
|
||||||
* wait for it.
|
* wait for it.
|
||||||
*/
|
*/
|
||||||
if (!ctx->engine->shutdown_recv) {
|
if (!m_sslctx->engine->shutdown_recv) {
|
||||||
br_ssl_engine_fail(
|
br_ssl_engine_fail(
|
||||||
ctx->engine, BR_ERR_IO);
|
m_sslctx->engine, BR_ERR_IO);
|
||||||
}
|
}
|
||||||
setWriteError(SSL_BR_WRITE_ERROR);
|
setWriteError(SSL_BR_WRITE_ERROR);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (wlen > 0) {
|
if (wlen > 0) {
|
||||||
br_ssl_engine_sendrec_ack(ctx->engine, wlen);
|
br_ssl_engine_sendrec_ack(m_sslctx->engine, wlen);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the client has specified there is client data to send, and
|
||||||
|
* the engine is ready to handle it, send it along.
|
||||||
|
*/
|
||||||
|
if (m_write_idx > 0) {
|
||||||
|
// if we've reached the point where BR_SSL_SENDAPP is off but
|
||||||
|
// data has been written to the io buffer, something is wrong
|
||||||
|
if (!(state & BR_SSL_SENDAPP)) {
|
||||||
|
m_print("Error m_write_idx > 0 but the ssl engine is not ready for data");
|
||||||
|
br_ssl_engine_fail(m_sslctx->engine, BR_ERR_IO);
|
||||||
|
setWriteError(SSL_BR_WRITE_ERROR);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// else time to send the application data
|
||||||
|
else if (state & BR_SSL_SENDAPP) {
|
||||||
|
size_t alen;
|
||||||
|
unsigned char *buf = br_ssl_engine_sendapp_buf(m_sslctx->engine, &alen);
|
||||||
|
// engine check
|
||||||
|
if (alen == 0 || buf == NULL) {
|
||||||
|
m_print("Error: engine set write flag but returned null buffer");
|
||||||
|
br_ssl_engine_fail(m_sslctx->engine, BR_ERR_IO);
|
||||||
|
setWriteError(SSL_BR_WRITE_ERROR);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// sanity check
|
||||||
|
if (alen < m_write_idx) {
|
||||||
|
m_print("Error: alen is less than m_write_idx");
|
||||||
|
br_ssl_engine_fail(m_sslctx->engine, BR_ERR_IO);
|
||||||
|
setWriteError(SSL_INTERNAL_ERROR);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// all good? lets send the data
|
||||||
|
// presumably the SSLClient::write function has already added
|
||||||
|
// data to *buf, so now we tell bearssl it's time for the
|
||||||
|
// encryption step.
|
||||||
|
// this will encrypt the data and presumably spit it out
|
||||||
|
// for BR_SSL_SENDREC to send over ethernet.
|
||||||
|
br_ssl_engine_sendapp_ack(m_sslctx->engine, m_write_idx);
|
||||||
|
// reset the iobuffer index
|
||||||
|
m_write_idx = 0;
|
||||||
|
// loop again!
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there is some record data to recieve, check if we've
|
* If there is some record data to recieve, check if we've
|
||||||
* recieved it so far. If we have, then we can update the state.
|
* recieved it so far. If we have, then we can update the state.
|
||||||
|
@ -209,18 +374,19 @@ unsigned SSLClient::m_update_engine() {
|
||||||
*/
|
*/
|
||||||
if (state & BR_SSL_RECVREC) {
|
if (state & BR_SSL_RECVREC) {
|
||||||
size_t len;
|
size_t len;
|
||||||
unsigned char * buf = br_ssl_engine_recvrec_buf(ctx->engine, &len);
|
unsigned char * buf = br_ssl_engine_recvrec_buf(m_sslctx->engine, &len);
|
||||||
// do we have the record you're looking for?
|
// do we have the record you're looking for?
|
||||||
if (m_client.available() >= len) {
|
if (m_client.available() >= len) {
|
||||||
// I suppose so!
|
// I suppose so!
|
||||||
int rlen = m_client.readBytes((char *)buf, len);
|
int rlen = m_client.readBytes((char *)buf, len);
|
||||||
if (rlen < 0) {
|
if (rlen < 0) {
|
||||||
br_ssl_engine_fail(ctx->engine, BR_ERR_IO);
|
m_print("Error reading bytes from m_client");
|
||||||
|
br_ssl_engine_fail(m_sslctx->engine, BR_ERR_IO);
|
||||||
setWriteError(SSL_BR_WRITE_ERROR);
|
setWriteError(SSL_BR_WRITE_ERROR);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (rlen > 0) {
|
if (rlen > 0) {
|
||||||
br_ssl_engine_recvrec_ack(ctx->engine, rlen);
|
br_ssl_engine_recvrec_ack(m_sslctx->engine, rlen);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
#include "bearssl.h"
|
#include "bearssl.h"
|
||||||
#include "Client.h"
|
#include "Client.h"
|
||||||
|
|
||||||
#ifdef SSLClient_H_
|
#ifndef SSLClient_H_
|
||||||
#define SSLClient_H_
|
#define SSLClient_H_
|
||||||
|
|
||||||
template <class C>
|
template <class C>
|
||||||
|
@ -46,20 +46,23 @@ class SSLClient : public Client {
|
||||||
* actually present on class C. It does this by first checking that the
|
* actually present on class C. It does this by first checking that the
|
||||||
* class inherits from Client, and then that it contains a status() function.
|
* class inherits from Client, and then that it contains a status() function.
|
||||||
*/
|
*/
|
||||||
static_assert(std::is_base_of(Client, C)::value, "C must be a Client Class!");
|
//static_assert(std::is_base_of(Client, C)::value, "C must be a Client Class!");
|
||||||
static_assert(std::is_function(decltype(C::status))::value, "C must have a status() function!");
|
//static_assert(std::is_function(decltype(C::status))::value, "C must have a status() function!");
|
||||||
|
|
||||||
/** error enums
|
/** error enums
|
||||||
* Static constants defining the possible errors encountered
|
* Static constants defining the possible errors encountered
|
||||||
* Read from getWriteError();
|
* Read from getWriteError();
|
||||||
*/
|
*/
|
||||||
|
/*
|
||||||
enum Error {
|
enum Error {
|
||||||
SSL_OK = 0,
|
SSL_OK = 0,
|
||||||
SSL_CLIENT_CONNECT_FAIL,
|
SSL_CLIENT_CONNECT_FAIL,
|
||||||
SSL_BR_CONNECT_FAIL,
|
SSL_BR_CONNECT_FAIL,
|
||||||
SSL_CLIENT_WRTIE_ERROR,
|
SSL_CLIENT_WRTIE_ERROR,
|
||||||
SSL_BR_WRITE_ERROR,
|
SSL_BR_WRITE_ERROR,
|
||||||
|
SSL_INTERNAL_ERROR
|
||||||
};
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
|
@ -77,12 +80,7 @@ public:
|
||||||
* @param trust_anchors_num The number of trust anchors stored
|
* @param trust_anchors_num The number of trust anchors stored
|
||||||
* @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 bool debug = true);
|
||||||
: m_client(client)
|
|
||||||
, m_trust_anchors(trust_anchors)
|
|
||||||
, m_trust_anchors_num(trust_anchors_num)
|
|
||||||
, m_debug(debug);
|
|
||||||
|
|
||||||
/** Dtor is implicit since unique_ptr handles it fine */
|
/** Dtor is implicit since unique_ptr handles it fine */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -127,7 +125,7 @@ public:
|
||||||
* @error SSL_CLIENT_CONNECT_FAIL The client object could not connect to the host or port
|
* @error SSL_CLIENT_CONNECT_FAIL The client object could not connect to the host or port
|
||||||
* @error SSL_BR_CONNECT_FAIL BearSSL could not initialize the SSL connection.
|
* @error SSL_BR_CONNECT_FAIL BearSSL could not initialize the SSL connection.
|
||||||
*/
|
*/
|
||||||
virtual int connect(IPAddress ip, uint16_t port = 443);
|
virtual int connect(IPAddress ip, uint16_t port);
|
||||||
/**
|
/**
|
||||||
* @brief Connect over SSL using connect(ip, port), but use a DNS lookup to
|
* @brief Connect over SSL using connect(ip, port), but use a DNS lookup to
|
||||||
* get the IP Address first.
|
* get the IP Address first.
|
||||||
|
@ -151,11 +149,11 @@ public:
|
||||||
* @error SSL_CLIENT_CONNECT_FAIL The client object could not connect to the host or port
|
* @error SSL_CLIENT_CONNECT_FAIL The client object could not connect to the host or port
|
||||||
* @error SSL_BR_CONNECT_FAIL BearSSL could not initialize the SSL connection.
|
* @error SSL_BR_CONNECT_FAIL BearSSL could not initialize the SSL connection.
|
||||||
*/
|
*/
|
||||||
virtual int connect(const char *host, uint16_t port = 443);
|
virtual int connect(const char *host, uint16_t port);
|
||||||
virtual size_t write(uint8_t b) { return write(&b, 1); }
|
virtual size_t write(uint8_t b) { return write(&b, 1); }
|
||||||
virtual size_t write(const uint8_t *buf, size_t size);
|
virtual size_t write(const uint8_t *buf, size_t size);
|
||||||
virtual int available();
|
virtual int available();
|
||||||
virtual int read();
|
virtual int read() { int peeked = peek(); if(peek != -1) br_ssl_engine_recvapp_ack(m_sslctx->engine, 1); return peek; }
|
||||||
virtual int read(uint8_t *buf, size_t size);
|
virtual int read(uint8_t *buf, size_t size);
|
||||||
virtual int peek();
|
virtual int peek();
|
||||||
virtual void flush();
|
virtual void flush();
|
||||||
|
@ -167,8 +165,8 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/** @brief debugging print function, only prints if m_debug is true */
|
/** @brief debugging print function, only prints if m_debug is true */
|
||||||
template<type T>
|
template<typename T>
|
||||||
constexpr void m_print(const T str) {
|
constexpr void m_print(const T str) const {
|
||||||
if (m_debug) {
|
if (m_debug) {
|
||||||
Serial.print("SSLClient: ");
|
Serial.print("SSLClient: ");
|
||||||
Serial.println(str);
|
Serial.println(str);
|
||||||
|
@ -177,15 +175,15 @@ private:
|
||||||
/** 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 */
|
||||||
int m_update_engine();
|
unsigned m_update_engine();
|
||||||
// create a copy of the client
|
// create a copy of the client
|
||||||
const C m_client;
|
C m_client;
|
||||||
// store pointers to the trust anchors
|
// store pointers to the trust anchors
|
||||||
// should not be computed at runtime
|
// should not be computed at runtime
|
||||||
constexpr br_x509_trust_anchor *m_trust_anchors;
|
const br_x509_trust_anchor *m_trust_anchors;
|
||||||
constexpr size_t m_trust_anchors_num;
|
const size_t m_trust_anchors_num;
|
||||||
// store whether to enable debug logging
|
// store whether to enable debug logging
|
||||||
constexpr bool m_debug;
|
const bool m_debug;
|
||||||
// store the context values required for SSL
|
// store the context values required for SSL
|
||||||
br_ssl_client_context m_sslctx;
|
br_ssl_client_context m_sslctx;
|
||||||
br_x509_minimal_context m_x509ctx;
|
br_x509_minimal_context m_x509ctx;
|
||||||
|
@ -194,8 +192,11 @@ private:
|
||||||
// or shrink to below BR_SSL_BUFSIZE_MONO, and bearSSL will adapt automatically
|
// or shrink to below BR_SSL_BUFSIZE_MONO, and bearSSL will adapt automatically
|
||||||
// simply edit this value to change the buffer size to the desired value
|
// simply edit this value to change the buffer size to the desired value
|
||||||
unsigned char m_iobuf[BR_SSL_BUFSIZE_MONO];
|
unsigned char m_iobuf[BR_SSL_BUFSIZE_MONO];
|
||||||
static_assert(sizeof m_iobuf <= BR_SSL_BUFSIZE_BIDI);
|
// static_assert(sizeof m_iobuf <= BR_SSL_BUFSIZE_BIDI);
|
||||||
br_sslio_context m_ioctx;
|
// store the index of where we are writing in the buffer
|
||||||
|
// so we can send our records all at once to prevent
|
||||||
|
// weird timing issues
|
||||||
|
size_t m_write_idx;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /** SSLClient_H_ */
|
#endif /** SSLClient_H_ */
|
Loading…
Reference in a new issue