From 79a0a6135b0db5de94d02f119c980172bc64ecf9 Mon Sep 17 00:00:00 2001 From: Noah Laptop Date: Thu, 28 Feb 2019 15:44:21 -0800 Subject: [PATCH] added unix timestamp macro, fixed RNG implementation with analog pin, fixed bugs (client works now!) --- src/SSLClientImpl.cpp | 42 +++++------ src/TLS12_only_profile.c | 34 +++++++-- src/bearssl/src/ssl/ssl_client_full.c | 19 +++++ src/time_macros.h | 101 ++++++++++++++++++++++++++ 4 files changed, 165 insertions(+), 31 deletions(-) create mode 100644 src/time_macros.h diff --git a/src/SSLClientImpl.cpp b/src/SSLClientImpl.cpp index 6156a0e..90ba029 100644 --- a/src/SSLClientImpl.cpp +++ b/src/SSLClientImpl.cpp @@ -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 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_ssl_client_init_full(&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); @@ -74,7 +74,7 @@ int SSLClientImpl::connect(const char *host, uint16_t port) { /** see SSLClientImpl.h*/ size_t SSLClientImpl::write(const uint8_t *buf, size_t size) { // 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?"); return 0; } @@ -119,7 +119,7 @@ size_t SSLClientImpl::write(const uint8_t *buf, size_t size) { /** see SSLClientImpl.h*/ int SSLClientImpl::available() { // 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"); return 0; } @@ -153,7 +153,7 @@ int SSLClientImpl::read(uint8_t *buf, size_t size) { 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.eng, read_amount); + br_ssl_engine_recvapp_ack(&m_sslctx.eng, read_amount); // tell the user we read that many bytes return read_amount; } @@ -221,7 +221,6 @@ int SSLClientImpl::m_start_ssl(const char* host) { // 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"); @@ -232,11 +231,13 @@ int SSLClientImpl::m_start_ssl(const char* host) { // 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"); + m_print(br_ssl_engine_last_error(&m_sslctx.eng)); setWriteError(SSL_BR_CONNECT_FAIL); return 0; } // all good to go! the SSL socket should be up and running m_print("SSL Initialized"); + m_print(m_sslctx.eng.selected_protocol); setWriteError(SSL_OK); return 1; } @@ -246,12 +247,12 @@ int SSLClientImpl::m_run_until(const unsigned target) { unsigned lastState = 0; size_t lastLen = 0; for (;;) { + unsigned state = m_update_engine(); // error check - if (!connected()) { + if (state == BR_SSL_CLOSED || getWriteError()) { 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; @@ -304,10 +305,7 @@ 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); - } + } } /** see SSLClientImpl.h*/ @@ -327,6 +325,7 @@ unsigned SSLClientImpl::m_update_engine() { buf = br_ssl_engine_sendrec_buf(&m_sslctx.eng, &len); wlen = m_client->write(buf, len); + // let the chip recover if (wlen < 0) { m_print("Error writing to m_client"); /* @@ -404,16 +403,7 @@ unsigned SSLClientImpl::m_update_engine() { 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->read(buf, len); if (rlen <= 0) { @@ -428,8 +418,12 @@ unsigned SSLClientImpl::m_update_engine() { } // guess not, tell the state we're waiting still else { - m_print("Bytes avail: "); - m_print(avail); + // m_print("Bytes 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; } } diff --git a/src/TLS12_only_profile.c b/src/TLS12_only_profile.c index f253e2b..e0b8295 100644 --- a/src/TLS12_only_profile.c +++ b/src/TLS12_only_profile.c @@ -24,6 +24,7 @@ #include "bearssl.h" #include "bearssl_ssl.h" +#include "time_macros.h" /* * 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, 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 * "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. */ // 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_ec_prime_i31, &br_ecdsa_i31_vrfy_asn1); 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 @@ -447,11 +467,11 @@ br_client_init_TLS12_only(br_ssl_client_context *cc, * Note: the engine explicitly rejects signatures that use MD5. * Thus, there is no need for MD5 here. */ - // br_ssl_engine_set_hash(xc, br_sha1_ID, &br_sha1_vtable); - br_ssl_engine_set_hash(xc, br_sha224_ID, &br_sha224_vtable); - br_ssl_engine_set_hash(xc, br_sha256_ID, &br_sha256_vtable); - br_ssl_engine_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_sha1_ID, &br_sha1_vtable); + br_x509_minimal_set_hash(xc, br_sha224_ID, &br_sha224_vtable); + br_x509_minimal_set_hash(xc, br_sha256_ID, &br_sha256_vtable); + br_x509_minimal_set_hash(xc, br_sha384_ID, &br_sha384_vtable); + // br_x509_minimal_set_hash(xc, br_sha512_ID, &br_sha512_vtable); /* * Link the X.509 engine in the SSL engine. diff --git a/src/bearssl/src/ssl/ssl_client_full.c b/src/bearssl/src/ssl/ssl_client_full.c index 9814349..fd35b3c 100644 --- a/src/bearssl/src/ssl/ssl_client_full.c +++ b/src/bearssl/src/ssl/ssl_client_full.c @@ -23,6 +23,7 @@ */ #include "inner.h" +#include "time_macros.h" /* see bearssl_ssl.h */ void @@ -155,6 +156,24 @@ br_ssl_client_init_full(br_ssl_client_context *cc, 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. */ diff --git a/src/time_macros.h b/src/time_macros.h new file mode 100644 index 0000000..937eddc --- /dev/null +++ b/src/time_macros.h @@ -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 \ No newline at end of file