added unix timestamp macro, fixed RNG implementation with analog pin, fixed bugs (client works now!)

This commit is contained in:
Noah Laptop 2019-02-28 15:44:21 -08:00
parent e7fdbfc00e
commit 79a0a6135b
4 changed files with 165 additions and 31 deletions

View file

@ -32,8 +32,8 @@ SSLClientImpl::SSLClientImpl(Client* client, const br_x509_trust_anchor *trust_a
// 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); // 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);
@ -74,7 +74,7 @@ int SSLClientImpl::connect(const char *host, uint16_t port) {
/** see SSLClientImpl.h*/ /** see SSLClientImpl.h*/
size_t SSLClientImpl::write(const uint8_t *buf, size_t size) { size_t SSLClientImpl::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(!connected()) { if(br_ssl_engine_current_state(&m_sslctx.eng) == BR_SSL_CLOSED || getWriteError()) {
m_print("Client is not connected! Perhaps something has happened?"); m_print("Client is not connected! Perhaps something has happened?");
return 0; return 0;
} }
@ -119,7 +119,7 @@ size_t SSLClientImpl::write(const uint8_t *buf, size_t size) {
/** see SSLClientImpl.h*/ /** see SSLClientImpl.h*/
int SSLClientImpl::available() { int SSLClientImpl::available() {
// connection check // connection check
if (!connected()) { if (br_ssl_engine_current_state(&m_sslctx.eng) == BR_SSL_CLOSED || getWriteError()) {
m_print("Warn: Cannot check available of disconnected client"); m_print("Warn: Cannot check available of disconnected client");
return 0; return 0;
} }
@ -153,7 +153,7 @@ int SSLClientImpl::read(uint8_t *buf, size_t size) {
const size_t read_amount = size > alen ? alen : size; const size_t read_amount = size > alen ? alen : size;
memcpy(buf, br_buf, read_amount); memcpy(buf, br_buf, read_amount);
// tell engine we read that many bytes // tell engine we read that many bytes
br_ssl_engine_sendapp_ack(&m_sslctx.eng, read_amount); br_ssl_engine_recvapp_ack(&m_sslctx.eng, read_amount);
// tell the user we read that many bytes // tell the user we read that many bytes
return read_amount; return read_amount;
} }
@ -221,7 +221,6 @@ int SSLClientImpl::m_start_ssl(const char* host) {
// take the bottom 8 bits of the analog read // 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)); 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); 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); auto ret = br_ssl_client_reset(&m_sslctx, host, 1);
if (!ret) { if (!ret) {
m_print("Error: reset failed"); m_print("Error: reset failed");
@ -232,11 +231,13 @@ int SSLClientImpl::m_start_ssl(const char* host) {
// a little more structural sense to put it here // a little more structural sense to put it here
if (m_run_until(BR_SSL_SENDAPP) < 0) { if (m_run_until(BR_SSL_SENDAPP) < 0) {
m_print("Error: Failed to initlalize the SSL layer"); m_print("Error: Failed to initlalize the SSL layer");
m_print(br_ssl_engine_last_error(&m_sslctx.eng));
setWriteError(SSL_BR_CONNECT_FAIL); setWriteError(SSL_BR_CONNECT_FAIL);
return 0; return 0;
} }
// all good to go! the SSL socket should be up and running // all good to go! the SSL socket should be up and running
m_print("SSL Initialized"); m_print("SSL Initialized");
m_print(m_sslctx.eng.selected_protocol);
setWriteError(SSL_OK); setWriteError(SSL_OK);
return 1; return 1;
} }
@ -246,12 +247,12 @@ int SSLClientImpl::m_run_until(const unsigned target) {
unsigned lastState = 0; unsigned lastState = 0;
size_t lastLen = 0; size_t lastLen = 0;
for (;;) { for (;;) {
unsigned state = m_update_engine();
// error check // error check
if (!connected()) { if (state == BR_SSL_CLOSED || getWriteError()) {
m_print("Error: tried to run_until when the engine is closed"); m_print("Error: tried to run_until when the engine is closed");
return -1; return -1;
} }
unsigned state = m_update_engine();
// debug // debug
if (state != lastState) { if (state != lastState) {
lastState = state; lastState = state;
@ -304,9 +305,6 @@ 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);
} }
} }
@ -327,6 +325,7 @@ unsigned SSLClientImpl::m_update_engine() {
buf = br_ssl_engine_sendrec_buf(&m_sslctx.eng, &len); buf = br_ssl_engine_sendrec_buf(&m_sslctx.eng, &len);
wlen = m_client->write(buf, len); wlen = m_client->write(buf, len);
// let the chip recover
if (wlen < 0) { if (wlen < 0) {
m_print("Error writing to m_client"); m_print("Error writing to m_client");
/* /*
@ -404,16 +403,7 @@ unsigned SSLClientImpl::m_update_engine() {
m_print("Read bytes from client: "); m_print("Read bytes from client: ");
m_print(avail); m_print(avail);
m_print(len); 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->read(buf, len); int rlen = m_client->read(buf, len);
if (rlen <= 0) { if (rlen <= 0) {
@ -428,8 +418,12 @@ unsigned SSLClientImpl::m_update_engine() {
} }
// guess not, tell the state we're waiting still // guess not, tell the state we're waiting still
else { else {
m_print("Bytes avail: "); // m_print("Bytes avail: ");
m_print(avail); // m_print(avail);
// m_print("Bytes needed: ");
// m_print(len);
// add a delay since spamming m_client->availible breaks the poor wiz chip
delay(10);
return state; return state;
} }
} }

View file

@ -24,6 +24,7 @@
#include "bearssl.h" #include "bearssl.h"
#include "bearssl_ssl.h" #include "bearssl_ssl.h"
#include "time_macros.h"
/* /*
* A "profile" is an initialisation function for a SSL context, that * A "profile" is an initialisation function for a SSL context, that
@ -420,6 +421,24 @@ br_client_init_TLS12_only(br_ssl_client_context *cc,
br_x509_minimal_init(xc, &br_sha256_vtable, br_x509_minimal_init(xc, &br_sha256_vtable,
trust_anchors, trust_anchors_num); trust_anchors, trust_anchors_num);
/*
* Set a fixed epoch time to validate certificates against.
* Since we are working with an embedded device, there isn't
* really a reliable source of time. To remedy this, we simply
* store the time this program was compiled, and assume that
* any certificate valid under that time is also valid at the
* current time. This is vulnerable to the use of expired
* certificates, however an attacker would have to use a
* certificate valid after the compile date, which is fairly
* difficult given the lifespan of projects here at the lab.
* For now, this solution is good enough.
*/
br_x509_minimal_set_time(xc,
// days since 1970 + days from 1970 to year 0
(UNIX_TIMESTAMP_UTC / SEC_PER_DAY) + 719528UL,
// seconds over start of day
UNIX_TIMESTAMP_UTC % SEC_PER_DAY);
/* /*
* Set suites and asymmetric crypto implementations. We use the * Set suites and asymmetric crypto implementations. We use the
* "i31" code for RSA (it is somewhat faster than the "i32" * "i31" code for RSA (it is somewhat faster than the "i32"
@ -431,11 +450,12 @@ br_client_init_TLS12_only(br_ssl_client_context *cc,
* the RSA verification function below. * the RSA verification function below.
*/ */
// br_x509_minimal_set_rsa(xc, &br_rsa_i31_pkcs1_vrfy); // br_x509_minimal_set_rsa(xc, &br_rsa_i31_pkcs1_vrfy);
br_x509_minimal_set_rsa(xc, &br_rsa_i15_pkcs1_vrfy); br_x509_minimal_set_rsa(xc, br_ssl_engine_get_rsavrfy(&cc->eng));
// br_x509_minimal_set_ecdsa(xc, // br_x509_minimal_set_ecdsa(xc,
// &br_ec_prime_i31, &br_ecdsa_i31_vrfy_asn1); // &br_ec_prime_i31, &br_ecdsa_i31_vrfy_asn1);
br_x509_minimal_set_ecdsa(xc, br_x509_minimal_set_ecdsa(xc,
&br_ec_all_m15, &br_ecdsa_i15_vrfy_asn1); br_ssl_engine_get_ec(&cc->eng),
br_ssl_engine_get_ecdsa(&cc->eng));
/* /*
* Set supported hash functions. These are for signatures on * Set supported hash functions. These are for signatures on
@ -447,11 +467,11 @@ br_client_init_TLS12_only(br_ssl_client_context *cc,
* Note: the engine explicitly rejects signatures that use MD5. * Note: the engine explicitly rejects signatures that use MD5.
* Thus, there is no need for MD5 here. * Thus, there is no need for MD5 here.
*/ */
// br_ssl_engine_set_hash(xc, br_sha1_ID, &br_sha1_vtable); // br_x509_minimal_set_hash(xc, br_sha1_ID, &br_sha1_vtable);
br_ssl_engine_set_hash(xc, br_sha224_ID, &br_sha224_vtable); br_x509_minimal_set_hash(xc, br_sha224_ID, &br_sha224_vtable);
br_ssl_engine_set_hash(xc, br_sha256_ID, &br_sha256_vtable); br_x509_minimal_set_hash(xc, br_sha256_ID, &br_sha256_vtable);
br_ssl_engine_set_hash(xc, br_sha384_ID, &br_sha384_vtable); br_x509_minimal_set_hash(xc, br_sha384_ID, &br_sha384_vtable);
// br_ssl_engine_set_hash(xc, br_sha512_ID, &br_sha512_vtable); // br_x509_minimal_set_hash(xc, br_sha512_ID, &br_sha512_vtable);
/* /*
* Link the X.509 engine in the SSL engine. * Link the X.509 engine in the SSL engine.

View file

@ -23,6 +23,7 @@
*/ */
#include "inner.h" #include "inner.h"
#include "time_macros.h"
/* see bearssl_ssl.h */ /* see bearssl_ssl.h */
void void
@ -155,6 +156,24 @@ br_ssl_client_init_full(br_ssl_client_context *cc,
br_x509_minimal_set_hash(xc, id, hc); br_x509_minimal_set_hash(xc, id, hc);
} }
/*
* Set a fixed epoch time to validate certificates against.
* Since we are working with an embedded device, there isn't
* really a reliable source of time. To remedy this, we simply
* store the time this program was compiled, and assume that
* any certificate valid under that time is also valid at the
* current time. This is vulnerable to the use of expired
* certificates, however an attacker would have to use a
* certificate valid after the compile date, which is fairly
* difficult given the lifespan of projects here at the lab.
* For now, this solution is good enough.
*/
br_x509_minimal_set_time(xc,
// days since 1970 + days from 1970 to year 0
(UNIX_TIMESTAMP_UTC / SEC_PER_DAY) + 719528UL,
// seconds over start of day
UNIX_TIMESTAMP_UTC % SEC_PER_DAY);
/* /*
* Link the X.509 engine in the SSL engine. * Link the X.509 engine in the SSL engine.
*/ */

101
src/time_macros.h Normal file
View file

@ -0,0 +1,101 @@
/*
*
* Created: 29.03.2018
*
* Authors:
*
* Assembled from the code released on Stackoverflow by:
* Dennis (instructable.com/member/nqtronix) | https://stackoverflow.com/questions/23032002/c-c-how-to-get-integer-unix-timestamp-of-build-time-not-string
* and
* Alexis Wilke | https://stackoverflow.com/questions/10538444/do-you-know-of-a-c-macro-to-compute-unix-time-and-date
*
* Assembled by Jean Rabault
*
* UNIX_TIMESTAMP gives the UNIX timestamp (unsigned long integer of seconds since 1st Jan 1970) of compilation from macros using the compiler defined __TIME__ macro.
* This should include Gregorian calendar leap days, in particular the 29ths of February, 100 and 400 years modulo leaps.
*
* Careful: __TIME__ is the local time of the computer, NOT the UTC time in general!
*
*/
#ifndef COMPILE_TIME_H_
#define COMPILE_TIME_H_
// add offset for pacific standard time
#define PST_OFFSET (8UL)
// Some definitions for calculation
#define SEC_PER_MIN (60UL)
#define SEC_PER_HOUR (3600UL)
#define SEC_PER_DAY (86400UL)
#define SEC_PER_YEAR (SEC_PER_DAY*365)
// extracts 1..4 characters from a string and interprets it as a decimal value
#define CONV_STR2DEC_1(str, i) (str[i]>'0'?str[i]-'0':0)
#define CONV_STR2DEC_2(str, i) (CONV_STR2DEC_1(str, i)*10 + str[i+1]-'0')
#define CONV_STR2DEC_3(str, i) (CONV_STR2DEC_2(str, i)*10 + str[i+2]-'0')
#define CONV_STR2DEC_4(str, i) (CONV_STR2DEC_3(str, i)*10 + str[i+3]-'0')
// Custom "glue logic" to convert the month name to a usable number
#define GET_MONTH(str, i) (str[i]=='J' && str[i+1]=='a' && str[i+2]=='n' ? 1 : \
str[i]=='F' && str[i+1]=='e' && str[i+2]=='b' ? 2 : \
str[i]=='M' && str[i+1]=='a' && str[i+2]=='r' ? 3 : \
str[i]=='A' && str[i+1]=='p' && str[i+2]=='r' ? 4 : \
str[i]=='M' && str[i+1]=='a' && str[i+2]=='y' ? 5 : \
str[i]=='J' && str[i+1]=='u' && str[i+2]=='n' ? 6 : \
str[i]=='J' && str[i+1]=='u' && str[i+2]=='l' ? 7 : \
str[i]=='A' && str[i+1]=='u' && str[i+2]=='g' ? 8 : \
str[i]=='S' && str[i+1]=='e' && str[i+2]=='p' ? 9 : \
str[i]=='O' && str[i+1]=='c' && str[i+2]=='t' ? 10 : \
str[i]=='N' && str[i+1]=='o' && str[i+2]=='v' ? 11 : \
str[i]=='D' && str[i+1]=='e' && str[i+2]=='c' ? 12 : 0)
// extract the information from the time string given by __TIME__ and __DATE__
#define __TIME_SECONDS__ CONV_STR2DEC_2(__TIME__, 6)
#define __TIME_MINUTES__ CONV_STR2DEC_2(__TIME__, 3)
#define __TIME_HOURS__ CONV_STR2DEC_2(__TIME__, 0)
#define __TIME_DAYS__ CONV_STR2DEC_2(__DATE__, 4)
#define __TIME_MONTH__ GET_MONTH(__DATE__, 0)
#define __TIME_YEARS__ CONV_STR2DEC_4(__DATE__, 7)
// Days in February
#define _UNIX_TIMESTAMP_FDAY(year) \
(((year) % 400) == 0UL ? 29UL : \
(((year) % 100) == 0UL ? 28UL : \
(((year) % 4) == 0UL ? 29UL : \
28UL)))
// Days in the year
#define _UNIX_TIMESTAMP_YDAY(year, month, day) \
( \
/* January */ day \
/* February */ + (month >= 2 ? 31UL : 0UL) \
/* March */ + (month >= 3 ? _UNIX_TIMESTAMP_FDAY(year) : 0UL) \
/* April */ + (month >= 4 ? 31UL : 0UL) \
/* May */ + (month >= 5 ? 30UL : 0UL) \
/* June */ + (month >= 6 ? 31UL : 0UL) \
/* July */ + (month >= 7 ? 30UL : 0UL) \
/* August */ + (month >= 8 ? 31UL : 0UL) \
/* September */+ (month >= 9 ? 31UL : 0UL) \
/* October */ + (month >= 10 ? 30UL : 0UL) \
/* November */ + (month >= 11 ? 31UL : 0UL) \
/* December */ + (month >= 12 ? 30UL : 0UL) \
)
// get the UNIX timestamp from a digits representation
#define _UNIX_TIMESTAMP(year, month, day, hour, minute, second) \
( /* time */ second \
+ minute * SEC_PER_MIN \
+ hour * SEC_PER_HOUR \
+ /* year day (month + day) */ (_UNIX_TIMESTAMP_YDAY(year, month, day) - 1) * SEC_PER_DAY \
+ /* year */ (year - 1970UL) * SEC_PER_YEAR \
+ ((year - 1969UL) / 4UL) * SEC_PER_DAY \
- ((year - 1901UL) / 100UL) * SEC_PER_DAY \
+ ((year - 1601UL) / 400UL) * SEC_PER_DAY \
)
// the UNIX timestamp
#define UNIX_TIMESTAMP _UNIX_TIMESTAMP(__TIME_YEARS__, __TIME_MONTH__, __TIME_DAYS__, __TIME_HOURS__, __TIME_MINUTES__, __TIME_SECONDS__)
#define UNIX_TIMESTAMP_UTC (UNIX_TIMESTAMP + (PST_OFFSET*SEC_PER_HOUR))
#endif