From 991197c48f3d73ee1c1c0a9326671336a224f9d7 Mon Sep 17 00:00:00 2001 From: Myles Eftos Date: Thu, 23 Mar 2017 08:15:07 +1100 Subject: [PATCH 01/12] Adding required axtls libraries. Code compiles. Untested though --- cores/esp8266/Updater.cpp | 126 ++++ cores/esp8266/Updater.h | 33 +- cores/esp8266/axtls/asn1.cpp | 757 +++++++++++++++++++++++ cores/esp8266/axtls/asn1.h | 55 ++ cores/esp8266/axtls/bigint.cpp | 978 ++++++++++++++++++++++++++++++ cores/esp8266/axtls/bigint.h | 77 +++ cores/esp8266/axtls/bigint_impl.h | 86 +++ cores/esp8266/axtls/ca.h | 86 +++ cores/esp8266/axtls/rsa.cpp | 266 ++++++++ cores/esp8266/axtls/rsa.h | 44 ++ cores/esp8266/axtls/sha1.cpp | 248 ++++++++ cores/esp8266/axtls/sha1.h | 23 + cores/esp8266/axtls/sha256.cpp | 273 +++++++++ cores/esp8266/axtls/sha256.h | 17 + cores/esp8266/axtls/x509.cpp | 567 +++++++++++++++++ cores/esp8266/axtls/x509.h | 83 +++ 16 files changed, 3717 insertions(+), 2 deletions(-) create mode 100644 cores/esp8266/axtls/asn1.cpp create mode 100644 cores/esp8266/axtls/asn1.h create mode 100644 cores/esp8266/axtls/bigint.cpp create mode 100644 cores/esp8266/axtls/bigint.h create mode 100644 cores/esp8266/axtls/bigint_impl.h create mode 100644 cores/esp8266/axtls/ca.h create mode 100644 cores/esp8266/axtls/rsa.cpp create mode 100644 cores/esp8266/axtls/rsa.h create mode 100644 cores/esp8266/axtls/sha1.cpp create mode 100644 cores/esp8266/axtls/sha1.h create mode 100644 cores/esp8266/axtls/sha256.cpp create mode 100644 cores/esp8266/axtls/sha256.h create mode 100644 cores/esp8266/axtls/x509.cpp create mode 100644 cores/esp8266/axtls/x509.h diff --git a/cores/esp8266/Updater.cpp b/cores/esp8266/Updater.cpp index 258d899c3a..629cf7ceef 100644 --- a/cores/esp8266/Updater.cpp +++ b/cores/esp8266/Updater.cpp @@ -23,6 +23,9 @@ UpdaterClass::UpdaterClass() , _currentAddress(0) , _command(U_FLASH) { +#ifdef VERIFY_SIGNATURE + _ca_ctx = (CA_CERT_CTX *)malloc(sizeof(CA_CERT_CTX)); +#endif } void UpdaterClass::_reset() { @@ -121,6 +124,22 @@ bool UpdaterClass::begin(size_t size, int command) { DEBUG_UPDATER.printf("[begin] _size: 0x%08X (%d)\n", _size, _size); #endif +#ifdef VERIFY_SIGNATURE + // If this package has been signed correctly, the last uint32 is the size of the signature + // the second-last uint32 is the size of the certificate + _signatureLen = (uint32_t)&_size - sizeof(uint32); + _certificateLen = (uint32_t)&_size - (2 * sizeof(uint32)); + _signatureStartAddress = (uint32_t)&_size - _signatureLen - (2 * sizeof(uint32)); + _certificateStartAddress = _signatureStartAddress - _certificateLen; + +#ifdef DEBUG_UPDATER + DEBUG_UPDATER.printf("[begin] _signatureLen: 0x%08X (%d)\n", _signatureLen, _signatureLen); + DEBUG_UPDATER.printf("[begin] _certificateLen: 0x%08X (%d)\n", _certificateLen, _certificateLen); + DEBUG_UPDATER.printf("[begin] _signatureStartAddress: 0x%08X (%d)\n", _signatureStartAddress, _signatureStartAddress); + DEBUG_UPDATER.printf("[begin] _certificateStartAddress: 0x%08X (%d)\n", _certificateStartAddress, _certificateStartAddress); +#endif +#endif + _md5.begin(); return true; } @@ -201,6 +220,113 @@ bool UpdaterClass::end(bool evenIfRemaining){ return true; } +#ifdef VERIFY_SIGNATURE + int UpdaterClass::addCA(const uint8_t *cert, int *len) { + // TODO: Allow more than one CA + int res = x509_new(cert, len, &(_ca_ctx->cert[0])); + +#ifdef DEBUG_UPDATER + if(res == X509_OK) { + DEBUG_UPDATER.printf("Loaded CA certificate. Common Name: %s\n", _ca_ctx->cert[0]->cert_dn[X509_COMMON_NAME]); + } else { + DEBUG_UPDATER.printf("Unable to load CA certificate: %i\n", res); + } +#endif + + return res; + } + + bool UpdaterClass::_loadCertificate(X509_CTX *ctx) { + uint8_t *cert = (uint8_t *)_certificateStartAddress; + int res = x509_new(cert, (int *)&_certificateLen, &ctx); + if(res != X509_OK) { +#ifdef DEBUG_UPDATER + DEBUG_UPDATER.printf("Unable to load developer certificate: %i\n", res); +#endif + return false; + } +#ifdef DEBUG_UPDATER + DEBUG_UPDATER.printf("Loaded developer certificate. Common Name: %s\n", ctx->cert_dn[X509_COMMON_NAME]); +#endif + return true; + } + + bool UpdaterClass::_verifyCertificate(X509_CTX *ctx) { + int constraint; + int res = x509_verify(_ca_ctx, ctx, &constraint); + +#ifdef DEBUG_UPDATER + if(res == 0) { + DEBUG_UPDATER.printf("Developer certificate verified\n"); + } else { + DEBUG_UPDATED.printf("Developer certificate not verified\n"); + } +#endif + + return res == 0; + } + + bool UpdaterClass::_decryptSignature(X509_CTX *ctx, unsigned char **hash) { + const uint8_t *sig = (uint8_t *)_signatureStartAddress; + +// This should be derived from the hash type +#define MAX_LEN_KEY 512 + + unsigned char sig_bytes[MAX_KEY_LEN]; + int len = RSA_decrypt(ctx->rsa_ctx, (const uint8_t*)sig, sig_bytes, MAX_KEY_LEN, 0); + + if(len == -1) { + return false; + } + + if(len != (int)_signatureLen) { + return false; + } + + (*hash) = sig_bytes + len - SHA256_SIZE; + return true; + } + + bool UpdaterClass::_compareHash(unsigned char **hash) { + unsigned char hash_computed[SHA256_SIZE]; + + SHA256_CTX sha256; + SHA256_Init(&sha256); + SHA256_Update(&sha256, _buffer, _bufferLen); + SHA256_Final(hash_computed, &sha256); + + if(memcmp(hash, hash_computed, SHA256_SIZE) == 0) { + return true; + } else { + return false; + } + } + + bool UpdaterClass::_verifySignature() { + X509_CTX ctx; + if(!_loadCertificate(&ctx)) { + return false; + } + + if(!_verifyCertificate(&ctx)) { + return false; + } + + unsigned char *hash; + if(!_decryptSignature(&ctx, &hash)) { + return false; + } + + if(_compareHash(&hash)) { + free(hash); + return true; + } else { + free(hash); + return false; + } + } +#endif + bool UpdaterClass::_writeBuffer(){ if(!_async) yield(); diff --git a/cores/esp8266/Updater.h b/cores/esp8266/Updater.h index 046ff1667b..1dc9d1c3c8 100644 --- a/cores/esp8266/Updater.h +++ b/cores/esp8266/Updater.h @@ -1,10 +1,21 @@ #ifndef ESP8266UPDATER_H #define ESP8266UPDATER_H +#define VERIFY_SIGNATURE 1 + #include #include #include +#ifdef VERIFY_SIGNATURE +#include "axtls/rsa.h" +#include "axtls/asn1.h" +#include "axtls/sha1.h" +#include "axtls/sha256.h" + +#define MAX_KEY_LEN 256 +#endif + #define UPDATE_ERROR_OK (0) #define UPDATE_ERROR_WRITE (1) #define UPDATE_ERROR_ERASE (2) @@ -141,6 +152,10 @@ class UpdaterClass { return written; } +#ifdef VERIFY_SIGNATURE + int addCA(const uint8_t *cert, int *len); +#endif + private: void _reset(); bool _writeBuffer(); @@ -148,11 +163,25 @@ class UpdaterClass { bool _verifyHeader(uint8_t data); bool _verifyEnd(); +#ifdef VERIFY_SIGNATURE + CA_CERT_CTX *_ca_ctx; + bool _loadCertificate(X509_CTX *ctx); + bool _verifyCertificate(X509_CTX *ctx); + bool _decryptSignature(X509_CTX *ctx, unsigned char **hash); + bool _compareHash(unsigned char **hash); + bool _verifySignature(); + + uint32_t _certificateStartAddress; + size_t _certificateLen; + uint32_t _signatureStartAddress; + size_t _signatureLen; +#endif + bool _async; uint8_t _error; uint8_t *_buffer; - size_t _bufferLen; - size_t _size; + uint32_t _bufferLen; + uint32_t _size; uint32_t _startAddress; uint32_t _currentAddress; uint32_t _command; diff --git a/cores/esp8266/axtls/asn1.cpp b/cores/esp8266/axtls/asn1.cpp new file mode 100644 index 0000000000..fe9733e656 --- /dev/null +++ b/cores/esp8266/axtls/asn1.cpp @@ -0,0 +1,757 @@ +/* + * Copyright (c) 2007-2016, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * Some primitive asn methods for extraction ASN.1 data. + */ + +#include +#include +#include "asn1.h" +#include "rsa.h" + +/* 1.2.840.113549.1.1 OID prefix - handle the following */ +/* md5WithRSAEncryption(4) */ +/* sha1WithRSAEncryption(5) */ +/* sha256WithRSAEncryption (11) */ +/* sha384WithRSAEncryption (12) */ +/* sha512WithRSAEncryption (13) */ +static const uint8_t sig_oid_prefix[] = +{ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01 +}; + +/* 1.3.14.3.2.29 SHA1 with RSA signature */ +static const uint8_t sig_sha1WithRSAEncrypt[] = +{ + 0x2b, 0x0e, 0x03, 0x02, 0x1d +}; + +/* 2.16.840.1.101.3.4.2.1 SHA-256 */ +static const uint8_t sig_sha256[] = +{ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 +}; + +/* 2.16.840.1.101.3.4.2.2 SHA-384 */ +static const uint8_t sig_sha384[] = +{ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02 +}; + +/* 2.16.840.1.101.3.4.2.3 SHA-512 */ +static const uint8_t sig_sha512[] = +{ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03 +}; + +static const uint8_t sig_subject_alt_name[] = +{ + 0x55, 0x1d, 0x11 +}; + +static const uint8_t sig_basic_constraints[] = +{ + 0x55, 0x1d, 0x13 +}; + +static const uint8_t sig_key_usage[] = +{ + 0x55, 0x1d, 0x0f +}; + +/* CN, O, OU, L, C, ST */ +static const uint8_t g_dn_types[] = { 3, 10, 11, 7, 6, 8 }; + +uint32_t get_asn1_length(const uint8_t *buf, int *offset) +{ + int i; + uint32_t len; + + if (!(buf[*offset] & 0x80)) /* short form */ + { + len = buf[(*offset)++]; + } + else /* long form */ + { + int length_bytes = buf[(*offset)++]&0x7f; + if (length_bytes > 4) /* limit number of bytes */ + return 0; + + len = 0; + for (i = 0; i < length_bytes; i++) + { + len <<= 8; + len += buf[(*offset)++]; + } + } + + return len; +} + +/** + * Skip the ASN1.1 object type and its length. Get ready to read the object's + * data. + */ +int asn1_next_obj(const uint8_t *buf, int *offset, int obj_type) +{ + if (buf[*offset] != obj_type) + return X509_NOT_OK; + + (*offset)++; + return get_asn1_length(buf, offset); +} + +/** + * Skip over an ASN.1 object type completely. Get ready to read the next + * object. + */ +int asn1_skip_obj(const uint8_t *buf, int *offset, int obj_type) +{ + int len; + + if (buf[*offset] != obj_type) + return X509_NOT_OK; + (*offset)++; + len = get_asn1_length(buf, offset); + *offset += len; + return 0; +} + +/** + * Read an integer value for ASN.1 data + * Note: This function allocates memory which must be freed by the user. + */ +int asn1_get_big_int(const uint8_t *buf, int *offset, uint8_t **object) +{ + int len; + + if ((len = asn1_next_obj(buf, offset, ASN1_INTEGER)) < 0) + goto end_big_int; + + if (len > 1 && buf[*offset] == 0x00) /* ignore the negative byte */ + { + len--; + (*offset)++; + } + + *object = (uint8_t *)malloc(len); + memcpy(*object, &buf[*offset], len); + *offset += len; + +end_big_int: + return len; +} + +/** + * Read an integer value for ASN.1 data + */ +int asn1_get_int(const uint8_t *buf, int *offset, int32_t *val) +{ + int res = X509_OK; + int len; + int i; + + if ((len = asn1_next_obj(buf, offset, ASN1_INTEGER)) < 0 || + len > sizeof(int32_t)) + { + res = X509_NOT_OK; + goto end_int; + } + + *val = 0; + for (i = 0; i < len; i++) + { + *val <<= 8; + *val |= buf[(*offset)++]; + } + +end_int: + return res; +} + +/** + * Read an boolean value for ASN.1 data + */ +int asn1_get_bool(const uint8_t *buf, int *offset, bool *val) +{ + int res = X509_OK; + + if (asn1_next_obj(buf, offset, ASN1_BOOLEAN) != 1) + { + res = X509_NOT_OK; + goto end_bool; + } + + /* DER demands that "If the encoding represents the boolean value TRUE, + its single contents octet shall have all eight bits set to one." + Thus only 0 and 255 are valid encoded values. */ + *val = buf[(*offset)++] == 0xFF; + +end_bool: + return res; +} + +/** + * Convert an ASN.1 bit string into a 32 bit integer. Used for key usage + */ +int asn1_get_bit_string_as_int(const uint8_t *buf, int *offset, uint32_t *val) +{ + int res = X509_OK; + int len, i; + int ignore_bits; + + if ((len = asn1_next_obj(buf, offset, ASN1_BIT_STRING)) < 0 || len > 5) + { + res = X509_NOT_OK; + goto end_bit_string_as_int; + } + + /* number of bits left unused in the final byte of content */ + ignore_bits = buf[(*offset)++]; + len--; + *val = 0; + + /* not sure why key usage doesn't used proper DER spec version */ + for (i = len-1; i >= 0; --i) + { + *val <<= 8; + *val |= buf[(*offset) + i]; + } + + *offset += len; + + /*for (i = 0; i < ignore_bits; i++) + { + *val >>= 1; + }*/ + +end_bit_string_as_int: + return res; +} + +/** + * Get all the RSA private key specifics from an ASN.1 encoded file + */ +int asn1_get_private_key(const uint8_t *buf, int len, RSA_CTX **rsa_ctx) +{ + int offset = 7; + uint8_t *modulus = NULL, *priv_exp = NULL, *pub_exp = NULL; + int mod_len, priv_len, pub_len; + uint8_t *p = NULL, *q = NULL, *dP = NULL, *dQ = NULL, *qInv = NULL; + int p_len, q_len, dP_len, dQ_len, qInv_len; + + /* not in der format */ + if (buf[0] != ASN1_SEQUENCE) /* basic sanity check */ + { + return X509_INVALID_PRIV_KEY; + } + + /* Use the private key to mix up the RNG if possible. */ + //RNG_custom_init(buf, len); + + mod_len = asn1_get_big_int(buf, &offset, &modulus); + pub_len = asn1_get_big_int(buf, &offset, &pub_exp); + priv_len = asn1_get_big_int(buf, &offset, &priv_exp); + + if (mod_len <= 0 || pub_len <= 0 || priv_len <= 0) + return X509_INVALID_PRIV_KEY; + + p_len = asn1_get_big_int(buf, &offset, &p); + q_len = asn1_get_big_int(buf, &offset, &q); + dP_len = asn1_get_big_int(buf, &offset, &dP); + dQ_len = asn1_get_big_int(buf, &offset, &dQ); + qInv_len = asn1_get_big_int(buf, &offset, &qInv); + + if (p_len <= 0 || q_len <= 0 || dP_len <= 0 || dQ_len <= 0 || qInv_len <= 0) + return X509_INVALID_PRIV_KEY; + + RSA_priv_key_new(rsa_ctx, + modulus, mod_len, pub_exp, pub_len, priv_exp, priv_len, + p, p_len, q, p_len, dP, dP_len, dQ, dQ_len, qInv, qInv_len); + + free(p); + free(q); + free(dP); + free(dQ); + free(qInv); + + free(modulus); + free(priv_exp); + free(pub_exp); + return X509_OK; +} + +/** + * Get the time of a certificate. Ignore hours/minutes/seconds. + */ +static int asn1_get_utc_time(const uint8_t *buf, int *offset, time_t *t) +{ + int ret = X509_NOT_OK, len, t_offset, abs_year; + struct tm tm; + + /* see http://tools.ietf.org/html/rfc5280#section-4.1.2.5 */ + if (buf[*offset] == ASN1_UTC_TIME) + { + (*offset)++; + + len = get_asn1_length(buf, offset); + t_offset = *offset; + + memset(&tm, 0, sizeof(struct tm)); + tm.tm_year = (buf[t_offset] - '0')*10 + (buf[t_offset+1] - '0'); + + if (tm.tm_year < 50) /* 1951-2050 thing */ + { + tm.tm_year += 100; + } + + tm.tm_mon = (buf[t_offset+2] - '0')*10 + (buf[t_offset+3] - '0') - 1; + tm.tm_mday = (buf[t_offset+4] - '0')*10 + (buf[t_offset+5] - '0'); + tm.tm_hour = (buf[t_offset+6] - '0')*10 + (buf[t_offset+7] - '0'); + tm.tm_min = (buf[t_offset+8] - '0')*10 + (buf[t_offset+9] - '0'); + tm.tm_sec = (buf[t_offset+10] - '0')*10 + (buf[t_offset+11] - '0'); + *t = mktime(&tm); + *offset += len; + ret = X509_OK; + } + else if (buf[*offset] == ASN1_GENERALIZED_TIME) + { + (*offset)++; + + len = get_asn1_length(buf, offset); + t_offset = *offset; + + memset(&tm, 0, sizeof(struct tm)); + abs_year = ((buf[t_offset] - '0')*1000 + + (buf[t_offset+1] - '0')*100 + (buf[t_offset+2] - '0')*10 + + (buf[t_offset+3] - '0')); + + if (abs_year <= 1901) + { + tm.tm_year = 1; + tm.tm_mon = 0; + tm.tm_mday = 1; + } + else + { + tm.tm_year = abs_year - 1900; + tm.tm_mon = (buf[t_offset+4] - '0')*10 + + (buf[t_offset+5] - '0') - 1; + tm.tm_mday = (buf[t_offset+6] - '0')*10 + (buf[t_offset+7] - '0'); + tm.tm_hour = (buf[t_offset+8] - '0')*10 + (buf[t_offset+9] - '0'); + tm.tm_min = (buf[t_offset+10] - '0')*10 + (buf[t_offset+11] - '0'); + tm.tm_sec = (buf[t_offset+12] - '0')*10 + (buf[t_offset+13] - '0'); + *t = mktime(&tm); + } + + *offset += len; + ret = X509_OK; + } + + return ret; +} + +/** + * Get the version type of a certificate + */ +int asn1_version(const uint8_t *cert, int *offset, int *val) +{ + (*offset) += 2; /* get past explicit tag */ + return asn1_get_int(cert, offset, val); +} + +/** + * Retrieve the notbefore and notafter certificate times. + */ +int asn1_validity(const uint8_t *cert, int *offset, X509_CTX *x509_ctx) +{ + return (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 || + asn1_get_utc_time(cert, offset, &x509_ctx->not_before) || + asn1_get_utc_time(cert, offset, &x509_ctx->not_after)); +} + +/** + * Get the components of a distinguished name + */ +static int asn1_get_oid_x520(const uint8_t *buf, int *offset) +{ + int dn_type = 0; + int len; + + if ((len = asn1_next_obj(buf, offset, ASN1_OID)) < 0) + goto end_oid; + + /* expect a sequence of 2.5.4.[x] where x is a one of distinguished name + components we are interested in. */ + if (len == 3 && buf[(*offset)++] == 0x55 && buf[(*offset)++] == 0x04) + dn_type = buf[(*offset)++]; + else + { + *offset += len; /* skip over it */ + } + +end_oid: + return dn_type; +} + +/** + * Obtain an ASN.1 printable string type. + */ +static int asn1_get_printable_str(const uint8_t *buf, int *offset, char **str) +{ + int len = X509_NOT_OK; + int asn1_type = buf[*offset]; + + /* some certs have this awful crud in them for some reason */ + if (asn1_type != ASN1_PRINTABLE_STR && + asn1_type != ASN1_PRINTABLE_STR2 && + asn1_type != ASN1_TELETEX_STR && + asn1_type != ASN1_IA5_STR && + asn1_type != ASN1_UNICODE_STR) + goto end_pnt_str; + + (*offset)++; + len = get_asn1_length(buf, offset); + + if (asn1_type == ASN1_UNICODE_STR) + { + int i; + *str = (char *)malloc(len/2+1); /* allow for null */ + + for (i = 0; i < len; i += 2) + (*str)[i/2] = buf[*offset + i + 1]; + + (*str)[len/2] = 0; /* null terminate */ + } + else + { + *str = (char *)malloc(len+1); /* allow for null */ + memcpy(*str, &buf[*offset], len); + (*str)[len] = 0; /* null terminate */ + } + + *offset += len; + +end_pnt_str: + return len; +} + +/** + * Get the subject name (or the issuer) of a certificate. + */ +int asn1_name(const uint8_t *cert, int *offset, char *dn[]) +{ + int ret = X509_NOT_OK; + int dn_type; + char *tmp; + + if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0) + goto end_name; + + while (asn1_next_obj(cert, offset, ASN1_SET) >= 0) + { + int i, found = 0; + + if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 || + (dn_type = asn1_get_oid_x520(cert, offset)) < 0) + goto end_name; + + tmp = NULL; + + if (asn1_get_printable_str(cert, offset, &tmp) < 0) + { + free(tmp); + goto end_name; + } + + /* find the distinguished named type */ + for (i = 0; i < X509_NUM_DN_TYPES; i++) + { + if (dn_type == g_dn_types[i]) + { + if (dn[i] == NULL) + { + dn[i] = tmp; + found = 1; + break; + } + } + } + + if (found == 0) /* not found so get rid of it */ + { + free(tmp); + } + } + + ret = X509_OK; +end_name: + return ret; +} + +/** + * Read the modulus and public exponent of a certificate. + */ +int asn1_public_key(const uint8_t *cert, int *offset, X509_CTX *x509_ctx) +{ + int ret = X509_NOT_OK, mod_len, pub_len; + uint8_t *modulus = NULL, *pub_exp = NULL; + + if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 || + asn1_skip_obj(cert, offset, ASN1_SEQUENCE) || + asn1_next_obj(cert, offset, ASN1_BIT_STRING) < 0) + goto end_pub_key; + + (*offset)++; /* ignore the padding bit field */ + + if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0) + goto end_pub_key; + + mod_len = asn1_get_big_int(cert, offset, &modulus); + pub_len = asn1_get_big_int(cert, offset, &pub_exp); + + RSA_pub_key_new(&x509_ctx->rsa_ctx, modulus, mod_len, pub_exp, pub_len); + + free(modulus); + free(pub_exp); + ret = X509_OK; + +end_pub_key: + return ret; +} + +/** + * Read the signature of the certificate. + */ +int asn1_signature(const uint8_t *cert, int *offset, X509_CTX *x509_ctx) +{ + int ret = X509_NOT_OK; + + if (cert[(*offset)++] != ASN1_BIT_STRING) + goto end_sig; + + x509_ctx->sig_len = get_asn1_length(cert, offset)-1; + (*offset)++; /* ignore bit string padding bits */ + x509_ctx->signature = (uint8_t *)malloc(x509_ctx->sig_len); + memcpy(x509_ctx->signature, &cert[*offset], x509_ctx->sig_len); + *offset += x509_ctx->sig_len; + ret = X509_OK; + +end_sig: + return ret; +} + +/* + * Compare 2 distinguished name components for equality + * @return 0 if a match + */ +static int asn1_compare_dn_comp(const char *dn1, const char *dn2) +{ + int ret; + + if (dn1 == NULL && dn2 == NULL) + ret = 0; + else + ret = (dn1 && dn2) ? strcmp(dn1, dn2) : 1; + + return ret; +} + +/** + * Clean up all of the CA certificates. + */ +void remove_ca_certs(CA_CERT_CTX *ca_cert_ctx) +{ + int i = 0; + + if (ca_cert_ctx == NULL) + return; + + while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i]) + { + x509_free(ca_cert_ctx->cert[i]); + ca_cert_ctx->cert[i++] = NULL; + } + + free(ca_cert_ctx); +} + +/* + * Compare 2 distinguished names for equality + * @return 0 if a match + */ +int asn1_compare_dn(char * const dn1[], char * const dn2[]) +{ + int i; + + for (i = 0; i < X509_NUM_DN_TYPES; i++) + { + if (asn1_compare_dn_comp(dn1[i], dn2[i])) + return 1; + } + + return 0; /* all good */ +} + +int asn1_find_oid(const uint8_t* cert, int* offset, + const uint8_t* oid, int oid_length) +{ + int seqlen; + if ((seqlen = asn1_next_obj(cert, offset, ASN1_SEQUENCE))> 0) + { + int end = *offset + seqlen; + + while (*offset < end) + { + int type = cert[(*offset)++]; + int length = get_asn1_length(cert, offset); + int noffset = *offset + length; + + if (type == ASN1_SEQUENCE) + { + type = cert[(*offset)++]; + length = get_asn1_length(cert, offset); + + if (type == ASN1_OID && length == oid_length && + memcmp(cert + *offset, oid, oid_length) == 0) + { + *offset += oid_length; + return 1; + } + } + + *offset = noffset; + } + } + + return 0; +} + +int asn1_is_subject_alt_name(const uint8_t *cert, int offset) +{ + if (asn1_find_oid(cert, &offset, sig_subject_alt_name, + sizeof(sig_subject_alt_name))) + { + return offset; + } + + return 0; +} + +int asn1_is_basic_constraints(const uint8_t *cert, int offset) +{ + if (asn1_find_oid(cert, &offset, sig_basic_constraints, + sizeof(sig_basic_constraints))) + { + return offset; + } + + return 0; +} + +int asn1_is_key_usage(const uint8_t *cert, int offset) +{ + if (asn1_find_oid(cert, &offset, sig_key_usage, + sizeof(sig_key_usage))) + { + return offset; + } + + return 0; +} + +bool asn1_is_critical_ext(const uint8_t *buf, int *offset) +{ + /* critical is optional */ + bool res = false; + + if (asn1_next_obj(buf, offset, ASN1_BOOLEAN) == 1) + res = buf[(*offset)++] == 0xFF; + + return res; +} + +/** + * Read the signature type of the certificate. We only support RSA-MD5 and + * RSA-SHA1 signature types. + */ +int asn1_signature_type(const uint8_t *cert, + int *offset, X509_CTX *x509_ctx) +{ + int ret = X509_NOT_OK, len; + + if (cert[(*offset)++] != ASN1_OID) + goto end_check_sig; + + len = get_asn1_length(cert, offset); + + if (len == sizeof(sig_sha1WithRSAEncrypt) && + memcmp(sig_sha1WithRSAEncrypt, &cert[*offset], + sizeof(sig_sha1WithRSAEncrypt)) == 0) + { + x509_ctx->sig_type = SIG_TYPE_SHA1; + } + else if (len == sizeof(sig_sha256) && + memcmp(sig_sha256, &cert[*offset], + sizeof(sig_sha256)) == 0) + { + x509_ctx->sig_type = SIG_TYPE_SHA256; + } + else if (len == sizeof(sig_sha384) && + memcmp(sig_sha384, &cert[*offset], + sizeof(sig_sha384)) == 0) + { + x509_ctx->sig_type = SIG_TYPE_SHA384; + } + else if (len == sizeof(sig_sha512) && + memcmp(sig_sha512, &cert[*offset], + sizeof(sig_sha512)) == 0) + { + x509_ctx->sig_type = SIG_TYPE_SHA512; + } + else + { + if (memcmp(sig_oid_prefix, &cert[*offset], sizeof(sig_oid_prefix))) + { + goto end_check_sig; /* unrecognised cert type */ + } + + x509_ctx->sig_type = cert[*offset + sizeof(sig_oid_prefix)]; + } + + *offset += len; + asn1_skip_obj(cert, offset, ASN1_NULL); /* if it's there */ + ret = X509_OK; + +end_check_sig: + return ret; +} + diff --git a/cores/esp8266/axtls/asn1.h b/cores/esp8266/axtls/asn1.h new file mode 100644 index 0000000000..5a5727aae9 --- /dev/null +++ b/cores/esp8266/axtls/asn1.h @@ -0,0 +1,55 @@ +#ifndef HEADER_ASN1_H +#define HEADER_ASN1_H +#include "x509.h" +/************************************************************************** + * ASN1 declarations + **************************************************************************/ +#define ASN1_BOOLEAN 0x01 +#define ASN1_INTEGER 0x02 +#define ASN1_BIT_STRING 0x03 +#define ASN1_OCTET_STRING 0x04 +#define ASN1_NULL 0x05 +#define ASN1_PRINTABLE_STR2 0x0C +#define ASN1_OID 0x06 +#define ASN1_PRINTABLE_STR2 0x0C +#define ASN1_PRINTABLE_STR 0x13 +#define ASN1_TELETEX_STR 0x14 +#define ASN1_IA5_STR 0x16 +#define ASN1_UTC_TIME 0x17 +#define ASN1_GENERALIZED_TIME 0x18 +#define ASN1_UNICODE_STR 0x1e +#define ASN1_SEQUENCE 0x30 +#define ASN1_CONTEXT_DNSNAME 0x82 +#define ASN1_SET 0x31 +#define ASN1_V3_DATA 0xa3 +#define ASN1_IMPLICIT_TAG 0x80 +#define ASN1_CONTEXT_DNSNAME 0x82 +#define ASN1_EXPLICIT_TAG 0xa0 +#define ASN1_V3_DATA 0xa3 + +#define SIG_TYPE_MD5 0x04 +#define SIG_TYPE_SHA1 0x05 +#define SIG_TYPE_SHA256 0x0b +#define SIG_TYPE_SHA384 0x0c +#define SIG_TYPE_SHA512 0x0d + +uint32_t get_asn1_length(const uint8_t *buf, int *offset); +int asn1_get_private_key(const uint8_t *buf, int len, RSA_CTX **rsa_ctx); +int asn1_next_obj(const uint8_t *buf, int *offset, int obj_type); +int asn1_skip_obj(const uint8_t *buf, int *offset, int obj_type); +int asn1_get_big_int(const uint8_t *buf, int *offset, uint8_t **object); +int asn1_get_int(const uint8_t *buf, int *offset, int32_t *val); +int asn1_get_bool(const uint8_t *buf, int *offset, bool *val); +int asn1_get_bit_string_as_int(const uint8_t *buf, int *offset, uint32_t *val); +int asn1_version(const uint8_t *cert, int *offset, int *val); +int asn1_validity(const uint8_t *cert, int *offset, X509_CTX *x509_ctx); +int asn1_name(const uint8_t *cert, int *offset, char *dn[]); +int asn1_public_key(const uint8_t *cert, int *offset, X509_CTX *x509_ctx); +int asn1_signature(const uint8_t *cert, int *offset, X509_CTX *x509_ctx); +int asn1_compare_dn(char * const dn1[], char * const dn2[]); +int asn1_is_subject_alt_name(const uint8_t *cert, int offset); +int asn1_is_basic_constraints(const uint8_t *cert, int offset); +int asn1_is_key_usage(const uint8_t *cert, int offset); +bool asn1_is_critical_ext(const uint8_t *buf, int *offset); +int asn1_signature_type(const uint8_t *cert, int *offset, X509_CTX *x509_ctx); +#endif diff --git a/cores/esp8266/axtls/bigint.cpp b/cores/esp8266/axtls/bigint.cpp new file mode 100644 index 0000000000..8b99b9d350 --- /dev/null +++ b/cores/esp8266/axtls/bigint.cpp @@ -0,0 +1,978 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @defgroup bigint_api Big Integer API + * @brief The bigint implementation as used by the axTLS project. + * + * The bigint library is for RSA encryption/decryption as well as signing. + * This code tries to minimise use of malloc/free by maintaining a small + * cache. A bigint context may maintain state by being made "permanent". + * It be be later released with a bi_depermanent() and bi_free() call. + * + * It supports the following reduction techniques: + * - Classical + * - Barrett + * - Montgomery + * + * It also implements the following: + * - Karatsuba multiplication + * - Squaring + * - Sliding window exponentiation + * - Chinese Remainder Theorem (implemented in rsa.c). + * + * All the algorithms used are pretty standard, and designed for different + * data bus sizes. Negative numbers are not dealt with at all, so a subtraction + * may need to be tested for negativity. + * + * This library steals some ideas from Jef Poskanzer + * + * and GMP . It gets most of its implementation + * detail from "The Handbook of Applied Cryptography" + * + * @{ + */ + +#include +#include "bigint.h" + +#define V1 v->comps[v->size-1] /**< v1 for division */ +#define V2 v->comps[v->size-2] /**< v2 for division */ +#define U(j) tmp_u->comps[tmp_u->size-j-1] /**< uj for division */ +#define Q(j) quotient->comps[quotient->size-j-1] /**< qj for division */ + +static bigint *bi_int_multiply(BI_CTX *ctx, bigint *bi, comp i); +static bigint *bi_int_divide(BI_CTX *ctx, bigint *biR, comp denom); +static bigint *alloc(BI_CTX *ctx, int size); +static bigint *trim(bigint *bi); +static void more_comps(bigint *bi, int n); + +#define check(A) + + +/** + * @brief Start a new bigint context. + * @return A bigint context. + */ +BI_CTX *bi_initialize(void) +{ + /* calloc() sets everything to zero */ + BI_CTX *ctx = (BI_CTX *)calloc(1, sizeof(BI_CTX)); + + /* the radix */ + ctx->bi_radix = alloc(ctx, 2); + ctx->bi_radix->comps[0] = 0; + ctx->bi_radix->comps[1] = 1; + bi_permanent(ctx->bi_radix); + return ctx; +} + +/** + * @brief Close the bigint context and free any resources. + * + * Free up any used memory - a check is done if all objects were not + * properly freed. + * @param ctx [in] The bigint session context. + */ +void bi_terminate(BI_CTX *ctx) +{ + bi_depermanent(ctx->bi_radix); + bi_free(ctx, ctx->bi_radix); + + if (ctx->active_count != 0) + { + abort(); + } + + bi_clear_cache(ctx); + free(ctx); +} + +/** + *@brief Clear the memory cache. + */ +void bi_clear_cache(BI_CTX *ctx) +{ + bigint *p, *pn; + + if (ctx->free_list == NULL) + return; + + for (p = ctx->free_list; p != NULL; p = pn) + { + pn = p->next; + free(p->comps); + free(p); + } + + ctx->free_count = 0; + ctx->free_list = NULL; +} + +/** + * @brief Increment the number of references to this object. + * It does not do a full copy. + * @param bi [in] The bigint to copy. + * @return A reference to the same bigint. + */ +bigint *bi_copy(bigint *bi) +{ + check(bi); + if (bi->refs != PERMANENT) + bi->refs++; + return bi; +} + +/** + * @brief Simply make a bigint object "unfreeable" if bi_free() is called on it. + * + * For this object to be freed, bi_depermanent() must be called. + * @param bi [in] The bigint to be made permanent. + */ +void bi_permanent(bigint *bi) +{ + check(bi); + if (bi->refs != 1) + { + abort(); + } + + bi->refs = PERMANENT; +} + +/** + * @brief Take a permanent object and make it eligible for freedom. + * @param bi [in] The bigint to be made back to temporary. + */ +void bi_depermanent(bigint *bi) +{ + check(bi); + if (bi->refs != PERMANENT) + { + abort(); + } + + bi->refs = 1; +} + +/** + * @brief Free a bigint object so it can be used again. + * + * The memory itself it not actually freed, just tagged as being available + * @param ctx [in] The bigint session context. + * @param bi [in] The bigint to be freed. + */ +void bi_free(BI_CTX *ctx, bigint *bi) +{ + check(bi); + if (bi->refs == PERMANENT) + { + return; + } + + if (--bi->refs > 0) + { + return; + } + + bi->next = ctx->free_list; + ctx->free_list = bi; + ctx->free_count++; + + if (--ctx->active_count < 0) + { + abort(); + } +} + +/** + * @brief Convert an (unsigned) integer into a bigint. + * @param ctx [in] The bigint session context. + * @param i [in] The (unsigned) integer to be converted. + * + */ +bigint *int_to_bi(BI_CTX *ctx, comp i) +{ + bigint *biR = alloc(ctx, 1); + biR->comps[0] = i; + return biR; +} + +/** + * @brief Do a full copy of the bigint object. + * @param ctx [in] The bigint session context. + * @param bi [in] The bigint object to be copied. + */ +bigint *bi_clone(BI_CTX *ctx, const bigint *bi) +{ + bigint *biR = alloc(ctx, bi->size); + check(bi); + memcpy(biR->comps, bi->comps, bi->size*COMP_BYTE_SIZE); + return biR; +} + +/** + * @brief Perform an addition operation between two bigints. + * @param ctx [in] The bigint session context. + * @param bia [in] A bigint. + * @param bib [in] Another bigint. + * @return The result of the addition. + */ +bigint *bi_add(BI_CTX *ctx, bigint *bia, bigint *bib) +{ + int n; + comp carry = 0; + comp *pa, *pb; + + check(bia); + check(bib); + + n = max(bia->size, bib->size); + more_comps(bia, n+1); + more_comps(bib, n); + pa = bia->comps; + pb = bib->comps; + + do + { + comp sl, rl, cy1; + sl = *pa + *pb++; + rl = sl + carry; + cy1 = sl < *pa; + carry = cy1 | (rl < sl); + *pa++ = rl; + } while (--n != 0); + + *pa = carry; /* do overflow */ + bi_free(ctx, bib); + return trim(bia); +} + +/** + * @brief Perform a subtraction operation between two bigints. + * @param ctx [in] The bigint session context. + * @param bia [in] A bigint. + * @param bib [in] Another bigint. + * @param is_negative [out] If defined, indicates that the result was negative. + * is_negative may be null. + * @return The result of the subtraction. The result is always positive. + */ +bigint *bi_subtract(BI_CTX *ctx, + bigint *bia, bigint *bib, int *is_negative) +{ + int n = bia->size; + comp *pa, *pb, carry = 0; + + check(bia); + check(bib); + + more_comps(bib, n); + pa = bia->comps; + pb = bib->comps; + + do + { + comp sl, rl, cy1; + sl = *pa - *pb++; + rl = sl - carry; + cy1 = sl > *pa; + carry = cy1 | (rl > sl); + *pa++ = rl; + } while (--n != 0); + + if (is_negative) /* indicate a negative result */ + { + *is_negative = carry; + } + + bi_free(ctx, trim(bib)); /* put bib back to the way it was */ + return trim(bia); +} + +/** + * Perform a multiply between a bigint an an (unsigned) integer + */ +static bigint *bi_int_multiply(BI_CTX *ctx, bigint *bia, comp b) +{ + int j = 0, n = bia->size; + bigint *biR = alloc(ctx, n + 1); + comp carry = 0; + comp *r = biR->comps; + comp *a = bia->comps; + + check(bia); + + /* clear things to start with */ + memset(r, 0, ((n+1)*COMP_BYTE_SIZE)); + + do + { + long_comp tmp = *r + (long_comp)a[j]*b + carry; + *r++ = (comp)tmp; /* downsize */ + carry = (comp)(tmp >> COMP_BIT_SIZE); + } while (++j < n); + + *r = carry; + bi_free(ctx, bia); + return trim(biR); +} + +/** + * @brief Does both division and modulo calculations. + * + * Used extensively when doing classical reduction. + * @param ctx [in] The bigint session context. + * @param u [in] A bigint which is the numerator. + * @param v [in] Either the denominator or the modulus depending on the mode. + * @param is_mod [n] Determines if this is a normal division (0) or a reduction + * (1). + * @return The result of the division/reduction. + */ +bigint *bi_divide(BI_CTX *ctx, bigint *u, bigint *v, int is_mod) +{ + int n = v->size, m = u->size-n; + int j = 0, orig_u_size = u->size; + uint8_t mod_offset = ctx->mod_offset; + comp d; + bigint *quotient, *tmp_u; + comp q_dash; + + check(u); + check(v); + + /* if doing reduction and we are < mod, then return mod */ + if (is_mod && bi_compare(v, u) > 0) + { + bi_free(ctx, v); + return u; + } + + quotient = alloc(ctx, m+1); + tmp_u = alloc(ctx, n+1); + v = trim(v); /* make sure we have no leading 0's */ + d = (comp)((long_comp)COMP_RADIX/(V1+1)); + + /* clear things to start with */ + memset(quotient->comps, 0, ((quotient->size)*COMP_BYTE_SIZE)); + + /* normalise */ + if (d > 1) + { + u = bi_int_multiply(ctx, u, d); + + if (is_mod) + { + v = ctx->bi_normalised_mod[mod_offset]; + } + else + { + v = bi_int_multiply(ctx, v, d); + } + } + + if (orig_u_size == u->size) /* new digit position u0 */ + { + more_comps(u, orig_u_size + 1); + } + + do + { + /* get a temporary short version of u */ + memcpy(tmp_u->comps, &u->comps[u->size-n-1-j], (n+1)*COMP_BYTE_SIZE); + + /* calculate q' */ + if (U(0) == V1) + { + q_dash = COMP_RADIX-1; + } + else + { + q_dash = (comp)(((long_comp)U(0)*COMP_RADIX + U(1))/V1); + + if (v->size > 1 && V2) + { + /* we are implementing the following: + if (V2*q_dash > (((U(0)*COMP_RADIX + U(1) - + q_dash*V1)*COMP_RADIX) + U(2))) ... */ + comp inner = (comp)((long_comp)COMP_RADIX*U(0) + U(1) - + (long_comp)q_dash*V1); + if ((long_comp)V2*q_dash > (long_comp)inner*COMP_RADIX + U(2)) + { + q_dash--; + } + } + } + + /* multiply and subtract */ + if (q_dash) + { + int is_negative; + tmp_u = bi_subtract(ctx, tmp_u, + bi_int_multiply(ctx, bi_copy(v), q_dash), &is_negative); + more_comps(tmp_u, n+1); + + Q(j) = q_dash; + + /* add back */ + if (is_negative) + { + Q(j)--; + tmp_u = bi_add(ctx, tmp_u, bi_copy(v)); + + /* lop off the carry */ + tmp_u->size--; + v->size--; + } + } + else + { + Q(j) = 0; + } + + /* copy back to u */ + memcpy(&u->comps[u->size-n-1-j], tmp_u->comps, (n+1)*COMP_BYTE_SIZE); + } while (++j <= m); + + bi_free(ctx, tmp_u); + bi_free(ctx, v); + + if (is_mod) /* get the remainder */ + { + bi_free(ctx, quotient); + return bi_int_divide(ctx, trim(u), d); + } + else /* get the quotient */ + { + bi_free(ctx, u); + return trim(quotient); + } +} + +/* + * Perform an integer divide on a bigint. + */ +static bigint *bi_int_divide(BI_CTX *ctx, bigint *biR, comp denom) +{ + int i = biR->size - 1; + long_comp r = 0; + + check(biR); + + do + { + r = (r<comps[i]; + biR->comps[i] = (comp)(r / denom); + r %= denom; + } while (--i >= 0); + + return trim(biR); +} + +/** + * @brief Allow a binary sequence to be imported as a bigint. + * @param ctx [in] The bigint session context. + * @param data [in] The data to be converted. + * @param size [in] The number of bytes of data. + * @return A bigint representing this data. + */ +bigint *bi_import(BI_CTX *ctx, const uint8_t *data, int size) +{ + bigint *biR = alloc(ctx, (size+COMP_BYTE_SIZE-1)/COMP_BYTE_SIZE); + int i, j = 0, offset = 0; + + memset(biR->comps, 0, biR->size*COMP_BYTE_SIZE); + + for (i = size-1; i >= 0; i--) + { + biR->comps[offset] += data[i] << (j*8); + + if (++j == COMP_BYTE_SIZE) + { + j = 0; + offset ++; + } + } + + return trim(biR); +} + +/** + * @brief Take a bigint and convert it into a byte sequence. + * + * This is useful after a decrypt operation. + * @param ctx [in] The bigint session context. + * @param x [in] The bigint to be converted. + * @param data [out] The converted data as a byte stream. + * @param size [in] The maximum size of the byte stream. Unused bytes will be + * zeroed. + */ +void bi_export(BI_CTX *ctx, bigint *x, uint8_t *data, int size) +{ + int i, j, k = size-1; + + check(x); + memset(data, 0, size); /* ensure all leading 0's are cleared */ + + for (i = 0; i < x->size; i++) + { + for (j = 0; j < COMP_BYTE_SIZE; j++) + { + comp mask = 0xff << (j*8); + int num = (x->comps[i] & mask) >> (j*8); + data[k--] = num; + + if (k < 0) + { + goto buf_done; + } + } + } +buf_done: + + bi_free(ctx, x); +} + +/* + * Work out the highest '1' bit in an exponent. Used when doing sliding-window + * exponentiation. + */ +static int find_max_exp_index(bigint *biexp) +{ + int i = COMP_BIT_SIZE-1; + comp shift = COMP_RADIX/2; + comp test = biexp->comps[biexp->size-1]; /* assume no leading zeroes */ + + check(biexp); + + do + { + if (test & shift) + { + return i+(biexp->size-1)*COMP_BIT_SIZE; + } + + shift >>= 1; + } while (i-- != 0); + + return -1; /* error - must have been a leading 0 */ +} + +/* + * Is a particular bit is an exponent 1 or 0? Used when doing sliding-window + * exponentiation. + */ +static int exp_bit_is_one(bigint *biexp, int offset) +{ + comp test = biexp->comps[offset / COMP_BIT_SIZE]; + int num_shifts = offset % COMP_BIT_SIZE; + comp shift = 1; + int i; + + check(biexp); + + for (i = 0; i < num_shifts; i++) + { + shift <<= 1; + } + + return (test & shift) != 0; +} + + + +/** + * @brief Perform a modular exponentiation. + * + * This function requires bi_set_mod() to have been called previously. This is + * one of the optimisations used for performance. + * @param ctx [in] The bigint session context. + * @param bi [in] The bigint on which to perform the mod power operation. + * @param biexp [in] The bigint exponent. + * @return The result of the mod exponentiation operation + * @see bi_set_mod(). + */ +bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp) +{ + int i = find_max_exp_index(biexp), j, window_size = 1; + bigint *biR = int_to_bi(ctx, 1); + check(bi); + check(biexp); + ctx->g = (bigint **)malloc(sizeof(bigint *)); + ctx->g[0] = bi_clone(ctx, bi); + ctx->window = 1; + bi_permanent(ctx->g[0]); + + /* if sliding-window is off, then only one bit will be done at a time and + * will reduce to standard left-to-right exponentiation */ + do + { + if (exp_bit_is_one(biexp, i)) + { + int l = i-window_size+1; + int part_exp = 0; + + if (l < 0) /* LSB of exponent will always be 1 */ + l = 0; + else + { + while (exp_bit_is_one(biexp, l) == 0) + l++; /* go back up */ + } + + /* build up the section of the exponent */ + for (j = i; j >= l; j--) + { + biR = bi_residue(ctx, bi_square(ctx, biR)); + if (exp_bit_is_one(biexp, j)) + part_exp++; + + if (j != l) + part_exp <<= 1; + } + + part_exp = (part_exp-1)/2; /* adjust for array */ + biR = bi_residue(ctx, bi_multiply(ctx, biR, ctx->g[part_exp])); + i = l-1; + } + else /* square it */ + { + biR = bi_residue(ctx, bi_square(ctx, biR)); + i--; + } + } while (i >= 0); + + /* cleanup */ + for (i = 0; i < ctx->window; i++) + { + bi_depermanent(ctx->g[i]); + bi_free(ctx, ctx->g[i]); + } + + free(ctx->g); + bi_free(ctx, bi); + bi_free(ctx, biexp); + return biR; /* convert back */ +} + +/** + * @brief Perform a modular exponentiation using a temporary modulus. + * + * We need this function to check the signatures of certificates. The modulus + * of this function is temporary as it's just used for authentication. + * @param ctx [in] The bigint session context. + * @param bi [in] The bigint to perform the exp/mod. + * @param bim [in] The temporary modulus. + * @param biexp [in] The bigint exponent. + * @return The result of the mod exponentiation operation + * @see bi_set_mod(). + */ +bigint *bi_mod_power2(BI_CTX *ctx, bigint *bi, bigint *bim, bigint *biexp) +{ + bigint *biR, *tmp_biR; + + /* Set up a temporary bigint context and transfer what we need between + * them. We need to do this since we want to keep the original modulus + * which is already in this context. This operation is only called when + * doing peer verification, and so is not expensive :-) */ + BI_CTX *tmp_ctx = bi_initialize(); + bi_set_mod(tmp_ctx, bi_clone(tmp_ctx, bim), BIGINT_M_OFFSET); + tmp_biR = bi_mod_power(tmp_ctx, + bi_clone(tmp_ctx, bi), + bi_clone(tmp_ctx, biexp)); + biR = bi_clone(ctx, tmp_biR); + bi_free(tmp_ctx, tmp_biR); + bi_free_mod(tmp_ctx, BIGINT_M_OFFSET); + bi_terminate(tmp_ctx); + + bi_free(ctx, bi); + bi_free(ctx, bim); + bi_free(ctx, biexp); + return biR; +} + + +/** + * @brief Pre-calculate some of the expensive steps in reduction. + * + * This function should only be called once (normally when a session starts). + * When the session is over, bi_free_mod() should be called. bi_mod_power() + * relies on this function being called. + * @param ctx [in] The bigint session context. + * @param bim [in] The bigint modulus that will be used. + * @param mod_offset [in] There are three moduluii that can be stored - the + * standard modulus, and its two primes p and q. This offset refers to which + * modulus we are referring to. + * @see bi_free_mod(), bi_mod_power(). + */ +void bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset) +{ + int k = bim->size; + comp d = (comp)((long_comp)COMP_RADIX/(bim->comps[k-1]+1)); + + ctx->bi_mod[mod_offset] = bim; + bi_permanent(ctx->bi_mod[mod_offset]); + ctx->bi_normalised_mod[mod_offset] = bi_int_multiply(ctx, bim, d); + bi_permanent(ctx->bi_normalised_mod[mod_offset]); +} + +/** + * @brief Used when cleaning various bigints at the end of a session. + * @param ctx [in] The bigint session context. + * @param mod_offset [in] The offset to use. + * @see bi_set_mod(). + */ +void bi_free_mod(BI_CTX *ctx, int mod_offset) +{ + bi_depermanent(ctx->bi_mod[mod_offset]); + bi_free(ctx, ctx->bi_mod[mod_offset]); + bi_depermanent(ctx->bi_normalised_mod[mod_offset]); + bi_free(ctx, ctx->bi_normalised_mod[mod_offset]); +} + +/** + * Perform a standard multiplication between two bigints. + * + * Barrett reduction has no need for some parts of the product, so ignore bits + * of the multiply. This routine gives Barrett its big performance + * improvements over Classical/Montgomery reduction methods. + */ +static bigint *regular_multiply(BI_CTX *ctx, bigint *bia, bigint *bib, + int inner_partial, int outer_partial) +{ + int i = 0, j; + int n = bia->size; + int t = bib->size; + bigint *biR = alloc(ctx, n + t); + comp *sr = biR->comps; + comp *sa = bia->comps; + comp *sb = bib->comps; + + check(bia); + check(bib); + + /* clear things to start with */ + memset(biR->comps, 0, ((n+t)*COMP_BYTE_SIZE)); + + do + { + long_comp tmp; + comp carry = 0; + int r_index = i; + j = 0; + + if (outer_partial && outer_partial-i > 0 && outer_partial < n) + { + r_index = outer_partial-1; + j = outer_partial-i-1; + } + + do + { + if (inner_partial && r_index >= inner_partial) + { + break; + } + + tmp = sr[r_index] + ((long_comp)sa[j])*sb[i] + carry; + sr[r_index++] = (comp)tmp; /* downsize */ + carry = tmp >> COMP_BIT_SIZE; + } while (++j < n); + + sr[r_index] = carry; + } while (++i < t); + + bi_free(ctx, bia); + bi_free(ctx, bib); + return trim(biR); +} + +/** + * @brief Perform a multiplication operation between two bigints. + * @param ctx [in] The bigint session context. + * @param bia [in] A bigint. + * @param bib [in] Another bigint. + * @return The result of the multiplication. + */ +bigint *bi_multiply(BI_CTX *ctx, bigint *bia, bigint *bib) +{ + check(bia); + check(bib); + + return regular_multiply(ctx, bia, bib, 0, 0); +} + +/** + * @brief Compare two bigints. + * @param bia [in] A bigint. + * @param bib [in] Another bigint. + * @return -1 if smaller, 1 if larger and 0 if equal. + */ +int bi_compare(bigint *bia, bigint *bib) +{ + int r, i; + + check(bia); + check(bib); + + if (bia->size > bib->size) + r = 1; + else if (bia->size < bib->size) + r = -1; + else + { + comp *a = bia->comps; + comp *b = bib->comps; + + /* Same number of components. Compare starting from the high end + * and working down. */ + r = 0; + i = bia->size - 1; + + do + { + if (a[i] > b[i]) + { + r = 1; + break; + } + else if (a[i] < b[i]) + { + r = -1; + break; + } + } while (--i >= 0); + } + + return r; +} + +/* + * Allocate and zero more components. Does not consume bi. + */ +static void more_comps(bigint *bi, int n) +{ + if (n > bi->max_comps) + { + bi->max_comps = max(bi->max_comps * 2, n); + bi->comps = (comp*)realloc(bi->comps, bi->max_comps * COMP_BYTE_SIZE); + } + + if (n > bi->size) + { + memset(&bi->comps[bi->size], 0, (n-bi->size)*COMP_BYTE_SIZE); + } + + bi->size = n; +} + +/* + * Make a new empty bigint. It may just use an old one if one is available. + * Otherwise get one off the heap. + */ +static bigint *alloc(BI_CTX *ctx, int size) +{ + bigint *biR; + + /* Can we recycle an old bigint? */ + if (ctx->free_list != NULL) + { + biR = ctx->free_list; + ctx->free_list = biR->next; + ctx->free_count--; + + if (biR->refs != 0) + { + abort(); /* create a stack trace from a core dump */ + } + + more_comps(biR, size); + } + else + { + /* No free bigints available - create a new one. */ + biR = (bigint *)malloc(sizeof(bigint)); + biR->comps = (comp*)malloc(size * COMP_BYTE_SIZE); + biR->max_comps = size; /* give some space to spare */ + } + + biR->size = size; + biR->refs = 1; + biR->next = NULL; + ctx->active_count++; + return biR; +} + +/* + * Delete any leading 0's (and allow for 0). + */ +static bigint *trim(bigint *bi) +{ + check(bi); + + while (bi->comps[bi->size-1] == 0 && bi->size > 1) + { + bi->size--; + } + + return bi; +} + +/** + * @brief Use the Chinese Remainder Theorem to quickly perform RSA decrypts. + * + * @param ctx [in] The bigint session context. + * @param bi [in] The bigint to perform the exp/mod. + * @param dP [in] CRT's dP bigint + * @param dQ [in] CRT's dQ bigint + * @param p [in] CRT's p bigint + * @param q [in] CRT's q bigint + * @param qInv [in] CRT's qInv bigint + * @return The result of the CRT operation + */ +bigint *bi_crt(BI_CTX *ctx, bigint *bi, + bigint *dP, bigint *dQ, + bigint *p, bigint *q, bigint *qInv) +{ + bigint *m1, *m2, *h; + + /* Montgomery has a condition the 0 < x, y < m and these products violate + * that condition. So disable Montgomery when using CRT */ + ctx->mod_offset = BIGINT_P_OFFSET; + m1 = bi_mod_power(ctx, bi_copy(bi), dP); + + ctx->mod_offset = BIGINT_Q_OFFSET; + m2 = bi_mod_power(ctx, bi, dQ); + + h = bi_subtract(ctx, bi_add(ctx, m1, p), bi_copy(m2), NULL); + h = bi_multiply(ctx, h, qInv); + ctx->mod_offset = BIGINT_P_OFFSET; + h = bi_residue(ctx, h); + return bi_add(ctx, m2, bi_multiply(ctx, q, h)); +} diff --git a/cores/esp8266/axtls/bigint.h b/cores/esp8266/axtls/bigint.h new file mode 100644 index 0000000000..5ba450bd9c --- /dev/null +++ b/cores/esp8266/axtls/bigint.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef BIGINT_HEADER +#define BIGINT_HEADER + +#include "bigint_impl.h" + +BI_CTX *bi_initialize(void); +void bi_terminate(BI_CTX *ctx); +void bi_permanent(bigint *bi); +void bi_depermanent(bigint *bi); +void bi_clear_cache(BI_CTX *ctx); +void bi_free(BI_CTX *ctx, bigint *bi); +bigint *bi_copy(bigint *bi); +bigint *bi_clone(BI_CTX *ctx, const bigint *bi); +void bi_export(BI_CTX *ctx, bigint *bi, uint8_t *data, int size); +bigint *bi_import(BI_CTX *ctx, const uint8_t *data, int len); +bigint *int_to_bi(BI_CTX *ctx, comp i); + +/* the functions that actually do something interesting */ +bigint *bi_add(BI_CTX *ctx, bigint *bia, bigint *bib); +bigint *bi_subtract(BI_CTX *ctx, bigint *bia, + bigint *bib, int *is_negative); +bigint *bi_divide(BI_CTX *ctx, bigint *bia, bigint *bim, int is_mod); +bigint *bi_multiply(BI_CTX *ctx, bigint *bia, bigint *bib); +bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp); +bigint *bi_mod_power2(BI_CTX *ctx, bigint *bi, bigint *bim, bigint *biexp); +int bi_compare(bigint *bia, bigint *bib); +void bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset); +void bi_free_mod(BI_CTX *ctx, int mod_offset); + +/** + * @def bi_mod + * Find the residue of B. bi_set_mod() must be called before hand. + */ +#define bi_mod(A, B) bi_divide(A, B, ctx->bi_mod[ctx->mod_offset], 1) + +/** + * bi_residue() is technically the same as bi_mod(), but it uses the + * appropriate reduction technique (which is bi_mod() when doing classical + * reduction). + */ +#define bi_residue(A, B) bi_mod(A, B) +#define bi_square(A, B) bi_multiply(A, bi_copy(B), B) +bigint *bi_crt(BI_CTX *ctx, bigint *bi, + bigint *dP, bigint *dQ, + bigint *p, bigint *q, + bigint *qInv); +#endif diff --git a/cores/esp8266/axtls/bigint_impl.h b/cores/esp8266/axtls/bigint_impl.h new file mode 100644 index 0000000000..481d8a149e --- /dev/null +++ b/cores/esp8266/axtls/bigint_impl.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef BIGINT_IMPL_HEADER +#define BIGINT_IMPL_HEADER +#include + +/* Maintain a number of precomputed variables when doing reduction */ +#define BIGINT_M_OFFSET 0 /**< Normal modulo offset. */ +#define BIGINT_P_OFFSET 1 /**< p modulo offset. */ +#define BIGINT_Q_OFFSET 2 /**< q module offset. */ +#define BIGINT_NUM_MODS 3 /**< The number of modulus constants used. */ + +/* Architecture specific functions for big ints */ +#define COMP_RADIX 256U /**< Max component + 1 */ +#define COMP_MAX 0xFFFFU/**< (Max dbl comp -1) */ +#define COMP_BIT_SIZE 8 /**< Number of bits in a component. */ +#define COMP_BYTE_SIZE 1 /**< Number of bytes in a component. */ +#define COMP_NUM_NIBBLES 2 /**< Used For diagnostics only. */ +typedef uint8_t comp; /**< A single precision component. */ +typedef uint16_t long_comp; /**< A double precision component. */ +typedef int16_t slong_comp; /**< A signed double precision component. */ + +/** + * @struct _bigint + * @brief A big integer basic object + */ +struct _bigint +{ + struct _bigint* next; /**< The next bigint in the cache. */ + short size; /**< The number of components in this bigint. */ + short max_comps; /**< The heapsize allocated for this bigint */ + int refs; /**< An internal reference count. */ + comp* comps; /**< A ptr to the actual component data */ +}; + +typedef struct _bigint bigint; /**< An alias for _bigint */ + +/** + * Maintains the state of the cache, and a number of variables used in + * reduction. + */ +typedef struct /**< A big integer "session" context. */ +{ + bigint *active_list; /**< Bigints currently used. */ + bigint *free_list; /**< Bigints not used. */ + bigint *bi_radix; /**< The radix used. */ + bigint *bi_mod[BIGINT_NUM_MODS]; /**< modulus */ + bigint *bi_normalised_mod[BIGINT_NUM_MODS]; /**< Normalised mod storage. */ + bigint **g; /**< Used by sliding-window. */ + int window; /**< The size of the sliding window */ + int active_count; /**< Number of active bigints. */ + int free_count; /**< Number of free bigints. */ + uint8_t mod_offset; /**< The mod offset we are using */ +} BI_CTX; + +#define PERMANENT 0x7FFF55AA /**< A magic number for permanents. */ + +#endif diff --git a/cores/esp8266/axtls/ca.h b/cores/esp8266/axtls/ca.h new file mode 100644 index 0000000000..e67947b163 --- /dev/null +++ b/cores/esp8266/axtls/ca.h @@ -0,0 +1,86 @@ +unsigned char ca_crt_der[] = { + 0x30, 0x82, 0x03, 0xdb, 0x30, 0x82, 0x02, 0xc3, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x09, 0x00, 0xd7, 0xff, 0x21, 0x58, 0x3c, 0x9d, 0x73, 0x93, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x0b, 0x05, 0x00, 0x30, 0x81, 0x83, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x0c, 0x30, 0x0a, 0x06, + 0x03, 0x55, 0x04, 0x08, 0x0c, 0x03, 0x56, 0x49, 0x43, 0x31, 0x12, 0x30, + 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x4d, 0x65, 0x6c, 0x62, + 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, + 0x04, 0x0a, 0x0c, 0x0d, 0x4d, 0x79, 0x6c, 0x65, 0x73, 0x20, 0x54, 0x65, + 0x73, 0x74, 0x20, 0x43, 0x41, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x0c, 0x0b, 0x4d, 0x79, 0x6c, 0x65, 0x73, 0x20, 0x45, 0x66, + 0x74, 0x6f, 0x73, 0x31, 0x24, 0x30, 0x22, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x15, 0x6d, 0x79, 0x6c, 0x65, + 0x73, 0x40, 0x6d, 0x61, 0x64, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x2e, 0x63, + 0x6f, 0x6d, 0x2e, 0x61, 0x75, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x37, 0x30, + 0x33, 0x31, 0x31, 0x30, 0x30, 0x35, 0x31, 0x35, 0x37, 0x5a, 0x17, 0x0d, + 0x32, 0x37, 0x30, 0x33, 0x30, 0x39, 0x30, 0x30, 0x35, 0x31, 0x35, 0x37, + 0x5a, 0x30, 0x81, 0x83, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, + 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, + 0x04, 0x08, 0x0c, 0x03, 0x56, 0x49, 0x43, 0x31, 0x12, 0x30, 0x10, 0x06, + 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x4d, 0x65, 0x6c, 0x62, 0x6f, 0x75, + 0x72, 0x6e, 0x65, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, + 0x0c, 0x0d, 0x4d, 0x79, 0x6c, 0x65, 0x73, 0x20, 0x54, 0x65, 0x73, 0x74, + 0x20, 0x43, 0x41, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x0c, 0x0b, 0x4d, 0x79, 0x6c, 0x65, 0x73, 0x20, 0x45, 0x66, 0x74, 0x6f, + 0x73, 0x31, 0x24, 0x30, 0x22, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x09, 0x01, 0x16, 0x15, 0x6d, 0x79, 0x6c, 0x65, 0x73, 0x40, + 0x6d, 0x61, 0x64, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x2e, 0x63, 0x6f, 0x6d, + 0x2e, 0x61, 0x75, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, + 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, + 0xab, 0xdf, 0x27, 0x4d, 0x17, 0xf2, 0xb3, 0xf7, 0x36, 0xa6, 0x5b, 0x5e, + 0xb9, 0x53, 0x32, 0x1c, 0x1d, 0x36, 0xad, 0xef, 0x91, 0xa1, 0x45, 0x4b, + 0x44, 0x26, 0xf5, 0x1a, 0xe2, 0x4c, 0xc9, 0x65, 0x8d, 0xd5, 0xfb, 0x72, + 0x38, 0x72, 0xd1, 0xe4, 0xdd, 0xca, 0xaa, 0xcc, 0xfd, 0x4d, 0x3a, 0xb3, + 0x64, 0x85, 0x91, 0xd2, 0x02, 0x98, 0xee, 0xcb, 0x32, 0x27, 0x9d, 0x5c, + 0xa1, 0x11, 0x25, 0xa8, 0x5f, 0xb8, 0xe6, 0x23, 0x6d, 0x5c, 0x49, 0xe7, + 0xec, 0x4d, 0xad, 0x11, 0xb4, 0xad, 0x8a, 0x18, 0x51, 0x26, 0xc4, 0xc8, + 0xa3, 0xfb, 0x30, 0xc7, 0x5c, 0xec, 0xee, 0x75, 0xcb, 0xb4, 0xa0, 0xab, + 0xed, 0xea, 0x2a, 0x59, 0x21, 0x51, 0x68, 0x30, 0x5f, 0x10, 0x93, 0xd5, + 0x80, 0x20, 0xad, 0x90, 0x9d, 0xc8, 0xcf, 0x2e, 0xd1, 0xea, 0x0b, 0xc5, + 0xa0, 0x4f, 0x75, 0x9c, 0x62, 0x66, 0x24, 0xa9, 0x95, 0x71, 0xeb, 0x5c, + 0xe1, 0x6c, 0x60, 0xb7, 0xb0, 0xf6, 0x99, 0x35, 0x75, 0x00, 0x00, 0x1b, + 0x27, 0xd3, 0x00, 0x04, 0x4d, 0xf3, 0x9b, 0xbb, 0xf9, 0xa1, 0x4a, 0x7c, + 0xb0, 0x62, 0x61, 0x1b, 0xde, 0x7f, 0xdb, 0x98, 0xb5, 0x17, 0x3c, 0xb4, + 0x10, 0xdb, 0x17, 0xb5, 0xba, 0x08, 0xf1, 0x82, 0xdb, 0xa8, 0x38, 0x72, + 0x2c, 0x35, 0x5f, 0x41, 0xcb, 0x6b, 0x0c, 0x88, 0xb5, 0x13, 0x70, 0x14, + 0x06, 0xdd, 0xb0, 0x30, 0xc5, 0xa0, 0xf4, 0xe0, 0x43, 0x5a, 0xfe, 0x7f, + 0xa1, 0xb0, 0x2b, 0x80, 0x51, 0x77, 0xff, 0x63, 0xfc, 0xe1, 0x52, 0xce, + 0x10, 0x63, 0x87, 0xea, 0x7f, 0x26, 0x21, 0xd7, 0x17, 0x70, 0xcd, 0xea, + 0x71, 0x26, 0x3a, 0xa2, 0x6c, 0xca, 0x47, 0x57, 0x98, 0xe5, 0xd9, 0xf4, + 0xc7, 0x0c, 0x0f, 0x47, 0x0f, 0xfd, 0xa7, 0x7d, 0x45, 0x4c, 0x2e, 0x62, + 0xbc, 0xfa, 0xe6, 0x29, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x50, 0x30, + 0x4e, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, + 0xf6, 0x18, 0xe8, 0x6e, 0x26, 0xdd, 0xcf, 0xfe, 0x7e, 0x00, 0x99, 0x46, + 0xa8, 0xa8, 0xa2, 0x06, 0xd2, 0xff, 0x0a, 0xe0, 0x30, 0x1f, 0x06, 0x03, + 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xf6, 0x18, 0xe8, + 0x6e, 0x26, 0xdd, 0xcf, 0xfe, 0x7e, 0x00, 0x99, 0x46, 0xa8, 0xa8, 0xa2, + 0x06, 0xd2, 0xff, 0x0a, 0xe0, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, + 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, + 0x01, 0x01, 0x00, 0x41, 0xab, 0x3f, 0x06, 0x1a, 0xd9, 0x00, 0xe1, 0xd0, + 0xfa, 0xbb, 0xd2, 0x82, 0xe5, 0x3e, 0x6a, 0xfe, 0x05, 0x66, 0x6b, 0x01, + 0x9d, 0x0b, 0x07, 0x19, 0xb4, 0xd8, 0x1c, 0x16, 0x5b, 0x8c, 0xd5, 0xa9, + 0xbf, 0xbc, 0x6f, 0x7a, 0x39, 0xd6, 0xb4, 0x40, 0x05, 0xc0, 0xf2, 0x07, + 0xfd, 0x26, 0xcf, 0x49, 0x71, 0x66, 0xda, 0x36, 0x08, 0x37, 0xdf, 0x4c, + 0x91, 0xc0, 0xad, 0x1e, 0xf7, 0xa0, 0x31, 0x6b, 0xfc, 0xb8, 0xe9, 0x5d, + 0x24, 0xc8, 0xc5, 0x63, 0xc2, 0xc3, 0x84, 0x41, 0x24, 0x67, 0xf0, 0xf4, + 0x8d, 0xc5, 0x24, 0xdf, 0xd2, 0x75, 0xc6, 0x55, 0xca, 0x61, 0x19, 0x1d, + 0x17, 0xd9, 0x57, 0x4c, 0x33, 0x30, 0xae, 0x23, 0x4b, 0x6a, 0x7a, 0xdb, + 0x8b, 0x11, 0x44, 0x2b, 0x48, 0xb3, 0xbb, 0x38, 0xcd, 0x16, 0x52, 0x1e, + 0x24, 0xf0, 0xff, 0xdc, 0xf6, 0x6d, 0x62, 0xdb, 0xd8, 0x2b, 0x5f, 0xa0, + 0x3e, 0x6d, 0x59, 0x0c, 0xa5, 0x02, 0x4e, 0xd0, 0xde, 0x46, 0xf0, 0x0d, + 0xdf, 0x0a, 0xa8, 0xc3, 0x61, 0xfd, 0x5e, 0x77, 0x80, 0xee, 0xd9, 0x44, + 0xf7, 0x1c, 0x15, 0x75, 0xf3, 0x85, 0x82, 0x21, 0x56, 0x91, 0x88, 0xc7, + 0xcb, 0x08, 0x6a, 0x85, 0x5a, 0x90, 0xbe, 0xc4, 0xd7, 0x49, 0xf2, 0x6b, + 0xc9, 0x59, 0xb6, 0x8a, 0xb1, 0xdc, 0x5a, 0xa3, 0xd5, 0x11, 0xe2, 0x5a, + 0x01, 0x6f, 0x6d, 0xf3, 0x76, 0xb4, 0xba, 0x61, 0x0e, 0x74, 0x75, 0x9f, + 0x07, 0xdc, 0x63, 0x96, 0xe8, 0x30, 0x62, 0xcc, 0x75, 0x4e, 0x0b, 0xe5, + 0x8c, 0x3c, 0x92, 0xb6, 0x25, 0xc9, 0x16, 0xcb, 0xd6, 0x9a, 0x2d, 0x6a, + 0xa2, 0xe9, 0xb4, 0x33, 0x3c, 0x88, 0x8a, 0x3d, 0x5f, 0x16, 0xab, 0x59, + 0xc5, 0x46, 0xb3, 0xab, 0x13, 0x46, 0xef, 0x4c, 0x88, 0xaa, 0xb6, 0x74, + 0x26, 0x88, 0x8d, 0xa7, 0x99, 0xc5, 0xee +}; +int ca_crt_der_len = 991; diff --git a/cores/esp8266/axtls/rsa.cpp b/cores/esp8266/axtls/rsa.cpp new file mode 100644 index 0000000000..f549f592eb --- /dev/null +++ b/cores/esp8266/axtls/rsa.cpp @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2007-2014, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * Implements the RSA public encryption algorithm. Uses the bigint library to + * perform its calculations. + */ +#include +#include "rsa.h" + +void RSA_priv_key_new(RSA_CTX **ctx, + const uint8_t *modulus, int mod_len, + const uint8_t *pub_exp, int pub_len, + const uint8_t *priv_exp, int priv_len, + const uint8_t *p, int p_len, + const uint8_t *q, int q_len, + const uint8_t *dP, int dP_len, + const uint8_t *dQ, int dQ_len, + const uint8_t *qInv, int qInv_len + ) +{ + RSA_CTX *rsa_ctx; + BI_CTX *bi_ctx; + RSA_pub_key_new(ctx, modulus, mod_len, pub_exp, pub_len); + rsa_ctx = *ctx; + bi_ctx = rsa_ctx->bi_ctx; + rsa_ctx->d = bi_import(bi_ctx, priv_exp, priv_len); + bi_permanent(rsa_ctx->d); + rsa_ctx->p = bi_import(bi_ctx, p, p_len); + rsa_ctx->q = bi_import(bi_ctx, q, q_len); + rsa_ctx->dP = bi_import(bi_ctx, dP, dP_len); + rsa_ctx->dQ = bi_import(bi_ctx, dQ, dQ_len); + rsa_ctx->qInv = bi_import(bi_ctx, qInv, qInv_len); + bi_permanent(rsa_ctx->dP); + bi_permanent(rsa_ctx->dQ); + bi_permanent(rsa_ctx->qInv); + bi_set_mod(bi_ctx, rsa_ctx->p, BIGINT_P_OFFSET); + bi_set_mod(bi_ctx, rsa_ctx->q, BIGINT_Q_OFFSET); +} + +void RSA_pub_key_new(RSA_CTX **ctx, + const uint8_t *modulus, int mod_len, + const uint8_t *pub_exp, int pub_len) +{ + RSA_CTX *rsa_ctx; + BI_CTX *bi_ctx; + + if (*ctx) /* if we load multiple certs, dump the old one */ + RSA_free(*ctx); + + bi_ctx = bi_initialize(); + *ctx = (RSA_CTX *)calloc(1, sizeof(RSA_CTX)); + rsa_ctx = *ctx; + rsa_ctx->bi_ctx = bi_ctx; + rsa_ctx->num_octets = mod_len; + rsa_ctx->m = bi_import(bi_ctx, modulus, mod_len); + bi_set_mod(bi_ctx, rsa_ctx->m, BIGINT_M_OFFSET); + rsa_ctx->e = bi_import(bi_ctx, pub_exp, pub_len); + bi_permanent(rsa_ctx->e); +} + +/** + * Free up any RSA context resources. + */ +void RSA_free(RSA_CTX *rsa_ctx) +{ + BI_CTX *bi_ctx; + if (rsa_ctx == NULL) /* deal with ptrs that are null */ + return; + + bi_ctx = rsa_ctx->bi_ctx; + + bi_depermanent(rsa_ctx->e); + bi_free(bi_ctx, rsa_ctx->e); + bi_free_mod(rsa_ctx->bi_ctx, BIGINT_M_OFFSET); + + if (rsa_ctx->d) + { + bi_depermanent(rsa_ctx->d); + bi_free(bi_ctx, rsa_ctx->d); + bi_depermanent(rsa_ctx->dP); + bi_depermanent(rsa_ctx->dQ); + bi_depermanent(rsa_ctx->qInv); + bi_free(bi_ctx, rsa_ctx->dP); + bi_free(bi_ctx, rsa_ctx->dQ); + bi_free(bi_ctx, rsa_ctx->qInv); + bi_free_mod(rsa_ctx->bi_ctx, BIGINT_P_OFFSET); + bi_free_mod(rsa_ctx->bi_ctx, BIGINT_Q_OFFSET); + } + + bi_terminate(bi_ctx); + free(rsa_ctx); +} + +/** + * @brief Use PKCS1.5 for decryption/verification. + * @param ctx [in] The context + * @param in_data [in] The data to decrypt (must be < modulus size-11) + * @param out_data [out] The decrypted data. + * @param out_len [int] The size of the decrypted buffer in bytes + * @param is_decryption [in] Decryption or verify operation. + * @return The number of bytes that were originally encrypted. -1 on error. + * @see http://www.rsasecurity.com/rsalabs/node.asp?id=2125 + */ +int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data, + uint8_t *out_data, int out_len, int is_decryption) +{ + const int byte_size = ctx->num_octets; + int i = 0, size; + bigint *decrypted_bi, *dat_bi; + uint8_t *block = (uint8_t *)alloca(byte_size); + int pad_count = 0; + + if (out_len < byte_size) /* check output has enough size */ + return -1; + + memset(out_data, 0, out_len); /* initialise */ + + /* decrypt */ + dat_bi = bi_import(ctx->bi_ctx, in_data, byte_size); + decrypted_bi = is_decryption ? RSA_private(ctx, dat_bi) : RSA_public(ctx, dat_bi); + + /* convert to a normal block */ + bi_export(ctx->bi_ctx, decrypted_bi, block, byte_size); + + if (block[i++] != 0) /* leading 0? */ + return -1; + + if (is_decryption == 0) + { + if (block[i++] != 0x01) /* BT correct? */ + return -1; + + while (block[i++] == 0xff && i < byte_size) + pad_count++; + } + else + { + if (block[i++] != 0x02) /* BT correct? */ + return -1; + + while (block[i++] && i < byte_size) + pad_count++; + } + + /* check separator byte 0x00 - and padding must be 8 or more bytes */ + if (i == byte_size || pad_count < 8) + return -1; + + size = byte_size - i; + + /* get only the bit we want */ + memcpy(out_data, &block[i], size); + return size; +} + +/** + * Performs m = c^d mod n + */ +bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg) +{ + return bi_crt(c->bi_ctx, bi_msg, c->dP, c->dQ, c->p, c->q, c->qInv); +} + +/** + * Performs c = m^e mod n + */ +bigint *RSA_public(const RSA_CTX * c, bigint *bi_msg) +{ + c->bi_ctx->mod_offset = BIGINT_M_OFFSET; + return bi_mod_power(c->bi_ctx, bi_msg, c->e); +} + +int get_random(int num_rand_bytes, uint8_t *rand_data) +{ + for(int i = 0; i < num_rand_bytes; i++) { + rand_data[i] = random(0, 255); + } + return 0; +} + +/** + * Set a series of bytes with a random number. Individual bytes are not zero. + */ +int get_random_NZ(int num_rand_bytes, uint8_t *rand_data) +{ + int i; + if (get_random(num_rand_bytes, rand_data)) + return -1; + + for (i = 0; i < num_rand_bytes; i++) + { + while (rand_data[i] == 0) /* can't be 0 */ + rand_data[i] = (uint8_t)(rand()); + } + + return 0; +} + +/** + * Use PKCS1.5 for encryption/signing. + * see http://www.rsasecurity.com/rsalabs/node.asp?id=2125 + */ +int RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len, + uint8_t *out_data, int is_signing) +{ + int byte_size = ctx->num_octets; + int num_pads_needed = byte_size-in_len-3; + bigint *dat_bi, *encrypt_bi; + + /* note: in_len+11 must be > byte_size */ + out_data[0] = 0; /* ensure encryption block is < modulus */ + + if (is_signing) + { + out_data[1] = 1; /* PKCS1.5 signing pads with "0xff"'s */ + memset(&out_data[2], 0xff, num_pads_needed); + } + else /* randomize the encryption padding with non-zero bytes */ + { + out_data[1] = 2; + if (get_random_NZ(num_pads_needed, &out_data[2]) < 0) + return -1; + } + + out_data[2+num_pads_needed] = 0; + memcpy(&out_data[3+num_pads_needed], in_data, in_len); + + /* now encrypt it */ + dat_bi = bi_import(ctx->bi_ctx, out_data, byte_size); + encrypt_bi = is_signing ? RSA_private(ctx, dat_bi) : + RSA_public(ctx, dat_bi); + bi_export(ctx->bi_ctx, encrypt_bi, out_data, byte_size); + + /* save a few bytes of memory */ + bi_clear_cache(ctx->bi_ctx); + return byte_size; +} + diff --git a/cores/esp8266/axtls/rsa.h b/cores/esp8266/axtls/rsa.h new file mode 100644 index 0000000000..604cd8f929 --- /dev/null +++ b/cores/esp8266/axtls/rsa.h @@ -0,0 +1,44 @@ +#ifndef HEADER_RSA_H +#define HEADER_RSA_H + +#include "bigint.h" + +typedef struct +{ + bigint *m; /* modulus */ + bigint *e; /* public exponent */ + bigint *d; /* private exponent */ + bigint *p; /* p as in m = pq */ + bigint *q; /* q as in m = pq */ + bigint *dP; /* d mod (p-1) */ + bigint *dQ; /* d mod (q-1) */ + bigint *qInv; /* q^-1 mod p */ + int num_octets; + BI_CTX *bi_ctx; +} RSA_CTX; + +void RSA_priv_key_new(RSA_CTX **rsa_ctx, + const uint8_t *modulus, int mod_len, + const uint8_t *pub_exp, int pub_len, + const uint8_t *priv_exp, int priv_len, + const uint8_t *p, int p_len, + const uint8_t *q, int q_len, + const uint8_t *dP, int dP_len, + const uint8_t *dQ, int dQ_len, + const uint8_t *qInv, int qInv_len + ); +void RSA_pub_key_new(RSA_CTX **rsa_ctx, + const uint8_t *modulus, int mod_len, + const uint8_t *pub_exp, int pub_len); +void RSA_free(RSA_CTX *ctx); +int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint8_t *out_data, + int out_len, int is_decryption); +bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg); +bigint *RSA_sign_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len, + bigint *modulus, bigint *pub_exp); +bigint *RSA_public(const RSA_CTX * c, bigint *bi_msg); +int RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len, + uint8_t *out_data, int is_signing); +void RSA_print(const RSA_CTX *ctx); + +#endif diff --git a/cores/esp8266/axtls/sha1.cpp b/cores/esp8266/axtls/sha1.cpp new file mode 100644 index 0000000000..dbd0c08268 --- /dev/null +++ b/cores/esp8266/axtls/sha1.cpp @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * SHA1 implementation - as defined in FIPS PUB 180-1 published April 17, 1995. + * This code was originally taken from RFC3174 + */ + +#include +#include "sha1.h" + +/* + * Define the SHA1 circular left shift macro + */ +#define SHA1CircularShift(bits,word) \ + (((word) << (bits)) | ((word) >> (32-(bits)))) + +/* ----- static functions ----- */ +static void SHA1PadMessage(SHA1_CTX *ctx); +static void SHA1ProcessMessageBlock(SHA1_CTX *ctx); + +/** + * Initialize the SHA1 context + */ +void SHA1_Init(SHA1_CTX *ctx) +{ + ctx->Length_Low = 0; + ctx->Length_High = 0; + ctx->Message_Block_Index = 0; + ctx->Intermediate_Hash[0] = 0x67452301; + ctx->Intermediate_Hash[1] = 0xEFCDAB89; + ctx->Intermediate_Hash[2] = 0x98BADCFE; + ctx->Intermediate_Hash[3] = 0x10325476; + ctx->Intermediate_Hash[4] = 0xC3D2E1F0; +} + +/** + * Accepts an array of octets as the next portion of the message. + */ +void SHA1_Update(SHA1_CTX *ctx, const uint8_t *msg, int len) +{ + while (len--) + { + ctx->Message_Block[ctx->Message_Block_Index++] = (*msg & 0xFF); + ctx->Length_Low += 8; + + if (ctx->Length_Low == 0) + ctx->Length_High++; + + if (ctx->Message_Block_Index == 64) + SHA1ProcessMessageBlock(ctx); + + msg++; + } +} + +/** + * Return the 160-bit message digest into the user's array + */ +void SHA1_Final(uint8_t *digest, SHA1_CTX *ctx) +{ + int i; + + SHA1PadMessage(ctx); + memset(ctx->Message_Block, 0, 64); + ctx->Length_Low = 0; /* and clear length */ + ctx->Length_High = 0; + + for (i = 0; i < SHA1_SIZE; i++) + { + digest[i] = ctx->Intermediate_Hash[i>>2] >> 8 * ( 3 - ( i & 0x03 ) ); + } +} + +/** + * Process the next 512 bits of the message stored in the array. + */ +static void SHA1ProcessMessageBlock(SHA1_CTX *ctx) +{ + const uint32_t K[] = { /* Constants defined in SHA-1 */ + 0x5A827999, + 0x6ED9EBA1, + 0x8F1BBCDC, + 0xCA62C1D6 + }; + int t; /* Loop counter */ + uint32_t temp; /* Temporary word value */ + uint32_t W[80]; /* Word sequence */ + uint32_t A, B, C, D, E; /* Word buffers */ + + /* + * Initialize the first 16 words in the array W + */ + for (t = 0; t < 16; t++) + { + W[t] = ctx->Message_Block[t * 4] << 24; + W[t] |= ctx->Message_Block[t * 4 + 1] << 16; + W[t] |= ctx->Message_Block[t * 4 + 2] << 8; + W[t] |= ctx->Message_Block[t * 4 + 3]; + } + + for (t = 16; t < 80; t++) + { + W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); + } + + A = ctx->Intermediate_Hash[0]; + B = ctx->Intermediate_Hash[1]; + C = ctx->Intermediate_Hash[2]; + D = ctx->Intermediate_Hash[3]; + E = ctx->Intermediate_Hash[4]; + + for (t = 0; t < 20; t++) + { + temp = SHA1CircularShift(5,A) + + ((B & C) | ((~B) & D)) + E + W[t] + K[0]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + + B = A; + A = temp; + } + + for (t = 20; t < 40; t++) + { + temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for (t = 40; t < 60; t++) + { + temp = SHA1CircularShift(5,A) + + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for (t = 60; t < 80; t++) + { + temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + ctx->Intermediate_Hash[0] += A; + ctx->Intermediate_Hash[1] += B; + ctx->Intermediate_Hash[2] += C; + ctx->Intermediate_Hash[3] += D; + ctx->Intermediate_Hash[4] += E; + ctx->Message_Block_Index = 0; +} + +/* + * According to the standard, the message must be padded to an even + * 512 bits. The first padding bit must be a '1'. The last 64 + * bits represent the length of the original message. All bits in + * between should be 0. This function will pad the message + * according to those rules by filling the Message_Block array + * accordingly. It will also call the ProcessMessageBlock function + * provided appropriately. When it returns, it can be assumed that + * the message digest has been computed. + * + * @param ctx [in, out] The SHA1 context + */ +static void SHA1PadMessage(SHA1_CTX *ctx) +{ + /* + * Check to see if the current message block is too small to hold + * the initial padding bits and length. If so, we will pad the + * block, process it, and then continue padding into a second + * block. + */ + if (ctx->Message_Block_Index > 55) + { + ctx->Message_Block[ctx->Message_Block_Index++] = 0x80; + while(ctx->Message_Block_Index < 64) + { + ctx->Message_Block[ctx->Message_Block_Index++] = 0; + } + + SHA1ProcessMessageBlock(ctx); + + while (ctx->Message_Block_Index < 56) + { + ctx->Message_Block[ctx->Message_Block_Index++] = 0; + } + } + else + { + ctx->Message_Block[ctx->Message_Block_Index++] = 0x80; + while(ctx->Message_Block_Index < 56) + { + + ctx->Message_Block[ctx->Message_Block_Index++] = 0; + } + } + + /* + * Store the message length as the last 8 octets + */ + ctx->Message_Block[56] = ctx->Length_High >> 24; + ctx->Message_Block[57] = ctx->Length_High >> 16; + ctx->Message_Block[58] = ctx->Length_High >> 8; + ctx->Message_Block[59] = ctx->Length_High; + ctx->Message_Block[60] = ctx->Length_Low >> 24; + ctx->Message_Block[61] = ctx->Length_Low >> 16; + ctx->Message_Block[62] = ctx->Length_Low >> 8; + ctx->Message_Block[63] = ctx->Length_Low; + SHA1ProcessMessageBlock(ctx); +} diff --git a/cores/esp8266/axtls/sha1.h b/cores/esp8266/axtls/sha1.h new file mode 100644 index 0000000000..6b817750c9 --- /dev/null +++ b/cores/esp8266/axtls/sha1.h @@ -0,0 +1,23 @@ +#ifndef HEADER_SHA1_H +#define HEADER_SHA1_H + +#define SHA1_SIZE 20 + +/* + * This structure will hold context information for the SHA-1 + * hashing operation + */ +typedef struct +{ + uint32_t Intermediate_Hash[SHA1_SIZE/4]; /* Message Digest */ + uint32_t Length_Low; /* Message length in bits */ + uint32_t Length_High; /* Message length in bits */ + uint16_t Message_Block_Index; /* Index into message block array */ + uint8_t Message_Block[64]; /* 512-bit message blocks */ +} SHA1_CTX; + +void SHA1_Init(SHA1_CTX *); +void SHA1_Update(SHA1_CTX *, const uint8_t * msg, int len); +void SHA1_Final(uint8_t *digest, SHA1_CTX *); + +#endif diff --git a/cores/esp8266/axtls/sha256.cpp b/cores/esp8266/axtls/sha256.cpp new file mode 100644 index 0000000000..cca88fa5bd --- /dev/null +++ b/cores/esp8266/axtls/sha256.cpp @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2015, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include "sha256.h" + +#define GET_UINT32(n,b,i) \ +{ \ + (n) = ((uint32_t) (b)[(i) ] << 24) \ + | ((uint32_t) (b)[(i) + 1] << 16) \ + | ((uint32_t) (b)[(i) + 2] << 8) \ + | ((uint32_t) (b)[(i) + 3] ); \ +} + +#define PUT_UINT32(n,b,i) \ +{ \ + (b)[(i) ] = (uint8_t) ((n) >> 24); \ + (b)[(i) + 1] = (uint8_t) ((n) >> 16); \ + (b)[(i) + 2] = (uint8_t) ((n) >> 8); \ + (b)[(i) + 3] = (uint8_t) ((n) ); \ +} + +static const uint8_t sha256_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/** + * Initialize the SHA256 context + */ +void SHA256_Init(SHA256_CTX *ctx) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x6A09E667; + ctx->state[1] = 0xBB67AE85; + ctx->state[2] = 0x3C6EF372; + ctx->state[3] = 0xA54FF53A; + ctx->state[4] = 0x510E527F; + ctx->state[5] = 0x9B05688C; + ctx->state[6] = 0x1F83D9AB; + ctx->state[7] = 0x5BE0CD19; +} + +static void SHA256_Process(const uint8_t digest[64], SHA256_CTX *ctx) +{ + uint32_t temp1, temp2, W[64]; + uint32_t A, B, C, D, E, F, G, H; + + GET_UINT32(W[0], digest, 0); + GET_UINT32(W[1], digest, 4); + GET_UINT32(W[2], digest, 8); + GET_UINT32(W[3], digest, 12); + GET_UINT32(W[4], digest, 16); + GET_UINT32(W[5], digest, 20); + GET_UINT32(W[6], digest, 24); + GET_UINT32(W[7], digest, 28); + GET_UINT32(W[8], digest, 32); + GET_UINT32(W[9], digest, 36); + GET_UINT32(W[10], digest, 40); + GET_UINT32(W[11], digest, 44); + GET_UINT32(W[12], digest, 48); + GET_UINT32(W[13], digest, 52); + GET_UINT32(W[14], digest, 56); + GET_UINT32(W[15], digest, 60); + +#define SHR(x,n) ((x & 0xFFFFFFFF) >> n) +#define ROTR(x,n) (SHR(x,n) | (x << (32 - n))) + +#define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ SHR(x, 3)) +#define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^ SHR(x,10)) + +#define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22)) +#define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25)) + +#define F0(x,y,z) ((x & y) | (z & (x | y))) +#define F1(x,y,z) (z ^ (x & (y ^ z))) + +#define R(t) \ +( \ + W[t] = S1(W[t - 2]) + W[t - 7] + \ + S0(W[t - 15]) + W[t - 16] \ +) + +#define P(a,b,c,d,e,f,g,h,x,K) \ +{ \ + temp1 = h + S3(e) + F1(e,f,g) + K + x; \ + temp2 = S2(a) + F0(a,b,c); \ + d += temp1; h = temp1 + temp2; \ +} + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + E = ctx->state[4]; + F = ctx->state[5]; + G = ctx->state[6]; + H = ctx->state[7]; + + P(A, B, C, D, E, F, G, H, W[ 0], 0x428A2F98); + P(H, A, B, C, D, E, F, G, W[ 1], 0x71374491); + P(G, H, A, B, C, D, E, F, W[ 2], 0xB5C0FBCF); + P(F, G, H, A, B, C, D, E, W[ 3], 0xE9B5DBA5); + P(E, F, G, H, A, B, C, D, W[ 4], 0x3956C25B); + P(D, E, F, G, H, A, B, C, W[ 5], 0x59F111F1); + P(C, D, E, F, G, H, A, B, W[ 6], 0x923F82A4); + P(B, C, D, E, F, G, H, A, W[ 7], 0xAB1C5ED5); + P(A, B, C, D, E, F, G, H, W[ 8], 0xD807AA98); + P(H, A, B, C, D, E, F, G, W[ 9], 0x12835B01); + P(G, H, A, B, C, D, E, F, W[10], 0x243185BE); + P(F, G, H, A, B, C, D, E, W[11], 0x550C7DC3); + P(E, F, G, H, A, B, C, D, W[12], 0x72BE5D74); + P(D, E, F, G, H, A, B, C, W[13], 0x80DEB1FE); + P(C, D, E, F, G, H, A, B, W[14], 0x9BDC06A7); + P(B, C, D, E, F, G, H, A, W[15], 0xC19BF174); + P(A, B, C, D, E, F, G, H, R(16), 0xE49B69C1); + P(H, A, B, C, D, E, F, G, R(17), 0xEFBE4786); + P(G, H, A, B, C, D, E, F, R(18), 0x0FC19DC6); + P(F, G, H, A, B, C, D, E, R(19), 0x240CA1CC); + P(E, F, G, H, A, B, C, D, R(20), 0x2DE92C6F); + P(D, E, F, G, H, A, B, C, R(21), 0x4A7484AA); + P(C, D, E, F, G, H, A, B, R(22), 0x5CB0A9DC); + P(B, C, D, E, F, G, H, A, R(23), 0x76F988DA); + P(A, B, C, D, E, F, G, H, R(24), 0x983E5152); + P(H, A, B, C, D, E, F, G, R(25), 0xA831C66D); + P(G, H, A, B, C, D, E, F, R(26), 0xB00327C8); + P(F, G, H, A, B, C, D, E, R(27), 0xBF597FC7); + P(E, F, G, H, A, B, C, D, R(28), 0xC6E00BF3); + P(D, E, F, G, H, A, B, C, R(29), 0xD5A79147); + P(C, D, E, F, G, H, A, B, R(30), 0x06CA6351); + P(B, C, D, E, F, G, H, A, R(31), 0x14292967); + P(A, B, C, D, E, F, G, H, R(32), 0x27B70A85); + P(H, A, B, C, D, E, F, G, R(33), 0x2E1B2138); + P(G, H, A, B, C, D, E, F, R(34), 0x4D2C6DFC); + P(F, G, H, A, B, C, D, E, R(35), 0x53380D13); + P(E, F, G, H, A, B, C, D, R(36), 0x650A7354); + P(D, E, F, G, H, A, B, C, R(37), 0x766A0ABB); + P(C, D, E, F, G, H, A, B, R(38), 0x81C2C92E); + P(B, C, D, E, F, G, H, A, R(39), 0x92722C85); + P(A, B, C, D, E, F, G, H, R(40), 0xA2BFE8A1); + P(H, A, B, C, D, E, F, G, R(41), 0xA81A664B); + P(G, H, A, B, C, D, E, F, R(42), 0xC24B8B70); + P(F, G, H, A, B, C, D, E, R(43), 0xC76C51A3); + P(E, F, G, H, A, B, C, D, R(44), 0xD192E819); + P(D, E, F, G, H, A, B, C, R(45), 0xD6990624); + P(C, D, E, F, G, H, A, B, R(46), 0xF40E3585); + P(B, C, D, E, F, G, H, A, R(47), 0x106AA070); + P(A, B, C, D, E, F, G, H, R(48), 0x19A4C116); + P(H, A, B, C, D, E, F, G, R(49), 0x1E376C08); + P(G, H, A, B, C, D, E, F, R(50), 0x2748774C); + P(F, G, H, A, B, C, D, E, R(51), 0x34B0BCB5); + P(E, F, G, H, A, B, C, D, R(52), 0x391C0CB3); + P(D, E, F, G, H, A, B, C, R(53), 0x4ED8AA4A); + P(C, D, E, F, G, H, A, B, R(54), 0x5B9CCA4F); + P(B, C, D, E, F, G, H, A, R(55), 0x682E6FF3); + P(A, B, C, D, E, F, G, H, R(56), 0x748F82EE); + P(H, A, B, C, D, E, F, G, R(57), 0x78A5636F); + P(G, H, A, B, C, D, E, F, R(58), 0x84C87814); + P(F, G, H, A, B, C, D, E, R(59), 0x8CC70208); + P(E, F, G, H, A, B, C, D, R(60), 0x90BEFFFA); + P(D, E, F, G, H, A, B, C, R(61), 0xA4506CEB); + P(C, D, E, F, G, H, A, B, R(62), 0xBEF9A3F7); + P(B, C, D, E, F, G, H, A, R(63), 0xC67178F2); + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + ctx->state[4] += E; + ctx->state[5] += F; + ctx->state[6] += G; + ctx->state[7] += H; +} + +/** + * Accepts an array of octets as the next portion of the message. + */ +void SHA256_Update(SHA256_CTX *ctx, const uint8_t * msg, int len) +{ + uint32_t left = ctx->total[0] & 0x3F; + uint32_t fill = 64 - left; + + ctx->total[0] += len; + ctx->total[0] &= 0xFFFFFFFF; + + if (ctx->total[0] < len) + ctx->total[1]++; + + if (left && len >= fill) + { + memcpy((void *) (ctx->buffer + left), (void *)msg, fill); + SHA256_Process(ctx->buffer, ctx); + len -= fill; + msg += fill; + left = 0; + } + + while (len >= 64) + { + SHA256_Process(msg, ctx); + len -= 64; + msg += 64; + } + + if (len) + { + memcpy((void *) (ctx->buffer + left), (void *) msg, len); + } +} + +/** + * Return the 256-bit message digest into the user's array + */ +void SHA256_Final(uint8_t *digest, SHA256_CTX *ctx) +{ + uint32_t last, padn; + uint32_t high, low; + uint8_t msglen[8]; + + high = (ctx->total[0] >> 29) + | (ctx->total[1] << 3); + low = (ctx->total[0] << 3); + + PUT_UINT32(high, msglen, 0); + PUT_UINT32(low, msglen, 4); + + last = ctx->total[0] & 0x3F; + padn = (last < 56) ? (56 - last) : (120 - last); + + SHA256_Update(ctx, sha256_padding, padn); + SHA256_Update(ctx, msglen, 8); + + PUT_UINT32(ctx->state[0], digest, 0); + PUT_UINT32(ctx->state[1], digest, 4); + PUT_UINT32(ctx->state[2], digest, 8); + PUT_UINT32(ctx->state[3], digest, 12); + PUT_UINT32(ctx->state[4], digest, 16); + PUT_UINT32(ctx->state[5], digest, 20); + PUT_UINT32(ctx->state[6], digest, 24); + PUT_UINT32(ctx->state[7], digest, 28); +} diff --git a/cores/esp8266/axtls/sha256.h b/cores/esp8266/axtls/sha256.h new file mode 100644 index 0000000000..5462042672 --- /dev/null +++ b/cores/esp8266/axtls/sha256.h @@ -0,0 +1,17 @@ +#ifndef HEADER_SHA256_H +#define HEADER_SHA256_H + +#define SHA256_SIZE 32 + +typedef struct +{ + uint32_t total[2]; + uint32_t state[8]; + uint8_t buffer[64]; +} SHA256_CTX; + +void SHA256_Init(SHA256_CTX *c); +void SHA256_Update(SHA256_CTX *, const uint8_t *input, int len); +void SHA256_Final(uint8_t *digest, SHA256_CTX *); + +#endif diff --git a/cores/esp8266/axtls/x509.cpp b/cores/esp8266/axtls/x509.cpp new file mode 100644 index 0000000000..6dc51c2d75 --- /dev/null +++ b/cores/esp8266/axtls/x509.cpp @@ -0,0 +1,567 @@ +/* + * Copyright (c) 2007-2016, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file x509.c + * + * Certificate processing. + */ + +#include +#include +#include "asn1.h" +#include "sha256.h" +#include "x509.h" + +static int x509_v3_subject_alt_name(const uint8_t *cert, int offset, + X509_CTX *x509_ctx); +static int x509_v3_basic_constraints(const uint8_t *cert, int offset, + X509_CTX *x509_ctx); +static int x509_v3_key_usage(const uint8_t *cert, int offset, + X509_CTX *x509_ctx); + +/** + * Retrieve the signature from a certificate. + */ +static const uint8_t *get_signature(const uint8_t *asn1_sig, int *len) +{ + int offset = 0; + const uint8_t *ptr = NULL; + + if (asn1_next_obj(asn1_sig, &offset, ASN1_SEQUENCE) < 0 || + asn1_skip_obj(asn1_sig, &offset, ASN1_SEQUENCE)) + goto end_get_sig; + + if (asn1_sig[offset++] != ASN1_OCTET_STRING) + goto end_get_sig; + *len = get_asn1_length(asn1_sig, &offset); + ptr = &asn1_sig[offset]; /* all ok */ + +end_get_sig: + return ptr; +} + +/** + * Construct a new x509 object. + * @return 0 if ok. < 0 if there was a problem. + */ +int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx) +{ + int begin_tbs, end_tbs; + int ret = X509_NOT_OK, offset = 0, cert_size = 0; + int version = 0; + X509_CTX *x509_ctx; + BI_CTX *bi_ctx; + + *ctx = (X509_CTX *)calloc(1, sizeof(X509_CTX)); + x509_ctx = *ctx; + + /* get the certificate size */ + asn1_skip_obj(cert, &cert_size, ASN1_SEQUENCE); + + if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0) + goto end_cert; + + begin_tbs = offset; /* start of the tbs */ + end_tbs = begin_tbs; /* work out the end of the tbs */ + asn1_skip_obj(cert, &end_tbs, ASN1_SEQUENCE); + + if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0) + goto end_cert; + + /* optional version */ + if (cert[offset] == ASN1_EXPLICIT_TAG && + asn1_version(cert, &offset, &version) == X509_NOT_OK) + goto end_cert; + + if (asn1_skip_obj(cert, &offset, ASN1_INTEGER) || /* serial number */ + asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0) + goto end_cert; + + /* make sure the signature is ok */ + if (asn1_signature_type(cert, &offset, x509_ctx)) + { + ret = X509_VFY_ERROR_UNSUPPORTED_DIGEST; + goto end_cert; + } + + if (asn1_name(cert, &offset, x509_ctx->ca_cert_dn) || + asn1_validity(cert, &offset, x509_ctx) || + asn1_name(cert, &offset, x509_ctx->cert_dn) || + asn1_public_key(cert, &offset, x509_ctx)) + { + goto end_cert; + } + + bi_ctx = x509_ctx->rsa_ctx->bi_ctx; + + /* use the appropriate signature algorithm */ + switch (x509_ctx->sig_type) + { + /* + case SIG_TYPE_MD5: + { + MD5_CTX md5_ctx; + uint8_t md5_dgst[MD5_SIZE]; + MD5_Init(&md5_ctx); + MD5_Update(&md5_ctx, &cert[begin_tbs], end_tbs-begin_tbs); + MD5_Final(md5_dgst, &md5_ctx); + x509_ctx->digest = bi_import(bi_ctx, md5_dgst, MD5_SIZE); + } + break; + + case SIG_TYPE_SHA1: + { + SHA1_CTX sha_ctx; + uint8_t sha_dgst[SHA1_SIZE]; + SHA1_Init(&sha_ctx); + SHA1_Update(&sha_ctx, &cert[begin_tbs], end_tbs-begin_tbs); + SHA1_Final(sha_dgst, &sha_ctx); + x509_ctx->digest = bi_import(bi_ctx, sha_dgst, SHA1_SIZE); + } + break; + */ + case SIG_TYPE_SHA256: + { + SHA256_CTX sha256_ctx; + uint8_t sha256_dgst[SHA256_SIZE]; + SHA256_Init(&sha256_ctx); + SHA256_Update(&sha256_ctx, &cert[begin_tbs], end_tbs-begin_tbs); + SHA256_Final(sha256_dgst, &sha256_ctx); + x509_ctx->digest = bi_import(bi_ctx, sha256_dgst, SHA256_SIZE); + } + break; + /* + case SIG_TYPE_SHA384: + { + SHA384_CTX sha384_ctx; + uint8_t sha384_dgst[SHA384_SIZE]; + SHA384_Init(&sha384_ctx); + SHA384_Update(&sha384_ctx, &cert[begin_tbs], end_tbs-begin_tbs); + SHA384_Final(sha384_dgst, &sha384_ctx); + x509_ctx->digest = bi_import(bi_ctx, sha384_dgst, SHA384_SIZE); + } + break; + + case SIG_TYPE_SHA512: + { + SHA512_CTX sha512_ctx; + uint8_t sha512_dgst[SHA512_SIZE]; + SHA512_Init(&sha512_ctx); + SHA512_Update(&sha512_ctx, &cert[begin_tbs], end_tbs-begin_tbs); + SHA512_Final(sha512_dgst, &sha512_ctx); + x509_ctx->digest = bi_import(bi_ctx, sha512_dgst, SHA512_SIZE); + } + break; + */ + } + + if (version == 2 && asn1_next_obj(cert, &offset, ASN1_V3_DATA) > 0) + { + x509_v3_subject_alt_name(cert, offset, x509_ctx); + x509_v3_basic_constraints(cert, offset, x509_ctx); + x509_v3_key_usage(cert, offset, x509_ctx); + } + + offset = end_tbs; /* skip the rest of v3 data */ + if (asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) || asn1_signature(cert, &offset, x509_ctx)) + goto end_cert; + + ret = X509_OK; + +end_cert: + if (len) + { + *len = cert_size; + } + + if (ret) + { + x509_free(x509_ctx); + *ctx = NULL; + } + + return ret; +} + +static int x509_v3_subject_alt_name(const uint8_t *cert, int offset, + X509_CTX *x509_ctx) +{ + if ((offset = asn1_is_subject_alt_name(cert, offset)) > 0) + { + x509_ctx->subject_alt_name_present = true; + x509_ctx->subject_alt_name_is_critical = + asn1_is_critical_ext(cert, &offset); + + if (asn1_next_obj(cert, &offset, ASN1_OCTET_STRING) > 0) + { + int altlen; + + if ((altlen = asn1_next_obj(cert, &offset, ASN1_SEQUENCE)) > 0) + { + int endalt = offset + altlen; + int totalnames = 0; + + while (offset < endalt) + { + int type = cert[offset++]; + int dnslen = get_asn1_length(cert, &offset); + + if (type == ASN1_CONTEXT_DNSNAME) + { + x509_ctx->subject_alt_dnsnames = (char**) + realloc(x509_ctx->subject_alt_dnsnames, + (totalnames + 2) * sizeof(char*)); + x509_ctx->subject_alt_dnsnames[totalnames] = + (char*)malloc(dnslen + 1); + x509_ctx->subject_alt_dnsnames[totalnames+1] = NULL; + memcpy(x509_ctx->subject_alt_dnsnames[totalnames], + cert + offset, dnslen); + x509_ctx->subject_alt_dnsnames[totalnames][dnslen] = 0; + totalnames++; + } + + offset += dnslen; + } + } + } + } + + return X509_OK; +} + +/** + * Basic constraints - see https://tools.ietf.org/html/rfc5280#page-39 + */ +static int x509_v3_basic_constraints(const uint8_t *cert, int offset, + X509_CTX *x509_ctx) +{ + int ret = X509_OK; + + if ((offset = asn1_is_basic_constraints(cert, offset)) == 0) + goto end_contraints; + + x509_ctx->basic_constraint_present = true; + x509_ctx->basic_constraint_is_critical = + asn1_is_critical_ext(cert, &offset); + + if (asn1_next_obj(cert, &offset, ASN1_OCTET_STRING) < 0 || + asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0 || + asn1_get_bool(cert, &offset, &x509_ctx->basic_constraint_cA) < 0 || + asn1_get_int(cert, &offset, + &x509_ctx->basic_constraint_pathLenConstraint) < 0) + { + ret = X509_NOT_OK; + } + +end_contraints: + return ret; +} + +/* + * Key usage - see https://tools.ietf.org/html/rfc5280#section-4.2.1.3 + */ +static int x509_v3_key_usage(const uint8_t *cert, int offset, + X509_CTX *x509_ctx) +{ + int ret = X509_OK; + + if ((offset = asn1_is_key_usage(cert, offset)) == 0) + goto end_key_usage; + + x509_ctx->key_usage_present = true; + x509_ctx->key_usage_is_critical = asn1_is_critical_ext(cert, &offset); + + if (asn1_next_obj(cert, &offset, ASN1_OCTET_STRING) < 0 || + asn1_get_bit_string_as_int(cert, &offset, &x509_ctx->key_usage)) + { + ret = X509_NOT_OK; + } + +end_key_usage: + return ret; +} + +/** + * Free an X.509 object's resources. + */ +void x509_free(X509_CTX *x509_ctx) +{ + X509_CTX *next; + int i; + + if (x509_ctx == NULL) /* if already null, then don't bother */ + return; + + for (i = 0; i < X509_NUM_DN_TYPES; i++) + { + free(x509_ctx->ca_cert_dn[i]); + free(x509_ctx->cert_dn[i]); + } + + free(x509_ctx->signature); + + if (x509_ctx->digest) + { + bi_free(x509_ctx->rsa_ctx->bi_ctx, x509_ctx->digest); + } + + if (x509_ctx->subject_alt_dnsnames) + { + for (i = 0; x509_ctx->subject_alt_dnsnames[i]; ++i) + free(x509_ctx->subject_alt_dnsnames[i]); + + free(x509_ctx->subject_alt_dnsnames); + } + + RSA_free(x509_ctx->rsa_ctx); + next = x509_ctx->next; + free(x509_ctx); + x509_free(next); /* clear the chain */ +} + +/** + * Take a signature and decrypt it. + */ +static bigint *sig_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len, + bigint *modulus, bigint *pub_exp) +{ + int i, size; + bigint *decrypted_bi, *dat_bi; + bigint *bir = NULL; + uint8_t *block = (uint8_t *)alloca(sig_len); + + /* decrypt */ + dat_bi = bi_import(ctx, sig, sig_len); + ctx->mod_offset = BIGINT_M_OFFSET; + + /* convert to a normal block */ + decrypted_bi = bi_mod_power2(ctx, dat_bi, modulus, pub_exp); + + bi_export(ctx, decrypted_bi, block, sig_len); + ctx->mod_offset = BIGINT_M_OFFSET; + + i = 10; /* start at the first possible non-padded byte */ + while (block[i++] && i < sig_len); + size = sig_len - i; + + /* get only the bit we want */ + if (size > 0) + { + int len; + const uint8_t *sig_ptr = get_signature(&block[i], &len); + + if (sig_ptr) + { + bir = bi_import(ctx, sig_ptr, len); + } + } + + /* save a few bytes of memory */ + bi_clear_cache(ctx); + return bir; +} + +/** + * Do some basic checks on the certificate chain. + * + * Certificate verification consists of a number of checks: + * - The date of the certificate is after the start date. + * - The date of the certificate is before the finish date. + * - A root certificate exists in the certificate store. + * - That the certificate(s) are not self-signed. + * - The certificate chain is valid. + * - The signature of the certificate is valid. + * - Basic constraints + */ +int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert, int *pathLenConstraint) +{ + int ret = X509_OK, i = 0; + bigint *cert_sig; + X509_CTX *next_cert = NULL; + BI_CTX *ctx = NULL; + bigint *mod = NULL, *expn = NULL; + int match_ca_cert = 0; + //struct timeval tv; + uint8_t is_self_signed = 0; + + if (cert == NULL) + { + ret = X509_VFY_ERROR_NO_TRUSTED_CERT; + goto end_verify; + } + + /* a self-signed certificate that is not in the CA store - use this + to check the signature */ + if (asn1_compare_dn(cert->ca_cert_dn, cert->cert_dn) == 0) + { + is_self_signed = 1; + ctx = cert->rsa_ctx->bi_ctx; + mod = cert->rsa_ctx->m; + expn = cert->rsa_ctx->e; + } + + /* + gettimeofday(&tv, NULL); + + / * check the not before date * / + if (tv.tv_sec < cert->not_before) + { + ret = X509_VFY_ERROR_NOT_YET_VALID; + goto end_verify; + } + + / * check the not after date * / + if (tv.tv_sec > cert->not_after) + { + ret = X509_VFY_ERROR_EXPIRED; + goto end_verify; + } + */ + + if (cert->basic_constraint_present) + { + /* If the cA boolean is not asserted, + then the keyCertSign bit in the key usage extension MUST NOT be + asserted. */ + if (!cert->basic_constraint_cA && + IS_SET_KEY_USAGE_FLAG(cert, KEY_USAGE_KEY_CERT_SIGN)) + { + ret = X509_VFY_ERROR_BASIC_CONSTRAINT; + goto end_verify; + } + + /* The pathLenConstraint field is meaningful only if the cA boolean is + asserted and the key usage extension, if present, asserts the + keyCertSign bit. In this case, it gives the maximum number of + non-self-issued intermediate certificates that may follow this + certificate in a valid certification path. */ + if (cert->basic_constraint_cA && + (!cert->key_usage_present || + IS_SET_KEY_USAGE_FLAG(cert, KEY_USAGE_KEY_CERT_SIGN)) && + (cert->basic_constraint_pathLenConstraint+1) < *pathLenConstraint) + { + ret = X509_VFY_ERROR_BASIC_CONSTRAINT; + goto end_verify; + } + } + + next_cert = cert->next; + + /* last cert in the chain - look for a trusted cert */ + if (next_cert == NULL) + { + if (ca_cert_ctx != NULL) + { + /* go thru the CA store */ + while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i]) + { + /* the extension is present but the cA boolean is not + asserted, then the certified public key MUST NOT be used + to verify certificate signatures. */ + if (cert->basic_constraint_present && + !ca_cert_ctx->cert[i]->basic_constraint_cA) + continue; + + if (asn1_compare_dn(cert->ca_cert_dn, + ca_cert_ctx->cert[i]->cert_dn) == 0) + { + /* use this CA certificate for signature verification */ + match_ca_cert = true; + ctx = ca_cert_ctx->cert[i]->rsa_ctx->bi_ctx; + mod = ca_cert_ctx->cert[i]->rsa_ctx->m; + expn = ca_cert_ctx->cert[i]->rsa_ctx->e; + + + break; + } + + i++; + } + } + + /* couldn't find a trusted cert (& let self-signed errors + be returned) */ + if (!match_ca_cert && !is_self_signed) + { + ret = X509_VFY_ERROR_NO_TRUSTED_CERT; + goto end_verify; + } + } + else if (asn1_compare_dn(cert->ca_cert_dn, next_cert->cert_dn) != 0) + { + /* check the chain */ + ret = X509_VFY_ERROR_INVALID_CHAIN; + goto end_verify; + } + else /* use the next certificate in the chain for signature verify */ + { + ctx = next_cert->rsa_ctx->bi_ctx; + mod = next_cert->rsa_ctx->m; + expn = next_cert->rsa_ctx->e; + } + + /* cert is self signed */ + if (!match_ca_cert && is_self_signed) + { + ret = X509_VFY_ERROR_SELF_SIGNED; + goto end_verify; + } + + /* check the signature */ + cert_sig = sig_verify(ctx, cert->signature, cert->sig_len, + bi_clone(ctx, mod), bi_clone(ctx, expn)); + + if (cert_sig && cert->digest) + { + if (bi_compare(cert_sig, cert->digest) != 0) + ret = X509_VFY_ERROR_BAD_SIGNATURE; + + + bi_free(ctx, cert_sig); + } + else + { + ret = X509_VFY_ERROR_BAD_SIGNATURE; + } + + if (ret) + goto end_verify; + + /* go down the certificate chain using recursion. */ + if (next_cert != NULL) + { + (*pathLenConstraint)++; /* don't include last certificate */ + ret = x509_verify(ca_cert_ctx, next_cert, pathLenConstraint); + } + +end_verify: + return ret; +} diff --git a/cores/esp8266/axtls/x509.h b/cores/esp8266/axtls/x509.h new file mode 100644 index 0000000000..35f2bcfb08 --- /dev/null +++ b/cores/esp8266/axtls/x509.h @@ -0,0 +1,83 @@ +#ifndef HEADER_X509_H +#define HEADER_X509_H + +#define CONFIG_X509_MAX_CA_CERTS 1 + +#include "rsa.h" +/************************************************************************** + * X509 declarations + **************************************************************************/ +#define X509_OK 0 +#define X509_NOT_OK -1 +#define X509_VFY_ERROR_NO_TRUSTED_CERT -2 +#define X509_VFY_ERROR_BAD_SIGNATURE -3 +#define X509_VFY_ERROR_NOT_YET_VALID -4 +#define X509_VFY_ERROR_EXPIRED -5 +#define X509_VFY_ERROR_SELF_SIGNED -6 +#define X509_VFY_ERROR_INVALID_CHAIN -7 +#define X509_VFY_ERROR_UNSUPPORTED_DIGEST -8 +#define X509_INVALID_PRIV_KEY -9 +#define X509_MAX_CERTS -10 +#define X509_VFY_ERROR_BASIC_CONSTRAINT -11 + +/* + * The Distinguished Name + */ +#define X509_NUM_DN_TYPES 6 +#define X509_COMMON_NAME 0 +#define X509_ORGANIZATION 1 +#define X509_ORGANIZATIONAL_UNIT 2 +#define X509_LOCATION 3 +#define X509_COUNTRY 4 +#define X509_STATE 5 + +/* + * Key Usage bits + */ +#define IS_SET_KEY_USAGE_FLAG(A, B) (A->key_usage & B) + +#define KEY_USAGE_DIGITAL_SIGNATURE 0x0080 +#define KEY_USAGE_NON_REPUDIATION 0x0040 +#define KEY_USAGE_KEY_ENCIPHERMENT 0x0020 +#define KEY_USAGE_DATA_ENCIPHERMENT 0x0010 +#define KEY_USAGE_KEY_AGREEMENT 0x0008 +#define KEY_USAGE_KEY_CERT_SIGN 0x0004 +#define KEY_USAGE_CRL_SIGN 0x0002 +#define KEY_USAGE_ENCIPHER_ONLY 0x0001 +#define KEY_USAGE_DECIPHER_ONLY 0x8000 + +struct _x509_ctx +{ + char *ca_cert_dn[X509_NUM_DN_TYPES]; + char *cert_dn[X509_NUM_DN_TYPES]; + char **subject_alt_dnsnames; + time_t not_before; + time_t not_after; + uint8_t *signature; + RSA_CTX *rsa_ctx; + bigint *digest; + uint16_t sig_len; + uint8_t sig_type; + bool basic_constraint_present; + bool basic_constraint_is_critical; + bool key_usage_present; + bool key_usage_is_critical; + bool subject_alt_name_present; + bool subject_alt_name_is_critical; + bool basic_constraint_cA; + int basic_constraint_pathLenConstraint; + uint32_t key_usage; + struct _x509_ctx *next; +}; + +typedef struct _x509_ctx X509_CTX; + +typedef struct +{ + X509_CTX *cert[CONFIG_X509_MAX_CA_CERTS]; +} CA_CERT_CTX; + +int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx); +void x509_free(X509_CTX *x509_ctx); +int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert, int *pathLenConstraint); +#endif From 15467325cc700280d4f9d1f272d69ab058611b46 Mon Sep 17 00:00:00 2001 From: Myles Eftos Date: Thu, 30 Mar 2017 08:34:04 +1100 Subject: [PATCH 02/12] Successfully reads bundled certificate and signature size from the flash --- cores/esp8266/Updater.cpp | 245 +++++++++++++++++++------------------- cores/esp8266/Updater.h | 6 +- 2 files changed, 126 insertions(+), 125 deletions(-) diff --git a/cores/esp8266/Updater.cpp b/cores/esp8266/Updater.cpp index 629cf7ceef..7e652da4f7 100644 --- a/cores/esp8266/Updater.cpp +++ b/cores/esp8266/Updater.cpp @@ -124,22 +124,6 @@ bool UpdaterClass::begin(size_t size, int command) { DEBUG_UPDATER.printf("[begin] _size: 0x%08X (%d)\n", _size, _size); #endif -#ifdef VERIFY_SIGNATURE - // If this package has been signed correctly, the last uint32 is the size of the signature - // the second-last uint32 is the size of the certificate - _signatureLen = (uint32_t)&_size - sizeof(uint32); - _certificateLen = (uint32_t)&_size - (2 * sizeof(uint32)); - _signatureStartAddress = (uint32_t)&_size - _signatureLen - (2 * sizeof(uint32)); - _certificateStartAddress = _signatureStartAddress - _certificateLen; - -#ifdef DEBUG_UPDATER - DEBUG_UPDATER.printf("[begin] _signatureLen: 0x%08X (%d)\n", _signatureLen, _signatureLen); - DEBUG_UPDATER.printf("[begin] _certificateLen: 0x%08X (%d)\n", _certificateLen, _certificateLen); - DEBUG_UPDATER.printf("[begin] _signatureStartAddress: 0x%08X (%d)\n", _signatureStartAddress, _signatureStartAddress); - DEBUG_UPDATER.printf("[begin] _certificateStartAddress: 0x%08X (%d)\n", _certificateStartAddress, _certificateStartAddress); -#endif -#endif - _md5.begin(); return true; } @@ -200,6 +184,23 @@ bool UpdaterClass::end(bool evenIfRemaining){ return false; } +#ifdef VERIFY_SIGNATURE + // If this package has been signed correctly, the last uint32 is the size of the signature + // the second-last uint32 is the size of the certificate + ESP.flashRead(_startAddress + _size - 4, &_signatureLen, sizeof(uint32_t)); + ESP.flashRead(_startAddress + _size - 8, &_certificateLen, sizeof(uint32_t)); + _signatureStartAddress = _startAddress + _size - 8 - _signatureLen; + _certificateStartAddress = _signatureStartAddress - _certificateLen; + +#ifdef DEBUG_UPDATER + DEBUG_UPDATER.printf("\n"); + DEBUG_UPDATER.printf("[begin] _signatureLen: 0x%08X (%d)\n", _signatureLen, _signatureLen); + DEBUG_UPDATER.printf("[begin] _certificateLen: 0x%08X (%d)\n", _certificateLen, _certificateLen); + DEBUG_UPDATER.printf("[begin] _signatureStartAddress: 0x%08X (%d)\n", _signatureStartAddress, _signatureStartAddress); + DEBUG_UPDATER.printf("[begin] _certificateStartAddress: 0x%08X (%d)\n", _certificateStartAddress, _certificateStartAddress); +#endif +#endif + if (_command == U_FLASH) { eboot_command ebcmd; ebcmd.action = ACTION_COPY_RAW; @@ -220,112 +221,112 @@ bool UpdaterClass::end(bool evenIfRemaining){ return true; } -#ifdef VERIFY_SIGNATURE - int UpdaterClass::addCA(const uint8_t *cert, int *len) { - // TODO: Allow more than one CA - int res = x509_new(cert, len, &(_ca_ctx->cert[0])); - -#ifdef DEBUG_UPDATER - if(res == X509_OK) { - DEBUG_UPDATER.printf("Loaded CA certificate. Common Name: %s\n", _ca_ctx->cert[0]->cert_dn[X509_COMMON_NAME]); - } else { - DEBUG_UPDATER.printf("Unable to load CA certificate: %i\n", res); - } -#endif - - return res; - } - - bool UpdaterClass::_loadCertificate(X509_CTX *ctx) { - uint8_t *cert = (uint8_t *)_certificateStartAddress; - int res = x509_new(cert, (int *)&_certificateLen, &ctx); - if(res != X509_OK) { -#ifdef DEBUG_UPDATER - DEBUG_UPDATER.printf("Unable to load developer certificate: %i\n", res); -#endif - return false; - } -#ifdef DEBUG_UPDATER - DEBUG_UPDATER.printf("Loaded developer certificate. Common Name: %s\n", ctx->cert_dn[X509_COMMON_NAME]); -#endif - return true; - } - - bool UpdaterClass::_verifyCertificate(X509_CTX *ctx) { - int constraint; - int res = x509_verify(_ca_ctx, ctx, &constraint); - -#ifdef DEBUG_UPDATER - if(res == 0) { - DEBUG_UPDATER.printf("Developer certificate verified\n"); - } else { - DEBUG_UPDATED.printf("Developer certificate not verified\n"); - } -#endif - - return res == 0; - } - - bool UpdaterClass::_decryptSignature(X509_CTX *ctx, unsigned char **hash) { - const uint8_t *sig = (uint8_t *)_signatureStartAddress; - -// This should be derived from the hash type -#define MAX_LEN_KEY 512 - - unsigned char sig_bytes[MAX_KEY_LEN]; - int len = RSA_decrypt(ctx->rsa_ctx, (const uint8_t*)sig, sig_bytes, MAX_KEY_LEN, 0); - - if(len == -1) { - return false; - } - - if(len != (int)_signatureLen) { - return false; - } - - (*hash) = sig_bytes + len - SHA256_SIZE; - return true; - } - - bool UpdaterClass::_compareHash(unsigned char **hash) { - unsigned char hash_computed[SHA256_SIZE]; - - SHA256_CTX sha256; - SHA256_Init(&sha256); - SHA256_Update(&sha256, _buffer, _bufferLen); - SHA256_Final(hash_computed, &sha256); - - if(memcmp(hash, hash_computed, SHA256_SIZE) == 0) { - return true; - } else { - return false; - } - } - - bool UpdaterClass::_verifySignature() { - X509_CTX ctx; - if(!_loadCertificate(&ctx)) { - return false; - } - - if(!_verifyCertificate(&ctx)) { - return false; - } - - unsigned char *hash; - if(!_decryptSignature(&ctx, &hash)) { - return false; - } - - if(_compareHash(&hash)) { - free(hash); - return true; - } else { - free(hash); - return false; - } - } -#endif +// #ifdef VERIFY_SIGNATURE +// int UpdaterClass::addCA(const uint8_t *cert, int *len) { +// // TODO: Allow more than one CA +// int res = x509_new(cert, len, &(_ca_ctx->cert[0])); + +// #ifdef DEBUG_UPDATER +// if(res == X509_OK) { +// DEBUG_UPDATER.printf("Loaded CA certificate. Common Name: %s\n", _ca_ctx->cert[0]->cert_dn[X509_COMMON_NAME]); +// } else { +// DEBUG_UPDATER.printf("Unable to load CA certificate: %i\n", res); +// } +// #endif + +// return res; +// } + +// bool UpdaterClass::_loadCertificate(X509_CTX *ctx) { +// uint8_t *cert = (uint8_t *)_certificateStartAddress; +// int res = x509_new(cert, (int *)&_certificateLen, &ctx); +// if(res != X509_OK) { +// #ifdef DEBUG_UPDATER +// DEBUG_UPDATER.printf("Unable to load developer certificate: %i\n", res); +// #endif +// return false; +// } +// #ifdef DEBUG_UPDATER +// DEBUG_UPDATER.printf("Loaded developer certificate. Common Name: %s\n", ctx->cert_dn[X509_COMMON_NAME]); +// #endif +// return true; +// } + +// bool UpdaterClass::_verifyCertificate(X509_CTX *ctx) { +// int constraint; +// int res = x509_verify(_ca_ctx, ctx, &constraint); + +// #ifdef DEBUG_UPDATER +// if(res == 0) { +// DEBUG_UPDATER.printf("Developer certificate verified\n"); +// } else { +// DEBUG_UPDATED.printf("Developer certificate not verified\n"); +// } +// #endif + +// return res == 0; +// } + +// bool UpdaterClass::_decryptSignature(X509_CTX *ctx, unsigned char **hash) { +// const uint8_t *sig = (uint8_t *)_signatureStartAddress; + +// // This should be derived from the hash type +// #define MAX_LEN_KEY 512 + +// unsigned char sig_bytes[MAX_KEY_LEN]; +// int len = RSA_decrypt(ctx->rsa_ctx, (const uint8_t*)sig, sig_bytes, MAX_KEY_LEN, 0); + +// if(len == -1) { +// return false; +// } + +// if(len != (int)_signatureLen) { +// return false; +// } + +// (*hash) = sig_bytes + len - SHA256_SIZE; +// return true; +// } + +// bool UpdaterClass::_compareHash(unsigned char **hash) { +// unsigned char hash_computed[SHA256_SIZE]; + +// SHA256_CTX sha256; +// SHA256_Init(&sha256); +// SHA256_Update(&sha256, _buffer, _bufferLen); +// SHA256_Final(hash_computed, &sha256); + +// if(memcmp(hash, hash_computed, SHA256_SIZE) == 0) { +// return true; +// } else { +// return false; +// } +// } + +// bool UpdaterClass::_verifySignature() { +// X509_CTX ctx; +// if(!_loadCertificate(&ctx)) { +// return false; +// } + +// if(!_verifyCertificate(&ctx)) { +// return false; +// } + +// unsigned char *hash; +// if(!_decryptSignature(&ctx, &hash)) { +// return false; +// } + +// if(_compareHash(&hash)) { +// free(hash); +// return true; +// } else { +// free(hash); +// return false; +// } +// } +// #endif bool UpdaterClass::_writeBuffer(){ diff --git a/cores/esp8266/Updater.h b/cores/esp8266/Updater.h index 1dc9d1c3c8..1a7e773a49 100644 --- a/cores/esp8266/Updater.h +++ b/cores/esp8266/Updater.h @@ -13,7 +13,7 @@ #include "axtls/sha1.h" #include "axtls/sha256.h" -#define MAX_KEY_LEN 256 +#define MAX_KEY_LEN 512 #endif #define UPDATE_ERROR_OK (0) @@ -172,9 +172,9 @@ class UpdaterClass { bool _verifySignature(); uint32_t _certificateStartAddress; - size_t _certificateLen; + uint32_t _certificateLen; uint32_t _signatureStartAddress; - size_t _signatureLen; + uint32_t _signatureLen; #endif bool _async; From effbb3f9696efe43ecac8372b6b2b1b6e581bad8 Mon Sep 17 00:00:00 2001 From: Myles Eftos Date: Sat, 1 Apr 2017 14:44:00 +1100 Subject: [PATCH 03/12] Succesfully loading the developer certificate from flash --- cores/esp8266/Updater.cpp | 241 +++++++++++++++++++++----------------- cores/esp8266/Updater.h | 2 +- 2 files changed, 136 insertions(+), 107 deletions(-) diff --git a/cores/esp8266/Updater.cpp b/cores/esp8266/Updater.cpp index 7e652da4f7..e2cd722171 100644 --- a/cores/esp8266/Updater.cpp +++ b/cores/esp8266/Updater.cpp @@ -199,6 +199,14 @@ bool UpdaterClass::end(bool evenIfRemaining){ DEBUG_UPDATER.printf("[begin] _signatureStartAddress: 0x%08X (%d)\n", _signatureStartAddress, _signatureStartAddress); DEBUG_UPDATER.printf("[begin] _certificateStartAddress: 0x%08X (%d)\n", _certificateStartAddress, _certificateStartAddress); #endif + + if(!_verifySignature()) { +#ifdef DEBUG_UPDATER + DEBUG_UPDATER.printf("Signature verification failed\n"); +#endif + _reset(); + return false; + } #endif if (_command == U_FLASH) { @@ -221,112 +229,133 @@ bool UpdaterClass::end(bool evenIfRemaining){ return true; } -// #ifdef VERIFY_SIGNATURE -// int UpdaterClass::addCA(const uint8_t *cert, int *len) { -// // TODO: Allow more than one CA -// int res = x509_new(cert, len, &(_ca_ctx->cert[0])); - -// #ifdef DEBUG_UPDATER -// if(res == X509_OK) { -// DEBUG_UPDATER.printf("Loaded CA certificate. Common Name: %s\n", _ca_ctx->cert[0]->cert_dn[X509_COMMON_NAME]); -// } else { -// DEBUG_UPDATER.printf("Unable to load CA certificate: %i\n", res); -// } -// #endif - -// return res; -// } - -// bool UpdaterClass::_loadCertificate(X509_CTX *ctx) { -// uint8_t *cert = (uint8_t *)_certificateStartAddress; -// int res = x509_new(cert, (int *)&_certificateLen, &ctx); -// if(res != X509_OK) { -// #ifdef DEBUG_UPDATER -// DEBUG_UPDATER.printf("Unable to load developer certificate: %i\n", res); -// #endif -// return false; -// } -// #ifdef DEBUG_UPDATER -// DEBUG_UPDATER.printf("Loaded developer certificate. Common Name: %s\n", ctx->cert_dn[X509_COMMON_NAME]); -// #endif -// return true; -// } - -// bool UpdaterClass::_verifyCertificate(X509_CTX *ctx) { -// int constraint; -// int res = x509_verify(_ca_ctx, ctx, &constraint); - -// #ifdef DEBUG_UPDATER -// if(res == 0) { -// DEBUG_UPDATER.printf("Developer certificate verified\n"); -// } else { -// DEBUG_UPDATED.printf("Developer certificate not verified\n"); -// } -// #endif - -// return res == 0; -// } - -// bool UpdaterClass::_decryptSignature(X509_CTX *ctx, unsigned char **hash) { -// const uint8_t *sig = (uint8_t *)_signatureStartAddress; - -// // This should be derived from the hash type -// #define MAX_LEN_KEY 512 - -// unsigned char sig_bytes[MAX_KEY_LEN]; -// int len = RSA_decrypt(ctx->rsa_ctx, (const uint8_t*)sig, sig_bytes, MAX_KEY_LEN, 0); - -// if(len == -1) { -// return false; -// } - -// if(len != (int)_signatureLen) { -// return false; -// } - -// (*hash) = sig_bytes + len - SHA256_SIZE; -// return true; -// } - -// bool UpdaterClass::_compareHash(unsigned char **hash) { -// unsigned char hash_computed[SHA256_SIZE]; - -// SHA256_CTX sha256; -// SHA256_Init(&sha256); -// SHA256_Update(&sha256, _buffer, _bufferLen); -// SHA256_Final(hash_computed, &sha256); - -// if(memcmp(hash, hash_computed, SHA256_SIZE) == 0) { -// return true; -// } else { -// return false; -// } -// } - -// bool UpdaterClass::_verifySignature() { -// X509_CTX ctx; -// if(!_loadCertificate(&ctx)) { -// return false; -// } - -// if(!_verifyCertificate(&ctx)) { -// return false; -// } - -// unsigned char *hash; -// if(!_decryptSignature(&ctx, &hash)) { -// return false; -// } - -// if(_compareHash(&hash)) { -// free(hash); -// return true; -// } else { -// free(hash); -// return false; -// } -// } -// #endif +#ifdef VERIFY_SIGNATURE + int UpdaterClass::addCA(const uint8_t *cert, int *len) { + // TODO: Allow more than one CA + int res = x509_new(cert, len, &(_ca_ctx->cert[0])); + +#ifdef DEBUG_UPDATER + if(res == X509_OK) { + DEBUG_UPDATER.printf("Loaded CA certificate. Common Name: %s\n", _ca_ctx->cert[0]->cert_dn[X509_COMMON_NAME]); + } else { + DEBUG_UPDATER.printf("Unable to load CA certificate: %i\n", res); + } +#endif + + return res; + } + + bool UpdaterClass::_loadCertificate(X509_CTX *ctx, uint32_t *cert) { + cert = (uint32_t *)malloc(sizeof(uint32_t) * _certificateLen); + ESP.flashRead(_certificateStartAddress, cert, _certificateLen); + int res = x509_new((uint8_t *)cert, (int *)&_certificateLen, &ctx); + + if(res != X509_OK) { +#ifdef DEBUG_UPDATER + DEBUG_UPDATER.printf("Unable to load developer certificate: %i\n", res); +#endif + return false; + } +#ifdef DEBUG_UPDATER + DEBUG_UPDATER.printf("Loaded developer certificate. Common Name: %s\n", ctx->cert_dn[X509_COMMON_NAME]); +#endif + return true; + } + + bool UpdaterClass::_verifyCertificate(X509_CTX *ctx) { + int constraint; + int res = x509_verify(_ca_ctx, ctx, &constraint); + +#ifdef DEBUG_UPDATER + if(res == 0) { + DEBUG_UPDATER.printf("Developer certificate verified\n"); + } else { + DEBUG_UPDATER.printf("Developer certificate not verified\n"); + } +#endif + + return res == 0; + } + + bool UpdaterClass::_decryptSignature(X509_CTX *ctx, unsigned char **hash) { + const uint8_t *sig = (uint8_t *)_signatureStartAddress; + +// This should be derived from the hash type +#define MAX_LEN_KEY 512 + + unsigned char sig_bytes[MAX_KEY_LEN]; + int len = RSA_decrypt(ctx->rsa_ctx, (const uint8_t*)sig, sig_bytes, MAX_KEY_LEN, 0); + + if(len == -1) { +#ifdef DEBUG_UPDATER + DEBUG_UPDATER.printf("Decryption failed\n"); +#endif + return false; + } + + if(len != (int)_signatureLen) { +#ifdef DEBUG_UPDATER + DEBUG_UPDATER.printf("Decryption failed: Signature length too short.\n"); +#endif + return false; + } + + (*hash) = sig_bytes + len - SHA256_SIZE; +#ifdef DEBUG_UPDATER + DEBUG_UPDATER.printf("Decryption successful.\n"); +#endif + return true; + } + + // bool UpdaterClass::_compareHash(unsigned char **hash) { + // unsigned char hash_computed[SHA256_SIZE]; + + // SHA256_CTX sha256; + // SHA256_Init(&sha256); + // SHA256_Update(&sha256, _buffer, _bufferLen); + // SHA256_Final(hash_computed, &sha256); + + // if(memcmp(hash, hash_computed, SHA256_SIZE) == 0) { + // return true; + // } else { + // return false; + // } + // } + + bool UpdaterClass::_verifySignature() { + X509_CTX ctx; + uint32_t *cert; + + if(!_loadCertificate(&ctx, cert)) { + free(cert); + return false; + } + + // if(!_verifyCertificate(&ctx)) { + // free(cert); + // return false; + // } + + free(cert); + return true; + + // unsigned char *hash; + // if(!_decryptSignature(&ctx, &hash)) { + // free(cert); + // return false; + // } + + // if(_compareHash(&hash)) { + // free(hash); + // free(cert); + // return true; + // } else { + // free(hash); + // free(cert); + // return false; + // } + } +#endif bool UpdaterClass::_writeBuffer(){ diff --git a/cores/esp8266/Updater.h b/cores/esp8266/Updater.h index 1a7e773a49..fbd0f13fa9 100644 --- a/cores/esp8266/Updater.h +++ b/cores/esp8266/Updater.h @@ -165,7 +165,7 @@ class UpdaterClass { #ifdef VERIFY_SIGNATURE CA_CERT_CTX *_ca_ctx; - bool _loadCertificate(X509_CTX *ctx); + bool _loadCertificate(X509_CTX *ctx, uint32_t *cert); bool _verifyCertificate(X509_CTX *ctx); bool _decryptSignature(X509_CTX *ctx, unsigned char **hash); bool _compareHash(unsigned char **hash); From 0b69fa4d0a45b5d012e56dea77962df11f19d0b1 Mon Sep 17 00:00:00 2001 From: Myles Eftos Date: Sun, 2 Apr 2017 12:07:50 +1000 Subject: [PATCH 04/12] Successfully verifies the developer certificate and decrypts the hash key. --- cores/esp8266/Updater.cpp | 62 +++++++++++++++++++-------------------- cores/esp8266/Updater.h | 6 ++-- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/cores/esp8266/Updater.cpp b/cores/esp8266/Updater.cpp index e2cd722171..616d77b5d9 100644 --- a/cores/esp8266/Updater.cpp +++ b/cores/esp8266/Updater.cpp @@ -245,11 +245,14 @@ bool UpdaterClass::end(bool evenIfRemaining){ return res; } - bool UpdaterClass::_loadCertificate(X509_CTX *ctx, uint32_t *cert) { - cert = (uint32_t *)malloc(sizeof(uint32_t) * _certificateLen); - ESP.flashRead(_certificateStartAddress, cert, _certificateLen); - int res = x509_new((uint8_t *)cert, (int *)&_certificateLen, &ctx); - + bool UpdaterClass::_loadCertificate(X509_CTX **ctx) { + size_t num_of_bits = sizeof(uint8_t) * _certificateLen; + uint8_t *cert = (uint8_t *)malloc(num_of_bits + (num_of_bits % 32)); // Round up to the next uint32_t boundary + ESP.flashRead(_certificateStartAddress, (uint32_t *)cert, num_of_bits); + + int res = x509_new(cert, (int *)&_certificateLen, ctx); + free(cert); + if(res != X509_OK) { #ifdef DEBUG_UPDATER DEBUG_UPDATER.printf("Unable to load developer certificate: %i\n", res); @@ -257,34 +260,36 @@ bool UpdaterClass::end(bool evenIfRemaining){ return false; } #ifdef DEBUG_UPDATER - DEBUG_UPDATER.printf("Loaded developer certificate. Common Name: %s\n", ctx->cert_dn[X509_COMMON_NAME]); + DEBUG_UPDATER.printf("Loaded developer certificate. Common Name: %s\n", (*ctx)->cert_dn[X509_COMMON_NAME]); #endif return true; } - bool UpdaterClass::_verifyCertificate(X509_CTX *ctx) { + bool UpdaterClass::_verifyCertificate(X509_CTX **ctx) { int constraint; - int res = x509_verify(_ca_ctx, ctx, &constraint); + int res = x509_verify(_ca_ctx, *ctx, &constraint); #ifdef DEBUG_UPDATER - if(res == 0) { + if(res == X509_OK) { DEBUG_UPDATER.printf("Developer certificate verified\n"); } else { - DEBUG_UPDATER.printf("Developer certificate not verified\n"); + DEBUG_UPDATER.printf("Developer certificate not verified: %i\n", res); } #endif - return res == 0; + return res == X509_OK; } - bool UpdaterClass::_decryptSignature(X509_CTX *ctx, unsigned char **hash) { - const uint8_t *sig = (uint8_t *)_signatureStartAddress; + bool UpdaterClass::_decryptSignature(X509_CTX **ctx, unsigned char **hash) { + size_t num_of_bits = sizeof(uint8_t) * _signatureLen; + uint8_t *sig = (uint8_t *)malloc(num_of_bits + (num_of_bits % 32)); // Round up to the next uint32_t boundary + ESP.flashRead(_signatureStartAddress, (uint32_t *)sig, num_of_bits); // This should be derived from the hash type #define MAX_LEN_KEY 512 unsigned char sig_bytes[MAX_KEY_LEN]; - int len = RSA_decrypt(ctx->rsa_ctx, (const uint8_t*)sig, sig_bytes, MAX_KEY_LEN, 0); + int len = RSA_decrypt((*ctx)->rsa_ctx, (const uint8_t*)sig, sig_bytes, MAX_KEY_LEN, 0); if(len == -1) { #ifdef DEBUG_UPDATER @@ -293,9 +298,9 @@ bool UpdaterClass::end(bool evenIfRemaining){ return false; } - if(len != (int)_signatureLen) { + if(len < SHA256_SIZE) { #ifdef DEBUG_UPDATER - DEBUG_UPDATER.printf("Decryption failed: Signature length too short.\n"); + DEBUG_UPDATER.printf("Decryption failed: Signature length too short. Expected %i, got %i\n", SHA256_SIZE, len); #endif return false; } @@ -323,28 +328,23 @@ bool UpdaterClass::end(bool evenIfRemaining){ // } bool UpdaterClass::_verifySignature() { - X509_CTX ctx; - uint32_t *cert; + X509_CTX *ctx; - if(!_loadCertificate(&ctx, cert)) { - free(cert); + if(!_loadCertificate(&ctx)) { return false; } - // if(!_verifyCertificate(&ctx)) { - // free(cert); - // return false; - // } + if(!_verifyCertificate(&ctx)) { + return false; + } + + unsigned char *hash; + if(!_decryptSignature(&ctx, &hash)) { + return false; + } - free(cert); return true; - // unsigned char *hash; - // if(!_decryptSignature(&ctx, &hash)) { - // free(cert); - // return false; - // } - // if(_compareHash(&hash)) { // free(hash); // free(cert); diff --git a/cores/esp8266/Updater.h b/cores/esp8266/Updater.h index fbd0f13fa9..ff1e547c93 100644 --- a/cores/esp8266/Updater.h +++ b/cores/esp8266/Updater.h @@ -165,9 +165,9 @@ class UpdaterClass { #ifdef VERIFY_SIGNATURE CA_CERT_CTX *_ca_ctx; - bool _loadCertificate(X509_CTX *ctx, uint32_t *cert); - bool _verifyCertificate(X509_CTX *ctx); - bool _decryptSignature(X509_CTX *ctx, unsigned char **hash); + bool _loadCertificate(X509_CTX **ctx); + bool _verifyCertificate(X509_CTX **ctx); + bool _decryptSignature(X509_CTX **ctx, unsigned char **hash); bool _compareHash(unsigned char **hash); bool _verifySignature(); From e5e674727326290736b4400f86f8424a6fba9334 Mon Sep 17 00:00:00 2001 From: Myles Eftos Date: Sun, 2 Apr 2017 14:55:47 +1000 Subject: [PATCH 05/12] Allow md5 and sha1 signed certs. Refactored so MD5 hash happens at the last moment, allowing us to ignore the additional signature and certificate --- cores/esp8266/MD5Builder.cpp | 8 +- cores/esp8266/MD5Builder.h | 4 +- cores/esp8266/Updater.cpp | 130 ++++++++-------- cores/esp8266/Updater.h | 4 +- cores/esp8266/axtls/md5.cpp | 293 +++++++++++++++++++++++++++++++++++ cores/esp8266/axtls/md5.h | 25 +++ cores/esp8266/axtls/x509.cpp | 6 +- cores/esp8266/md5.h | 44 ------ 8 files changed, 397 insertions(+), 117 deletions(-) create mode 100644 cores/esp8266/axtls/md5.cpp create mode 100644 cores/esp8266/axtls/md5.h delete mode 100644 cores/esp8266/md5.h diff --git a/cores/esp8266/MD5Builder.cpp b/cores/esp8266/MD5Builder.cpp index ac4fa29ee2..aaab3864ec 100644 --- a/cores/esp8266/MD5Builder.cpp +++ b/cores/esp8266/MD5Builder.cpp @@ -11,12 +11,12 @@ uint8_t hex_char_to_byte(uint8_t c) void MD5Builder::begin(void) { memset(_buf, 0x00, 16); - MD5Init(&_ctx); + MD5_Init(&_ctx); } void MD5Builder::add(uint8_t * data, uint16_t len) { - MD5Update(&_ctx, data, len); + MD5_Update(&_ctx, data, len); } void MD5Builder::addHexString(const char * data) @@ -64,7 +64,7 @@ bool MD5Builder::addStream(Stream & stream, const size_t maxLen) } // Update MD5 with buffer payload - MD5Update(&_ctx, buf, numBytesRead); + MD5_Update(&_ctx, buf, numBytesRead); yield(); // time for network streams @@ -78,7 +78,7 @@ bool MD5Builder::addStream(Stream & stream, const size_t maxLen) void MD5Builder::calculate(void) { - MD5Final(_buf, &_ctx); + MD5_Final(_buf, &_ctx); } void MD5Builder::getBytes(uint8_t * output) diff --git a/cores/esp8266/MD5Builder.h b/cores/esp8266/MD5Builder.h index d4e336fca9..4c312e54b3 100644 --- a/cores/esp8266/MD5Builder.h +++ b/cores/esp8266/MD5Builder.h @@ -23,11 +23,11 @@ #include #include -#include "md5.h" +#include "axtls/md5.h" class MD5Builder { private: - md5_context_t _ctx; + MD5_CTX _ctx; uint8_t _buf[16]; public: void begin(void); diff --git a/cores/esp8266/Updater.cpp b/cores/esp8266/Updater.cpp index 616d77b5d9..19b28f129d 100644 --- a/cores/esp8266/Updater.cpp +++ b/cores/esp8266/Updater.cpp @@ -161,8 +161,52 @@ bool UpdaterClass::end(bool evenIfRemaining){ _size = progress(); } - _md5.calculate(); +#ifdef VERIFY_SIGNATURE + // If this package has been signed correctly, the last uint32 is the size of the signature + // the second-last uint32 is the size of the certificate + ESP.flashRead(_startAddress + _size - sizeof(uint32_t), &_signatureLen, sizeof(uint32_t)); + ESP.flashRead(_startAddress + _size - (2 * sizeof(uint32_t)), &_certificateLen, sizeof(uint32_t)); + _signatureStartAddress = _startAddress + _size - (2 * sizeof(uint32_t)) - _signatureLen; + _certificateStartAddress = _signatureStartAddress - _certificateLen; + +#ifdef DEBUG_UPDATER + DEBUG_UPDATER.printf("\n"); + DEBUG_UPDATER.printf("[begin] _signatureLen: 0x%08X (%d)\n", _signatureLen, _signatureLen); + DEBUG_UPDATER.printf("[begin] _certificateLen: 0x%08X (%d)\n", _certificateLen, _certificateLen); + DEBUG_UPDATER.printf("[begin] _signatureStartAddress: 0x%08X (%d)\n", _signatureStartAddress, _signatureStartAddress); + DEBUG_UPDATER.printf("[begin] _certificateStartAddress: 0x%08X (%d)\n", _certificateStartAddress, _certificateStartAddress); +#endif + + if(!_decryptMD5()) { +#ifdef DEBUG_UPDATER + DEBUG_UPDATER.printf("MD5 Decryption Failed.\n"); +#endif + _reset(); + return false; + } +#endif + if(_target_md5.length()) { + // If there is a target MD5 hash set, we now take the md5 hash of the binary + int bin_size = (int)_size; +#ifdef VERIFY_SIGNATURE + bin_size -= (int)(_signatureLen + _certificateLen + (2 * sizeof(uint32_t))); +#endif + + uint8_t *bin_buffer = (uint8_t *)malloc(sizeof(uint8_t) * 32); + for(int i = 0; i < bin_size; i += 32) { + ESP.flashRead(_startAddress + i, (uint32_t *)bin_buffer, 32); + + int read = bin_size - i; + if(read > 32) { + read = 32; + } + + _md5.add(bin_buffer, read); + } + _md5.calculate(); + free(bin_buffer); + if(_target_md5 != _md5.toString()){ _error = UPDATE_ERROR_MD5; #ifdef DEBUG_UPDATER @@ -184,31 +228,6 @@ bool UpdaterClass::end(bool evenIfRemaining){ return false; } -#ifdef VERIFY_SIGNATURE - // If this package has been signed correctly, the last uint32 is the size of the signature - // the second-last uint32 is the size of the certificate - ESP.flashRead(_startAddress + _size - 4, &_signatureLen, sizeof(uint32_t)); - ESP.flashRead(_startAddress + _size - 8, &_certificateLen, sizeof(uint32_t)); - _signatureStartAddress = _startAddress + _size - 8 - _signatureLen; - _certificateStartAddress = _signatureStartAddress - _certificateLen; - -#ifdef DEBUG_UPDATER - DEBUG_UPDATER.printf("\n"); - DEBUG_UPDATER.printf("[begin] _signatureLen: 0x%08X (%d)\n", _signatureLen, _signatureLen); - DEBUG_UPDATER.printf("[begin] _certificateLen: 0x%08X (%d)\n", _certificateLen, _certificateLen); - DEBUG_UPDATER.printf("[begin] _signatureStartAddress: 0x%08X (%d)\n", _signatureStartAddress, _signatureStartAddress); - DEBUG_UPDATER.printf("[begin] _certificateStartAddress: 0x%08X (%d)\n", _certificateStartAddress, _certificateStartAddress); -#endif - - if(!_verifySignature()) { -#ifdef DEBUG_UPDATER - DEBUG_UPDATER.printf("Signature verification failed\n"); -#endif - _reset(); - return false; - } -#endif - if (_command == U_FLASH) { eboot_command ebcmd; ebcmd.action = ACTION_COPY_RAW; @@ -285,11 +304,13 @@ bool UpdaterClass::end(bool evenIfRemaining){ uint8_t *sig = (uint8_t *)malloc(num_of_bits + (num_of_bits % 32)); // Round up to the next uint32_t boundary ESP.flashRead(_signatureStartAddress, (uint32_t *)sig, num_of_bits); -// This should be derived from the hash type -#define MAX_LEN_KEY 512 - - unsigned char sig_bytes[MAX_KEY_LEN]; - int len = RSA_decrypt((*ctx)->rsa_ctx, (const uint8_t*)sig, sig_bytes, MAX_KEY_LEN, 0); + const int signature_size = (*ctx)->rsa_ctx->num_octets; +#ifdef DEBUG_UPDATER + DEBUG_UPDATER.printf("Size of output buffer: %i\n", signature_size); +#endif + uint8_t sig_data[signature_size]; + int len = RSA_decrypt((*ctx)->rsa_ctx, (const uint8_t *)sig, sig_data, signature_size, 0); + free(sig); if(len == -1) { #ifdef DEBUG_UPDATER @@ -298,36 +319,29 @@ bool UpdaterClass::end(bool evenIfRemaining){ return false; } - if(len < SHA256_SIZE) { + if(len < MD5_SIZE) { #ifdef DEBUG_UPDATER - DEBUG_UPDATER.printf("Decryption failed: Signature length too short. Expected %i, got %i\n", SHA256_SIZE, len); + DEBUG_UPDATER.printf("Decryption failed: Signature is too short. Expected %i, got %i\n", MD5_SIZE, len); #endif return false; } - - (*hash) = sig_bytes + len - SHA256_SIZE; + #ifdef DEBUG_UPDATER DEBUG_UPDATER.printf("Decryption successful.\n"); #endif - return true; - } - - // bool UpdaterClass::_compareHash(unsigned char **hash) { - // unsigned char hash_computed[SHA256_SIZE]; - // SHA256_CTX sha256; - // SHA256_Init(&sha256); - // SHA256_Update(&sha256, _buffer, _bufferLen); - // SHA256_Final(hash_computed, &sha256); + (*hash) = (unsigned char *)calloc((MD5_SIZE * 2) + 1, sizeof(unsigned char)); + for(int i = 0; i < MD5_SIZE; i++) { + sprintf((char *)(*hash + (i * 2)), "%02x", sig_data[i]); + } - // if(memcmp(hash, hash_computed, SHA256_SIZE) == 0) { - // return true; - // } else { - // return false; - // } - // } +#ifdef DEBUG_UPDATER + DEBUG_UPDATER.printf("MD5 hash: %s\n", *hash); +#endif + return true; + } - bool UpdaterClass::_verifySignature() { + bool UpdaterClass::_decryptMD5() { X509_CTX *ctx; if(!_loadCertificate(&ctx)) { @@ -343,17 +357,10 @@ bool UpdaterClass::end(bool evenIfRemaining){ return false; } - return true; + DEBUG_UPDATER.printf("Length of hash: %i\n", strlen((const char *)hash)); + setMD5((const char *)hash); - // if(_compareHash(&hash)) { - // free(hash); - // free(cert); - // return true; - // } else { - // free(hash); - // free(cert); - // return false; - // } + return true; } #endif @@ -375,7 +382,6 @@ bool UpdaterClass::_writeBuffer(){ #endif return false; } - _md5.add(_buffer, _bufferLen); _currentAddress += _bufferLen; _bufferLen = 0; return true; diff --git a/cores/esp8266/Updater.h b/cores/esp8266/Updater.h index ff1e547c93..e363d49ed6 100644 --- a/cores/esp8266/Updater.h +++ b/cores/esp8266/Updater.h @@ -12,8 +12,6 @@ #include "axtls/asn1.h" #include "axtls/sha1.h" #include "axtls/sha256.h" - -#define MAX_KEY_LEN 512 #endif #define UPDATE_ERROR_OK (0) @@ -169,7 +167,7 @@ class UpdaterClass { bool _verifyCertificate(X509_CTX **ctx); bool _decryptSignature(X509_CTX **ctx, unsigned char **hash); bool _compareHash(unsigned char **hash); - bool _verifySignature(); + bool _decryptMD5(); uint32_t _certificateStartAddress; uint32_t _certificateLen; diff --git a/cores/esp8266/axtls/md5.cpp b/cores/esp8266/axtls/md5.cpp new file mode 100644 index 0000000000..254d9c5bae --- /dev/null +++ b/cores/esp8266/axtls/md5.cpp @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * This file implements the MD5 algorithm as defined in RFC1321 + */ + +#include +#include "md5.h" + +/* Constants for MD5Transform routine. + */ +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +/* ----- static functions ----- */ +static void MD5Transform(uint32_t state[4], const uint8_t block[64]); +static void Encode(uint8_t *output, uint32_t *input, uint32_t len); +static void Decode(uint32_t *output, const uint8_t *input, uint32_t len); + +static const uint8_t PADDING[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* F, G, H and I are basic MD5 functions. + */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits. */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. + Rotation is separate from addition to prevent recomputation. */ +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (uint32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (uint32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (uint32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (uint32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +/** + * MD5 initialization - begins an MD5 operation, writing a new ctx. + */ +extern void MD5_Init(MD5_CTX *ctx) +{ + ctx->count[0] = ctx->count[1] = 0; + + /* Load magic initialization constants. + */ + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xefcdab89; + ctx->state[2] = 0x98badcfe; + ctx->state[3] = 0x10325476; +} + +/** + * Accepts an array of octets as the next portion of the message. + */ +extern void MD5_Update(MD5_CTX *ctx, const uint8_t * msg, int len) +{ + uint32_t x; + int i, partLen; + + /* Compute number of bytes mod 64 */ + x = (uint32_t)((ctx->count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ((ctx->count[0] += ((uint32_t)len << 3)) < ((uint32_t)len << 3)) + ctx->count[1]++; + ctx->count[1] += ((uint32_t)len >> 29); + + partLen = 64 - x; + + /* Transform as many times as possible. */ + if (len >= partLen) + { + memcpy(&ctx->buffer[x], msg, partLen); + MD5Transform(ctx->state, ctx->buffer); + + for (i = partLen; i + 63 < len; i += 64) + MD5Transform(ctx->state, &msg[i]); + + x = 0; + } + else + i = 0; + + /* Buffer remaining input */ + memcpy(&ctx->buffer[x], &msg[i], len-i); +} + +/** + * Return the 128-bit message digest into the user's array + */ +extern void MD5_Final(uint8_t *digest, MD5_CTX *ctx) +{ + uint8_t bits[8]; + uint32_t x, padLen; + + /* Save number of bits */ + Encode(bits, ctx->count, 8); + + /* Pad out to 56 mod 64. + */ + x = (uint32_t)((ctx->count[0] >> 3) & 0x3f); + padLen = (x < 56) ? (56 - x) : (120 - x); + MD5_Update(ctx, PADDING, padLen); + + /* Append length (before padding) */ + MD5_Update(ctx, bits, 8); + + /* Store state in digest */ + Encode(digest, ctx->state, MD5_SIZE); +} + +/** + * MD5 basic transformation. Transforms state based on block. + */ +static void MD5Transform(uint32_t state[4], const uint8_t block[64]) +{ + uint32_t a = state[0], b = state[1], c = state[2], + d = state[3], x[MD5_SIZE]; + + Decode(x, block, 64); + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; +} + +/** + * Encodes input (uint32_t) into output (uint8_t). Assumes len is + * a multiple of 4. + */ +static void Encode(uint8_t *output, uint32_t *input, uint32_t len) +{ + uint32_t i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + { + output[j] = (uint8_t)(input[i] & 0xff); + output[j+1] = (uint8_t)((input[i] >> 8) & 0xff); + output[j+2] = (uint8_t)((input[i] >> 16) & 0xff); + output[j+3] = (uint8_t)((input[i] >> 24) & 0xff); + } +} + +/** + * Decodes input (uint8_t) into output (uint32_t). Assumes len is + * a multiple of 4. + */ +static void Decode(uint32_t *output, const uint8_t *input, uint32_t len) +{ + uint32_t i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((uint32_t)input[j]) | (((uint32_t)input[j+1]) << 8) | + (((uint32_t)input[j+2]) << 16) | (((uint32_t)input[j+3]) << 24); +} diff --git a/cores/esp8266/axtls/md5.h b/cores/esp8266/axtls/md5.h new file mode 100644 index 0000000000..40eb900c95 --- /dev/null +++ b/cores/esp8266/axtls/md5.h @@ -0,0 +1,25 @@ +#ifndef HEADER_MD5_H +#define HEADER_MD5_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MD5_SIZE 16 + +typedef struct +{ + uint32_t state[4]; /* state (ABCD) */ + uint32_t count[2]; /* number of bits, modulo 2^64 (lsb first) */ + uint8_t buffer[64]; /* input buffer */ +} MD5_CTX; + +extern void MD5_Init(MD5_CTX *); +extern void MD5_Update(MD5_CTX *, const uint8_t *msg, int len); +extern void MD5_Final(uint8_t *digest, MD5_CTX *); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif \ No newline at end of file diff --git a/cores/esp8266/axtls/x509.cpp b/cores/esp8266/axtls/x509.cpp index 6dc51c2d75..c434fce4df 100644 --- a/cores/esp8266/axtls/x509.cpp +++ b/cores/esp8266/axtls/x509.cpp @@ -37,6 +37,8 @@ #include #include #include "asn1.h" +#include "md5.h" +#include "sha1.h" #include "sha256.h" #include "x509.h" @@ -125,7 +127,7 @@ int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx) /* use the appropriate signature algorithm */ switch (x509_ctx->sig_type) { - /* + case SIG_TYPE_MD5: { MD5_CTX md5_ctx; @@ -147,7 +149,7 @@ int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx) x509_ctx->digest = bi_import(bi_ctx, sha_dgst, SHA1_SIZE); } break; - */ + case SIG_TYPE_SHA256: { SHA256_CTX sha256_ctx; diff --git a/cores/esp8266/md5.h b/cores/esp8266/md5.h deleted file mode 100644 index b3f1f54533..0000000000 --- a/cores/esp8266/md5.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - md5.h - exposed md5 ROM functions for esp8266 - - Copyright (c) 2015 Hristo Gochkov. All rights reserved. - This file is part of the esp8266 core for Arduino environment. - - original C source from https://github.com/morrissinger/ESP8266-Websocket/raw/master/MD5.h - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ -#ifndef __ESP8266_MD5__ -#define __ESP8266_MD5__ - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - uint32_t state[4]; - uint32_t count[2]; - uint8_t buffer[64]; -} md5_context_t; - -extern void MD5Init (md5_context_t *); -extern void MD5Update (md5_context_t *, uint8_t *, uint16_t); -extern void MD5Final (uint8_t [16], md5_context_t *); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif From d4e81ed070701b4c28365785f738f12110dca8e0 Mon Sep 17 00:00:00 2001 From: Myles Eftos Date: Sun, 2 Apr 2017 15:41:53 +1000 Subject: [PATCH 06/12] Successfully parsed binary, verified signature, decrypted hash and verified it. --- cores/esp8266/Updater.cpp | 16 +++++++--------- cores/esp8266/Updater.h | 3 +-- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/cores/esp8266/Updater.cpp b/cores/esp8266/Updater.cpp index 19b28f129d..c74b9deb58 100644 --- a/cores/esp8266/Updater.cpp +++ b/cores/esp8266/Updater.cpp @@ -299,7 +299,7 @@ bool UpdaterClass::end(bool evenIfRemaining){ return res == X509_OK; } - bool UpdaterClass::_decryptSignature(X509_CTX **ctx, unsigned char **hash) { + bool UpdaterClass::_decryptSignature(X509_CTX **ctx, char **hash) { size_t num_of_bits = sizeof(uint8_t) * _signatureLen; uint8_t *sig = (uint8_t *)malloc(num_of_bits + (num_of_bits % 32)); // Round up to the next uint32_t boundary ESP.flashRead(_signatureStartAddress, (uint32_t *)sig, num_of_bits); @@ -330,14 +330,13 @@ bool UpdaterClass::end(bool evenIfRemaining){ DEBUG_UPDATER.printf("Decryption successful.\n"); #endif - (*hash) = (unsigned char *)calloc((MD5_SIZE * 2) + 1, sizeof(unsigned char)); + // Fetch the last part of the encrypted string - that is the MD5 hash, and then save the string + // version of it in to the hash pointer. + (*hash) = (char *)calloc((MD5_SIZE * 2) + 1, sizeof(char)); for(int i = 0; i < MD5_SIZE; i++) { - sprintf((char *)(*hash + (i * 2)), "%02x", sig_data[i]); + sprintf(*hash + (i * 2), "%02x", sig_data[len - MD5_SIZE + i]); } - -#ifdef DEBUG_UPDATER - DEBUG_UPDATER.printf("MD5 hash: %s\n", *hash); -#endif + return true; } @@ -352,12 +351,11 @@ bool UpdaterClass::end(bool evenIfRemaining){ return false; } - unsigned char *hash; + char *hash; if(!_decryptSignature(&ctx, &hash)) { return false; } - DEBUG_UPDATER.printf("Length of hash: %i\n", strlen((const char *)hash)); setMD5((const char *)hash); return true; diff --git a/cores/esp8266/Updater.h b/cores/esp8266/Updater.h index e363d49ed6..03666b059f 100644 --- a/cores/esp8266/Updater.h +++ b/cores/esp8266/Updater.h @@ -165,8 +165,7 @@ class UpdaterClass { CA_CERT_CTX *_ca_ctx; bool _loadCertificate(X509_CTX **ctx); bool _verifyCertificate(X509_CTX **ctx); - bool _decryptSignature(X509_CTX **ctx, unsigned char **hash); - bool _compareHash(unsigned char **hash); + bool _decryptSignature(X509_CTX **ctx, char **hash); bool _decryptMD5(); uint32_t _certificateStartAddress; From 60c1b5b47aba286ef1f10525996525e3fc2c50ed Mon Sep 17 00:00:00 2001 From: Myles Eftos Date: Mon, 3 Apr 2017 19:21:21 +1000 Subject: [PATCH 07/12] Adding axtls headers from axtls-esp8266 so I can use the binary blob to do certificate validation --- cores/esp8266/MD5Builder.h | 2 +- cores/esp8266/Updater.cpp | 228 ++-- cores/esp8266/Updater.h | 6 +- cores/esp8266/axtls/asn1.cpp | 757 -------------- cores/esp8266/axtls/asn1.h | 55 - cores/esp8266/axtls/bigint.cpp | 978 ------------------ cores/esp8266/axtls/ca.h | 86 -- cores/esp8266/axtls/md5.cpp | 293 ------ cores/esp8266/axtls/md5.h | 25 - cores/esp8266/axtls/rsa.cpp | 266 ----- cores/esp8266/axtls/rsa.h | 44 - cores/esp8266/axtls/sha1.cpp | 248 ----- cores/esp8266/axtls/sha1.h | 23 - cores/esp8266/axtls/sha256.cpp | 273 ----- cores/esp8266/axtls/sha256.h | 17 - cores/esp8266/axtls/x509.cpp | 569 ---------- cores/esp8266/axtls/x509.h | 83 -- .../sdk/include/crypto}/bigint.h | 42 +- .../sdk/include/crypto}/bigint_impl.h | 47 +- tools/sdk/include/crypto/crypto.h | 267 +++++ tools/sdk/include/crypto/os_int.h | 67 ++ tools/sdk/include/ssl/config.h | 127 +++ tools/sdk/include/ssl/crypto_misc.h | 179 ++++ tools/sdk/include/ssl/os_int.h | 8 + tools/sdk/include/ssl/os_port.h | 241 +++++ tools/sdk/include/ssl/ssl.h | 553 ++++++++++ tools/sdk/include/ssl/tls1.h | 321 ++++++ tools/sdk/include/ssl/version.h | 1 + 28 files changed, 1959 insertions(+), 3847 deletions(-) delete mode 100644 cores/esp8266/axtls/asn1.cpp delete mode 100644 cores/esp8266/axtls/asn1.h delete mode 100644 cores/esp8266/axtls/bigint.cpp delete mode 100644 cores/esp8266/axtls/ca.h delete mode 100644 cores/esp8266/axtls/md5.cpp delete mode 100644 cores/esp8266/axtls/md5.h delete mode 100644 cores/esp8266/axtls/rsa.cpp delete mode 100644 cores/esp8266/axtls/rsa.h delete mode 100644 cores/esp8266/axtls/sha1.cpp delete mode 100644 cores/esp8266/axtls/sha1.h delete mode 100644 cores/esp8266/axtls/sha256.cpp delete mode 100644 cores/esp8266/axtls/sha256.h delete mode 100644 cores/esp8266/axtls/x509.cpp delete mode 100644 cores/esp8266/axtls/x509.h rename {cores/esp8266/axtls => tools/sdk/include/crypto}/bigint.h (81%) rename {cores/esp8266/axtls => tools/sdk/include/crypto}/bigint_impl.h (66%) create mode 100644 tools/sdk/include/crypto/crypto.h create mode 100644 tools/sdk/include/crypto/os_int.h create mode 100644 tools/sdk/include/ssl/config.h create mode 100644 tools/sdk/include/ssl/crypto_misc.h create mode 100644 tools/sdk/include/ssl/os_int.h create mode 100644 tools/sdk/include/ssl/os_port.h create mode 100644 tools/sdk/include/ssl/ssl.h create mode 100644 tools/sdk/include/ssl/tls1.h create mode 100644 tools/sdk/include/ssl/version.h diff --git a/cores/esp8266/MD5Builder.h b/cores/esp8266/MD5Builder.h index 4c312e54b3..e4a446eb94 100644 --- a/cores/esp8266/MD5Builder.h +++ b/cores/esp8266/MD5Builder.h @@ -23,7 +23,7 @@ #include #include -#include "axtls/md5.h" +#include class MD5Builder { private: diff --git a/cores/esp8266/Updater.cpp b/cores/esp8266/Updater.cpp index c74b9deb58..a9e2e06cd8 100644 --- a/cores/esp8266/Updater.cpp +++ b/cores/esp8266/Updater.cpp @@ -248,120 +248,6 @@ bool UpdaterClass::end(bool evenIfRemaining){ return true; } -#ifdef VERIFY_SIGNATURE - int UpdaterClass::addCA(const uint8_t *cert, int *len) { - // TODO: Allow more than one CA - int res = x509_new(cert, len, &(_ca_ctx->cert[0])); - -#ifdef DEBUG_UPDATER - if(res == X509_OK) { - DEBUG_UPDATER.printf("Loaded CA certificate. Common Name: %s\n", _ca_ctx->cert[0]->cert_dn[X509_COMMON_NAME]); - } else { - DEBUG_UPDATER.printf("Unable to load CA certificate: %i\n", res); - } -#endif - - return res; - } - - bool UpdaterClass::_loadCertificate(X509_CTX **ctx) { - size_t num_of_bits = sizeof(uint8_t) * _certificateLen; - uint8_t *cert = (uint8_t *)malloc(num_of_bits + (num_of_bits % 32)); // Round up to the next uint32_t boundary - ESP.flashRead(_certificateStartAddress, (uint32_t *)cert, num_of_bits); - - int res = x509_new(cert, (int *)&_certificateLen, ctx); - free(cert); - - if(res != X509_OK) { -#ifdef DEBUG_UPDATER - DEBUG_UPDATER.printf("Unable to load developer certificate: %i\n", res); -#endif - return false; - } -#ifdef DEBUG_UPDATER - DEBUG_UPDATER.printf("Loaded developer certificate. Common Name: %s\n", (*ctx)->cert_dn[X509_COMMON_NAME]); -#endif - return true; - } - - bool UpdaterClass::_verifyCertificate(X509_CTX **ctx) { - int constraint; - int res = x509_verify(_ca_ctx, *ctx, &constraint); - -#ifdef DEBUG_UPDATER - if(res == X509_OK) { - DEBUG_UPDATER.printf("Developer certificate verified\n"); - } else { - DEBUG_UPDATER.printf("Developer certificate not verified: %i\n", res); - } -#endif - - return res == X509_OK; - } - - bool UpdaterClass::_decryptSignature(X509_CTX **ctx, char **hash) { - size_t num_of_bits = sizeof(uint8_t) * _signatureLen; - uint8_t *sig = (uint8_t *)malloc(num_of_bits + (num_of_bits % 32)); // Round up to the next uint32_t boundary - ESP.flashRead(_signatureStartAddress, (uint32_t *)sig, num_of_bits); - - const int signature_size = (*ctx)->rsa_ctx->num_octets; -#ifdef DEBUG_UPDATER - DEBUG_UPDATER.printf("Size of output buffer: %i\n", signature_size); -#endif - uint8_t sig_data[signature_size]; - int len = RSA_decrypt((*ctx)->rsa_ctx, (const uint8_t *)sig, sig_data, signature_size, 0); - free(sig); - - if(len == -1) { -#ifdef DEBUG_UPDATER - DEBUG_UPDATER.printf("Decryption failed\n"); -#endif - return false; - } - - if(len < MD5_SIZE) { -#ifdef DEBUG_UPDATER - DEBUG_UPDATER.printf("Decryption failed: Signature is too short. Expected %i, got %i\n", MD5_SIZE, len); -#endif - return false; - } - -#ifdef DEBUG_UPDATER - DEBUG_UPDATER.printf("Decryption successful.\n"); -#endif - - // Fetch the last part of the encrypted string - that is the MD5 hash, and then save the string - // version of it in to the hash pointer. - (*hash) = (char *)calloc((MD5_SIZE * 2) + 1, sizeof(char)); - for(int i = 0; i < MD5_SIZE; i++) { - sprintf(*hash + (i * 2), "%02x", sig_data[len - MD5_SIZE + i]); - } - - return true; - } - - bool UpdaterClass::_decryptMD5() { - X509_CTX *ctx; - - if(!_loadCertificate(&ctx)) { - return false; - } - - if(!_verifyCertificate(&ctx)) { - return false; - } - - char *hash; - if(!_decryptSignature(&ctx, &hash)) { - return false; - } - - setMD5((const char *)hash); - - return true; - } -#endif - bool UpdaterClass::_writeBuffer(){ if(!_async) yield(); @@ -508,6 +394,120 @@ size_t UpdaterClass::writeStream(Stream &data) { return written; } +#ifdef VERIFY_SIGNATURE + int UpdaterClass::addCA(const uint8_t *cert, int *len) { + // TODO: Allow more than one CA + int res = x509_new(cert, len, &(_ca_ctx->cert[0])); + +#ifdef DEBUG_UPDATER + if(res == X509_OK) { + DEBUG_UPDATER.printf("Loaded CA certificate. Common Name: %s\n", _ca_ctx->cert[0]->cert_dn[X509_COMMON_NAME]); + } else { + DEBUG_UPDATER.printf("Unable to load CA certificate: %i\n", res); + } +#endif + + return res; + } + + bool UpdaterClass::_loadCertificate(X509_CTX **ctx) { + size_t num_of_bits = sizeof(uint8_t) * _certificateLen; + uint8_t *cert = (uint8_t *)malloc(num_of_bits + (num_of_bits % 32)); // Round up to the next uint32_t boundary + ESP.flashRead(_certificateStartAddress, (uint32_t *)cert, num_of_bits); + + int res = x509_new(cert, (int *)&_certificateLen, ctx); + free(cert); + + if(res != X509_OK) { +#ifdef DEBUG_UPDATER + DEBUG_UPDATER.printf("Unable to load developer certificate: %i\n", res); +#endif + return false; + } +#ifdef DEBUG_UPDATER + DEBUG_UPDATER.printf("Loaded developer certificate. Common Name: %s\n", (*ctx)->cert_dn[X509_COMMON_NAME]); +#endif + return true; + } + + bool UpdaterClass::_verifyCertificate(X509_CTX **ctx) { + int res = x509_verify(_ca_ctx, *ctx); + +#ifdef DEBUG_UPDATER + if(res == X509_OK) { + DEBUG_UPDATER.printf("Developer certificate verified\n"); + } else { + DEBUG_UPDATER.printf("Developer certificate not verified: %i\n", res); + } +#endif + + return res == X509_OK; + } + + bool UpdaterClass::_decryptSignature(X509_CTX **ctx, char **hash) { + size_t num_of_bits = sizeof(uint8_t) * _signatureLen; + uint8_t *sig = (uint8_t *)malloc(num_of_bits + (num_of_bits % 32)); // Round up to the next uint32_t boundary + ESP.flashRead(_signatureStartAddress, (uint32_t *)sig, num_of_bits); + + //const int signature_size = (*ctx)->rsa_ctx->num_octets; + const int signature_size = _signatureLen; // In this version of the library, the num_octects is 0. Not sure why... +#ifdef DEBUG_UPDATER + DEBUG_UPDATER.printf("Size of output buffer: %i\n", signature_size); +#endif + uint8_t sig_data[signature_size]; + int len = RSA_decrypt((*ctx)->rsa_ctx, (const uint8_t *)sig, sig_data, signature_size, 0); + free(sig); + + if(len == -1) { +#ifdef DEBUG_UPDATER + DEBUG_UPDATER.printf("Decryption failed\n"); +#endif + return false; + } + + if(len < MD5_SIZE) { +#ifdef DEBUG_UPDATER + DEBUG_UPDATER.printf("Decryption failed: Signature is too short. Expected %i, got %i\n", MD5_SIZE, len); +#endif + return false; + } + +#ifdef DEBUG_UPDATER + DEBUG_UPDATER.printf("Decryption successful.\n"); +#endif + + // Fetch the last part of the encrypted string - that is the MD5 hash, and then save the string + // version of it in to the hash pointer. + (*hash) = (char *)calloc((MD5_SIZE * 2) + 1, sizeof(char)); + for(int i = 0; i < MD5_SIZE; i++) { + sprintf(*hash + (i * 2), "%02x", sig_data[len - MD5_SIZE + i]); + } + + return true; + } + + bool UpdaterClass::_decryptMD5() { + X509_CTX *ctx; + + if(!_loadCertificate(&ctx)) { + return false; + } + + if(!_verifyCertificate(&ctx)) { + return false; + } + + char *hash; + if(!_decryptSignature(&ctx, &hash)) { + return false; + } + + setMD5((const char *)hash); + + return true; + } +#endif + void UpdaterClass::printError(Stream &out){ out.printf("ERROR[%u]: ", _error); if(_error == UPDATE_ERROR_OK){ diff --git a/cores/esp8266/Updater.h b/cores/esp8266/Updater.h index 03666b059f..af942bcd62 100644 --- a/cores/esp8266/Updater.h +++ b/cores/esp8266/Updater.h @@ -8,10 +8,8 @@ #include #ifdef VERIFY_SIGNATURE -#include "axtls/rsa.h" -#include "axtls/asn1.h" -#include "axtls/sha1.h" -#include "axtls/sha256.h" +#include +#include #endif #define UPDATE_ERROR_OK (0) diff --git a/cores/esp8266/axtls/asn1.cpp b/cores/esp8266/axtls/asn1.cpp deleted file mode 100644 index fe9733e656..0000000000 --- a/cores/esp8266/axtls/asn1.cpp +++ /dev/null @@ -1,757 +0,0 @@ -/* - * Copyright (c) 2007-2016, Cameron Rich - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of the axTLS project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * Some primitive asn methods for extraction ASN.1 data. - */ - -#include -#include -#include "asn1.h" -#include "rsa.h" - -/* 1.2.840.113549.1.1 OID prefix - handle the following */ -/* md5WithRSAEncryption(4) */ -/* sha1WithRSAEncryption(5) */ -/* sha256WithRSAEncryption (11) */ -/* sha384WithRSAEncryption (12) */ -/* sha512WithRSAEncryption (13) */ -static const uint8_t sig_oid_prefix[] = -{ - 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01 -}; - -/* 1.3.14.3.2.29 SHA1 with RSA signature */ -static const uint8_t sig_sha1WithRSAEncrypt[] = -{ - 0x2b, 0x0e, 0x03, 0x02, 0x1d -}; - -/* 2.16.840.1.101.3.4.2.1 SHA-256 */ -static const uint8_t sig_sha256[] = -{ - 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 -}; - -/* 2.16.840.1.101.3.4.2.2 SHA-384 */ -static const uint8_t sig_sha384[] = -{ - 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02 -}; - -/* 2.16.840.1.101.3.4.2.3 SHA-512 */ -static const uint8_t sig_sha512[] = -{ - 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03 -}; - -static const uint8_t sig_subject_alt_name[] = -{ - 0x55, 0x1d, 0x11 -}; - -static const uint8_t sig_basic_constraints[] = -{ - 0x55, 0x1d, 0x13 -}; - -static const uint8_t sig_key_usage[] = -{ - 0x55, 0x1d, 0x0f -}; - -/* CN, O, OU, L, C, ST */ -static const uint8_t g_dn_types[] = { 3, 10, 11, 7, 6, 8 }; - -uint32_t get_asn1_length(const uint8_t *buf, int *offset) -{ - int i; - uint32_t len; - - if (!(buf[*offset] & 0x80)) /* short form */ - { - len = buf[(*offset)++]; - } - else /* long form */ - { - int length_bytes = buf[(*offset)++]&0x7f; - if (length_bytes > 4) /* limit number of bytes */ - return 0; - - len = 0; - for (i = 0; i < length_bytes; i++) - { - len <<= 8; - len += buf[(*offset)++]; - } - } - - return len; -} - -/** - * Skip the ASN1.1 object type and its length. Get ready to read the object's - * data. - */ -int asn1_next_obj(const uint8_t *buf, int *offset, int obj_type) -{ - if (buf[*offset] != obj_type) - return X509_NOT_OK; - - (*offset)++; - return get_asn1_length(buf, offset); -} - -/** - * Skip over an ASN.1 object type completely. Get ready to read the next - * object. - */ -int asn1_skip_obj(const uint8_t *buf, int *offset, int obj_type) -{ - int len; - - if (buf[*offset] != obj_type) - return X509_NOT_OK; - (*offset)++; - len = get_asn1_length(buf, offset); - *offset += len; - return 0; -} - -/** - * Read an integer value for ASN.1 data - * Note: This function allocates memory which must be freed by the user. - */ -int asn1_get_big_int(const uint8_t *buf, int *offset, uint8_t **object) -{ - int len; - - if ((len = asn1_next_obj(buf, offset, ASN1_INTEGER)) < 0) - goto end_big_int; - - if (len > 1 && buf[*offset] == 0x00) /* ignore the negative byte */ - { - len--; - (*offset)++; - } - - *object = (uint8_t *)malloc(len); - memcpy(*object, &buf[*offset], len); - *offset += len; - -end_big_int: - return len; -} - -/** - * Read an integer value for ASN.1 data - */ -int asn1_get_int(const uint8_t *buf, int *offset, int32_t *val) -{ - int res = X509_OK; - int len; - int i; - - if ((len = asn1_next_obj(buf, offset, ASN1_INTEGER)) < 0 || - len > sizeof(int32_t)) - { - res = X509_NOT_OK; - goto end_int; - } - - *val = 0; - for (i = 0; i < len; i++) - { - *val <<= 8; - *val |= buf[(*offset)++]; - } - -end_int: - return res; -} - -/** - * Read an boolean value for ASN.1 data - */ -int asn1_get_bool(const uint8_t *buf, int *offset, bool *val) -{ - int res = X509_OK; - - if (asn1_next_obj(buf, offset, ASN1_BOOLEAN) != 1) - { - res = X509_NOT_OK; - goto end_bool; - } - - /* DER demands that "If the encoding represents the boolean value TRUE, - its single contents octet shall have all eight bits set to one." - Thus only 0 and 255 are valid encoded values. */ - *val = buf[(*offset)++] == 0xFF; - -end_bool: - return res; -} - -/** - * Convert an ASN.1 bit string into a 32 bit integer. Used for key usage - */ -int asn1_get_bit_string_as_int(const uint8_t *buf, int *offset, uint32_t *val) -{ - int res = X509_OK; - int len, i; - int ignore_bits; - - if ((len = asn1_next_obj(buf, offset, ASN1_BIT_STRING)) < 0 || len > 5) - { - res = X509_NOT_OK; - goto end_bit_string_as_int; - } - - /* number of bits left unused in the final byte of content */ - ignore_bits = buf[(*offset)++]; - len--; - *val = 0; - - /* not sure why key usage doesn't used proper DER spec version */ - for (i = len-1; i >= 0; --i) - { - *val <<= 8; - *val |= buf[(*offset) + i]; - } - - *offset += len; - - /*for (i = 0; i < ignore_bits; i++) - { - *val >>= 1; - }*/ - -end_bit_string_as_int: - return res; -} - -/** - * Get all the RSA private key specifics from an ASN.1 encoded file - */ -int asn1_get_private_key(const uint8_t *buf, int len, RSA_CTX **rsa_ctx) -{ - int offset = 7; - uint8_t *modulus = NULL, *priv_exp = NULL, *pub_exp = NULL; - int mod_len, priv_len, pub_len; - uint8_t *p = NULL, *q = NULL, *dP = NULL, *dQ = NULL, *qInv = NULL; - int p_len, q_len, dP_len, dQ_len, qInv_len; - - /* not in der format */ - if (buf[0] != ASN1_SEQUENCE) /* basic sanity check */ - { - return X509_INVALID_PRIV_KEY; - } - - /* Use the private key to mix up the RNG if possible. */ - //RNG_custom_init(buf, len); - - mod_len = asn1_get_big_int(buf, &offset, &modulus); - pub_len = asn1_get_big_int(buf, &offset, &pub_exp); - priv_len = asn1_get_big_int(buf, &offset, &priv_exp); - - if (mod_len <= 0 || pub_len <= 0 || priv_len <= 0) - return X509_INVALID_PRIV_KEY; - - p_len = asn1_get_big_int(buf, &offset, &p); - q_len = asn1_get_big_int(buf, &offset, &q); - dP_len = asn1_get_big_int(buf, &offset, &dP); - dQ_len = asn1_get_big_int(buf, &offset, &dQ); - qInv_len = asn1_get_big_int(buf, &offset, &qInv); - - if (p_len <= 0 || q_len <= 0 || dP_len <= 0 || dQ_len <= 0 || qInv_len <= 0) - return X509_INVALID_PRIV_KEY; - - RSA_priv_key_new(rsa_ctx, - modulus, mod_len, pub_exp, pub_len, priv_exp, priv_len, - p, p_len, q, p_len, dP, dP_len, dQ, dQ_len, qInv, qInv_len); - - free(p); - free(q); - free(dP); - free(dQ); - free(qInv); - - free(modulus); - free(priv_exp); - free(pub_exp); - return X509_OK; -} - -/** - * Get the time of a certificate. Ignore hours/minutes/seconds. - */ -static int asn1_get_utc_time(const uint8_t *buf, int *offset, time_t *t) -{ - int ret = X509_NOT_OK, len, t_offset, abs_year; - struct tm tm; - - /* see http://tools.ietf.org/html/rfc5280#section-4.1.2.5 */ - if (buf[*offset] == ASN1_UTC_TIME) - { - (*offset)++; - - len = get_asn1_length(buf, offset); - t_offset = *offset; - - memset(&tm, 0, sizeof(struct tm)); - tm.tm_year = (buf[t_offset] - '0')*10 + (buf[t_offset+1] - '0'); - - if (tm.tm_year < 50) /* 1951-2050 thing */ - { - tm.tm_year += 100; - } - - tm.tm_mon = (buf[t_offset+2] - '0')*10 + (buf[t_offset+3] - '0') - 1; - tm.tm_mday = (buf[t_offset+4] - '0')*10 + (buf[t_offset+5] - '0'); - tm.tm_hour = (buf[t_offset+6] - '0')*10 + (buf[t_offset+7] - '0'); - tm.tm_min = (buf[t_offset+8] - '0')*10 + (buf[t_offset+9] - '0'); - tm.tm_sec = (buf[t_offset+10] - '0')*10 + (buf[t_offset+11] - '0'); - *t = mktime(&tm); - *offset += len; - ret = X509_OK; - } - else if (buf[*offset] == ASN1_GENERALIZED_TIME) - { - (*offset)++; - - len = get_asn1_length(buf, offset); - t_offset = *offset; - - memset(&tm, 0, sizeof(struct tm)); - abs_year = ((buf[t_offset] - '0')*1000 + - (buf[t_offset+1] - '0')*100 + (buf[t_offset+2] - '0')*10 + - (buf[t_offset+3] - '0')); - - if (abs_year <= 1901) - { - tm.tm_year = 1; - tm.tm_mon = 0; - tm.tm_mday = 1; - } - else - { - tm.tm_year = abs_year - 1900; - tm.tm_mon = (buf[t_offset+4] - '0')*10 + - (buf[t_offset+5] - '0') - 1; - tm.tm_mday = (buf[t_offset+6] - '0')*10 + (buf[t_offset+7] - '0'); - tm.tm_hour = (buf[t_offset+8] - '0')*10 + (buf[t_offset+9] - '0'); - tm.tm_min = (buf[t_offset+10] - '0')*10 + (buf[t_offset+11] - '0'); - tm.tm_sec = (buf[t_offset+12] - '0')*10 + (buf[t_offset+13] - '0'); - *t = mktime(&tm); - } - - *offset += len; - ret = X509_OK; - } - - return ret; -} - -/** - * Get the version type of a certificate - */ -int asn1_version(const uint8_t *cert, int *offset, int *val) -{ - (*offset) += 2; /* get past explicit tag */ - return asn1_get_int(cert, offset, val); -} - -/** - * Retrieve the notbefore and notafter certificate times. - */ -int asn1_validity(const uint8_t *cert, int *offset, X509_CTX *x509_ctx) -{ - return (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 || - asn1_get_utc_time(cert, offset, &x509_ctx->not_before) || - asn1_get_utc_time(cert, offset, &x509_ctx->not_after)); -} - -/** - * Get the components of a distinguished name - */ -static int asn1_get_oid_x520(const uint8_t *buf, int *offset) -{ - int dn_type = 0; - int len; - - if ((len = asn1_next_obj(buf, offset, ASN1_OID)) < 0) - goto end_oid; - - /* expect a sequence of 2.5.4.[x] where x is a one of distinguished name - components we are interested in. */ - if (len == 3 && buf[(*offset)++] == 0x55 && buf[(*offset)++] == 0x04) - dn_type = buf[(*offset)++]; - else - { - *offset += len; /* skip over it */ - } - -end_oid: - return dn_type; -} - -/** - * Obtain an ASN.1 printable string type. - */ -static int asn1_get_printable_str(const uint8_t *buf, int *offset, char **str) -{ - int len = X509_NOT_OK; - int asn1_type = buf[*offset]; - - /* some certs have this awful crud in them for some reason */ - if (asn1_type != ASN1_PRINTABLE_STR && - asn1_type != ASN1_PRINTABLE_STR2 && - asn1_type != ASN1_TELETEX_STR && - asn1_type != ASN1_IA5_STR && - asn1_type != ASN1_UNICODE_STR) - goto end_pnt_str; - - (*offset)++; - len = get_asn1_length(buf, offset); - - if (asn1_type == ASN1_UNICODE_STR) - { - int i; - *str = (char *)malloc(len/2+1); /* allow for null */ - - for (i = 0; i < len; i += 2) - (*str)[i/2] = buf[*offset + i + 1]; - - (*str)[len/2] = 0; /* null terminate */ - } - else - { - *str = (char *)malloc(len+1); /* allow for null */ - memcpy(*str, &buf[*offset], len); - (*str)[len] = 0; /* null terminate */ - } - - *offset += len; - -end_pnt_str: - return len; -} - -/** - * Get the subject name (or the issuer) of a certificate. - */ -int asn1_name(const uint8_t *cert, int *offset, char *dn[]) -{ - int ret = X509_NOT_OK; - int dn_type; - char *tmp; - - if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0) - goto end_name; - - while (asn1_next_obj(cert, offset, ASN1_SET) >= 0) - { - int i, found = 0; - - if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 || - (dn_type = asn1_get_oid_x520(cert, offset)) < 0) - goto end_name; - - tmp = NULL; - - if (asn1_get_printable_str(cert, offset, &tmp) < 0) - { - free(tmp); - goto end_name; - } - - /* find the distinguished named type */ - for (i = 0; i < X509_NUM_DN_TYPES; i++) - { - if (dn_type == g_dn_types[i]) - { - if (dn[i] == NULL) - { - dn[i] = tmp; - found = 1; - break; - } - } - } - - if (found == 0) /* not found so get rid of it */ - { - free(tmp); - } - } - - ret = X509_OK; -end_name: - return ret; -} - -/** - * Read the modulus and public exponent of a certificate. - */ -int asn1_public_key(const uint8_t *cert, int *offset, X509_CTX *x509_ctx) -{ - int ret = X509_NOT_OK, mod_len, pub_len; - uint8_t *modulus = NULL, *pub_exp = NULL; - - if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 || - asn1_skip_obj(cert, offset, ASN1_SEQUENCE) || - asn1_next_obj(cert, offset, ASN1_BIT_STRING) < 0) - goto end_pub_key; - - (*offset)++; /* ignore the padding bit field */ - - if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0) - goto end_pub_key; - - mod_len = asn1_get_big_int(cert, offset, &modulus); - pub_len = asn1_get_big_int(cert, offset, &pub_exp); - - RSA_pub_key_new(&x509_ctx->rsa_ctx, modulus, mod_len, pub_exp, pub_len); - - free(modulus); - free(pub_exp); - ret = X509_OK; - -end_pub_key: - return ret; -} - -/** - * Read the signature of the certificate. - */ -int asn1_signature(const uint8_t *cert, int *offset, X509_CTX *x509_ctx) -{ - int ret = X509_NOT_OK; - - if (cert[(*offset)++] != ASN1_BIT_STRING) - goto end_sig; - - x509_ctx->sig_len = get_asn1_length(cert, offset)-1; - (*offset)++; /* ignore bit string padding bits */ - x509_ctx->signature = (uint8_t *)malloc(x509_ctx->sig_len); - memcpy(x509_ctx->signature, &cert[*offset], x509_ctx->sig_len); - *offset += x509_ctx->sig_len; - ret = X509_OK; - -end_sig: - return ret; -} - -/* - * Compare 2 distinguished name components for equality - * @return 0 if a match - */ -static int asn1_compare_dn_comp(const char *dn1, const char *dn2) -{ - int ret; - - if (dn1 == NULL && dn2 == NULL) - ret = 0; - else - ret = (dn1 && dn2) ? strcmp(dn1, dn2) : 1; - - return ret; -} - -/** - * Clean up all of the CA certificates. - */ -void remove_ca_certs(CA_CERT_CTX *ca_cert_ctx) -{ - int i = 0; - - if (ca_cert_ctx == NULL) - return; - - while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i]) - { - x509_free(ca_cert_ctx->cert[i]); - ca_cert_ctx->cert[i++] = NULL; - } - - free(ca_cert_ctx); -} - -/* - * Compare 2 distinguished names for equality - * @return 0 if a match - */ -int asn1_compare_dn(char * const dn1[], char * const dn2[]) -{ - int i; - - for (i = 0; i < X509_NUM_DN_TYPES; i++) - { - if (asn1_compare_dn_comp(dn1[i], dn2[i])) - return 1; - } - - return 0; /* all good */ -} - -int asn1_find_oid(const uint8_t* cert, int* offset, - const uint8_t* oid, int oid_length) -{ - int seqlen; - if ((seqlen = asn1_next_obj(cert, offset, ASN1_SEQUENCE))> 0) - { - int end = *offset + seqlen; - - while (*offset < end) - { - int type = cert[(*offset)++]; - int length = get_asn1_length(cert, offset); - int noffset = *offset + length; - - if (type == ASN1_SEQUENCE) - { - type = cert[(*offset)++]; - length = get_asn1_length(cert, offset); - - if (type == ASN1_OID && length == oid_length && - memcmp(cert + *offset, oid, oid_length) == 0) - { - *offset += oid_length; - return 1; - } - } - - *offset = noffset; - } - } - - return 0; -} - -int asn1_is_subject_alt_name(const uint8_t *cert, int offset) -{ - if (asn1_find_oid(cert, &offset, sig_subject_alt_name, - sizeof(sig_subject_alt_name))) - { - return offset; - } - - return 0; -} - -int asn1_is_basic_constraints(const uint8_t *cert, int offset) -{ - if (asn1_find_oid(cert, &offset, sig_basic_constraints, - sizeof(sig_basic_constraints))) - { - return offset; - } - - return 0; -} - -int asn1_is_key_usage(const uint8_t *cert, int offset) -{ - if (asn1_find_oid(cert, &offset, sig_key_usage, - sizeof(sig_key_usage))) - { - return offset; - } - - return 0; -} - -bool asn1_is_critical_ext(const uint8_t *buf, int *offset) -{ - /* critical is optional */ - bool res = false; - - if (asn1_next_obj(buf, offset, ASN1_BOOLEAN) == 1) - res = buf[(*offset)++] == 0xFF; - - return res; -} - -/** - * Read the signature type of the certificate. We only support RSA-MD5 and - * RSA-SHA1 signature types. - */ -int asn1_signature_type(const uint8_t *cert, - int *offset, X509_CTX *x509_ctx) -{ - int ret = X509_NOT_OK, len; - - if (cert[(*offset)++] != ASN1_OID) - goto end_check_sig; - - len = get_asn1_length(cert, offset); - - if (len == sizeof(sig_sha1WithRSAEncrypt) && - memcmp(sig_sha1WithRSAEncrypt, &cert[*offset], - sizeof(sig_sha1WithRSAEncrypt)) == 0) - { - x509_ctx->sig_type = SIG_TYPE_SHA1; - } - else if (len == sizeof(sig_sha256) && - memcmp(sig_sha256, &cert[*offset], - sizeof(sig_sha256)) == 0) - { - x509_ctx->sig_type = SIG_TYPE_SHA256; - } - else if (len == sizeof(sig_sha384) && - memcmp(sig_sha384, &cert[*offset], - sizeof(sig_sha384)) == 0) - { - x509_ctx->sig_type = SIG_TYPE_SHA384; - } - else if (len == sizeof(sig_sha512) && - memcmp(sig_sha512, &cert[*offset], - sizeof(sig_sha512)) == 0) - { - x509_ctx->sig_type = SIG_TYPE_SHA512; - } - else - { - if (memcmp(sig_oid_prefix, &cert[*offset], sizeof(sig_oid_prefix))) - { - goto end_check_sig; /* unrecognised cert type */ - } - - x509_ctx->sig_type = cert[*offset + sizeof(sig_oid_prefix)]; - } - - *offset += len; - asn1_skip_obj(cert, offset, ASN1_NULL); /* if it's there */ - ret = X509_OK; - -end_check_sig: - return ret; -} - diff --git a/cores/esp8266/axtls/asn1.h b/cores/esp8266/axtls/asn1.h deleted file mode 100644 index 5a5727aae9..0000000000 --- a/cores/esp8266/axtls/asn1.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef HEADER_ASN1_H -#define HEADER_ASN1_H -#include "x509.h" -/************************************************************************** - * ASN1 declarations - **************************************************************************/ -#define ASN1_BOOLEAN 0x01 -#define ASN1_INTEGER 0x02 -#define ASN1_BIT_STRING 0x03 -#define ASN1_OCTET_STRING 0x04 -#define ASN1_NULL 0x05 -#define ASN1_PRINTABLE_STR2 0x0C -#define ASN1_OID 0x06 -#define ASN1_PRINTABLE_STR2 0x0C -#define ASN1_PRINTABLE_STR 0x13 -#define ASN1_TELETEX_STR 0x14 -#define ASN1_IA5_STR 0x16 -#define ASN1_UTC_TIME 0x17 -#define ASN1_GENERALIZED_TIME 0x18 -#define ASN1_UNICODE_STR 0x1e -#define ASN1_SEQUENCE 0x30 -#define ASN1_CONTEXT_DNSNAME 0x82 -#define ASN1_SET 0x31 -#define ASN1_V3_DATA 0xa3 -#define ASN1_IMPLICIT_TAG 0x80 -#define ASN1_CONTEXT_DNSNAME 0x82 -#define ASN1_EXPLICIT_TAG 0xa0 -#define ASN1_V3_DATA 0xa3 - -#define SIG_TYPE_MD5 0x04 -#define SIG_TYPE_SHA1 0x05 -#define SIG_TYPE_SHA256 0x0b -#define SIG_TYPE_SHA384 0x0c -#define SIG_TYPE_SHA512 0x0d - -uint32_t get_asn1_length(const uint8_t *buf, int *offset); -int asn1_get_private_key(const uint8_t *buf, int len, RSA_CTX **rsa_ctx); -int asn1_next_obj(const uint8_t *buf, int *offset, int obj_type); -int asn1_skip_obj(const uint8_t *buf, int *offset, int obj_type); -int asn1_get_big_int(const uint8_t *buf, int *offset, uint8_t **object); -int asn1_get_int(const uint8_t *buf, int *offset, int32_t *val); -int asn1_get_bool(const uint8_t *buf, int *offset, bool *val); -int asn1_get_bit_string_as_int(const uint8_t *buf, int *offset, uint32_t *val); -int asn1_version(const uint8_t *cert, int *offset, int *val); -int asn1_validity(const uint8_t *cert, int *offset, X509_CTX *x509_ctx); -int asn1_name(const uint8_t *cert, int *offset, char *dn[]); -int asn1_public_key(const uint8_t *cert, int *offset, X509_CTX *x509_ctx); -int asn1_signature(const uint8_t *cert, int *offset, X509_CTX *x509_ctx); -int asn1_compare_dn(char * const dn1[], char * const dn2[]); -int asn1_is_subject_alt_name(const uint8_t *cert, int offset); -int asn1_is_basic_constraints(const uint8_t *cert, int offset); -int asn1_is_key_usage(const uint8_t *cert, int offset); -bool asn1_is_critical_ext(const uint8_t *buf, int *offset); -int asn1_signature_type(const uint8_t *cert, int *offset, X509_CTX *x509_ctx); -#endif diff --git a/cores/esp8266/axtls/bigint.cpp b/cores/esp8266/axtls/bigint.cpp deleted file mode 100644 index 8b99b9d350..0000000000 --- a/cores/esp8266/axtls/bigint.cpp +++ /dev/null @@ -1,978 +0,0 @@ -/* - * Copyright (c) 2007, Cameron Rich - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of the axTLS project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @defgroup bigint_api Big Integer API - * @brief The bigint implementation as used by the axTLS project. - * - * The bigint library is for RSA encryption/decryption as well as signing. - * This code tries to minimise use of malloc/free by maintaining a small - * cache. A bigint context may maintain state by being made "permanent". - * It be be later released with a bi_depermanent() and bi_free() call. - * - * It supports the following reduction techniques: - * - Classical - * - Barrett - * - Montgomery - * - * It also implements the following: - * - Karatsuba multiplication - * - Squaring - * - Sliding window exponentiation - * - Chinese Remainder Theorem (implemented in rsa.c). - * - * All the algorithms used are pretty standard, and designed for different - * data bus sizes. Negative numbers are not dealt with at all, so a subtraction - * may need to be tested for negativity. - * - * This library steals some ideas from Jef Poskanzer - * - * and GMP . It gets most of its implementation - * detail from "The Handbook of Applied Cryptography" - * - * @{ - */ - -#include -#include "bigint.h" - -#define V1 v->comps[v->size-1] /**< v1 for division */ -#define V2 v->comps[v->size-2] /**< v2 for division */ -#define U(j) tmp_u->comps[tmp_u->size-j-1] /**< uj for division */ -#define Q(j) quotient->comps[quotient->size-j-1] /**< qj for division */ - -static bigint *bi_int_multiply(BI_CTX *ctx, bigint *bi, comp i); -static bigint *bi_int_divide(BI_CTX *ctx, bigint *biR, comp denom); -static bigint *alloc(BI_CTX *ctx, int size); -static bigint *trim(bigint *bi); -static void more_comps(bigint *bi, int n); - -#define check(A) - - -/** - * @brief Start a new bigint context. - * @return A bigint context. - */ -BI_CTX *bi_initialize(void) -{ - /* calloc() sets everything to zero */ - BI_CTX *ctx = (BI_CTX *)calloc(1, sizeof(BI_CTX)); - - /* the radix */ - ctx->bi_radix = alloc(ctx, 2); - ctx->bi_radix->comps[0] = 0; - ctx->bi_radix->comps[1] = 1; - bi_permanent(ctx->bi_radix); - return ctx; -} - -/** - * @brief Close the bigint context and free any resources. - * - * Free up any used memory - a check is done if all objects were not - * properly freed. - * @param ctx [in] The bigint session context. - */ -void bi_terminate(BI_CTX *ctx) -{ - bi_depermanent(ctx->bi_radix); - bi_free(ctx, ctx->bi_radix); - - if (ctx->active_count != 0) - { - abort(); - } - - bi_clear_cache(ctx); - free(ctx); -} - -/** - *@brief Clear the memory cache. - */ -void bi_clear_cache(BI_CTX *ctx) -{ - bigint *p, *pn; - - if (ctx->free_list == NULL) - return; - - for (p = ctx->free_list; p != NULL; p = pn) - { - pn = p->next; - free(p->comps); - free(p); - } - - ctx->free_count = 0; - ctx->free_list = NULL; -} - -/** - * @brief Increment the number of references to this object. - * It does not do a full copy. - * @param bi [in] The bigint to copy. - * @return A reference to the same bigint. - */ -bigint *bi_copy(bigint *bi) -{ - check(bi); - if (bi->refs != PERMANENT) - bi->refs++; - return bi; -} - -/** - * @brief Simply make a bigint object "unfreeable" if bi_free() is called on it. - * - * For this object to be freed, bi_depermanent() must be called. - * @param bi [in] The bigint to be made permanent. - */ -void bi_permanent(bigint *bi) -{ - check(bi); - if (bi->refs != 1) - { - abort(); - } - - bi->refs = PERMANENT; -} - -/** - * @brief Take a permanent object and make it eligible for freedom. - * @param bi [in] The bigint to be made back to temporary. - */ -void bi_depermanent(bigint *bi) -{ - check(bi); - if (bi->refs != PERMANENT) - { - abort(); - } - - bi->refs = 1; -} - -/** - * @brief Free a bigint object so it can be used again. - * - * The memory itself it not actually freed, just tagged as being available - * @param ctx [in] The bigint session context. - * @param bi [in] The bigint to be freed. - */ -void bi_free(BI_CTX *ctx, bigint *bi) -{ - check(bi); - if (bi->refs == PERMANENT) - { - return; - } - - if (--bi->refs > 0) - { - return; - } - - bi->next = ctx->free_list; - ctx->free_list = bi; - ctx->free_count++; - - if (--ctx->active_count < 0) - { - abort(); - } -} - -/** - * @brief Convert an (unsigned) integer into a bigint. - * @param ctx [in] The bigint session context. - * @param i [in] The (unsigned) integer to be converted. - * - */ -bigint *int_to_bi(BI_CTX *ctx, comp i) -{ - bigint *biR = alloc(ctx, 1); - biR->comps[0] = i; - return biR; -} - -/** - * @brief Do a full copy of the bigint object. - * @param ctx [in] The bigint session context. - * @param bi [in] The bigint object to be copied. - */ -bigint *bi_clone(BI_CTX *ctx, const bigint *bi) -{ - bigint *biR = alloc(ctx, bi->size); - check(bi); - memcpy(biR->comps, bi->comps, bi->size*COMP_BYTE_SIZE); - return biR; -} - -/** - * @brief Perform an addition operation between two bigints. - * @param ctx [in] The bigint session context. - * @param bia [in] A bigint. - * @param bib [in] Another bigint. - * @return The result of the addition. - */ -bigint *bi_add(BI_CTX *ctx, bigint *bia, bigint *bib) -{ - int n; - comp carry = 0; - comp *pa, *pb; - - check(bia); - check(bib); - - n = max(bia->size, bib->size); - more_comps(bia, n+1); - more_comps(bib, n); - pa = bia->comps; - pb = bib->comps; - - do - { - comp sl, rl, cy1; - sl = *pa + *pb++; - rl = sl + carry; - cy1 = sl < *pa; - carry = cy1 | (rl < sl); - *pa++ = rl; - } while (--n != 0); - - *pa = carry; /* do overflow */ - bi_free(ctx, bib); - return trim(bia); -} - -/** - * @brief Perform a subtraction operation between two bigints. - * @param ctx [in] The bigint session context. - * @param bia [in] A bigint. - * @param bib [in] Another bigint. - * @param is_negative [out] If defined, indicates that the result was negative. - * is_negative may be null. - * @return The result of the subtraction. The result is always positive. - */ -bigint *bi_subtract(BI_CTX *ctx, - bigint *bia, bigint *bib, int *is_negative) -{ - int n = bia->size; - comp *pa, *pb, carry = 0; - - check(bia); - check(bib); - - more_comps(bib, n); - pa = bia->comps; - pb = bib->comps; - - do - { - comp sl, rl, cy1; - sl = *pa - *pb++; - rl = sl - carry; - cy1 = sl > *pa; - carry = cy1 | (rl > sl); - *pa++ = rl; - } while (--n != 0); - - if (is_negative) /* indicate a negative result */ - { - *is_negative = carry; - } - - bi_free(ctx, trim(bib)); /* put bib back to the way it was */ - return trim(bia); -} - -/** - * Perform a multiply between a bigint an an (unsigned) integer - */ -static bigint *bi_int_multiply(BI_CTX *ctx, bigint *bia, comp b) -{ - int j = 0, n = bia->size; - bigint *biR = alloc(ctx, n + 1); - comp carry = 0; - comp *r = biR->comps; - comp *a = bia->comps; - - check(bia); - - /* clear things to start with */ - memset(r, 0, ((n+1)*COMP_BYTE_SIZE)); - - do - { - long_comp tmp = *r + (long_comp)a[j]*b + carry; - *r++ = (comp)tmp; /* downsize */ - carry = (comp)(tmp >> COMP_BIT_SIZE); - } while (++j < n); - - *r = carry; - bi_free(ctx, bia); - return trim(biR); -} - -/** - * @brief Does both division and modulo calculations. - * - * Used extensively when doing classical reduction. - * @param ctx [in] The bigint session context. - * @param u [in] A bigint which is the numerator. - * @param v [in] Either the denominator or the modulus depending on the mode. - * @param is_mod [n] Determines if this is a normal division (0) or a reduction - * (1). - * @return The result of the division/reduction. - */ -bigint *bi_divide(BI_CTX *ctx, bigint *u, bigint *v, int is_mod) -{ - int n = v->size, m = u->size-n; - int j = 0, orig_u_size = u->size; - uint8_t mod_offset = ctx->mod_offset; - comp d; - bigint *quotient, *tmp_u; - comp q_dash; - - check(u); - check(v); - - /* if doing reduction and we are < mod, then return mod */ - if (is_mod && bi_compare(v, u) > 0) - { - bi_free(ctx, v); - return u; - } - - quotient = alloc(ctx, m+1); - tmp_u = alloc(ctx, n+1); - v = trim(v); /* make sure we have no leading 0's */ - d = (comp)((long_comp)COMP_RADIX/(V1+1)); - - /* clear things to start with */ - memset(quotient->comps, 0, ((quotient->size)*COMP_BYTE_SIZE)); - - /* normalise */ - if (d > 1) - { - u = bi_int_multiply(ctx, u, d); - - if (is_mod) - { - v = ctx->bi_normalised_mod[mod_offset]; - } - else - { - v = bi_int_multiply(ctx, v, d); - } - } - - if (orig_u_size == u->size) /* new digit position u0 */ - { - more_comps(u, orig_u_size + 1); - } - - do - { - /* get a temporary short version of u */ - memcpy(tmp_u->comps, &u->comps[u->size-n-1-j], (n+1)*COMP_BYTE_SIZE); - - /* calculate q' */ - if (U(0) == V1) - { - q_dash = COMP_RADIX-1; - } - else - { - q_dash = (comp)(((long_comp)U(0)*COMP_RADIX + U(1))/V1); - - if (v->size > 1 && V2) - { - /* we are implementing the following: - if (V2*q_dash > (((U(0)*COMP_RADIX + U(1) - - q_dash*V1)*COMP_RADIX) + U(2))) ... */ - comp inner = (comp)((long_comp)COMP_RADIX*U(0) + U(1) - - (long_comp)q_dash*V1); - if ((long_comp)V2*q_dash > (long_comp)inner*COMP_RADIX + U(2)) - { - q_dash--; - } - } - } - - /* multiply and subtract */ - if (q_dash) - { - int is_negative; - tmp_u = bi_subtract(ctx, tmp_u, - bi_int_multiply(ctx, bi_copy(v), q_dash), &is_negative); - more_comps(tmp_u, n+1); - - Q(j) = q_dash; - - /* add back */ - if (is_negative) - { - Q(j)--; - tmp_u = bi_add(ctx, tmp_u, bi_copy(v)); - - /* lop off the carry */ - tmp_u->size--; - v->size--; - } - } - else - { - Q(j) = 0; - } - - /* copy back to u */ - memcpy(&u->comps[u->size-n-1-j], tmp_u->comps, (n+1)*COMP_BYTE_SIZE); - } while (++j <= m); - - bi_free(ctx, tmp_u); - bi_free(ctx, v); - - if (is_mod) /* get the remainder */ - { - bi_free(ctx, quotient); - return bi_int_divide(ctx, trim(u), d); - } - else /* get the quotient */ - { - bi_free(ctx, u); - return trim(quotient); - } -} - -/* - * Perform an integer divide on a bigint. - */ -static bigint *bi_int_divide(BI_CTX *ctx, bigint *biR, comp denom) -{ - int i = biR->size - 1; - long_comp r = 0; - - check(biR); - - do - { - r = (r<comps[i]; - biR->comps[i] = (comp)(r / denom); - r %= denom; - } while (--i >= 0); - - return trim(biR); -} - -/** - * @brief Allow a binary sequence to be imported as a bigint. - * @param ctx [in] The bigint session context. - * @param data [in] The data to be converted. - * @param size [in] The number of bytes of data. - * @return A bigint representing this data. - */ -bigint *bi_import(BI_CTX *ctx, const uint8_t *data, int size) -{ - bigint *biR = alloc(ctx, (size+COMP_BYTE_SIZE-1)/COMP_BYTE_SIZE); - int i, j = 0, offset = 0; - - memset(biR->comps, 0, biR->size*COMP_BYTE_SIZE); - - for (i = size-1; i >= 0; i--) - { - biR->comps[offset] += data[i] << (j*8); - - if (++j == COMP_BYTE_SIZE) - { - j = 0; - offset ++; - } - } - - return trim(biR); -} - -/** - * @brief Take a bigint and convert it into a byte sequence. - * - * This is useful after a decrypt operation. - * @param ctx [in] The bigint session context. - * @param x [in] The bigint to be converted. - * @param data [out] The converted data as a byte stream. - * @param size [in] The maximum size of the byte stream. Unused bytes will be - * zeroed. - */ -void bi_export(BI_CTX *ctx, bigint *x, uint8_t *data, int size) -{ - int i, j, k = size-1; - - check(x); - memset(data, 0, size); /* ensure all leading 0's are cleared */ - - for (i = 0; i < x->size; i++) - { - for (j = 0; j < COMP_BYTE_SIZE; j++) - { - comp mask = 0xff << (j*8); - int num = (x->comps[i] & mask) >> (j*8); - data[k--] = num; - - if (k < 0) - { - goto buf_done; - } - } - } -buf_done: - - bi_free(ctx, x); -} - -/* - * Work out the highest '1' bit in an exponent. Used when doing sliding-window - * exponentiation. - */ -static int find_max_exp_index(bigint *biexp) -{ - int i = COMP_BIT_SIZE-1; - comp shift = COMP_RADIX/2; - comp test = biexp->comps[biexp->size-1]; /* assume no leading zeroes */ - - check(biexp); - - do - { - if (test & shift) - { - return i+(biexp->size-1)*COMP_BIT_SIZE; - } - - shift >>= 1; - } while (i-- != 0); - - return -1; /* error - must have been a leading 0 */ -} - -/* - * Is a particular bit is an exponent 1 or 0? Used when doing sliding-window - * exponentiation. - */ -static int exp_bit_is_one(bigint *biexp, int offset) -{ - comp test = biexp->comps[offset / COMP_BIT_SIZE]; - int num_shifts = offset % COMP_BIT_SIZE; - comp shift = 1; - int i; - - check(biexp); - - for (i = 0; i < num_shifts; i++) - { - shift <<= 1; - } - - return (test & shift) != 0; -} - - - -/** - * @brief Perform a modular exponentiation. - * - * This function requires bi_set_mod() to have been called previously. This is - * one of the optimisations used for performance. - * @param ctx [in] The bigint session context. - * @param bi [in] The bigint on which to perform the mod power operation. - * @param biexp [in] The bigint exponent. - * @return The result of the mod exponentiation operation - * @see bi_set_mod(). - */ -bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp) -{ - int i = find_max_exp_index(biexp), j, window_size = 1; - bigint *biR = int_to_bi(ctx, 1); - check(bi); - check(biexp); - ctx->g = (bigint **)malloc(sizeof(bigint *)); - ctx->g[0] = bi_clone(ctx, bi); - ctx->window = 1; - bi_permanent(ctx->g[0]); - - /* if sliding-window is off, then only one bit will be done at a time and - * will reduce to standard left-to-right exponentiation */ - do - { - if (exp_bit_is_one(biexp, i)) - { - int l = i-window_size+1; - int part_exp = 0; - - if (l < 0) /* LSB of exponent will always be 1 */ - l = 0; - else - { - while (exp_bit_is_one(biexp, l) == 0) - l++; /* go back up */ - } - - /* build up the section of the exponent */ - for (j = i; j >= l; j--) - { - biR = bi_residue(ctx, bi_square(ctx, biR)); - if (exp_bit_is_one(biexp, j)) - part_exp++; - - if (j != l) - part_exp <<= 1; - } - - part_exp = (part_exp-1)/2; /* adjust for array */ - biR = bi_residue(ctx, bi_multiply(ctx, biR, ctx->g[part_exp])); - i = l-1; - } - else /* square it */ - { - biR = bi_residue(ctx, bi_square(ctx, biR)); - i--; - } - } while (i >= 0); - - /* cleanup */ - for (i = 0; i < ctx->window; i++) - { - bi_depermanent(ctx->g[i]); - bi_free(ctx, ctx->g[i]); - } - - free(ctx->g); - bi_free(ctx, bi); - bi_free(ctx, biexp); - return biR; /* convert back */ -} - -/** - * @brief Perform a modular exponentiation using a temporary modulus. - * - * We need this function to check the signatures of certificates. The modulus - * of this function is temporary as it's just used for authentication. - * @param ctx [in] The bigint session context. - * @param bi [in] The bigint to perform the exp/mod. - * @param bim [in] The temporary modulus. - * @param biexp [in] The bigint exponent. - * @return The result of the mod exponentiation operation - * @see bi_set_mod(). - */ -bigint *bi_mod_power2(BI_CTX *ctx, bigint *bi, bigint *bim, bigint *biexp) -{ - bigint *biR, *tmp_biR; - - /* Set up a temporary bigint context and transfer what we need between - * them. We need to do this since we want to keep the original modulus - * which is already in this context. This operation is only called when - * doing peer verification, and so is not expensive :-) */ - BI_CTX *tmp_ctx = bi_initialize(); - bi_set_mod(tmp_ctx, bi_clone(tmp_ctx, bim), BIGINT_M_OFFSET); - tmp_biR = bi_mod_power(tmp_ctx, - bi_clone(tmp_ctx, bi), - bi_clone(tmp_ctx, biexp)); - biR = bi_clone(ctx, tmp_biR); - bi_free(tmp_ctx, tmp_biR); - bi_free_mod(tmp_ctx, BIGINT_M_OFFSET); - bi_terminate(tmp_ctx); - - bi_free(ctx, bi); - bi_free(ctx, bim); - bi_free(ctx, biexp); - return biR; -} - - -/** - * @brief Pre-calculate some of the expensive steps in reduction. - * - * This function should only be called once (normally when a session starts). - * When the session is over, bi_free_mod() should be called. bi_mod_power() - * relies on this function being called. - * @param ctx [in] The bigint session context. - * @param bim [in] The bigint modulus that will be used. - * @param mod_offset [in] There are three moduluii that can be stored - the - * standard modulus, and its two primes p and q. This offset refers to which - * modulus we are referring to. - * @see bi_free_mod(), bi_mod_power(). - */ -void bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset) -{ - int k = bim->size; - comp d = (comp)((long_comp)COMP_RADIX/(bim->comps[k-1]+1)); - - ctx->bi_mod[mod_offset] = bim; - bi_permanent(ctx->bi_mod[mod_offset]); - ctx->bi_normalised_mod[mod_offset] = bi_int_multiply(ctx, bim, d); - bi_permanent(ctx->bi_normalised_mod[mod_offset]); -} - -/** - * @brief Used when cleaning various bigints at the end of a session. - * @param ctx [in] The bigint session context. - * @param mod_offset [in] The offset to use. - * @see bi_set_mod(). - */ -void bi_free_mod(BI_CTX *ctx, int mod_offset) -{ - bi_depermanent(ctx->bi_mod[mod_offset]); - bi_free(ctx, ctx->bi_mod[mod_offset]); - bi_depermanent(ctx->bi_normalised_mod[mod_offset]); - bi_free(ctx, ctx->bi_normalised_mod[mod_offset]); -} - -/** - * Perform a standard multiplication between two bigints. - * - * Barrett reduction has no need for some parts of the product, so ignore bits - * of the multiply. This routine gives Barrett its big performance - * improvements over Classical/Montgomery reduction methods. - */ -static bigint *regular_multiply(BI_CTX *ctx, bigint *bia, bigint *bib, - int inner_partial, int outer_partial) -{ - int i = 0, j; - int n = bia->size; - int t = bib->size; - bigint *biR = alloc(ctx, n + t); - comp *sr = biR->comps; - comp *sa = bia->comps; - comp *sb = bib->comps; - - check(bia); - check(bib); - - /* clear things to start with */ - memset(biR->comps, 0, ((n+t)*COMP_BYTE_SIZE)); - - do - { - long_comp tmp; - comp carry = 0; - int r_index = i; - j = 0; - - if (outer_partial && outer_partial-i > 0 && outer_partial < n) - { - r_index = outer_partial-1; - j = outer_partial-i-1; - } - - do - { - if (inner_partial && r_index >= inner_partial) - { - break; - } - - tmp = sr[r_index] + ((long_comp)sa[j])*sb[i] + carry; - sr[r_index++] = (comp)tmp; /* downsize */ - carry = tmp >> COMP_BIT_SIZE; - } while (++j < n); - - sr[r_index] = carry; - } while (++i < t); - - bi_free(ctx, bia); - bi_free(ctx, bib); - return trim(biR); -} - -/** - * @brief Perform a multiplication operation between two bigints. - * @param ctx [in] The bigint session context. - * @param bia [in] A bigint. - * @param bib [in] Another bigint. - * @return The result of the multiplication. - */ -bigint *bi_multiply(BI_CTX *ctx, bigint *bia, bigint *bib) -{ - check(bia); - check(bib); - - return regular_multiply(ctx, bia, bib, 0, 0); -} - -/** - * @brief Compare two bigints. - * @param bia [in] A bigint. - * @param bib [in] Another bigint. - * @return -1 if smaller, 1 if larger and 0 if equal. - */ -int bi_compare(bigint *bia, bigint *bib) -{ - int r, i; - - check(bia); - check(bib); - - if (bia->size > bib->size) - r = 1; - else if (bia->size < bib->size) - r = -1; - else - { - comp *a = bia->comps; - comp *b = bib->comps; - - /* Same number of components. Compare starting from the high end - * and working down. */ - r = 0; - i = bia->size - 1; - - do - { - if (a[i] > b[i]) - { - r = 1; - break; - } - else if (a[i] < b[i]) - { - r = -1; - break; - } - } while (--i >= 0); - } - - return r; -} - -/* - * Allocate and zero more components. Does not consume bi. - */ -static void more_comps(bigint *bi, int n) -{ - if (n > bi->max_comps) - { - bi->max_comps = max(bi->max_comps * 2, n); - bi->comps = (comp*)realloc(bi->comps, bi->max_comps * COMP_BYTE_SIZE); - } - - if (n > bi->size) - { - memset(&bi->comps[bi->size], 0, (n-bi->size)*COMP_BYTE_SIZE); - } - - bi->size = n; -} - -/* - * Make a new empty bigint. It may just use an old one if one is available. - * Otherwise get one off the heap. - */ -static bigint *alloc(BI_CTX *ctx, int size) -{ - bigint *biR; - - /* Can we recycle an old bigint? */ - if (ctx->free_list != NULL) - { - biR = ctx->free_list; - ctx->free_list = biR->next; - ctx->free_count--; - - if (biR->refs != 0) - { - abort(); /* create a stack trace from a core dump */ - } - - more_comps(biR, size); - } - else - { - /* No free bigints available - create a new one. */ - biR = (bigint *)malloc(sizeof(bigint)); - biR->comps = (comp*)malloc(size * COMP_BYTE_SIZE); - biR->max_comps = size; /* give some space to spare */ - } - - biR->size = size; - biR->refs = 1; - biR->next = NULL; - ctx->active_count++; - return biR; -} - -/* - * Delete any leading 0's (and allow for 0). - */ -static bigint *trim(bigint *bi) -{ - check(bi); - - while (bi->comps[bi->size-1] == 0 && bi->size > 1) - { - bi->size--; - } - - return bi; -} - -/** - * @brief Use the Chinese Remainder Theorem to quickly perform RSA decrypts. - * - * @param ctx [in] The bigint session context. - * @param bi [in] The bigint to perform the exp/mod. - * @param dP [in] CRT's dP bigint - * @param dQ [in] CRT's dQ bigint - * @param p [in] CRT's p bigint - * @param q [in] CRT's q bigint - * @param qInv [in] CRT's qInv bigint - * @return The result of the CRT operation - */ -bigint *bi_crt(BI_CTX *ctx, bigint *bi, - bigint *dP, bigint *dQ, - bigint *p, bigint *q, bigint *qInv) -{ - bigint *m1, *m2, *h; - - /* Montgomery has a condition the 0 < x, y < m and these products violate - * that condition. So disable Montgomery when using CRT */ - ctx->mod_offset = BIGINT_P_OFFSET; - m1 = bi_mod_power(ctx, bi_copy(bi), dP); - - ctx->mod_offset = BIGINT_Q_OFFSET; - m2 = bi_mod_power(ctx, bi, dQ); - - h = bi_subtract(ctx, bi_add(ctx, m1, p), bi_copy(m2), NULL); - h = bi_multiply(ctx, h, qInv); - ctx->mod_offset = BIGINT_P_OFFSET; - h = bi_residue(ctx, h); - return bi_add(ctx, m2, bi_multiply(ctx, q, h)); -} diff --git a/cores/esp8266/axtls/ca.h b/cores/esp8266/axtls/ca.h deleted file mode 100644 index e67947b163..0000000000 --- a/cores/esp8266/axtls/ca.h +++ /dev/null @@ -1,86 +0,0 @@ -unsigned char ca_crt_der[] = { - 0x30, 0x82, 0x03, 0xdb, 0x30, 0x82, 0x02, 0xc3, 0xa0, 0x03, 0x02, 0x01, - 0x02, 0x02, 0x09, 0x00, 0xd7, 0xff, 0x21, 0x58, 0x3c, 0x9d, 0x73, 0x93, - 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, - 0x0b, 0x05, 0x00, 0x30, 0x81, 0x83, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, - 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x0c, 0x30, 0x0a, 0x06, - 0x03, 0x55, 0x04, 0x08, 0x0c, 0x03, 0x56, 0x49, 0x43, 0x31, 0x12, 0x30, - 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x4d, 0x65, 0x6c, 0x62, - 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, - 0x04, 0x0a, 0x0c, 0x0d, 0x4d, 0x79, 0x6c, 0x65, 0x73, 0x20, 0x54, 0x65, - 0x73, 0x74, 0x20, 0x43, 0x41, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, - 0x04, 0x03, 0x0c, 0x0b, 0x4d, 0x79, 0x6c, 0x65, 0x73, 0x20, 0x45, 0x66, - 0x74, 0x6f, 0x73, 0x31, 0x24, 0x30, 0x22, 0x06, 0x09, 0x2a, 0x86, 0x48, - 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x15, 0x6d, 0x79, 0x6c, 0x65, - 0x73, 0x40, 0x6d, 0x61, 0x64, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x2e, 0x63, - 0x6f, 0x6d, 0x2e, 0x61, 0x75, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x37, 0x30, - 0x33, 0x31, 0x31, 0x30, 0x30, 0x35, 0x31, 0x35, 0x37, 0x5a, 0x17, 0x0d, - 0x32, 0x37, 0x30, 0x33, 0x30, 0x39, 0x30, 0x30, 0x35, 0x31, 0x35, 0x37, - 0x5a, 0x30, 0x81, 0x83, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, - 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, - 0x04, 0x08, 0x0c, 0x03, 0x56, 0x49, 0x43, 0x31, 0x12, 0x30, 0x10, 0x06, - 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x4d, 0x65, 0x6c, 0x62, 0x6f, 0x75, - 0x72, 0x6e, 0x65, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, - 0x0c, 0x0d, 0x4d, 0x79, 0x6c, 0x65, 0x73, 0x20, 0x54, 0x65, 0x73, 0x74, - 0x20, 0x43, 0x41, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x03, - 0x0c, 0x0b, 0x4d, 0x79, 0x6c, 0x65, 0x73, 0x20, 0x45, 0x66, 0x74, 0x6f, - 0x73, 0x31, 0x24, 0x30, 0x22, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, - 0x0d, 0x01, 0x09, 0x01, 0x16, 0x15, 0x6d, 0x79, 0x6c, 0x65, 0x73, 0x40, - 0x6d, 0x61, 0x64, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x2e, 0x63, 0x6f, 0x6d, - 0x2e, 0x61, 0x75, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, - 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, - 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, - 0xab, 0xdf, 0x27, 0x4d, 0x17, 0xf2, 0xb3, 0xf7, 0x36, 0xa6, 0x5b, 0x5e, - 0xb9, 0x53, 0x32, 0x1c, 0x1d, 0x36, 0xad, 0xef, 0x91, 0xa1, 0x45, 0x4b, - 0x44, 0x26, 0xf5, 0x1a, 0xe2, 0x4c, 0xc9, 0x65, 0x8d, 0xd5, 0xfb, 0x72, - 0x38, 0x72, 0xd1, 0xe4, 0xdd, 0xca, 0xaa, 0xcc, 0xfd, 0x4d, 0x3a, 0xb3, - 0x64, 0x85, 0x91, 0xd2, 0x02, 0x98, 0xee, 0xcb, 0x32, 0x27, 0x9d, 0x5c, - 0xa1, 0x11, 0x25, 0xa8, 0x5f, 0xb8, 0xe6, 0x23, 0x6d, 0x5c, 0x49, 0xe7, - 0xec, 0x4d, 0xad, 0x11, 0xb4, 0xad, 0x8a, 0x18, 0x51, 0x26, 0xc4, 0xc8, - 0xa3, 0xfb, 0x30, 0xc7, 0x5c, 0xec, 0xee, 0x75, 0xcb, 0xb4, 0xa0, 0xab, - 0xed, 0xea, 0x2a, 0x59, 0x21, 0x51, 0x68, 0x30, 0x5f, 0x10, 0x93, 0xd5, - 0x80, 0x20, 0xad, 0x90, 0x9d, 0xc8, 0xcf, 0x2e, 0xd1, 0xea, 0x0b, 0xc5, - 0xa0, 0x4f, 0x75, 0x9c, 0x62, 0x66, 0x24, 0xa9, 0x95, 0x71, 0xeb, 0x5c, - 0xe1, 0x6c, 0x60, 0xb7, 0xb0, 0xf6, 0x99, 0x35, 0x75, 0x00, 0x00, 0x1b, - 0x27, 0xd3, 0x00, 0x04, 0x4d, 0xf3, 0x9b, 0xbb, 0xf9, 0xa1, 0x4a, 0x7c, - 0xb0, 0x62, 0x61, 0x1b, 0xde, 0x7f, 0xdb, 0x98, 0xb5, 0x17, 0x3c, 0xb4, - 0x10, 0xdb, 0x17, 0xb5, 0xba, 0x08, 0xf1, 0x82, 0xdb, 0xa8, 0x38, 0x72, - 0x2c, 0x35, 0x5f, 0x41, 0xcb, 0x6b, 0x0c, 0x88, 0xb5, 0x13, 0x70, 0x14, - 0x06, 0xdd, 0xb0, 0x30, 0xc5, 0xa0, 0xf4, 0xe0, 0x43, 0x5a, 0xfe, 0x7f, - 0xa1, 0xb0, 0x2b, 0x80, 0x51, 0x77, 0xff, 0x63, 0xfc, 0xe1, 0x52, 0xce, - 0x10, 0x63, 0x87, 0xea, 0x7f, 0x26, 0x21, 0xd7, 0x17, 0x70, 0xcd, 0xea, - 0x71, 0x26, 0x3a, 0xa2, 0x6c, 0xca, 0x47, 0x57, 0x98, 0xe5, 0xd9, 0xf4, - 0xc7, 0x0c, 0x0f, 0x47, 0x0f, 0xfd, 0xa7, 0x7d, 0x45, 0x4c, 0x2e, 0x62, - 0xbc, 0xfa, 0xe6, 0x29, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x50, 0x30, - 0x4e, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, - 0xf6, 0x18, 0xe8, 0x6e, 0x26, 0xdd, 0xcf, 0xfe, 0x7e, 0x00, 0x99, 0x46, - 0xa8, 0xa8, 0xa2, 0x06, 0xd2, 0xff, 0x0a, 0xe0, 0x30, 0x1f, 0x06, 0x03, - 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xf6, 0x18, 0xe8, - 0x6e, 0x26, 0xdd, 0xcf, 0xfe, 0x7e, 0x00, 0x99, 0x46, 0xa8, 0xa8, 0xa2, - 0x06, 0xd2, 0xff, 0x0a, 0xe0, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, - 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, - 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, - 0x01, 0x01, 0x00, 0x41, 0xab, 0x3f, 0x06, 0x1a, 0xd9, 0x00, 0xe1, 0xd0, - 0xfa, 0xbb, 0xd2, 0x82, 0xe5, 0x3e, 0x6a, 0xfe, 0x05, 0x66, 0x6b, 0x01, - 0x9d, 0x0b, 0x07, 0x19, 0xb4, 0xd8, 0x1c, 0x16, 0x5b, 0x8c, 0xd5, 0xa9, - 0xbf, 0xbc, 0x6f, 0x7a, 0x39, 0xd6, 0xb4, 0x40, 0x05, 0xc0, 0xf2, 0x07, - 0xfd, 0x26, 0xcf, 0x49, 0x71, 0x66, 0xda, 0x36, 0x08, 0x37, 0xdf, 0x4c, - 0x91, 0xc0, 0xad, 0x1e, 0xf7, 0xa0, 0x31, 0x6b, 0xfc, 0xb8, 0xe9, 0x5d, - 0x24, 0xc8, 0xc5, 0x63, 0xc2, 0xc3, 0x84, 0x41, 0x24, 0x67, 0xf0, 0xf4, - 0x8d, 0xc5, 0x24, 0xdf, 0xd2, 0x75, 0xc6, 0x55, 0xca, 0x61, 0x19, 0x1d, - 0x17, 0xd9, 0x57, 0x4c, 0x33, 0x30, 0xae, 0x23, 0x4b, 0x6a, 0x7a, 0xdb, - 0x8b, 0x11, 0x44, 0x2b, 0x48, 0xb3, 0xbb, 0x38, 0xcd, 0x16, 0x52, 0x1e, - 0x24, 0xf0, 0xff, 0xdc, 0xf6, 0x6d, 0x62, 0xdb, 0xd8, 0x2b, 0x5f, 0xa0, - 0x3e, 0x6d, 0x59, 0x0c, 0xa5, 0x02, 0x4e, 0xd0, 0xde, 0x46, 0xf0, 0x0d, - 0xdf, 0x0a, 0xa8, 0xc3, 0x61, 0xfd, 0x5e, 0x77, 0x80, 0xee, 0xd9, 0x44, - 0xf7, 0x1c, 0x15, 0x75, 0xf3, 0x85, 0x82, 0x21, 0x56, 0x91, 0x88, 0xc7, - 0xcb, 0x08, 0x6a, 0x85, 0x5a, 0x90, 0xbe, 0xc4, 0xd7, 0x49, 0xf2, 0x6b, - 0xc9, 0x59, 0xb6, 0x8a, 0xb1, 0xdc, 0x5a, 0xa3, 0xd5, 0x11, 0xe2, 0x5a, - 0x01, 0x6f, 0x6d, 0xf3, 0x76, 0xb4, 0xba, 0x61, 0x0e, 0x74, 0x75, 0x9f, - 0x07, 0xdc, 0x63, 0x96, 0xe8, 0x30, 0x62, 0xcc, 0x75, 0x4e, 0x0b, 0xe5, - 0x8c, 0x3c, 0x92, 0xb6, 0x25, 0xc9, 0x16, 0xcb, 0xd6, 0x9a, 0x2d, 0x6a, - 0xa2, 0xe9, 0xb4, 0x33, 0x3c, 0x88, 0x8a, 0x3d, 0x5f, 0x16, 0xab, 0x59, - 0xc5, 0x46, 0xb3, 0xab, 0x13, 0x46, 0xef, 0x4c, 0x88, 0xaa, 0xb6, 0x74, - 0x26, 0x88, 0x8d, 0xa7, 0x99, 0xc5, 0xee -}; -int ca_crt_der_len = 991; diff --git a/cores/esp8266/axtls/md5.cpp b/cores/esp8266/axtls/md5.cpp deleted file mode 100644 index 254d9c5bae..0000000000 --- a/cores/esp8266/axtls/md5.cpp +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Copyright (c) 2007, Cameron Rich - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of the axTLS project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * This file implements the MD5 algorithm as defined in RFC1321 - */ - -#include -#include "md5.h" - -/* Constants for MD5Transform routine. - */ -#define S11 7 -#define S12 12 -#define S13 17 -#define S14 22 -#define S21 5 -#define S22 9 -#define S23 14 -#define S24 20 -#define S31 4 -#define S32 11 -#define S33 16 -#define S34 23 -#define S41 6 -#define S42 10 -#define S43 15 -#define S44 21 - -/* ----- static functions ----- */ -static void MD5Transform(uint32_t state[4], const uint8_t block[64]); -static void Encode(uint8_t *output, uint32_t *input, uint32_t len); -static void Decode(uint32_t *output, const uint8_t *input, uint32_t len); - -static const uint8_t PADDING[64] = -{ - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -/* F, G, H and I are basic MD5 functions. - */ -#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) -#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define I(x, y, z) ((y) ^ ((x) | (~z))) - -/* ROTATE_LEFT rotates x left n bits. */ -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) - -/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. - Rotation is separate from addition to prevent recomputation. */ -#define FF(a, b, c, d, x, s, ac) { \ - (a) += F ((b), (c), (d)) + (x) + (uint32_t)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define GG(a, b, c, d, x, s, ac) { \ - (a) += G ((b), (c), (d)) + (x) + (uint32_t)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define HH(a, b, c, d, x, s, ac) { \ - (a) += H ((b), (c), (d)) + (x) + (uint32_t)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define II(a, b, c, d, x, s, ac) { \ - (a) += I ((b), (c), (d)) + (x) + (uint32_t)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } - -/** - * MD5 initialization - begins an MD5 operation, writing a new ctx. - */ -extern void MD5_Init(MD5_CTX *ctx) -{ - ctx->count[0] = ctx->count[1] = 0; - - /* Load magic initialization constants. - */ - ctx->state[0] = 0x67452301; - ctx->state[1] = 0xefcdab89; - ctx->state[2] = 0x98badcfe; - ctx->state[3] = 0x10325476; -} - -/** - * Accepts an array of octets as the next portion of the message. - */ -extern void MD5_Update(MD5_CTX *ctx, const uint8_t * msg, int len) -{ - uint32_t x; - int i, partLen; - - /* Compute number of bytes mod 64 */ - x = (uint32_t)((ctx->count[0] >> 3) & 0x3F); - - /* Update number of bits */ - if ((ctx->count[0] += ((uint32_t)len << 3)) < ((uint32_t)len << 3)) - ctx->count[1]++; - ctx->count[1] += ((uint32_t)len >> 29); - - partLen = 64 - x; - - /* Transform as many times as possible. */ - if (len >= partLen) - { - memcpy(&ctx->buffer[x], msg, partLen); - MD5Transform(ctx->state, ctx->buffer); - - for (i = partLen; i + 63 < len; i += 64) - MD5Transform(ctx->state, &msg[i]); - - x = 0; - } - else - i = 0; - - /* Buffer remaining input */ - memcpy(&ctx->buffer[x], &msg[i], len-i); -} - -/** - * Return the 128-bit message digest into the user's array - */ -extern void MD5_Final(uint8_t *digest, MD5_CTX *ctx) -{ - uint8_t bits[8]; - uint32_t x, padLen; - - /* Save number of bits */ - Encode(bits, ctx->count, 8); - - /* Pad out to 56 mod 64. - */ - x = (uint32_t)((ctx->count[0] >> 3) & 0x3f); - padLen = (x < 56) ? (56 - x) : (120 - x); - MD5_Update(ctx, PADDING, padLen); - - /* Append length (before padding) */ - MD5_Update(ctx, bits, 8); - - /* Store state in digest */ - Encode(digest, ctx->state, MD5_SIZE); -} - -/** - * MD5 basic transformation. Transforms state based on block. - */ -static void MD5Transform(uint32_t state[4], const uint8_t block[64]) -{ - uint32_t a = state[0], b = state[1], c = state[2], - d = state[3], x[MD5_SIZE]; - - Decode(x, block, 64); - - /* Round 1 */ - FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ - FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ - FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ - FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ - FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ - FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ - FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ - FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ - FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ - FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ - FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ - FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ - FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ - FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ - FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ - FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ - - /* Round 2 */ - GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ - GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ - GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ - GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ - GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ - GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ - GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ - GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ - GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ - GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ - GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ - GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ - GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ - GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ - GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ - GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ - - /* Round 3 */ - HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ - HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ - HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ - HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ - HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ - HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ - HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ - HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ - HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ - HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ - HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ - HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ - HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ - HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ - HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ - HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ - - /* Round 4 */ - II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ - II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ - II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ - II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ - II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ - II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ - II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ - II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ - II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ - II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ - II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ - II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ - II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ - II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ - II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ - II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ - - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; -} - -/** - * Encodes input (uint32_t) into output (uint8_t). Assumes len is - * a multiple of 4. - */ -static void Encode(uint8_t *output, uint32_t *input, uint32_t len) -{ - uint32_t i, j; - - for (i = 0, j = 0; j < len; i++, j += 4) - { - output[j] = (uint8_t)(input[i] & 0xff); - output[j+1] = (uint8_t)((input[i] >> 8) & 0xff); - output[j+2] = (uint8_t)((input[i] >> 16) & 0xff); - output[j+3] = (uint8_t)((input[i] >> 24) & 0xff); - } -} - -/** - * Decodes input (uint8_t) into output (uint32_t). Assumes len is - * a multiple of 4. - */ -static void Decode(uint32_t *output, const uint8_t *input, uint32_t len) -{ - uint32_t i, j; - - for (i = 0, j = 0; j < len; i++, j += 4) - output[i] = ((uint32_t)input[j]) | (((uint32_t)input[j+1]) << 8) | - (((uint32_t)input[j+2]) << 16) | (((uint32_t)input[j+3]) << 24); -} diff --git a/cores/esp8266/axtls/md5.h b/cores/esp8266/axtls/md5.h deleted file mode 100644 index 40eb900c95..0000000000 --- a/cores/esp8266/axtls/md5.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef HEADER_MD5_H -#define HEADER_MD5_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define MD5_SIZE 16 - -typedef struct -{ - uint32_t state[4]; /* state (ABCD) */ - uint32_t count[2]; /* number of bits, modulo 2^64 (lsb first) */ - uint8_t buffer[64]; /* input buffer */ -} MD5_CTX; - -extern void MD5_Init(MD5_CTX *); -extern void MD5_Update(MD5_CTX *, const uint8_t *msg, int len); -extern void MD5_Final(uint8_t *digest, MD5_CTX *); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif \ No newline at end of file diff --git a/cores/esp8266/axtls/rsa.cpp b/cores/esp8266/axtls/rsa.cpp deleted file mode 100644 index f549f592eb..0000000000 --- a/cores/esp8266/axtls/rsa.cpp +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright (c) 2007-2014, Cameron Rich - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of the axTLS project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * Implements the RSA public encryption algorithm. Uses the bigint library to - * perform its calculations. - */ -#include -#include "rsa.h" - -void RSA_priv_key_new(RSA_CTX **ctx, - const uint8_t *modulus, int mod_len, - const uint8_t *pub_exp, int pub_len, - const uint8_t *priv_exp, int priv_len, - const uint8_t *p, int p_len, - const uint8_t *q, int q_len, - const uint8_t *dP, int dP_len, - const uint8_t *dQ, int dQ_len, - const uint8_t *qInv, int qInv_len - ) -{ - RSA_CTX *rsa_ctx; - BI_CTX *bi_ctx; - RSA_pub_key_new(ctx, modulus, mod_len, pub_exp, pub_len); - rsa_ctx = *ctx; - bi_ctx = rsa_ctx->bi_ctx; - rsa_ctx->d = bi_import(bi_ctx, priv_exp, priv_len); - bi_permanent(rsa_ctx->d); - rsa_ctx->p = bi_import(bi_ctx, p, p_len); - rsa_ctx->q = bi_import(bi_ctx, q, q_len); - rsa_ctx->dP = bi_import(bi_ctx, dP, dP_len); - rsa_ctx->dQ = bi_import(bi_ctx, dQ, dQ_len); - rsa_ctx->qInv = bi_import(bi_ctx, qInv, qInv_len); - bi_permanent(rsa_ctx->dP); - bi_permanent(rsa_ctx->dQ); - bi_permanent(rsa_ctx->qInv); - bi_set_mod(bi_ctx, rsa_ctx->p, BIGINT_P_OFFSET); - bi_set_mod(bi_ctx, rsa_ctx->q, BIGINT_Q_OFFSET); -} - -void RSA_pub_key_new(RSA_CTX **ctx, - const uint8_t *modulus, int mod_len, - const uint8_t *pub_exp, int pub_len) -{ - RSA_CTX *rsa_ctx; - BI_CTX *bi_ctx; - - if (*ctx) /* if we load multiple certs, dump the old one */ - RSA_free(*ctx); - - bi_ctx = bi_initialize(); - *ctx = (RSA_CTX *)calloc(1, sizeof(RSA_CTX)); - rsa_ctx = *ctx; - rsa_ctx->bi_ctx = bi_ctx; - rsa_ctx->num_octets = mod_len; - rsa_ctx->m = bi_import(bi_ctx, modulus, mod_len); - bi_set_mod(bi_ctx, rsa_ctx->m, BIGINT_M_OFFSET); - rsa_ctx->e = bi_import(bi_ctx, pub_exp, pub_len); - bi_permanent(rsa_ctx->e); -} - -/** - * Free up any RSA context resources. - */ -void RSA_free(RSA_CTX *rsa_ctx) -{ - BI_CTX *bi_ctx; - if (rsa_ctx == NULL) /* deal with ptrs that are null */ - return; - - bi_ctx = rsa_ctx->bi_ctx; - - bi_depermanent(rsa_ctx->e); - bi_free(bi_ctx, rsa_ctx->e); - bi_free_mod(rsa_ctx->bi_ctx, BIGINT_M_OFFSET); - - if (rsa_ctx->d) - { - bi_depermanent(rsa_ctx->d); - bi_free(bi_ctx, rsa_ctx->d); - bi_depermanent(rsa_ctx->dP); - bi_depermanent(rsa_ctx->dQ); - bi_depermanent(rsa_ctx->qInv); - bi_free(bi_ctx, rsa_ctx->dP); - bi_free(bi_ctx, rsa_ctx->dQ); - bi_free(bi_ctx, rsa_ctx->qInv); - bi_free_mod(rsa_ctx->bi_ctx, BIGINT_P_OFFSET); - bi_free_mod(rsa_ctx->bi_ctx, BIGINT_Q_OFFSET); - } - - bi_terminate(bi_ctx); - free(rsa_ctx); -} - -/** - * @brief Use PKCS1.5 for decryption/verification. - * @param ctx [in] The context - * @param in_data [in] The data to decrypt (must be < modulus size-11) - * @param out_data [out] The decrypted data. - * @param out_len [int] The size of the decrypted buffer in bytes - * @param is_decryption [in] Decryption or verify operation. - * @return The number of bytes that were originally encrypted. -1 on error. - * @see http://www.rsasecurity.com/rsalabs/node.asp?id=2125 - */ -int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data, - uint8_t *out_data, int out_len, int is_decryption) -{ - const int byte_size = ctx->num_octets; - int i = 0, size; - bigint *decrypted_bi, *dat_bi; - uint8_t *block = (uint8_t *)alloca(byte_size); - int pad_count = 0; - - if (out_len < byte_size) /* check output has enough size */ - return -1; - - memset(out_data, 0, out_len); /* initialise */ - - /* decrypt */ - dat_bi = bi_import(ctx->bi_ctx, in_data, byte_size); - decrypted_bi = is_decryption ? RSA_private(ctx, dat_bi) : RSA_public(ctx, dat_bi); - - /* convert to a normal block */ - bi_export(ctx->bi_ctx, decrypted_bi, block, byte_size); - - if (block[i++] != 0) /* leading 0? */ - return -1; - - if (is_decryption == 0) - { - if (block[i++] != 0x01) /* BT correct? */ - return -1; - - while (block[i++] == 0xff && i < byte_size) - pad_count++; - } - else - { - if (block[i++] != 0x02) /* BT correct? */ - return -1; - - while (block[i++] && i < byte_size) - pad_count++; - } - - /* check separator byte 0x00 - and padding must be 8 or more bytes */ - if (i == byte_size || pad_count < 8) - return -1; - - size = byte_size - i; - - /* get only the bit we want */ - memcpy(out_data, &block[i], size); - return size; -} - -/** - * Performs m = c^d mod n - */ -bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg) -{ - return bi_crt(c->bi_ctx, bi_msg, c->dP, c->dQ, c->p, c->q, c->qInv); -} - -/** - * Performs c = m^e mod n - */ -bigint *RSA_public(const RSA_CTX * c, bigint *bi_msg) -{ - c->bi_ctx->mod_offset = BIGINT_M_OFFSET; - return bi_mod_power(c->bi_ctx, bi_msg, c->e); -} - -int get_random(int num_rand_bytes, uint8_t *rand_data) -{ - for(int i = 0; i < num_rand_bytes; i++) { - rand_data[i] = random(0, 255); - } - return 0; -} - -/** - * Set a series of bytes with a random number. Individual bytes are not zero. - */ -int get_random_NZ(int num_rand_bytes, uint8_t *rand_data) -{ - int i; - if (get_random(num_rand_bytes, rand_data)) - return -1; - - for (i = 0; i < num_rand_bytes; i++) - { - while (rand_data[i] == 0) /* can't be 0 */ - rand_data[i] = (uint8_t)(rand()); - } - - return 0; -} - -/** - * Use PKCS1.5 for encryption/signing. - * see http://www.rsasecurity.com/rsalabs/node.asp?id=2125 - */ -int RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len, - uint8_t *out_data, int is_signing) -{ - int byte_size = ctx->num_octets; - int num_pads_needed = byte_size-in_len-3; - bigint *dat_bi, *encrypt_bi; - - /* note: in_len+11 must be > byte_size */ - out_data[0] = 0; /* ensure encryption block is < modulus */ - - if (is_signing) - { - out_data[1] = 1; /* PKCS1.5 signing pads with "0xff"'s */ - memset(&out_data[2], 0xff, num_pads_needed); - } - else /* randomize the encryption padding with non-zero bytes */ - { - out_data[1] = 2; - if (get_random_NZ(num_pads_needed, &out_data[2]) < 0) - return -1; - } - - out_data[2+num_pads_needed] = 0; - memcpy(&out_data[3+num_pads_needed], in_data, in_len); - - /* now encrypt it */ - dat_bi = bi_import(ctx->bi_ctx, out_data, byte_size); - encrypt_bi = is_signing ? RSA_private(ctx, dat_bi) : - RSA_public(ctx, dat_bi); - bi_export(ctx->bi_ctx, encrypt_bi, out_data, byte_size); - - /* save a few bytes of memory */ - bi_clear_cache(ctx->bi_ctx); - return byte_size; -} - diff --git a/cores/esp8266/axtls/rsa.h b/cores/esp8266/axtls/rsa.h deleted file mode 100644 index 604cd8f929..0000000000 --- a/cores/esp8266/axtls/rsa.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef HEADER_RSA_H -#define HEADER_RSA_H - -#include "bigint.h" - -typedef struct -{ - bigint *m; /* modulus */ - bigint *e; /* public exponent */ - bigint *d; /* private exponent */ - bigint *p; /* p as in m = pq */ - bigint *q; /* q as in m = pq */ - bigint *dP; /* d mod (p-1) */ - bigint *dQ; /* d mod (q-1) */ - bigint *qInv; /* q^-1 mod p */ - int num_octets; - BI_CTX *bi_ctx; -} RSA_CTX; - -void RSA_priv_key_new(RSA_CTX **rsa_ctx, - const uint8_t *modulus, int mod_len, - const uint8_t *pub_exp, int pub_len, - const uint8_t *priv_exp, int priv_len, - const uint8_t *p, int p_len, - const uint8_t *q, int q_len, - const uint8_t *dP, int dP_len, - const uint8_t *dQ, int dQ_len, - const uint8_t *qInv, int qInv_len - ); -void RSA_pub_key_new(RSA_CTX **rsa_ctx, - const uint8_t *modulus, int mod_len, - const uint8_t *pub_exp, int pub_len); -void RSA_free(RSA_CTX *ctx); -int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint8_t *out_data, - int out_len, int is_decryption); -bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg); -bigint *RSA_sign_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len, - bigint *modulus, bigint *pub_exp); -bigint *RSA_public(const RSA_CTX * c, bigint *bi_msg); -int RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len, - uint8_t *out_data, int is_signing); -void RSA_print(const RSA_CTX *ctx); - -#endif diff --git a/cores/esp8266/axtls/sha1.cpp b/cores/esp8266/axtls/sha1.cpp deleted file mode 100644 index dbd0c08268..0000000000 --- a/cores/esp8266/axtls/sha1.cpp +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright (c) 2007, Cameron Rich - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of the axTLS project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * SHA1 implementation - as defined in FIPS PUB 180-1 published April 17, 1995. - * This code was originally taken from RFC3174 - */ - -#include -#include "sha1.h" - -/* - * Define the SHA1 circular left shift macro - */ -#define SHA1CircularShift(bits,word) \ - (((word) << (bits)) | ((word) >> (32-(bits)))) - -/* ----- static functions ----- */ -static void SHA1PadMessage(SHA1_CTX *ctx); -static void SHA1ProcessMessageBlock(SHA1_CTX *ctx); - -/** - * Initialize the SHA1 context - */ -void SHA1_Init(SHA1_CTX *ctx) -{ - ctx->Length_Low = 0; - ctx->Length_High = 0; - ctx->Message_Block_Index = 0; - ctx->Intermediate_Hash[0] = 0x67452301; - ctx->Intermediate_Hash[1] = 0xEFCDAB89; - ctx->Intermediate_Hash[2] = 0x98BADCFE; - ctx->Intermediate_Hash[3] = 0x10325476; - ctx->Intermediate_Hash[4] = 0xC3D2E1F0; -} - -/** - * Accepts an array of octets as the next portion of the message. - */ -void SHA1_Update(SHA1_CTX *ctx, const uint8_t *msg, int len) -{ - while (len--) - { - ctx->Message_Block[ctx->Message_Block_Index++] = (*msg & 0xFF); - ctx->Length_Low += 8; - - if (ctx->Length_Low == 0) - ctx->Length_High++; - - if (ctx->Message_Block_Index == 64) - SHA1ProcessMessageBlock(ctx); - - msg++; - } -} - -/** - * Return the 160-bit message digest into the user's array - */ -void SHA1_Final(uint8_t *digest, SHA1_CTX *ctx) -{ - int i; - - SHA1PadMessage(ctx); - memset(ctx->Message_Block, 0, 64); - ctx->Length_Low = 0; /* and clear length */ - ctx->Length_High = 0; - - for (i = 0; i < SHA1_SIZE; i++) - { - digest[i] = ctx->Intermediate_Hash[i>>2] >> 8 * ( 3 - ( i & 0x03 ) ); - } -} - -/** - * Process the next 512 bits of the message stored in the array. - */ -static void SHA1ProcessMessageBlock(SHA1_CTX *ctx) -{ - const uint32_t K[] = { /* Constants defined in SHA-1 */ - 0x5A827999, - 0x6ED9EBA1, - 0x8F1BBCDC, - 0xCA62C1D6 - }; - int t; /* Loop counter */ - uint32_t temp; /* Temporary word value */ - uint32_t W[80]; /* Word sequence */ - uint32_t A, B, C, D, E; /* Word buffers */ - - /* - * Initialize the first 16 words in the array W - */ - for (t = 0; t < 16; t++) - { - W[t] = ctx->Message_Block[t * 4] << 24; - W[t] |= ctx->Message_Block[t * 4 + 1] << 16; - W[t] |= ctx->Message_Block[t * 4 + 2] << 8; - W[t] |= ctx->Message_Block[t * 4 + 3]; - } - - for (t = 16; t < 80; t++) - { - W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); - } - - A = ctx->Intermediate_Hash[0]; - B = ctx->Intermediate_Hash[1]; - C = ctx->Intermediate_Hash[2]; - D = ctx->Intermediate_Hash[3]; - E = ctx->Intermediate_Hash[4]; - - for (t = 0; t < 20; t++) - { - temp = SHA1CircularShift(5,A) + - ((B & C) | ((~B) & D)) + E + W[t] + K[0]; - E = D; - D = C; - C = SHA1CircularShift(30,B); - - B = A; - A = temp; - } - - for (t = 20; t < 40; t++) - { - temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1]; - E = D; - D = C; - C = SHA1CircularShift(30,B); - B = A; - A = temp; - } - - for (t = 40; t < 60; t++) - { - temp = SHA1CircularShift(5,A) + - ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; - E = D; - D = C; - C = SHA1CircularShift(30,B); - B = A; - A = temp; - } - - for (t = 60; t < 80; t++) - { - temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3]; - E = D; - D = C; - C = SHA1CircularShift(30,B); - B = A; - A = temp; - } - - ctx->Intermediate_Hash[0] += A; - ctx->Intermediate_Hash[1] += B; - ctx->Intermediate_Hash[2] += C; - ctx->Intermediate_Hash[3] += D; - ctx->Intermediate_Hash[4] += E; - ctx->Message_Block_Index = 0; -} - -/* - * According to the standard, the message must be padded to an even - * 512 bits. The first padding bit must be a '1'. The last 64 - * bits represent the length of the original message. All bits in - * between should be 0. This function will pad the message - * according to those rules by filling the Message_Block array - * accordingly. It will also call the ProcessMessageBlock function - * provided appropriately. When it returns, it can be assumed that - * the message digest has been computed. - * - * @param ctx [in, out] The SHA1 context - */ -static void SHA1PadMessage(SHA1_CTX *ctx) -{ - /* - * Check to see if the current message block is too small to hold - * the initial padding bits and length. If so, we will pad the - * block, process it, and then continue padding into a second - * block. - */ - if (ctx->Message_Block_Index > 55) - { - ctx->Message_Block[ctx->Message_Block_Index++] = 0x80; - while(ctx->Message_Block_Index < 64) - { - ctx->Message_Block[ctx->Message_Block_Index++] = 0; - } - - SHA1ProcessMessageBlock(ctx); - - while (ctx->Message_Block_Index < 56) - { - ctx->Message_Block[ctx->Message_Block_Index++] = 0; - } - } - else - { - ctx->Message_Block[ctx->Message_Block_Index++] = 0x80; - while(ctx->Message_Block_Index < 56) - { - - ctx->Message_Block[ctx->Message_Block_Index++] = 0; - } - } - - /* - * Store the message length as the last 8 octets - */ - ctx->Message_Block[56] = ctx->Length_High >> 24; - ctx->Message_Block[57] = ctx->Length_High >> 16; - ctx->Message_Block[58] = ctx->Length_High >> 8; - ctx->Message_Block[59] = ctx->Length_High; - ctx->Message_Block[60] = ctx->Length_Low >> 24; - ctx->Message_Block[61] = ctx->Length_Low >> 16; - ctx->Message_Block[62] = ctx->Length_Low >> 8; - ctx->Message_Block[63] = ctx->Length_Low; - SHA1ProcessMessageBlock(ctx); -} diff --git a/cores/esp8266/axtls/sha1.h b/cores/esp8266/axtls/sha1.h deleted file mode 100644 index 6b817750c9..0000000000 --- a/cores/esp8266/axtls/sha1.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef HEADER_SHA1_H -#define HEADER_SHA1_H - -#define SHA1_SIZE 20 - -/* - * This structure will hold context information for the SHA-1 - * hashing operation - */ -typedef struct -{ - uint32_t Intermediate_Hash[SHA1_SIZE/4]; /* Message Digest */ - uint32_t Length_Low; /* Message length in bits */ - uint32_t Length_High; /* Message length in bits */ - uint16_t Message_Block_Index; /* Index into message block array */ - uint8_t Message_Block[64]; /* 512-bit message blocks */ -} SHA1_CTX; - -void SHA1_Init(SHA1_CTX *); -void SHA1_Update(SHA1_CTX *, const uint8_t * msg, int len); -void SHA1_Final(uint8_t *digest, SHA1_CTX *); - -#endif diff --git a/cores/esp8266/axtls/sha256.cpp b/cores/esp8266/axtls/sha256.cpp deleted file mode 100644 index cca88fa5bd..0000000000 --- a/cores/esp8266/axtls/sha256.cpp +++ /dev/null @@ -1,273 +0,0 @@ -/* - * Copyright (c) 2015, Cameron Rich - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of the axTLS project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include "sha256.h" - -#define GET_UINT32(n,b,i) \ -{ \ - (n) = ((uint32_t) (b)[(i) ] << 24) \ - | ((uint32_t) (b)[(i) + 1] << 16) \ - | ((uint32_t) (b)[(i) + 2] << 8) \ - | ((uint32_t) (b)[(i) + 3] ); \ -} - -#define PUT_UINT32(n,b,i) \ -{ \ - (b)[(i) ] = (uint8_t) ((n) >> 24); \ - (b)[(i) + 1] = (uint8_t) ((n) >> 16); \ - (b)[(i) + 2] = (uint8_t) ((n) >> 8); \ - (b)[(i) + 3] = (uint8_t) ((n) ); \ -} - -static const uint8_t sha256_padding[64] = -{ - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -/** - * Initialize the SHA256 context - */ -void SHA256_Init(SHA256_CTX *ctx) -{ - ctx->total[0] = 0; - ctx->total[1] = 0; - - ctx->state[0] = 0x6A09E667; - ctx->state[1] = 0xBB67AE85; - ctx->state[2] = 0x3C6EF372; - ctx->state[3] = 0xA54FF53A; - ctx->state[4] = 0x510E527F; - ctx->state[5] = 0x9B05688C; - ctx->state[6] = 0x1F83D9AB; - ctx->state[7] = 0x5BE0CD19; -} - -static void SHA256_Process(const uint8_t digest[64], SHA256_CTX *ctx) -{ - uint32_t temp1, temp2, W[64]; - uint32_t A, B, C, D, E, F, G, H; - - GET_UINT32(W[0], digest, 0); - GET_UINT32(W[1], digest, 4); - GET_UINT32(W[2], digest, 8); - GET_UINT32(W[3], digest, 12); - GET_UINT32(W[4], digest, 16); - GET_UINT32(W[5], digest, 20); - GET_UINT32(W[6], digest, 24); - GET_UINT32(W[7], digest, 28); - GET_UINT32(W[8], digest, 32); - GET_UINT32(W[9], digest, 36); - GET_UINT32(W[10], digest, 40); - GET_UINT32(W[11], digest, 44); - GET_UINT32(W[12], digest, 48); - GET_UINT32(W[13], digest, 52); - GET_UINT32(W[14], digest, 56); - GET_UINT32(W[15], digest, 60); - -#define SHR(x,n) ((x & 0xFFFFFFFF) >> n) -#define ROTR(x,n) (SHR(x,n) | (x << (32 - n))) - -#define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ SHR(x, 3)) -#define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^ SHR(x,10)) - -#define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22)) -#define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25)) - -#define F0(x,y,z) ((x & y) | (z & (x | y))) -#define F1(x,y,z) (z ^ (x & (y ^ z))) - -#define R(t) \ -( \ - W[t] = S1(W[t - 2]) + W[t - 7] + \ - S0(W[t - 15]) + W[t - 16] \ -) - -#define P(a,b,c,d,e,f,g,h,x,K) \ -{ \ - temp1 = h + S3(e) + F1(e,f,g) + K + x; \ - temp2 = S2(a) + F0(a,b,c); \ - d += temp1; h = temp1 + temp2; \ -} - - A = ctx->state[0]; - B = ctx->state[1]; - C = ctx->state[2]; - D = ctx->state[3]; - E = ctx->state[4]; - F = ctx->state[5]; - G = ctx->state[6]; - H = ctx->state[7]; - - P(A, B, C, D, E, F, G, H, W[ 0], 0x428A2F98); - P(H, A, B, C, D, E, F, G, W[ 1], 0x71374491); - P(G, H, A, B, C, D, E, F, W[ 2], 0xB5C0FBCF); - P(F, G, H, A, B, C, D, E, W[ 3], 0xE9B5DBA5); - P(E, F, G, H, A, B, C, D, W[ 4], 0x3956C25B); - P(D, E, F, G, H, A, B, C, W[ 5], 0x59F111F1); - P(C, D, E, F, G, H, A, B, W[ 6], 0x923F82A4); - P(B, C, D, E, F, G, H, A, W[ 7], 0xAB1C5ED5); - P(A, B, C, D, E, F, G, H, W[ 8], 0xD807AA98); - P(H, A, B, C, D, E, F, G, W[ 9], 0x12835B01); - P(G, H, A, B, C, D, E, F, W[10], 0x243185BE); - P(F, G, H, A, B, C, D, E, W[11], 0x550C7DC3); - P(E, F, G, H, A, B, C, D, W[12], 0x72BE5D74); - P(D, E, F, G, H, A, B, C, W[13], 0x80DEB1FE); - P(C, D, E, F, G, H, A, B, W[14], 0x9BDC06A7); - P(B, C, D, E, F, G, H, A, W[15], 0xC19BF174); - P(A, B, C, D, E, F, G, H, R(16), 0xE49B69C1); - P(H, A, B, C, D, E, F, G, R(17), 0xEFBE4786); - P(G, H, A, B, C, D, E, F, R(18), 0x0FC19DC6); - P(F, G, H, A, B, C, D, E, R(19), 0x240CA1CC); - P(E, F, G, H, A, B, C, D, R(20), 0x2DE92C6F); - P(D, E, F, G, H, A, B, C, R(21), 0x4A7484AA); - P(C, D, E, F, G, H, A, B, R(22), 0x5CB0A9DC); - P(B, C, D, E, F, G, H, A, R(23), 0x76F988DA); - P(A, B, C, D, E, F, G, H, R(24), 0x983E5152); - P(H, A, B, C, D, E, F, G, R(25), 0xA831C66D); - P(G, H, A, B, C, D, E, F, R(26), 0xB00327C8); - P(F, G, H, A, B, C, D, E, R(27), 0xBF597FC7); - P(E, F, G, H, A, B, C, D, R(28), 0xC6E00BF3); - P(D, E, F, G, H, A, B, C, R(29), 0xD5A79147); - P(C, D, E, F, G, H, A, B, R(30), 0x06CA6351); - P(B, C, D, E, F, G, H, A, R(31), 0x14292967); - P(A, B, C, D, E, F, G, H, R(32), 0x27B70A85); - P(H, A, B, C, D, E, F, G, R(33), 0x2E1B2138); - P(G, H, A, B, C, D, E, F, R(34), 0x4D2C6DFC); - P(F, G, H, A, B, C, D, E, R(35), 0x53380D13); - P(E, F, G, H, A, B, C, D, R(36), 0x650A7354); - P(D, E, F, G, H, A, B, C, R(37), 0x766A0ABB); - P(C, D, E, F, G, H, A, B, R(38), 0x81C2C92E); - P(B, C, D, E, F, G, H, A, R(39), 0x92722C85); - P(A, B, C, D, E, F, G, H, R(40), 0xA2BFE8A1); - P(H, A, B, C, D, E, F, G, R(41), 0xA81A664B); - P(G, H, A, B, C, D, E, F, R(42), 0xC24B8B70); - P(F, G, H, A, B, C, D, E, R(43), 0xC76C51A3); - P(E, F, G, H, A, B, C, D, R(44), 0xD192E819); - P(D, E, F, G, H, A, B, C, R(45), 0xD6990624); - P(C, D, E, F, G, H, A, B, R(46), 0xF40E3585); - P(B, C, D, E, F, G, H, A, R(47), 0x106AA070); - P(A, B, C, D, E, F, G, H, R(48), 0x19A4C116); - P(H, A, B, C, D, E, F, G, R(49), 0x1E376C08); - P(G, H, A, B, C, D, E, F, R(50), 0x2748774C); - P(F, G, H, A, B, C, D, E, R(51), 0x34B0BCB5); - P(E, F, G, H, A, B, C, D, R(52), 0x391C0CB3); - P(D, E, F, G, H, A, B, C, R(53), 0x4ED8AA4A); - P(C, D, E, F, G, H, A, B, R(54), 0x5B9CCA4F); - P(B, C, D, E, F, G, H, A, R(55), 0x682E6FF3); - P(A, B, C, D, E, F, G, H, R(56), 0x748F82EE); - P(H, A, B, C, D, E, F, G, R(57), 0x78A5636F); - P(G, H, A, B, C, D, E, F, R(58), 0x84C87814); - P(F, G, H, A, B, C, D, E, R(59), 0x8CC70208); - P(E, F, G, H, A, B, C, D, R(60), 0x90BEFFFA); - P(D, E, F, G, H, A, B, C, R(61), 0xA4506CEB); - P(C, D, E, F, G, H, A, B, R(62), 0xBEF9A3F7); - P(B, C, D, E, F, G, H, A, R(63), 0xC67178F2); - - ctx->state[0] += A; - ctx->state[1] += B; - ctx->state[2] += C; - ctx->state[3] += D; - ctx->state[4] += E; - ctx->state[5] += F; - ctx->state[6] += G; - ctx->state[7] += H; -} - -/** - * Accepts an array of octets as the next portion of the message. - */ -void SHA256_Update(SHA256_CTX *ctx, const uint8_t * msg, int len) -{ - uint32_t left = ctx->total[0] & 0x3F; - uint32_t fill = 64 - left; - - ctx->total[0] += len; - ctx->total[0] &= 0xFFFFFFFF; - - if (ctx->total[0] < len) - ctx->total[1]++; - - if (left && len >= fill) - { - memcpy((void *) (ctx->buffer + left), (void *)msg, fill); - SHA256_Process(ctx->buffer, ctx); - len -= fill; - msg += fill; - left = 0; - } - - while (len >= 64) - { - SHA256_Process(msg, ctx); - len -= 64; - msg += 64; - } - - if (len) - { - memcpy((void *) (ctx->buffer + left), (void *) msg, len); - } -} - -/** - * Return the 256-bit message digest into the user's array - */ -void SHA256_Final(uint8_t *digest, SHA256_CTX *ctx) -{ - uint32_t last, padn; - uint32_t high, low; - uint8_t msglen[8]; - - high = (ctx->total[0] >> 29) - | (ctx->total[1] << 3); - low = (ctx->total[0] << 3); - - PUT_UINT32(high, msglen, 0); - PUT_UINT32(low, msglen, 4); - - last = ctx->total[0] & 0x3F; - padn = (last < 56) ? (56 - last) : (120 - last); - - SHA256_Update(ctx, sha256_padding, padn); - SHA256_Update(ctx, msglen, 8); - - PUT_UINT32(ctx->state[0], digest, 0); - PUT_UINT32(ctx->state[1], digest, 4); - PUT_UINT32(ctx->state[2], digest, 8); - PUT_UINT32(ctx->state[3], digest, 12); - PUT_UINT32(ctx->state[4], digest, 16); - PUT_UINT32(ctx->state[5], digest, 20); - PUT_UINT32(ctx->state[6], digest, 24); - PUT_UINT32(ctx->state[7], digest, 28); -} diff --git a/cores/esp8266/axtls/sha256.h b/cores/esp8266/axtls/sha256.h deleted file mode 100644 index 5462042672..0000000000 --- a/cores/esp8266/axtls/sha256.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef HEADER_SHA256_H -#define HEADER_SHA256_H - -#define SHA256_SIZE 32 - -typedef struct -{ - uint32_t total[2]; - uint32_t state[8]; - uint8_t buffer[64]; -} SHA256_CTX; - -void SHA256_Init(SHA256_CTX *c); -void SHA256_Update(SHA256_CTX *, const uint8_t *input, int len); -void SHA256_Final(uint8_t *digest, SHA256_CTX *); - -#endif diff --git a/cores/esp8266/axtls/x509.cpp b/cores/esp8266/axtls/x509.cpp deleted file mode 100644 index c434fce4df..0000000000 --- a/cores/esp8266/axtls/x509.cpp +++ /dev/null @@ -1,569 +0,0 @@ -/* - * Copyright (c) 2007-2016, Cameron Rich - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of the axTLS project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file x509.c - * - * Certificate processing. - */ - -#include -#include -#include "asn1.h" -#include "md5.h" -#include "sha1.h" -#include "sha256.h" -#include "x509.h" - -static int x509_v3_subject_alt_name(const uint8_t *cert, int offset, - X509_CTX *x509_ctx); -static int x509_v3_basic_constraints(const uint8_t *cert, int offset, - X509_CTX *x509_ctx); -static int x509_v3_key_usage(const uint8_t *cert, int offset, - X509_CTX *x509_ctx); - -/** - * Retrieve the signature from a certificate. - */ -static const uint8_t *get_signature(const uint8_t *asn1_sig, int *len) -{ - int offset = 0; - const uint8_t *ptr = NULL; - - if (asn1_next_obj(asn1_sig, &offset, ASN1_SEQUENCE) < 0 || - asn1_skip_obj(asn1_sig, &offset, ASN1_SEQUENCE)) - goto end_get_sig; - - if (asn1_sig[offset++] != ASN1_OCTET_STRING) - goto end_get_sig; - *len = get_asn1_length(asn1_sig, &offset); - ptr = &asn1_sig[offset]; /* all ok */ - -end_get_sig: - return ptr; -} - -/** - * Construct a new x509 object. - * @return 0 if ok. < 0 if there was a problem. - */ -int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx) -{ - int begin_tbs, end_tbs; - int ret = X509_NOT_OK, offset = 0, cert_size = 0; - int version = 0; - X509_CTX *x509_ctx; - BI_CTX *bi_ctx; - - *ctx = (X509_CTX *)calloc(1, sizeof(X509_CTX)); - x509_ctx = *ctx; - - /* get the certificate size */ - asn1_skip_obj(cert, &cert_size, ASN1_SEQUENCE); - - if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0) - goto end_cert; - - begin_tbs = offset; /* start of the tbs */ - end_tbs = begin_tbs; /* work out the end of the tbs */ - asn1_skip_obj(cert, &end_tbs, ASN1_SEQUENCE); - - if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0) - goto end_cert; - - /* optional version */ - if (cert[offset] == ASN1_EXPLICIT_TAG && - asn1_version(cert, &offset, &version) == X509_NOT_OK) - goto end_cert; - - if (asn1_skip_obj(cert, &offset, ASN1_INTEGER) || /* serial number */ - asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0) - goto end_cert; - - /* make sure the signature is ok */ - if (asn1_signature_type(cert, &offset, x509_ctx)) - { - ret = X509_VFY_ERROR_UNSUPPORTED_DIGEST; - goto end_cert; - } - - if (asn1_name(cert, &offset, x509_ctx->ca_cert_dn) || - asn1_validity(cert, &offset, x509_ctx) || - asn1_name(cert, &offset, x509_ctx->cert_dn) || - asn1_public_key(cert, &offset, x509_ctx)) - { - goto end_cert; - } - - bi_ctx = x509_ctx->rsa_ctx->bi_ctx; - - /* use the appropriate signature algorithm */ - switch (x509_ctx->sig_type) - { - - case SIG_TYPE_MD5: - { - MD5_CTX md5_ctx; - uint8_t md5_dgst[MD5_SIZE]; - MD5_Init(&md5_ctx); - MD5_Update(&md5_ctx, &cert[begin_tbs], end_tbs-begin_tbs); - MD5_Final(md5_dgst, &md5_ctx); - x509_ctx->digest = bi_import(bi_ctx, md5_dgst, MD5_SIZE); - } - break; - - case SIG_TYPE_SHA1: - { - SHA1_CTX sha_ctx; - uint8_t sha_dgst[SHA1_SIZE]; - SHA1_Init(&sha_ctx); - SHA1_Update(&sha_ctx, &cert[begin_tbs], end_tbs-begin_tbs); - SHA1_Final(sha_dgst, &sha_ctx); - x509_ctx->digest = bi_import(bi_ctx, sha_dgst, SHA1_SIZE); - } - break; - - case SIG_TYPE_SHA256: - { - SHA256_CTX sha256_ctx; - uint8_t sha256_dgst[SHA256_SIZE]; - SHA256_Init(&sha256_ctx); - SHA256_Update(&sha256_ctx, &cert[begin_tbs], end_tbs-begin_tbs); - SHA256_Final(sha256_dgst, &sha256_ctx); - x509_ctx->digest = bi_import(bi_ctx, sha256_dgst, SHA256_SIZE); - } - break; - /* - case SIG_TYPE_SHA384: - { - SHA384_CTX sha384_ctx; - uint8_t sha384_dgst[SHA384_SIZE]; - SHA384_Init(&sha384_ctx); - SHA384_Update(&sha384_ctx, &cert[begin_tbs], end_tbs-begin_tbs); - SHA384_Final(sha384_dgst, &sha384_ctx); - x509_ctx->digest = bi_import(bi_ctx, sha384_dgst, SHA384_SIZE); - } - break; - - case SIG_TYPE_SHA512: - { - SHA512_CTX sha512_ctx; - uint8_t sha512_dgst[SHA512_SIZE]; - SHA512_Init(&sha512_ctx); - SHA512_Update(&sha512_ctx, &cert[begin_tbs], end_tbs-begin_tbs); - SHA512_Final(sha512_dgst, &sha512_ctx); - x509_ctx->digest = bi_import(bi_ctx, sha512_dgst, SHA512_SIZE); - } - break; - */ - } - - if (version == 2 && asn1_next_obj(cert, &offset, ASN1_V3_DATA) > 0) - { - x509_v3_subject_alt_name(cert, offset, x509_ctx); - x509_v3_basic_constraints(cert, offset, x509_ctx); - x509_v3_key_usage(cert, offset, x509_ctx); - } - - offset = end_tbs; /* skip the rest of v3 data */ - if (asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) || asn1_signature(cert, &offset, x509_ctx)) - goto end_cert; - - ret = X509_OK; - -end_cert: - if (len) - { - *len = cert_size; - } - - if (ret) - { - x509_free(x509_ctx); - *ctx = NULL; - } - - return ret; -} - -static int x509_v3_subject_alt_name(const uint8_t *cert, int offset, - X509_CTX *x509_ctx) -{ - if ((offset = asn1_is_subject_alt_name(cert, offset)) > 0) - { - x509_ctx->subject_alt_name_present = true; - x509_ctx->subject_alt_name_is_critical = - asn1_is_critical_ext(cert, &offset); - - if (asn1_next_obj(cert, &offset, ASN1_OCTET_STRING) > 0) - { - int altlen; - - if ((altlen = asn1_next_obj(cert, &offset, ASN1_SEQUENCE)) > 0) - { - int endalt = offset + altlen; - int totalnames = 0; - - while (offset < endalt) - { - int type = cert[offset++]; - int dnslen = get_asn1_length(cert, &offset); - - if (type == ASN1_CONTEXT_DNSNAME) - { - x509_ctx->subject_alt_dnsnames = (char**) - realloc(x509_ctx->subject_alt_dnsnames, - (totalnames + 2) * sizeof(char*)); - x509_ctx->subject_alt_dnsnames[totalnames] = - (char*)malloc(dnslen + 1); - x509_ctx->subject_alt_dnsnames[totalnames+1] = NULL; - memcpy(x509_ctx->subject_alt_dnsnames[totalnames], - cert + offset, dnslen); - x509_ctx->subject_alt_dnsnames[totalnames][dnslen] = 0; - totalnames++; - } - - offset += dnslen; - } - } - } - } - - return X509_OK; -} - -/** - * Basic constraints - see https://tools.ietf.org/html/rfc5280#page-39 - */ -static int x509_v3_basic_constraints(const uint8_t *cert, int offset, - X509_CTX *x509_ctx) -{ - int ret = X509_OK; - - if ((offset = asn1_is_basic_constraints(cert, offset)) == 0) - goto end_contraints; - - x509_ctx->basic_constraint_present = true; - x509_ctx->basic_constraint_is_critical = - asn1_is_critical_ext(cert, &offset); - - if (asn1_next_obj(cert, &offset, ASN1_OCTET_STRING) < 0 || - asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0 || - asn1_get_bool(cert, &offset, &x509_ctx->basic_constraint_cA) < 0 || - asn1_get_int(cert, &offset, - &x509_ctx->basic_constraint_pathLenConstraint) < 0) - { - ret = X509_NOT_OK; - } - -end_contraints: - return ret; -} - -/* - * Key usage - see https://tools.ietf.org/html/rfc5280#section-4.2.1.3 - */ -static int x509_v3_key_usage(const uint8_t *cert, int offset, - X509_CTX *x509_ctx) -{ - int ret = X509_OK; - - if ((offset = asn1_is_key_usage(cert, offset)) == 0) - goto end_key_usage; - - x509_ctx->key_usage_present = true; - x509_ctx->key_usage_is_critical = asn1_is_critical_ext(cert, &offset); - - if (asn1_next_obj(cert, &offset, ASN1_OCTET_STRING) < 0 || - asn1_get_bit_string_as_int(cert, &offset, &x509_ctx->key_usage)) - { - ret = X509_NOT_OK; - } - -end_key_usage: - return ret; -} - -/** - * Free an X.509 object's resources. - */ -void x509_free(X509_CTX *x509_ctx) -{ - X509_CTX *next; - int i; - - if (x509_ctx == NULL) /* if already null, then don't bother */ - return; - - for (i = 0; i < X509_NUM_DN_TYPES; i++) - { - free(x509_ctx->ca_cert_dn[i]); - free(x509_ctx->cert_dn[i]); - } - - free(x509_ctx->signature); - - if (x509_ctx->digest) - { - bi_free(x509_ctx->rsa_ctx->bi_ctx, x509_ctx->digest); - } - - if (x509_ctx->subject_alt_dnsnames) - { - for (i = 0; x509_ctx->subject_alt_dnsnames[i]; ++i) - free(x509_ctx->subject_alt_dnsnames[i]); - - free(x509_ctx->subject_alt_dnsnames); - } - - RSA_free(x509_ctx->rsa_ctx); - next = x509_ctx->next; - free(x509_ctx); - x509_free(next); /* clear the chain */ -} - -/** - * Take a signature and decrypt it. - */ -static bigint *sig_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len, - bigint *modulus, bigint *pub_exp) -{ - int i, size; - bigint *decrypted_bi, *dat_bi; - bigint *bir = NULL; - uint8_t *block = (uint8_t *)alloca(sig_len); - - /* decrypt */ - dat_bi = bi_import(ctx, sig, sig_len); - ctx->mod_offset = BIGINT_M_OFFSET; - - /* convert to a normal block */ - decrypted_bi = bi_mod_power2(ctx, dat_bi, modulus, pub_exp); - - bi_export(ctx, decrypted_bi, block, sig_len); - ctx->mod_offset = BIGINT_M_OFFSET; - - i = 10; /* start at the first possible non-padded byte */ - while (block[i++] && i < sig_len); - size = sig_len - i; - - /* get only the bit we want */ - if (size > 0) - { - int len; - const uint8_t *sig_ptr = get_signature(&block[i], &len); - - if (sig_ptr) - { - bir = bi_import(ctx, sig_ptr, len); - } - } - - /* save a few bytes of memory */ - bi_clear_cache(ctx); - return bir; -} - -/** - * Do some basic checks on the certificate chain. - * - * Certificate verification consists of a number of checks: - * - The date of the certificate is after the start date. - * - The date of the certificate is before the finish date. - * - A root certificate exists in the certificate store. - * - That the certificate(s) are not self-signed. - * - The certificate chain is valid. - * - The signature of the certificate is valid. - * - Basic constraints - */ -int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert, int *pathLenConstraint) -{ - int ret = X509_OK, i = 0; - bigint *cert_sig; - X509_CTX *next_cert = NULL; - BI_CTX *ctx = NULL; - bigint *mod = NULL, *expn = NULL; - int match_ca_cert = 0; - //struct timeval tv; - uint8_t is_self_signed = 0; - - if (cert == NULL) - { - ret = X509_VFY_ERROR_NO_TRUSTED_CERT; - goto end_verify; - } - - /* a self-signed certificate that is not in the CA store - use this - to check the signature */ - if (asn1_compare_dn(cert->ca_cert_dn, cert->cert_dn) == 0) - { - is_self_signed = 1; - ctx = cert->rsa_ctx->bi_ctx; - mod = cert->rsa_ctx->m; - expn = cert->rsa_ctx->e; - } - - /* - gettimeofday(&tv, NULL); - - / * check the not before date * / - if (tv.tv_sec < cert->not_before) - { - ret = X509_VFY_ERROR_NOT_YET_VALID; - goto end_verify; - } - - / * check the not after date * / - if (tv.tv_sec > cert->not_after) - { - ret = X509_VFY_ERROR_EXPIRED; - goto end_verify; - } - */ - - if (cert->basic_constraint_present) - { - /* If the cA boolean is not asserted, - then the keyCertSign bit in the key usage extension MUST NOT be - asserted. */ - if (!cert->basic_constraint_cA && - IS_SET_KEY_USAGE_FLAG(cert, KEY_USAGE_KEY_CERT_SIGN)) - { - ret = X509_VFY_ERROR_BASIC_CONSTRAINT; - goto end_verify; - } - - /* The pathLenConstraint field is meaningful only if the cA boolean is - asserted and the key usage extension, if present, asserts the - keyCertSign bit. In this case, it gives the maximum number of - non-self-issued intermediate certificates that may follow this - certificate in a valid certification path. */ - if (cert->basic_constraint_cA && - (!cert->key_usage_present || - IS_SET_KEY_USAGE_FLAG(cert, KEY_USAGE_KEY_CERT_SIGN)) && - (cert->basic_constraint_pathLenConstraint+1) < *pathLenConstraint) - { - ret = X509_VFY_ERROR_BASIC_CONSTRAINT; - goto end_verify; - } - } - - next_cert = cert->next; - - /* last cert in the chain - look for a trusted cert */ - if (next_cert == NULL) - { - if (ca_cert_ctx != NULL) - { - /* go thru the CA store */ - while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i]) - { - /* the extension is present but the cA boolean is not - asserted, then the certified public key MUST NOT be used - to verify certificate signatures. */ - if (cert->basic_constraint_present && - !ca_cert_ctx->cert[i]->basic_constraint_cA) - continue; - - if (asn1_compare_dn(cert->ca_cert_dn, - ca_cert_ctx->cert[i]->cert_dn) == 0) - { - /* use this CA certificate for signature verification */ - match_ca_cert = true; - ctx = ca_cert_ctx->cert[i]->rsa_ctx->bi_ctx; - mod = ca_cert_ctx->cert[i]->rsa_ctx->m; - expn = ca_cert_ctx->cert[i]->rsa_ctx->e; - - - break; - } - - i++; - } - } - - /* couldn't find a trusted cert (& let self-signed errors - be returned) */ - if (!match_ca_cert && !is_self_signed) - { - ret = X509_VFY_ERROR_NO_TRUSTED_CERT; - goto end_verify; - } - } - else if (asn1_compare_dn(cert->ca_cert_dn, next_cert->cert_dn) != 0) - { - /* check the chain */ - ret = X509_VFY_ERROR_INVALID_CHAIN; - goto end_verify; - } - else /* use the next certificate in the chain for signature verify */ - { - ctx = next_cert->rsa_ctx->bi_ctx; - mod = next_cert->rsa_ctx->m; - expn = next_cert->rsa_ctx->e; - } - - /* cert is self signed */ - if (!match_ca_cert && is_self_signed) - { - ret = X509_VFY_ERROR_SELF_SIGNED; - goto end_verify; - } - - /* check the signature */ - cert_sig = sig_verify(ctx, cert->signature, cert->sig_len, - bi_clone(ctx, mod), bi_clone(ctx, expn)); - - if (cert_sig && cert->digest) - { - if (bi_compare(cert_sig, cert->digest) != 0) - ret = X509_VFY_ERROR_BAD_SIGNATURE; - - - bi_free(ctx, cert_sig); - } - else - { - ret = X509_VFY_ERROR_BAD_SIGNATURE; - } - - if (ret) - goto end_verify; - - /* go down the certificate chain using recursion. */ - if (next_cert != NULL) - { - (*pathLenConstraint)++; /* don't include last certificate */ - ret = x509_verify(ca_cert_ctx, next_cert, pathLenConstraint); - } - -end_verify: - return ret; -} diff --git a/cores/esp8266/axtls/x509.h b/cores/esp8266/axtls/x509.h deleted file mode 100644 index 35f2bcfb08..0000000000 --- a/cores/esp8266/axtls/x509.h +++ /dev/null @@ -1,83 +0,0 @@ -#ifndef HEADER_X509_H -#define HEADER_X509_H - -#define CONFIG_X509_MAX_CA_CERTS 1 - -#include "rsa.h" -/************************************************************************** - * X509 declarations - **************************************************************************/ -#define X509_OK 0 -#define X509_NOT_OK -1 -#define X509_VFY_ERROR_NO_TRUSTED_CERT -2 -#define X509_VFY_ERROR_BAD_SIGNATURE -3 -#define X509_VFY_ERROR_NOT_YET_VALID -4 -#define X509_VFY_ERROR_EXPIRED -5 -#define X509_VFY_ERROR_SELF_SIGNED -6 -#define X509_VFY_ERROR_INVALID_CHAIN -7 -#define X509_VFY_ERROR_UNSUPPORTED_DIGEST -8 -#define X509_INVALID_PRIV_KEY -9 -#define X509_MAX_CERTS -10 -#define X509_VFY_ERROR_BASIC_CONSTRAINT -11 - -/* - * The Distinguished Name - */ -#define X509_NUM_DN_TYPES 6 -#define X509_COMMON_NAME 0 -#define X509_ORGANIZATION 1 -#define X509_ORGANIZATIONAL_UNIT 2 -#define X509_LOCATION 3 -#define X509_COUNTRY 4 -#define X509_STATE 5 - -/* - * Key Usage bits - */ -#define IS_SET_KEY_USAGE_FLAG(A, B) (A->key_usage & B) - -#define KEY_USAGE_DIGITAL_SIGNATURE 0x0080 -#define KEY_USAGE_NON_REPUDIATION 0x0040 -#define KEY_USAGE_KEY_ENCIPHERMENT 0x0020 -#define KEY_USAGE_DATA_ENCIPHERMENT 0x0010 -#define KEY_USAGE_KEY_AGREEMENT 0x0008 -#define KEY_USAGE_KEY_CERT_SIGN 0x0004 -#define KEY_USAGE_CRL_SIGN 0x0002 -#define KEY_USAGE_ENCIPHER_ONLY 0x0001 -#define KEY_USAGE_DECIPHER_ONLY 0x8000 - -struct _x509_ctx -{ - char *ca_cert_dn[X509_NUM_DN_TYPES]; - char *cert_dn[X509_NUM_DN_TYPES]; - char **subject_alt_dnsnames; - time_t not_before; - time_t not_after; - uint8_t *signature; - RSA_CTX *rsa_ctx; - bigint *digest; - uint16_t sig_len; - uint8_t sig_type; - bool basic_constraint_present; - bool basic_constraint_is_critical; - bool key_usage_present; - bool key_usage_is_critical; - bool subject_alt_name_present; - bool subject_alt_name_is_critical; - bool basic_constraint_cA; - int basic_constraint_pathLenConstraint; - uint32_t key_usage; - struct _x509_ctx *next; -}; - -typedef struct _x509_ctx X509_CTX; - -typedef struct -{ - X509_CTX *cert[CONFIG_X509_MAX_CA_CERTS]; -} CA_CERT_CTX; - -int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx); -void x509_free(X509_CTX *x509_ctx); -int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert, int *pathLenConstraint); -#endif diff --git a/cores/esp8266/axtls/bigint.h b/tools/sdk/include/crypto/bigint.h similarity index 81% rename from cores/esp8266/axtls/bigint.h rename to tools/sdk/include/crypto/bigint.h index 5ba450bd9c..f8915e994d 100644 --- a/cores/esp8266/axtls/bigint.h +++ b/tools/sdk/include/crypto/bigint.h @@ -1,18 +1,18 @@ /* * Copyright (c) 2007, Cameron Rich - * + * * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without + * + * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - * * Redistributions of source code must retain the above copyright notice, + * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * * Neither the name of the axTLS project nor the names of its contributors - * may be used to endorse or promote products derived from this software + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS @@ -31,7 +31,7 @@ #ifndef BIGINT_HEADER #define BIGINT_HEADER -#include "bigint_impl.h" +#include "crypto/crypto.h" BI_CTX *bi_initialize(void); void bi_terminate(BI_CTX *ctx); @@ -47,7 +47,7 @@ bigint *int_to_bi(BI_CTX *ctx, comp i); /* the functions that actually do something interesting */ bigint *bi_add(BI_CTX *ctx, bigint *bia, bigint *bib); -bigint *bi_subtract(BI_CTX *ctx, bigint *bia, +bigint *bi_subtract(BI_CTX *ctx, bigint *bia, bigint *bib, int *is_negative); bigint *bi_divide(BI_CTX *ctx, bigint *bia, bigint *bim, int is_mod); bigint *bi_multiply(BI_CTX *ctx, bigint *bia, bigint *bib); @@ -57,6 +57,11 @@ int bi_compare(bigint *bia, bigint *bib); void bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset); void bi_free_mod(BI_CTX *ctx, int mod_offset); +#ifdef CONFIG_SSL_FULL_MODE +void bi_print(const char *label, bigint *bi); +bigint *bi_str_import(BI_CTX *ctx, const char *data); +#endif + /** * @def bi_mod * Find the residue of B. bi_set_mod() must be called before hand. @@ -68,10 +73,27 @@ void bi_free_mod(BI_CTX *ctx, int mod_offset); * appropriate reduction technique (which is bi_mod() when doing classical * reduction). */ +#if defined(CONFIG_BIGINT_MONTGOMERY) +#define bi_residue(A, B) bi_mont(A, B) +bigint *bi_mont(BI_CTX *ctx, bigint *bixy); +#elif defined(CONFIG_BIGINT_BARRETT) +#define bi_residue(A, B) bi_barrett(A, B) +bigint *bi_barrett(BI_CTX *ctx, bigint *bi); +#else /* if defined(CONFIG_BIGINT_CLASSICAL) */ #define bi_residue(A, B) bi_mod(A, B) +#endif + +#ifdef CONFIG_BIGINT_SQUARE +bigint *bi_square(BI_CTX *ctx, bigint *bi); +#else #define bi_square(A, B) bi_multiply(A, bi_copy(B), B) +#endif + +#ifdef CONFIG_BIGINT_CRT bigint *bi_crt(BI_CTX *ctx, bigint *bi, bigint *dP, bigint *dQ, bigint *p, bigint *q, bigint *qInv); #endif + +#endif diff --git a/cores/esp8266/axtls/bigint_impl.h b/tools/sdk/include/crypto/bigint_impl.h similarity index 66% rename from cores/esp8266/axtls/bigint_impl.h rename to tools/sdk/include/crypto/bigint_impl.h index 481d8a149e..fef6e0378b 100644 --- a/cores/esp8266/axtls/bigint_impl.h +++ b/tools/sdk/include/crypto/bigint_impl.h @@ -30,15 +30,19 @@ #ifndef BIGINT_IMPL_HEADER #define BIGINT_IMPL_HEADER -#include /* Maintain a number of precomputed variables when doing reduction */ #define BIGINT_M_OFFSET 0 /**< Normal modulo offset. */ +#ifdef CONFIG_BIGINT_CRT #define BIGINT_P_OFFSET 1 /**< p modulo offset. */ #define BIGINT_Q_OFFSET 2 /**< q module offset. */ #define BIGINT_NUM_MODS 3 /**< The number of modulus constants used. */ +#else +#define BIGINT_NUM_MODS 1 +#endif /* Architecture specific functions for big ints */ +#if defined(CONFIG_INTEGER_8BIT) #define COMP_RADIX 256U /**< Max component + 1 */ #define COMP_MAX 0xFFFFU/**< (Max dbl comp -1) */ #define COMP_BIT_SIZE 8 /**< Number of bits in a component. */ @@ -47,6 +51,30 @@ typedef uint8_t comp; /**< A single precision component. */ typedef uint16_t long_comp; /**< A double precision component. */ typedef int16_t slong_comp; /**< A signed double precision component. */ +#elif defined(CONFIG_INTEGER_16BIT) +#define COMP_RADIX 65536U /**< Max component + 1 */ +#define COMP_MAX 0xFFFFFFFFU/**< (Max dbl comp -1) */ +#define COMP_BIT_SIZE 16 /**< Number of bits in a component. */ +#define COMP_BYTE_SIZE 2 /**< Number of bytes in a component. */ +#define COMP_NUM_NIBBLES 4 /**< Used For diagnostics only. */ +typedef uint16_t comp; /**< A single precision component. */ +typedef uint32_t long_comp; /**< A double precision component. */ +typedef int32_t slong_comp; /**< A signed double precision component. */ +#else /* regular 32 bit */ +#ifdef WIN32 +#define COMP_RADIX 4294967296i64 +#define COMP_MAX 0xFFFFFFFFFFFFFFFFui64 +#else +#define COMP_RADIX 4294967296ULL /**< Max component + 1 */ +#define COMP_MAX 0xFFFFFFFFFFFFFFFFULL/**< (Max dbl comp -1) */ +#endif +#define COMP_BIT_SIZE 32 /**< Number of bits in a component. */ +#define COMP_BYTE_SIZE 4 /**< Number of bytes in a component. */ +#define COMP_NUM_NIBBLES 8 /**< Used For diagnostics only. */ +typedef uint32_t comp; /**< A single precision component. */ +typedef uint64_t long_comp; /**< A double precision component. */ +typedef int64_t slong_comp; /**< A signed double precision component. */ +#endif /** * @struct _bigint @@ -73,14 +101,31 @@ typedef struct /**< A big integer "session" context. */ bigint *free_list; /**< Bigints not used. */ bigint *bi_radix; /**< The radix used. */ bigint *bi_mod[BIGINT_NUM_MODS]; /**< modulus */ + +#if defined(CONFIG_BIGINT_MONTGOMERY) + bigint *bi_RR_mod_m[BIGINT_NUM_MODS]; /**< R^2 mod m */ + bigint *bi_R_mod_m[BIGINT_NUM_MODS]; /**< R mod m */ + comp N0_dash[BIGINT_NUM_MODS]; +#elif defined(CONFIG_BIGINT_BARRETT) + bigint *bi_mu[BIGINT_NUM_MODS]; /**< Storage for mu */ +#endif bigint *bi_normalised_mod[BIGINT_NUM_MODS]; /**< Normalised mod storage. */ bigint **g; /**< Used by sliding-window. */ int window; /**< The size of the sliding window */ int active_count; /**< Number of active bigints. */ int free_count; /**< Number of free bigints. */ + +#ifdef CONFIG_BIGINT_MONTGOMERY + uint8_t use_classical; /**< Use classical reduction. */ +#endif uint8_t mod_offset; /**< The mod offset we are using */ } BI_CTX; +#ifndef WIN32 +#define max(a,b) ((a)>(b)?(a):(b)) /**< Find the maximum of 2 numbers. */ +#define min(a,b) ((a)<(b)?(a):(b)) /**< Find the minimum of 2 numbers. */ +#endif + #define PERMANENT 0x7FFF55AA /**< A magic number for permanents. */ #endif diff --git a/tools/sdk/include/crypto/crypto.h b/tools/sdk/include/crypto/crypto.h new file mode 100644 index 0000000000..7ec8238796 --- /dev/null +++ b/tools/sdk/include/crypto/crypto.h @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2007-2016, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file crypto.h + */ + +#ifndef HEADER_CRYPTO_H +#define HEADER_CRYPTO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "crypto/bigint_impl.h" +#include "crypto/bigint.h" + +#ifndef STDCALL +#define STDCALL +#endif +#ifndef EXP_FUNC +#define EXP_FUNC +#endif + + +/* enable features based on a 'super-set' capbaility. */ +#if defined(CONFIG_SSL_FULL_MODE) +#define CONFIG_SSL_ENABLE_CLIENT +#define CONFIG_SSL_CERT_VERIFICATION +#elif defined(CONFIG_SSL_ENABLE_CLIENT) +#define CONFIG_SSL_CERT_VERIFICATION +#endif + +/************************************************************************** + * AES declarations + **************************************************************************/ + +#define AES_MAXROUNDS 14 +#define AES_BLOCKSIZE 16 +#define AES_IV_SIZE 16 + +typedef struct aes_key_st +{ + uint16_t rounds; + uint16_t key_size; + uint32_t ks[(AES_MAXROUNDS+1)*8]; + uint8_t iv[AES_IV_SIZE]; +} AES_CTX; + +typedef enum +{ + AES_MODE_128, + AES_MODE_256 +} AES_MODE; + +void AES_set_key(AES_CTX *ctx, const uint8_t *key, + const uint8_t *iv, AES_MODE mode); +void AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg, + uint8_t *out, int length); +void AES_cbc_decrypt(AES_CTX *ks, const uint8_t *in, uint8_t *out, int length); +void AES_convert_key(AES_CTX *ctx); + +/************************************************************************** + * RC4 declarations + **************************************************************************/ + +typedef struct +{ + uint8_t x, y, m[256]; +} RC4_CTX; + +void RC4_setup(RC4_CTX *s, const uint8_t *key, int length); +void RC4_crypt(RC4_CTX *s, const uint8_t *msg, uint8_t *data, int length); + +/************************************************************************** + * SHA1 declarations + **************************************************************************/ + +#define SHA1_SIZE 20 + +/* + * This structure will hold context information for the SHA-1 + * hashing operation + */ +typedef struct +{ + uint32_t Intermediate_Hash[SHA1_SIZE/4]; /* Message Digest */ + uint32_t Length_Low; /* Message length in bits */ + uint32_t Length_High; /* Message length in bits */ + uint16_t Message_Block_Index; /* Index into message block array */ + uint8_t Message_Block[64]; /* 512-bit message blocks */ +} SHA1_CTX; + +void SHA1_Init(SHA1_CTX *); +void SHA1_Update(SHA1_CTX *, const uint8_t * msg, int len); +void SHA1_Final(uint8_t *digest, SHA1_CTX *); + +/************************************************************************** + * SHA256 declarations + **************************************************************************/ + +#define SHA256_SIZE 32 + +typedef struct +{ + uint32_t total[2]; + uint32_t state[8]; + uint8_t buffer[64]; +} SHA256_CTX; + +void SHA256_Init(SHA256_CTX *c); +void SHA256_Update(SHA256_CTX *, const uint8_t *input, int len); +void SHA256_Final(uint8_t *digest, SHA256_CTX *); + +/************************************************************************** + * SHA512 declarations + **************************************************************************/ + +#define SHA512_SIZE 64 + +typedef struct +{ + union + { + uint64_t h[8]; + uint8_t digest[64]; + } h_dig; + union + { + uint64_t w[80]; + uint8_t buffer[128]; + } w_buf; + size_t size; + uint64_t totalSize; +} SHA512_CTX; + +void SHA512_Init(SHA512_CTX *c); +void SHA512_Update(SHA512_CTX *, const uint8_t *input, int len); +void SHA512_Final(uint8_t *digest, SHA512_CTX *); + +/************************************************************************** + * SHA384 declarations + **************************************************************************/ + +#define SHA384_SIZE 48 + +typedef SHA512_CTX SHA384_CTX; +void SHA384_Init(SHA384_CTX *c); +void SHA384_Update(SHA384_CTX *, const uint8_t *input, int len); +void SHA384_Final(uint8_t *digest, SHA384_CTX *); + +/************************************************************************** + * MD5 declarations + **************************************************************************/ + +#define MD5_SIZE 16 + +typedef struct +{ + uint32_t state[4]; /* state (ABCD) */ + uint32_t count[2]; /* number of bits, modulo 2^64 (lsb first) */ + uint8_t buffer[64]; /* input buffer */ +} MD5_CTX; + +EXP_FUNC void STDCALL MD5_Init(MD5_CTX *); +EXP_FUNC void STDCALL MD5_Update(MD5_CTX *, const uint8_t *msg, int len); +EXP_FUNC void STDCALL MD5_Final(uint8_t *digest, MD5_CTX *); + +/************************************************************************** + * HMAC declarations + **************************************************************************/ +void hmac_md5(const uint8_t *msg, int length, const uint8_t *key, + int key_len, uint8_t *digest); +void hmac_sha1(const uint8_t *msg, int length, const uint8_t *key, + int key_len, uint8_t *digest); +void hmac_sha256(const uint8_t *msg, int length, const uint8_t *key, + int key_len, uint8_t *digest); + +/************************************************************************** + * RSA declarations + **************************************************************************/ + +typedef struct +{ + bigint *m; /* modulus */ + bigint *e; /* public exponent */ + bigint *d; /* private exponent */ +#ifdef CONFIG_BIGINT_CRT + bigint *p; /* p as in m = pq */ + bigint *q; /* q as in m = pq */ + bigint *dP; /* d mod (p-1) */ + bigint *dQ; /* d mod (q-1) */ + bigint *qInv; /* q^-1 mod p */ +#endif + int num_octets; + BI_CTX *bi_ctx; +} RSA_CTX; + +void RSA_priv_key_new(RSA_CTX **rsa_ctx, + const uint8_t *modulus, int mod_len, + const uint8_t *pub_exp, int pub_len, + const uint8_t *priv_exp, int priv_len +#ifdef CONFIG_BIGINT_CRT + , const uint8_t *p, int p_len, + const uint8_t *q, int q_len, + const uint8_t *dP, int dP_len, + const uint8_t *dQ, int dQ_len, + const uint8_t *qInv, int qInv_len +#endif + ); +void RSA_pub_key_new(RSA_CTX **rsa_ctx, + const uint8_t *modulus, int mod_len, + const uint8_t *pub_exp, int pub_len); +void RSA_free(RSA_CTX *ctx); +int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint8_t *out_data, + int out_len, int is_decryption); +bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg); +#if defined(CONFIG_SSL_CERT_VERIFICATION) || defined(CONFIG_SSL_GENERATE_X509_CERT) +bigint *RSA_sign_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len, + bigint *modulus, bigint *pub_exp); +bigint *RSA_public(const RSA_CTX * c, bigint *bi_msg); +int RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len, + uint8_t *out_data, int is_signing); +void RSA_print(const RSA_CTX *ctx); +#endif + +/************************************************************************** + * RNG declarations + **************************************************************************/ +EXP_FUNC void STDCALL RNG_initialize(void); +EXP_FUNC void STDCALL RNG_custom_init(const uint8_t *seed_buf, int size); +EXP_FUNC void STDCALL RNG_terminate(void); +EXP_FUNC int STDCALL get_random(int num_rand_bytes, uint8_t *rand_data); +int get_random_NZ(int num_rand_bytes, uint8_t *rand_data); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tools/sdk/include/crypto/os_int.h b/tools/sdk/include/crypto/os_int.h new file mode 100644 index 0000000000..a849e5b1a4 --- /dev/null +++ b/tools/sdk/include/crypto/os_int.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2012-2016, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file os_int.h + * + * Ensure a consistent bit size + */ + +#ifndef HEADER_OS_INT_H +#define HEADER_OS_INT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(WIN32) +typedef UINT8 uint8_t; +typedef INT8 int8_t; +typedef UINT16 uint16_t; +typedef INT16 int16_t; +typedef UINT32 uint32_t; +typedef INT32 int32_t; +typedef UINT64 uint64_t; +typedef INT64 int64_t; +#else /* Not Win32 */ + +#ifdef CONFIG_PLATFORM_SOLARIS +#include +#else +#include +#endif /* Not Solaris */ + +#endif /* Not Win32 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tools/sdk/include/ssl/config.h b/tools/sdk/include/ssl/config.h new file mode 100644 index 0000000000..8b90bb09c4 --- /dev/null +++ b/tools/sdk/include/ssl/config.h @@ -0,0 +1,127 @@ +/* + * Automatically generated header file: don't edit + */ + +#define HAVE_DOT_CONFIG 1 +#undef CONFIG_PLATFORM_LINUX +#define CONFIG_PLATFORM_CYGWIN 1 +#undef CONFIG_PLATFORM_WIN32 + +/* + * General Configuration + */ +#define PREFIX "/usr/local" +#define CONFIG_DEBUG 1 +#undef CONFIG_STRIP_UNWANTED_SECTIONS +#undef CONFIG_VISUAL_STUDIO_7_0 +#undef CONFIG_VISUAL_STUDIO_8_0 +#undef CONFIG_VISUAL_STUDIO_10_0 +#define CONFIG_VISUAL_STUDIO_7_0_BASE "" +#define CONFIG_VISUAL_STUDIO_8_0_BASE "" +#define CONFIG_VISUAL_STUDIO_10_0_BASE "" +#define CONFIG_EXTRA_CFLAGS_OPTIONS "" +#define CONFIG_EXTRA_LDFLAGS_OPTIONS "" + +/* + * SSL Library + */ +#undef CONFIG_SSL_SERVER_ONLY +#define CONFIG_SSL_CERT_VERIFICATION +#undef CONFIG_SSL_ENABLE_CLIENT +#define CONFIG_SSL_FULL_MODE 1 +#undef CONFIG_SSL_SKELETON_MODE +#undef CONFIG_SSL_PROT_LOW +#define CONFIG_SSL_PROT_MEDIUM 1 +#undef CONFIG_SSL_PROT_HIGH +#undef CONFIG_SSL_USE_DEFAULT_KEY +#define CONFIG_SSL_PRIVATE_KEY_LOCATION "" +#define CONFIG_SSL_PRIVATE_KEY_PASSWORD "" +#define CONFIG_SSL_X509_CERT_LOCATION "" +#undef CONFIG_SSL_GENERATE_X509_CERT +#define CONFIG_SSL_X509_COMMON_NAME "" +#define CONFIG_SSL_X509_ORGANIZATION_NAME "" +#define CONFIG_SSL_X509_ORGANIZATION_UNIT_NAME "" +#undef CONFIG_SSL_ENABLE_V23_HANDSHAKE +#define CONFIG_SSL_HAS_PEM 1 +#undef CONFIG_SSL_USE_PKCS12 +#define CONFIG_SSL_EXPIRY_TIME 24 +#define CONFIG_X509_MAX_CA_CERTS 150 +#define CONFIG_SSL_MAX_CERTS 1 +#undef CONFIG_SSL_CTX_MUTEXING +#undef CONFIG_USE_DEV_URANDOM +#undef CONFIG_WIN32_USE_CRYPTO_LIB +#undef CONFIG_OPENSSL_COMPATIBLE +#undef CONFIG_PERFORMANCE_TESTING +#define CONFIG_SSL_TEST 1 +#undef CONFIG_AXTLSWRAP +#define CONFIG_AXHTTPD 1 + +/* + * Axhttpd Configuration + */ +#undef CONFIG_HTTP_STATIC_BUILD +#define CONFIG_HTTP_PORT 80 +#define CONFIG_HTTP_HTTPS_PORT 443 +#define CONFIG_HTTP_SESSION_CACHE_SIZE 5 +#define CONFIG_HTTP_WEBROOT "../www" +#define CONFIG_HTTP_TIMEOUT 300 + +/* + * CGI + */ +#undef CONFIG_HTTP_HAS_CGI +#define CONFIG_HTTP_CGI_EXTENSIONS ".lua,.lp,.php" +#define CONFIG_HTTP_ENABLE_LUA 1 +#define CONFIG_HTTP_LUA_PREFIX "/usr" +#undef CONFIG_HTTP_BUILD_LUA +#define CONFIG_HTTP_CGI_LAUNCHER "/usr/bin/cgi" +#define CONFIG_HTTP_DIRECTORIES 1 +#define CONFIG_HTTP_HAS_AUTHORIZATION 1 +#undef CONFIG_HTTP_HAS_IPV6 +#undef CONFIG_HTTP_ENABLE_DIFFERENT_USER +#define CONFIG_HTTP_USER "" +#define CONFIG_HTTP_VERBOSE 0 +#undef CONFIG_HTTP_IS_DAEMON + +/* + * Language Bindings + */ +#undef CONFIG_BINDINGS +#undef CONFIG_CSHARP_BINDINGS +#undef CONFIG_VBNET_BINDINGS +#define CONFIG_DOT_NET_FRAMEWORK_BASE "" +#undef CONFIG_JAVA_BINDINGS +#define CONFIG_JAVA_HOME "" +#undef CONFIG_PERL_BINDINGS +#define CONFIG_PERL_CORE "" +#define CONFIG_PERL_LIB "" +#undef CONFIG_LUA_BINDINGS +#define CONFIG_LUA_CORE "" + +/* + * Samples + */ +#define CONFIG_SAMPLES 1 +#define CONFIG_C_SAMPLES 1 +#undef CONFIG_CSHARP_SAMPLES +#undef CONFIG_VBNET_SAMPLES +#undef CONFIG_JAVA_SAMPLES +#undef CONFIG_PERL_SAMPLES +#undef CONFIG_LUA_SAMPLES + +/* + * BigInt Options + */ +#undef CONFIG_BIGINT_CLASSICAL +#undef CONFIG_BIGINT_MONTGOMERY +#define CONFIG_BIGINT_BARRETT 1 +#define CONFIG_BIGINT_CRT 1 +#undef CONFIG_BIGINT_KARATSUBA +#define MUL_KARATSUBA_THRESH +#define SQU_KARATSUBA_THRESH +#define CONFIG_BIGINT_SLIDING_WINDOW 1 +#define CONFIG_BIGINT_SQUARE 1 +#define CONFIG_BIGINT_CHECK_ON 1 +#define CONFIG_INTEGER_32BIT 1 +#undef CONFIG_INTEGER_16BIT +#undef CONFIG_INTEGER_8BIT diff --git a/tools/sdk/include/ssl/crypto_misc.h b/tools/sdk/include/ssl/crypto_misc.h new file mode 100644 index 0000000000..97626bba77 --- /dev/null +++ b/tools/sdk/include/ssl/crypto_misc.h @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2007-2015, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file crypto_misc.h + */ + +#ifndef HEADER_CRYPTO_MISC_H +#define HEADER_CRYPTO_MISC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ssl/config.h" +#include "crypto/crypto.h" +#include "crypto/bigint.h" + +/************************************************************************** + * X509 declarations + **************************************************************************/ +#define X509_OK 0 +#define X509_NOT_OK -1 +#define X509_VFY_ERROR_NO_TRUSTED_CERT -2 +#define X509_VFY_ERROR_BAD_SIGNATURE -3 +#define X509_VFY_ERROR_NOT_YET_VALID -4 +#define X509_VFY_ERROR_EXPIRED -5 +#define X509_VFY_ERROR_SELF_SIGNED -6 +#define X509_VFY_ERROR_INVALID_CHAIN -7 +#define X509_VFY_ERROR_UNSUPPORTED_DIGEST -8 +#define X509_INVALID_PRIV_KEY -9 +#define X509_MAX_CERTS -10 + +/* + * The Distinguished Name + */ +#define X509_NUM_DN_TYPES 3 +#define X509_COMMON_NAME 0 +#define X509_ORGANIZATION 1 +#define X509_ORGANIZATIONAL_UNIT 2 + +struct _x509_ctx +{ + char *ca_cert_dn[X509_NUM_DN_TYPES]; + char *cert_dn[X509_NUM_DN_TYPES]; + char **subject_alt_dnsnames; + time_t not_before; + time_t not_after; + uint8_t *signature; + uint16_t sig_len; + uint8_t sig_type; + RSA_CTX *rsa_ctx; + bigint *digest; + uint8_t *fingerprint; + uint8_t *spki_sha256; + struct _x509_ctx *next; +}; + +typedef struct _x509_ctx X509_CTX; + +#ifdef CONFIG_SSL_CERT_VERIFICATION +typedef struct +{ + X509_CTX *cert[CONFIG_X509_MAX_CA_CERTS]; +} CA_CERT_CTX; +#endif + +int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx); +void x509_free(X509_CTX *x509_ctx); +#ifdef CONFIG_SSL_CERT_VERIFICATION +int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert); +#endif +#ifdef CONFIG_SSL_FULL_MODE +void x509_print(const X509_CTX *cert, CA_CERT_CTX *ca_cert_ctx); +const char * x509_display_error(int error); +#endif + +/************************************************************************** + * ASN1 declarations + **************************************************************************/ +#define ASN1_INTEGER 0x02 +#define ASN1_BIT_STRING 0x03 +#define ASN1_OCTET_STRING 0x04 +#define ASN1_NULL 0x05 +#define ASN1_PRINTABLE_STR2 0x0C +#define ASN1_OID 0x06 +#define ASN1_PRINTABLE_STR2 0x0C +#define ASN1_PRINTABLE_STR 0x13 +#define ASN1_TELETEX_STR 0x14 +#define ASN1_IA5_STR 0x16 +#define ASN1_UTC_TIME 0x17 +#define ASN1_GENERALIZED_TIME 0x18 +#define ASN1_UNICODE_STR 0x1e +#define ASN1_SEQUENCE 0x30 +#define ASN1_CONTEXT_DNSNAME 0x82 +#define ASN1_SET 0x31 +#define ASN1_V3_DATA 0xa3 +#define ASN1_IMPLICIT_TAG 0x80 +#define ASN1_CONTEXT_DNSNAME 0x82 +#define ASN1_EXPLICIT_TAG 0xa0 +#define ASN1_V3_DATA 0xa3 + +#define SIG_TYPE_MD5 0x04 +#define SIG_TYPE_SHA1 0x05 +#define SIG_TYPE_SHA256 0x0b +#define SIG_TYPE_SHA384 0x0c +#define SIG_TYPE_SHA512 0x0d + +uint32_t get_asn1_length(const uint8_t *buf, int *offset); +int asn1_get_private_key(const uint8_t *buf, int len, RSA_CTX **rsa_ctx); +int asn1_next_obj(const uint8_t *buf, int *offset, int obj_type); +int asn1_skip_obj(const uint8_t *buf, int *offset, int obj_type); +int asn1_get_int(const uint8_t *buf, int *offset, uint8_t **object); +int asn1_version(const uint8_t *cert, int *offset, X509_CTX *x509_ctx); +int asn1_validity(const uint8_t *cert, int *offset, X509_CTX *x509_ctx); +int asn1_name(const uint8_t *cert, int *offset, char *dn[]); +int asn1_public_key(const uint8_t *cert, int *offset, X509_CTX *x509_ctx); +#ifdef CONFIG_SSL_CERT_VERIFICATION +int asn1_signature(const uint8_t *cert, int *offset, X509_CTX *x509_ctx); +int asn1_find_subjectaltname(const uint8_t* cert, int offset); +int asn1_compare_dn(char * const dn1[], char * const dn2[]); +#endif /* CONFIG_SSL_CERT_VERIFICATION */ +int asn1_signature_type(const uint8_t *cert, + int *offset, X509_CTX *x509_ctx); + +/************************************************************************** + * MISC declarations + **************************************************************************/ +#define SALT_SIZE 8 + +extern const char * const unsupported_str; + +typedef void (*crypt_func)(void *, const uint8_t *, uint8_t *, int); +typedef void (*hmac_func)(const uint8_t *msg, int length, const uint8_t *key, + int key_len, uint8_t *digest); + +int get_file(const char *filename, uint8_t **buf); + +#if defined(CONFIG_SSL_FULL_MODE) || defined(WIN32) || defined(CONFIG_DEBUG) +EXP_FUNC void STDCALL print_blob(const char *format, const uint8_t *data, int size, ...); +#else + #define print_blob(...) +#endif + +EXP_FUNC int STDCALL base64_decode(const char *in, int len, + uint8_t *out, int *outlen); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tools/sdk/include/ssl/os_int.h b/tools/sdk/include/ssl/os_int.h new file mode 100644 index 0000000000..a6207f1d42 --- /dev/null +++ b/tools/sdk/include/ssl/os_int.h @@ -0,0 +1,8 @@ +#ifndef OS_INT_H +#define OS_INT_H + +#include +#include +#include + +#endif //OS_INT_H \ No newline at end of file diff --git a/tools/sdk/include/ssl/os_port.h b/tools/sdk/include/ssl/os_port.h new file mode 100644 index 0000000000..e672f102c2 --- /dev/null +++ b/tools/sdk/include/ssl/os_port.h @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2007-2016, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file os_port.h + * + * Some stuff to minimise the differences between windows and linux/unix + */ + +#ifndef HEADER_OS_PORT_H +#define HEADER_OS_PORT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "os_int.h" +#include "config.h" +#include + +#ifdef WIN32 +#define STDCALL __stdcall +#define EXP_FUNC __declspec(dllexport) +#else +#define STDCALL +#define EXP_FUNC +#endif + +#if defined(_WIN32_WCE) +#undef WIN32 +#define WIN32 +#endif + +#if defined(ESP8266) + +#include "util/time.h" +#include +#define alloca(size) __builtin_alloca(size) +#define TTY_FLUSH() +#ifdef putc +#undef putc +#endif +#define putc(x, f) ets_putc(x) +#ifdef printf +#undef printf +#endif +#define printf(...) ets_printf(__VA_ARGS__) + +#define SOCKET_READ(A,B,C) ax_port_read(A,B,C) +#define SOCKET_WRITE(A,B,C) ax_port_write(A,B,C) +#define SOCKET_CLOSE(A) ax_port_close(A) +#define get_file ax_get_file +#define EWOULDBLOCK EAGAIN + +#define hmac_sha1 ax_hmac_sha1 +#define hmac_sha256 ax_hmac_sha256 +#define hmac_md5 ax_hmac_md5 + +#ifndef be64toh +# define __bswap_constant_64(x) \ + ((((x) & 0xff00000000000000ull) >> 56) \ + | (((x) & 0x00ff000000000000ull) >> 40) \ + | (((x) & 0x0000ff0000000000ull) >> 24) \ + | (((x) & 0x000000ff00000000ull) >> 8) \ + | (((x) & 0x00000000ff000000ull) << 8) \ + | (((x) & 0x0000000000ff0000ull) << 24) \ + | (((x) & 0x000000000000ff00ull) << 40) \ + | (((x) & 0x00000000000000ffull) << 56)) +#define be64toh(x) __bswap_constant_64(x) +#endif + +void ax_wdt_feed(); + +#elif defined(WIN32) + +/* Windows CE stuff */ +#if defined(_WIN32_WCE) +#include +#define abort() exit(1) +#else +#include +#include +#include +#include +#endif /* _WIN32_WCE */ + +#include +#include +#undef getpid +#undef open +#undef close +#undef sleep +#undef gettimeofday +#undef dup2 +#undef unlink + +#define SOCKET_READ(A,B,C) recv(A,B,C,0) +#define SOCKET_WRITE(A,B,C) send(A,B,C,0) +#define SOCKET_CLOSE(A) closesocket(A) +#define srandom(A) srand(A) +#define random() rand() +#define getpid() _getpid() +#define snprintf _snprintf +#define open(A,B) _open(A,B) +#define dup2(A,B) _dup2(A,B) +#define unlink(A) _unlink(A) +#define close(A) _close(A) +#define read(A,B,C) _read(A,B,C) +#define write(A,B,C) _write(A,B,C) +#define sleep(A) Sleep(A*1000) +#define usleep(A) Sleep(A/1000) +#define strdup(A) _strdup(A) +#define chroot(A) _chdir(A) +#define chdir(A) _chdir(A) +#define alloca(A) _alloca(A) +#ifndef lseek +#define lseek(A,B,C) _lseek(A,B,C) +#endif + +/* This fix gets around a problem where a win32 application on a cygwin xterm + doesn't display regular output (until a certain buffer limit) - but it works + fine under a normal DOS window. This is a hack to get around the issue - + see http://www.khngai.com/emacs/tty.php */ +#define TTY_FLUSH() if (!_isatty(_fileno(stdout))) fflush(stdout); + +/* + * automatically build some library dependencies. + */ +#pragma comment(lib, "WS2_32.lib") +#pragma comment(lib, "AdvAPI32.lib") + +typedef int socklen_t; + +EXP_FUNC void STDCALL gettimeofday(struct timeval* t,void* timezone); +EXP_FUNC int STDCALL strcasecmp(const char *s1, const char *s2); +EXP_FUNC int STDCALL getdomainname(char *buf, int buf_size); + +#else /* Not Win32 */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SOCKET_READ(A,B,C) read(A,B,C) +#define SOCKET_WRITE(A,B,C) write(A,B,C) +#define SOCKET_CLOSE(A) if (A >= 0) close(A) +#define TTY_FLUSH() + +#ifndef be64toh +#define be64toh(x) __be64_to_cpu(x) +#endif + +#endif /* Not Win32 */ + +/* some functions to mutate the way these work */ +inline uint32_t htonl(uint32_t n){ + return ((n & 0xff) << 24) | + ((n & 0xff00) << 8) | + ((n & 0xff0000UL) >> 8) | + ((n & 0xff000000UL) >> 24); +} + +#define ntohl htonl + +EXP_FUNC int STDCALL ax_open(const char *pathname, int flags); + +#ifdef CONFIG_PLATFORM_LINUX +void exit_now(const char *format, ...) __attribute((noreturn)); +#else +void exit_now(const char *format, ...); +#endif + +/* Mutexing definitions */ +#if defined(CONFIG_SSL_CTX_MUTEXING) +#if defined(WIN32) +#define SSL_CTX_MUTEX_TYPE HANDLE +#define SSL_CTX_MUTEX_INIT(A) A=CreateMutex(0, FALSE, 0) +#define SSL_CTX_MUTEX_DESTROY(A) CloseHandle(A) +#define SSL_CTX_LOCK(A) WaitForSingleObject(A, INFINITE) +#define SSL_CTX_UNLOCK(A) ReleaseMutex(A) +#else +#include +#define SSL_CTX_MUTEX_TYPE pthread_mutex_t +#define SSL_CTX_MUTEX_INIT(A) pthread_mutex_init(&A, NULL) +#define SSL_CTX_MUTEX_DESTROY(A) pthread_mutex_destroy(&A) +#define SSL_CTX_LOCK(A) pthread_mutex_lock(&A) +#define SSL_CTX_UNLOCK(A) pthread_mutex_unlock(&A) +#endif +#else /* no mutexing */ +#define SSL_CTX_MUTEX_INIT(A) +#define SSL_CTX_MUTEX_DESTROY(A) +#define SSL_CTX_LOCK(A) +#define SSL_CTX_UNLOCK(A) +#endif + +#ifndef PROGMEM +#define PROGMEM +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tools/sdk/include/ssl/ssl.h b/tools/sdk/include/ssl/ssl.h new file mode 100644 index 0000000000..f03ffbfbb4 --- /dev/null +++ b/tools/sdk/include/ssl/ssl.h @@ -0,0 +1,553 @@ +/* + * Copyright (c) 2007-2016, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @mainpage axTLS API + * + * @image html axolotl.jpg + * + * The axTLS library has features such as: + * - The TLSv1 SSL client/server protocol + * - No requirement to use any openssl libraries. + * - A choice between AES block (128/256 bit) and RC4 (128 bit) stream ciphers. + * - RSA encryption/decryption with variable sized keys (up to 4096 bits). + * - Certificate chaining and peer authentication. + * - Session resumption, session renegotiation. + * - ASN.1, X.509, PKCS#8, PKCS#12 keys/certificates with DER/PEM encoding. + * - Highly configurable compile time options. + * - Portable across many platforms (written in ANSI C), and has language + * bindings in C, C#, VB.NET, Java, Perl and Lua. + * - Partial openssl API compatibility (via a wrapper). + * - A very small footprint (around 50-60kB for the library in 'server-only' + * mode). + * - No dependencies on sockets - can use serial connections for example. + * - A very simple API - ~ 20 functions/methods. + * + * A list of these functions/methods are described below. + * + * @ref c_api + * + * @ref bigint_api + * + * @ref csharp_api + * + * @ref java_api + */ +#ifndef HEADER_SSL_H +#define HEADER_SSL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* need to predefine before ssl_lib.h gets to it */ +#define SSL_SESSION_ID_SIZE 32 + +#include "ssl/tls1.h" + +/* The optional parameters that can be given to the client/server SSL engine */ +#define SSL_CLIENT_AUTHENTICATION 0x00010000 +#define SSL_SERVER_VERIFY_LATER 0x00020000 +#define SSL_NO_DEFAULT_KEY 0x00040000 +#define SSL_DISPLAY_STATES 0x00080000 +#define SSL_DISPLAY_BYTES 0x00100000 +#define SSL_DISPLAY_CERTS 0x00200000 +#define SSL_DISPLAY_RSA 0x00400000 +#define SSL_CONNECT_IN_PARTS 0x00800000 +#define SSL_READ_BLOCKING 0x01000000 + +/* errors that can be generated */ +#define SSL_OK 0 +#define SSL_NOT_OK -1 +#define SSL_ERROR_DEAD -2 +#define SSL_CLOSE_NOTIFY -3 +#define SSL_ERROR_CONN_LOST -256 +#define SSL_ERROR_RECORD_OVERFLOW -257 +#define SSL_ERROR_SOCK_SETUP_FAILURE -258 +#define SSL_ERROR_INVALID_HANDSHAKE -260 +#define SSL_ERROR_INVALID_PROT_MSG -261 +#define SSL_ERROR_INVALID_HMAC -262 +#define SSL_ERROR_INVALID_VERSION -263 +#define SSL_ERROR_UNSUPPORTED_EXTENSION -264 +#define SSL_ERROR_INVALID_SESSION -265 +#define SSL_ERROR_NO_CIPHER -266 +#define SSL_ERROR_INVALID_CERT_HASH_ALG -267 +#define SSL_ERROR_BAD_CERTIFICATE -268 +#define SSL_ERROR_INVALID_KEY -269 +#define SSL_ERROR_FINISHED_INVALID -271 +#define SSL_ERROR_NO_CERT_DEFINED -272 +#define SSL_ERROR_NO_CLIENT_RENOG -273 +#define SSL_ERROR_NOT_SUPPORTED -274 +#define SSL_X509_OFFSET -512 +#define SSL_X509_ERROR(A) (SSL_X509_OFFSET+A) + +/* alert types that are recognized */ +#define SSL_ALERT_TYPE_WARNING 1 +#define SLL_ALERT_TYPE_FATAL 2 + +/* these are all the alerts that are recognized */ +#define SSL_ALERT_CLOSE_NOTIFY 0 +#define SSL_ALERT_UNEXPECTED_MESSAGE 10 +#define SSL_ALERT_BAD_RECORD_MAC 20 +#define SSL_ALERT_RECORD_OVERFLOW 22 +#define SSL_ALERT_HANDSHAKE_FAILURE 40 +#define SSL_ALERT_BAD_CERTIFICATE 42 +#define SSL_ALERT_UNSUPPORTED_CERTIFICATE 43 +#define SSL_ALERT_CERTIFICATE_EXPIRED 45 +#define SSL_ALERT_CERTIFICATE_UNKNOWN 46 +#define SSL_ALERT_ILLEGAL_PARAMETER 47 +#define SSL_ALERT_UNKNOWN_CA 48 +#define SSL_ALERT_DECODE_ERROR 50 +#define SSL_ALERT_DECRYPT_ERROR 51 +#define SSL_ALERT_INVALID_VERSION 70 +#define SSL_ALERT_NO_RENEGOTIATION 100 +#define SSL_ALERT_UNSUPPORTED_EXTENSION 110 + +/* The ciphers that are supported */ +#define SSL_AES128_SHA 0x2f +#define SSL_AES256_SHA 0x35 +#define SSL_AES128_SHA256 0x3c +#define SSL_AES256_SHA256 0x3d + +/* build mode ids' */ +#define SSL_BUILD_SKELETON_MODE 0x01 +#define SSL_BUILD_SERVER_ONLY 0x02 +#define SSL_BUILD_ENABLE_VERIFICATION 0x03 +#define SSL_BUILD_ENABLE_CLIENT 0x04 +#define SSL_BUILD_FULL_MODE 0x05 + +/* offsets to retrieve configuration information */ +#define SSL_BUILD_MODE 0 +#define SSL_MAX_CERT_CFG_OFFSET 1 +#define SSL_MAX_CA_CERT_CFG_OFFSET 2 +#define SSL_HAS_PEM 3 + +/* default session sizes */ +#define SSL_DEFAULT_SVR_SESS 5 +#define SSL_DEFAULT_CLNT_SESS 1 + +/* X.509/X.520 distinguished name types */ +#define SSL_X509_CERT_COMMON_NAME 0 +#define SSL_X509_CERT_ORGANIZATION 1 +#define SSL_X509_CERT_ORGANIZATIONAL_NAME 2 +#define SSL_X509_CA_CERT_COMMON_NAME 3 +#define SSL_X509_CA_CERT_ORGANIZATION 4 +#define SSL_X509_CA_CERT_ORGANIZATIONAL_NAME 5 + +/* SSL object loader types */ +#define SSL_OBJ_X509_CERT 1 +#define SSL_OBJ_X509_CACERT 2 +#define SSL_OBJ_RSA_KEY 3 +#define SSL_OBJ_PKCS8 4 +#define SSL_OBJ_PKCS12 5 + +/** + * @defgroup c_api Standard C API + * @brief The standard interface in C. + * @{ + */ + +/** + * @brief Establish a new client/server context. + * + * This function is called before any client/server SSL connections are made. + * + * Each new connection will use the this context's private key and + * certificate chain. If a different certificate chain is required, then a + * different context needs to be be used. + * + * There are two threading models supported - a single thread with one + * SSL_CTX can support any number of SSL connections - and multiple threads can + * support one SSL_CTX object each (the default). But if a single SSL_CTX + * object uses many SSL objects in individual threads, then the + * CONFIG_SSL_CTX_MUTEXING option needs to be configured. + * + * @param options [in] Any particular options. At present the options + * supported are: + * - SSL_SERVER_VERIFY_LATER (client only): Don't stop a handshake if the server + * authentication fails. The certificate can be authenticated later with a + * call to ssl_verify_cert(). + * - SSL_CLIENT_AUTHENTICATION (server only): Enforce client authentication + * i.e. each handshake will include a "certificate request" message from the + * server. Only available if verification has been enabled. + * - SSL_DISPLAY_BYTES (full mode build only): Display the byte sequences + * during the handshake. + * - SSL_DISPLAY_STATES (full mode build only): Display the state changes + * during the handshake. + * - SSL_DISPLAY_CERTS (full mode build only): Display the certificates that + * are passed during a handshake. + * - SSL_DISPLAY_RSA (full mode build only): Display the RSA key details that + * are passed during a handshake. + * - SSL_CONNECT_IN_PARTS (client only): To use a non-blocking version of + * ssl_client_new(). + * @param num_sessions [in] The number of sessions to be used for session + * caching. If this value is 0, then there is no session caching. This option + * is not used in skeleton mode. + * @return A client/server context. + */ +EXP_FUNC SSL_CTX * STDCALL ssl_ctx_new(uint32_t options, int num_sessions); + +/** + * @brief Remove a client/server context. + * + * Frees any used resources used by this context. Each connection will be + * sent a "Close Notify" alert (if possible). + * @param ssl_ctx [in] The client/server context. + */ +EXP_FUNC void STDCALL ssl_ctx_free(SSL_CTX *ssl_ctx); + +/** + * @brief Allocates new SSL extensions structure and returns pointer to it + * + * @return ssl_ext Pointer to SSL_EXTENSIONS structure + * + */ +EXP_FUNC SSL_EXTENSIONS * STDCALL ssl_ext_new(); + +/** + * @brief Frees SSL extensions structure + * + * @param ssl_ext [in] Pointer to SSL_EXTENSION structure + * + */ +EXP_FUNC void STDCALL ssl_ext_free(SSL_EXTENSIONS *ssl_ext); + +/** + * @brief (server only) Establish a new SSL connection to an SSL client. + * + * It is up to the application to establish the logical connection (whether it + * is a socket, serial connection etc). + * @param ssl_ctx [in] The server context. + * @param client_fd [in] The client's file descriptor. + * @return An SSL object reference. + */ +EXP_FUNC SSL * STDCALL ssl_server_new(SSL_CTX *ssl_ctx, int client_fd); + +/** + * @brief (client only) Establish a new SSL connection to an SSL server. + * + * It is up to the application to establish the initial logical connection + * (whether it is a socket, serial connection etc). + * + * This is a normally a blocking call - it will finish when the handshake is + * complete (or has failed). To use in non-blocking mode, set + * SSL_CONNECT_IN_PARTS in ssl_ctx_new(). + * @param ssl_ctx [in] The client context. + * @param client_fd [in] The client's file descriptor. + * @param session_id [in] A 32 byte session id for session resumption. This + * can be null if no session resumption is being used or required. This option + * is not used in skeleton mode. + * @param sess_id_size The size of the session id (max 32) + * @param ssl_ext pointer to a structure with the activated SSL extensions and their values + * @return An SSL object reference. Use ssl_handshake_status() to check + * if a handshake succeeded. + */ +EXP_FUNC SSL * STDCALL ssl_client_new(SSL_CTX *ssl_ctx, int client_fd, const uint8_t *session_id, uint8_t sess_id_size, SSL_EXTENSIONS* ssl_ext); + +/** + * @brief Free any used resources on this connection. + + * A "Close Notify" message is sent on this connection (if possible). It is up + * to the application to close the socket or file descriptor. + * @param ssl [in] The ssl object reference. + */ +EXP_FUNC void STDCALL ssl_free(SSL *ssl); + +/** + * @brief Read the SSL data stream. + * If the socket is non-blocking and data is blocked then SSO_OK will be + * returned. + * @param ssl [in] An SSL object reference. + * @param in_data [out] If the read was successful, a pointer to the read + * buffer will be here. Do NOT ever free this memory as this buffer is used in + * sucessive calls. If the call was unsuccessful, this value will be null. + * @return The number of decrypted bytes: + * - if > 0, then the handshaking is complete and we are returning the number + * of decrypted bytes. + * - SSL_OK if the handshaking stage is successful (but not yet complete). + * - < 0 if an error. + * @see ssl.h for the error code list. + * @note Use in_data before doing any successive ssl calls. + */ +EXP_FUNC int STDCALL ssl_read(SSL *ssl, uint8_t **in_data); + +/** + * @brief Write to the SSL data stream. + * if the socket is non-blocking and data is blocked then a check is made + * to ensure that all data is sent (i.e. blocked mode is forced). + * @param ssl [in] An SSL obect reference. + * @param out_data [in] The data to be written + * @param out_len [in] The number of bytes to be written. + * @return The number of bytes sent, or if < 0 if an error. + * @see ssl.h for the error code list. + */ +EXP_FUNC int STDCALL ssl_write(SSL *ssl, const uint8_t *out_data, int out_len); + +/** + * @brief Calculate the size of the encrypted data from what you are about to send + * @param ssl [in] An SSL obect reference. + * @param out_len [in] The number of bytes to be written. + * @return The number of bytes that will be sent, or if < 0 if an error. + * @see ssl.h for the error code list. + */ +EXP_FUNC int STDCALL ssl_calculate_write_length(SSL *ssl, int out_len); + +/** + * @brief Find an ssl object based on a file descriptor. + * + * Goes through the list of SSL objects maintained in a client/server context + * to look for a file descriptor match. + * @param ssl_ctx [in] The client/server context. + * @param client_fd [in] The file descriptor. + * @return A reference to the SSL object. Returns null if the object could not + * be found. + */ +EXP_FUNC SSL * STDCALL ssl_find(SSL_CTX *ssl_ctx, int client_fd); + +/** + * @brief Get the session id for a handshake. + * + * This will be a 32 byte sequence and is available after the first + * handshaking messages are sent. + * @param ssl [in] An SSL object reference. + * @return The session id as a 32 byte sequence. + * @note A SSLv23 handshake may have only 16 valid bytes. + */ +EXP_FUNC const uint8_t * STDCALL ssl_get_session_id(const SSL *ssl); + +/** + * @brief Get the session id size for a handshake. + * + * This will normally be 32 but could be 0 (no session id) or something else. + * @param ssl [in] An SSL object reference. + * @return The size of the session id. + */ +EXP_FUNC uint8_t STDCALL ssl_get_session_id_size(const SSL *ssl); + +/** + * @brief Return the cipher id (in the SSL form). + * @param ssl [in] An SSL object reference. + * @return The cipher id. This will be one of the following: + * - SSL_AES128_SHA (0x2f) + * - SSL_AES256_SHA (0x35) + * - SSL_RC4_128_SHA (0x05) + * - SSL_RC4_128_MD5 (0x04) + */ +EXP_FUNC uint8_t STDCALL ssl_get_cipher_id(const SSL *ssl); + +/** + * @brief Return the status of the handshake. + * @param ssl [in] An SSL object reference. + * @return SSL_OK if the handshake is complete and ok. + * @see ssl.h for the error code list. + */ +EXP_FUNC int STDCALL ssl_handshake_status(const SSL *ssl); + +/** + * @brief Retrieve various parameters about the axTLS engine. + * @param offset [in] The configuration offset. It will be one of the following: + * - SSL_BUILD_MODE The build mode. This will be one of the following: + * - SSL_BUILD_SERVER_ONLY (basic server mode) + * - SSL_BUILD_ENABLE_VERIFICATION (server can do client authentication) + * - SSL_BUILD_ENABLE_CLIENT (client/server capabilties) + * - SSL_BUILD_FULL_MODE (client/server with diagnostics) + * - SSL_BUILD_SKELETON_MODE (skeleton mode) + * - SSL_MAX_CERT_CFG_OFFSET The maximum number of certificates allowed. + * - SSL_MAX_CA_CERT_CFG_OFFSET The maximum number of CA certificates allowed. + * - SSL_HAS_PEM 1 if supported + * @return The value of the requested parameter. + */ +EXP_FUNC int STDCALL ssl_get_config(int offset); + +/** + * @brief Display why the handshake failed. + * + * This call is only useful in a 'full mode' build. The output is to stdout. + * @param error_code [in] An error code. + * @see ssl.h for the error code list. + */ +EXP_FUNC void STDCALL ssl_display_error(int error_code); + +/** + * @brief Authenticate a received certificate. + * + * This call is usually made by a client after a handshake is complete and the + * context is in SSL_SERVER_VERIFY_LATER mode. + * @param ssl [in] An SSL object reference. + * @return SSL_OK if the certificate is verified. + */ +EXP_FUNC int STDCALL ssl_verify_cert(const SSL *ssl); + +/** + * @brief Check if certificate fingerprint (SHA1) matches the one given. + * + * @param ssl [in] An SSL object reference. + * @param fp [in] SHA1 fingerprint to match against + * @return SSL_OK if the certificate is verified. + */ +EXP_FUNC int STDCALL ssl_match_fingerprint(const SSL *ssl, const uint8_t* fp); + +/** + * @brief Check if SHA256 hash of Subject Public Key Info matches the one given. + * + * @param ssl [in] An SSL object reference. + * @param fp [in] SHA256 hash to match against + * @return SSL_OK if the certificate is verified. + */ +EXP_FUNC int STDCALL ssl_match_spki_sha256(const SSL *ssl, const uint8_t* hash); + +/** + * @brief Retrieve an X.509 distinguished name component. + * + * When a handshake is complete and a certificate has been exchanged, then the + * details of the remote certificate can be retrieved. + * + * This will usually be used by a client to check that the server's common + * name matches the URL. + * + * @param ssl [in] An SSL object reference. + * @param component [in] one of: + * - SSL_X509_CERT_COMMON_NAME + * - SSL_X509_CERT_ORGANIZATION + * - SSL_X509_CERT_ORGANIZATIONAL_NAME + * - SSL_X509_CA_CERT_COMMON_NAME + * - SSL_X509_CA_CERT_ORGANIZATION + * - SSL_X509_CA_CERT_ORGANIZATIONAL_NAME + * @return The appropriate string (or null if not defined) + * @note Verification build mode must be enabled. + */ +EXP_FUNC const char * STDCALL ssl_get_cert_dn(const SSL *ssl, int component); + +/** + * @brief Retrieve a Subject Alternative DNSName + * + * When a handshake is complete and a certificate has been exchanged, then the + * details of the remote certificate can be retrieved. + * + * This will usually be used by a client to check that the server's DNS + * name matches the URL. + * + * @param ssl [in] An SSL object reference. + * @param dnsindex [in] The index of the DNS name to retrieve. + * @return The appropriate string (or null if not defined) + * @note Verification build mode must be enabled. + */ +EXP_FUNC const char * STDCALL ssl_get_cert_subject_alt_dnsname(const SSL *ssl, int dnsindex); + +/** + * @brief Force the client to perform its handshake again. + * + * For a client this involves sending another "client hello" message. + * For the server is means sending a "hello request" message. + * + * This is a blocking call on the client (until the handshake completes). + * + * @param ssl [in] An SSL object reference. + * @return SSL_OK if renegotiation instantiation was ok + */ +EXP_FUNC int STDCALL ssl_renegotiate(SSL *ssl); + +/** + * @brief Process a file that is in binary DER or ASCII PEM format. + * + * These are temporary objects that are used to load private keys, + * certificates etc into memory. + * @param ssl_ctx [in] The client/server context. + * @param obj_type [in] The format of the file. Can be one of: + * - SSL_OBJ_X509_CERT (no password required) + * - SSL_OBJ_X509_CACERT (no password required) + * - SSL_OBJ_RSA_KEY (AES128/AES256 PEM encryption supported) + * - SSL_OBJ_PKCS8 (RC4-128 encrypted data supported) + * - SSL_OBJ_PKCS12 (RC4-128 encrypted data supported) + * + * PEM files are automatically detected (if supported). The object type is + * also detected, and so is not relevant for these types of files. + * @param filename [in] The location of a file in DER/PEM format. + * @param password [in] The password used. Can be null if not required. + * @return SSL_OK if all ok + * @note Not available in skeleton build mode. + */ +EXP_FUNC int STDCALL ssl_obj_load(SSL_CTX *ssl_ctx, int obj_type, const char *filename, const char *password); + +/** + * @brief Process binary data. + * + * These are temporary objects that are used to load private keys, + * certificates etc into memory. + * @param ssl_ctx [in] The client/server context. + * @param obj_type [in] The format of the memory data. + * @param data [in] The binary data to be loaded. + * @param len [in] The amount of data to be loaded. + * @param password [in] The password used. Can be null if not required. + * @return SSL_OK if all ok + * @see ssl_obj_load for more details on obj_type. + */ +EXP_FUNC int STDCALL ssl_obj_memory_load(SSL_CTX *ssl_ctx, int obj_type, const uint8_t *data, int len, const char *password); + +#ifdef CONFIG_SSL_GENERATE_X509_CERT +/** + * @brief Create an X.509 certificate. + * + * This certificate is a self-signed v1 cert with a fixed start/stop validity + * times. It is signed with an internal private key in ssl_ctx. + * + * @param ssl_ctx [in] The client/server context. + * @param options [in] Not used yet. + * @param dn [in] An array of distinguished name strings. The array is defined + * by: + * - SSL_X509_CERT_COMMON_NAME (0) + * - If SSL_X509_CERT_COMMON_NAME is empty or not defined, then the + * hostname will be used. + * - SSL_X509_CERT_ORGANIZATION (1) + * - If SSL_X509_CERT_ORGANIZATION is empty or not defined, then $USERNAME + * will be used. + * - SSL_X509_CERT_ORGANIZATIONAL_NAME (2) + * - SSL_X509_CERT_ORGANIZATIONAL_NAME is optional. + * @param cert_data [out] The certificate as a sequence of bytes. + * @return < 0 if an error, or the size of the certificate in bytes. + * @note cert_data must be freed when there is no more need for it. + */ +EXP_FUNC int STDCALL ssl_x509_create(SSL_CTX *ssl_ctx, uint32_t options, const char * dn[], uint8_t **cert_data); +#endif + +/** + * @brief Return the axTLS library version as a string. + */ +EXP_FUNC const char * STDCALL ssl_version(void); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tools/sdk/include/ssl/tls1.h b/tools/sdk/include/ssl/tls1.h new file mode 100644 index 0000000000..c278a029e0 --- /dev/null +++ b/tools/sdk/include/ssl/tls1.h @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2007-2016, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file tls1.h + * + * @brief The definitions for the TLS library. + */ +#ifndef HEADER_SSL_LIB_H +#define HEADER_SSL_LIB_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ss/version.h" +#include "ssl/config.h" +#include "ssl/os_int.h" +#include "ssl/os_port.h" +#include "crypto/crypto.h" +#include "crypto/crypto_misc.h" + +#define SSL_PROTOCOL_MIN_VERSION 0x31 /* TLS v1.0 */ +#define SSL_PROTOCOL_VERSION_MAX 0x33 /* TLS v1.3 */ +#define SSL_PROTOCOL_VERSION_TLS1_1 0x32 /* TLS v1.1 */ +#define SSL_PROTOCOL_VERSION_TLS1_2 0x33 /* TLS v1.2 */ +#define SSL_RANDOM_SIZE 32 +#define SSL_SECRET_SIZE 48 +#define SSL_FINISHED_HASH_SIZE 12 +#define SSL_RECORD_SIZE 5 +#define SSL_SERVER_READ 0 +#define SSL_SERVER_WRITE 1 +#define SSL_CLIENT_READ 2 +#define SSL_CLIENT_WRITE 3 +#define SSL_HS_HDR_SIZE 4 + +/* the flags we use while establishing a connection */ +#define SSL_NEED_RECORD 0x0001 +#define SSL_TX_ENCRYPTED 0x0002 +#define SSL_RX_ENCRYPTED 0x0004 +#define SSL_SESSION_RESUME 0x0008 +#define SSL_IS_CLIENT 0x0010 +#define SSL_HAS_CERT_REQ 0x0020 +#define SSL_SENT_CLOSE_NOTIFY 0x0040 + +/* some macros to muck around with flag bits */ +#define SET_SSL_FLAG(A) (ssl->flag |= A) +#define CLR_SSL_FLAG(A) (ssl->flag &= ~A) +#define IS_SET_SSL_FLAG(A) (ssl->flag & A) + +#define MAX_KEY_BYTE_SIZE 512 /* for a 4096 bit key */ +#define RT_MAX_PLAIN_LENGTH 16384 +#define RT_EXTRA 1024 +#define BM_RECORD_OFFSET 5 + +#define NUM_PROTOCOLS 4 + +#define MAX_SIG_ALGORITHMS 4 +#define SIG_ALG_SHA1 2 +#define SIG_ALG_SHA256 4 +#define SIG_ALG_SHA384 5 +#define SIG_ALG_SHA512 6 +#define SIG_ALG_RSA 1 + +#define PARANOIA_CHECK(A, B) if (A < B) { \ + ret = SSL_ERROR_INVALID_HANDSHAKE; goto error; } + +/* protocol types */ +enum +{ + PT_CHANGE_CIPHER_SPEC = 20, + PT_ALERT_PROTOCOL, + PT_HANDSHAKE_PROTOCOL, + PT_APP_PROTOCOL_DATA +}; + +/* handshaking types */ +enum +{ + HS_HELLO_REQUEST, + HS_CLIENT_HELLO, + HS_SERVER_HELLO, + HS_CERTIFICATE = 11, + HS_SERVER_KEY_XCHG, + HS_CERT_REQ, + HS_SERVER_HELLO_DONE, + HS_CERT_VERIFY, + HS_CLIENT_KEY_XCHG, + HS_FINISHED = 20 +}; + +/* SSL extension types */ +enum +{ + SSL_EXT_SERVER_NAME = 0, + SSL_EXT_MAX_FRAGMENT_SIZE, + SSL_EXT_SIG_ALG = 0x0d, +}; + +typedef struct +{ + uint8_t cipher; + uint8_t key_size; + uint8_t iv_size; + uint8_t padding_size; + uint8_t digest_size; + uint8_t key_block_size; + hmac_func hmac; + crypt_func encrypt; + crypt_func decrypt; +} cipher_info_t; + +struct _SSLObjLoader +{ + uint8_t *buf; + int len; +}; + +typedef struct _SSLObjLoader SSLObjLoader; + +typedef struct +{ + time_t conn_time; + uint8_t session_id[SSL_SESSION_ID_SIZE]; + uint8_t master_secret[SSL_SECRET_SIZE]; +} SSL_SESSION; + +typedef struct +{ + uint8_t *buf; + int size; + uint8_t hash_alg; +} SSL_CERT; + +typedef struct +{ + MD5_CTX md5_ctx; + SHA1_CTX sha1_ctx; + SHA256_CTX sha256_ctx; + uint8_t client_random[SSL_RANDOM_SIZE]; /* client's random sequence */ + uint8_t server_random[SSL_RANDOM_SIZE]; /* server's random sequence */ + uint8_t final_finish_mac[128]; + uint8_t master_secret[SSL_SECRET_SIZE]; + uint8_t key_block[256]; + uint16_t bm_proc_index; + uint8_t key_block_generated; +} DISPOSABLE_CTX; + +typedef struct { + char *host_name; /* Needed for the SNI support */ + uint16_t max_fragment_size; /* Needed for the Max Fragment Size Extension. Allowed values: 2^9, 2^10 .. 2^14 */ +} SSL_EXTENSIONS; + +struct _SSL +{ + uint32_t flag; + uint16_t need_bytes; + uint16_t got_bytes; + uint8_t record_type; + uint8_t cipher; + uint8_t sess_id_size; + uint8_t version; + uint8_t client_version; + int16_t next_state; + int16_t hs_status; + DISPOSABLE_CTX *dc; /* temporary data which we'll get rid of soon */ + int client_fd; + const cipher_info_t *cipher_info; + void *encrypt_ctx; + void *decrypt_ctx; + uint8_t *bm_all_data; + uint8_t *bm_data; + uint16_t bm_index; + uint16_t bm_read_index; + size_t max_plain_length; + uint8_t sig_algs[MAX_SIG_ALGORITHMS]; + uint8_t num_sig_algs; + struct _SSL *next; /* doubly linked list */ + struct _SSL *prev; + struct _SSL_CTX *ssl_ctx; /* back reference to a clnt/svr ctx */ +#ifndef CONFIG_SSL_SKELETON_MODE + uint16_t session_index; + SSL_SESSION *session; +#endif +#ifdef CONFIG_SSL_CERT_VERIFICATION + X509_CTX *x509_ctx; + bool can_free_certificates; +#endif + uint8_t session_id[SSL_SESSION_ID_SIZE]; + uint8_t client_mac[SHA256_SIZE]; /* for HMAC verification */ + uint8_t server_mac[SHA256_SIZE]; /* for HMAC verification */ + uint8_t read_sequence[8]; /* 64 bit sequence number */ + uint8_t write_sequence[8]; /* 64 bit sequence number */ + uint8_t hmac_header[SSL_RECORD_SIZE]; /* rx hmac */ + SSL_EXTENSIONS *extensions; /* Contains the SSL (client) extensions */ +}; + +typedef struct _SSL SSL; + +struct _SSL_CTX +{ + uint32_t options; + uint8_t chain_length; + RSA_CTX *rsa_ctx; +#ifdef CONFIG_SSL_CERT_VERIFICATION + CA_CERT_CTX *ca_cert_ctx; +#endif + SSL *head; + SSL *tail; + SSL_CERT certs[CONFIG_SSL_MAX_CERTS]; +#ifndef CONFIG_SSL_SKELETON_MODE + uint16_t num_sessions; + SSL_SESSION **ssl_sessions; +#endif +#ifdef CONFIG_SSL_CTX_MUTEXING + SSL_CTX_MUTEX_TYPE mutex; +#endif +#ifdef CONFIG_OPENSSL_COMPATIBLE + void *bonus_attr; +#endif +}; + +typedef struct _SSL_CTX SSL_CTX; + +/* backwards compatibility */ +typedef struct _SSL_CTX SSLCTX; + +extern const uint8_t ssl_prot_prefs[NUM_PROTOCOLS]; + +SSL *ssl_new(SSL_CTX *ssl_ctx, int client_fd); +void disposable_new(SSL *ssl); +void disposable_free(SSL *ssl); +int send_packet(SSL *ssl, uint8_t protocol, + const uint8_t *in, int length); +int do_svr_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len); +int do_clnt_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len); +int process_finished(SSL *ssl, uint8_t *buf, int hs_len); +int process_sslv23_client_hello(SSL *ssl); +int send_alert(SSL *ssl, int error_code); +int send_finished(SSL *ssl); +int send_certificate(SSL *ssl); +int basic_read(SSL *ssl, uint8_t **in_data); +int send_change_cipher_spec(SSL *ssl); +int finished_digest(SSL *ssl, const char *label, uint8_t *digest); +void generate_master_secret(SSL *ssl, const uint8_t *premaster_secret); +void add_packet(SSL *ssl, const uint8_t *pkt, int len); +int add_cert(SSL_CTX *ssl_ctx, const uint8_t *buf, int len); +int add_private_key(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj); +void ssl_obj_free(SSLObjLoader *ssl_obj); +int pkcs8_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password); +int pkcs12_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password); +int load_key_certs(SSL_CTX *ssl_ctx); +#ifdef CONFIG_SSL_CERT_VERIFICATION +int add_cert_auth(SSL_CTX *ssl_ctx, const uint8_t *buf, int len); +void remove_ca_certs(CA_CERT_CTX *ca_cert_ctx); +#endif +#ifdef CONFIG_SSL_ENABLE_CLIENT +int do_client_connect(SSL *ssl); +#endif + +#ifdef CONFIG_SSL_FULL_MODE +void DISPLAY_STATE(SSL *ssl, int is_send, uint8_t state, int not_ok); +void DISPLAY_BYTES(SSL *ssl, const char *format, + const uint8_t *data, int size, ...); +void DISPLAY_CERT(SSL *ssl, const X509_CTX *x509_ctx); +void DISPLAY_RSA(SSL *ssl, const RSA_CTX *rsa_ctx); +void DISPLAY_ALERT(SSL *ssl, int alert); +#else +#define DISPLAY_STATE(A,B,C,D) +#define DISPLAY_CERT(A,B) +#define DISPLAY_RSA(A,B) +#define DISPLAY_ALERT(A, B) +#ifdef WIN32 +void DISPLAY_BYTES(SSL *ssl, const char *format,/* win32 has no variadic macros */ + const uint8_t *data, int size, ...); +#else +#define DISPLAY_BYTES(A,B,C,D,...) +#endif +#endif + +#ifdef CONFIG_SSL_CERT_VERIFICATION +int process_certificate(SSL *ssl, X509_CTX **x509_ctx); +#endif + +SSL_SESSION *ssl_session_update(int max_sessions, + SSL_SESSION *ssl_sessions[], SSL *ssl, + const uint8_t *session_id); +void kill_ssl_session(SSL_SESSION **ssl_sessions, SSL *ssl); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tools/sdk/include/ssl/version.h b/tools/sdk/include/ssl/version.h new file mode 100644 index 0000000000..e8158cc0d9 --- /dev/null +++ b/tools/sdk/include/ssl/version.h @@ -0,0 +1 @@ +#define AXTLS_VERSION "1.4.9" From b819b6cac5a07b8a2d3ace69415f6f3bf6138adc Mon Sep 17 00:00:00 2001 From: Myles Eftos Date: Wed, 5 Apr 2017 17:56:55 +1000 Subject: [PATCH 08/12] Adding SDK path to test include path --- tests/host/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/host/Makefile b/tests/host/Makefile index a59cff4068..d030bd1477 100644 --- a/tests/host/Makefile +++ b/tests/host/Makefile @@ -1,6 +1,7 @@ BINARY_DIRECTORY := bin OUTPUT_BINARY := $(BINARY_DIRECTORY)/host_tests CORE_PATH := ../../cores/esp8266 +SDK_PATH := ../../tools/sdk/include # I wasn't able to build with clang when -coverage flag is enabled, forcing GCC on OS X ifeq ($(shell uname -s),Darwin) @@ -43,6 +44,7 @@ MOCK_C_FILES := $(addprefix common/,\ INC_PATHS += $(addprefix -I, \ common \ $(CORE_PATH) \ + $(SDK_PATH) \ ) TEST_CPP_FILES := \ From 9b880f93c6e47e6ca8a80f1aa0b07c34a620c0a6 Mon Sep 17 00:00:00 2001 From: Myles Eftos Date: Thu, 13 Apr 2017 19:37:11 +1000 Subject: [PATCH 09/12] Adding object fiels to gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index c36bdd3aa3..90e6545fc1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +Dockerfile .DS_Store tools/dist/ tools/xtensa-lx106-elf/ @@ -9,4 +10,6 @@ tools/sdk/lib/liblwip_src.a tools/sdk/lwip/src/build tools/sdk/lwip/src/liblwip_src.a +*.o +*.gcno *.pyc From 024ef360ea0594f8bba0894310d9a40869c3444b Mon Sep 17 00:00:00 2001 From: Myles Eftos Date: Thu, 13 Apr 2017 21:03:22 +1000 Subject: [PATCH 10/12] Adding static version of libaxtls so the test suite will work. Removing clashing version of max() and min() --- .gitignore | 3 ++- tests/host/Makefile | 3 ++- tests/host/lib/libaxtls.a | Bin 0 -> 298362 bytes tools/sdk/include/crypto/bigint_impl.h | 4 ++-- 4 files changed, 6 insertions(+), 4 deletions(-) create mode 100644 tests/host/lib/libaxtls.a diff --git a/.gitignore b/.gitignore index 90e6545fc1..a89e984662 100644 --- a/.gitignore +++ b/.gitignore @@ -11,5 +11,6 @@ tools/sdk/lwip/src/build tools/sdk/lwip/src/liblwip_src.a *.o -*.gcno +*.gc?? +*.gc?? *.pyc diff --git a/tests/host/Makefile b/tests/host/Makefile index d030bd1477..9a3adae409 100644 --- a/tests/host/Makefile +++ b/tests/host/Makefile @@ -1,4 +1,5 @@ BINARY_DIRECTORY := bin +LIB_DIRECTORY := lib OUTPUT_BINARY := $(BINARY_DIRECTORY)/host_tests CORE_PATH := ../../cores/esp8266 SDK_PATH := ../../tools/sdk/include @@ -112,4 +113,4 @@ $(BINARY_DIRECTORY)/core.a: $(C_OBJECTS) $(CPP_OBJECTS_CORE) ranlib -c $@ $(OUTPUT_BINARY): $(BINARY_DIRECTORY) $(CPP_OBJECTS_TESTS) $(BINARY_DIRECTORY)/core.a - $(CXX) $(LDFLAGS) $(CPP_OBJECTS_TESTS) $(BINARY_DIRECTORY)/core.a $(LIBS) -o $(OUTPUT_BINARY) + $(CXX) $(LDFLAGS) $(CPP_OBJECTS_TESTS) $(BINARY_DIRECTORY)/core.a $(LIB_DIRECTORY)/libaxtls.a $(LIBS) -o $(OUTPUT_BINARY) diff --git a/tests/host/lib/libaxtls.a b/tests/host/lib/libaxtls.a new file mode 100644 index 0000000000000000000000000000000000000000..d89223a2617fd35ae3d2fc44400e52368ea0567c GIT binary patch literal 298362 zcmd443w%|@wLiZ1IU#JG2_z5@m4k|aNFKZq(C|2V5KxM6i;9LkP9Bn%=K;a;ssYPs zOiO&XMUB?B_{K+(8pMETg7s=_xtdmc8~eu^gtk$rr54NoyVk7PXP-^d_TJyGpU-bY z&YtzRh}FaDY4w+;R~Z;fH5*eTJ$3UccHf|CfKB zQNJ@1{%*U=@VNhe{B6VY|M;Kx`&SzL_vs~uSN@Ww4K-YUbNtukg@cj2)xmWJg$t`H z*91e3ctK%au(B|;t~#R95ibg=ctKfSS!G$IEWf<$wxEGnbud(sUm2{7P$Ys#S!I5N zQ;LEKX~m%+!-eI+{7_zDeqpJKR#mSv$|@syk*d6cGGbC#URB9S`9(z(4@V0kq5MKF zpr~w3S&`(csLl^@u&koGD#Xd*NGLBJs}6xLaR}Df1gLgJ6|*IIbhsi~9x1CXU&qDW z8Wp|;`JqrS!W@t%uexe&Fhmq~WFo~1QFOF29Id7@f<<|d!6-p7#bxC|W9ce8yjRVW8i>QSNyAq96j?fgHIwj9eog%4A z=S?PSiB=mFQdY3^x;c3$e+`*XUS)8t!9cViA3EFmaE-GCzl$RB%AU73(+VHLm z%*jzwaY)4Cu#%dzl^?Fm$tw?5mPASo4p#x2RZnby;;hMj6N;n2;h=1IWVt zfI;+va9LHQqF4hHFDi?y6UO-!K^3Zw7C`EFrf^vaEItZT3n!Hd@VF(u5p{nX&CG)QiRgr>%#bJ&X zMryd7sWb}PMXNv%b;>VCrH!JpaCKEUzo0xAr$I^Rart3rjf1Pp%FFYJQ#crAeN%XC zs0?NiCQjA)g{y;Tr=lWOq#el1kD{H4m|BnOMp{jXiz*=urG;6aL_m6G%22Q}SW<=Y z3xzpkB^xF>I#am`ra^HfQVDX0$Yd(=!|1oDKp{p51KiO!(f5nWN`m2tF@M2zOBT(! zK5y>z%ly~bvFn!2S?0H6a~AoRE>ra_EX}Vhf!&ld+dw!NLUwM1qN=>`noyoyBGVR@ zm*GOA(=q)Agbw5snW|Dr2BrisazI!xnoBOcSJVYFk;q>o$<in(6vD7;M5glIQAuLeaoD_)pPazLz zjiW92L59Esf%^2Vgn;N&z@+@mDZ7o7-Oc+uhQ;<%6j@CTrS{Q~M?;nkc@@;BHRe&Q zkui~dTcB<^_#H?}**!RA_b+1a?*C|*K)n>S|97c<-W4cWLzWHoR#2ZeW2u2!f3sEV z|B%X>=|7Tk=Y%t7&IIavab;ruE~<6POGe5|%@AXMhbQLmB(3;AJh~o@rvwBXs9$m# zq^Nsaoe}eQAmMv|*>EJ*wzWBBYaMH;1KNN#73-AUNvJxsW5xW(>--)2JFRY$Q~OAA zYPZS5bn-AaXCy$LF0I~Sll;da7HZpN)^0drrEL8c3nfz4o=S?YgBaZu@{i@Sv;f`9 zXN!N9e6S17N>V8;CRz}%@%|%ZSp6M_)mmpv@^{2MXfP8LGyR<@ch>wJ4Mw(EzwHQ` z1i?Llx+PYi&IrWJKi$-Xvm8MkPr*FVZFP#*8bcWR%e(o&C(<36~R<JSo}+9@LhpARX5e-? z!*z+}ZMX6HTN~q663^J-(no{CT&OYP=0Y);3u~+P6*|FO-ozm05Z0;w?cEjE>?-aZ zUHAX70o5K~g-*W{oxbrbQ}ORqgJaD97OJyThR*gD|3NmASpeH*Xlbv*Y~i3|v~CQT zt#ylmOs*&5K;2>>pVjrr!9};$e-MMfLGPMrQF~vEEi*u~G`yAa}nPUDuoXOKurtYrBG5=o9o#sq` z>&6Pq#3uRoO!DuYV>g!&;E|oJ~;2iWTQ`8Ka`EgK{d9iW=OfCp3F~LH5;i3im&hQ z0aO>+is8@E-bPMW%(Pqb&02peF3GJk{cok*IT7ss(V$g(yc#z50Bmmi**5opwz-`s z4%h!BNiaQ{13nPg-;o3}zyuT~*vPZjd4bxB_9T*v?5`23jx{@sa621eW9?BhcF19g zfVCx7G{O=ajp$1){>Ru7SMU^>xgY&2TVi8v^I1&}4n3LUQzS?8S(c@9bZ?HkIMZ1+ ztTT0QjxdwPM4MOi-C827XD3_YV=3SH0yVAkKQ+lu7o^8duraZ9@0tXoZ0T&!5SbBd z7SKiw9c0^l3eai|wc3WcLPKw{RUQPDUqdkXw_x3XCTa-QPbG4%K-%FP>R}K|A#IF6 z1QOIi0|^uYGDQOc8tVgR*v8rBF|lTwKPWce8hbM~|K5&cV>IDY(m8esAvz0pjy;O7 zR?H%0>sMb<&rrrTmGrGF%)Z-!#?hS=T(<~a#I{Ex2X`=kbc z_Rv4b2D?8B*RTD?=c}t;&o)cO|NZ?Z*SvZAp$%VNe^uAhhaY`*$77-9m%h6D;;C2s z<*ms-`uMY3+jE8_wOshxu={#_zxUwHzdJVO`DmZoOV1fmc|+sUneV+Y?*Gf$a^1Ve zAAF~uyYZHv@0)S;q80D7{ppFn&09QatN*W_O-p7yyz^^6%>C|N4^IE{-rc_*m3rpH zFaEQC+VQ;m=Vu)J$;R15Hw_Q3`sTGCUU13wZCCzrPx^n~-0y>qiI??VkbKd~1HXK# zpyA#l>pp3nR#E?7*F0YSA16Nz-u8_3a?R+>bASBe8=b$2j9mCi-M6bR|7mf+`^CWg zDPRBD9sAFF=%Z5)3@ZE8ckcPY`QJMF_VTg6z4MXSfLDJ%w{*_;CZz0I)--f!pIiPb zd+Lv-znc5QhrW5@{lBgM|7P6&gRC>(n*5!4^AG;_(Vs8-#yt~%eBi>_e_V8Lzqwz& zc8!(!Nb%TTUG)5#8y{UzQTOiX(5Wwq?kIg==;6m!zI9V@_g&@HfhAx4;b*_TdB~Mt z|4IFWTei19Y23N@mwo?oWJRw%FZh$&El+M{_{6Y%BToOvR)c{u@kBl9lSq-8^DydHa)#zn^vU z-oiKTpK{CL7dCwPr`H?)qqkwuh-erV1}($rPe0D%_XFZFj|FPO&?gVayh*)iCDdak zbDEqyd?)O&_{0Txva2btX%U%1a%S4WNp!XMBqi`ynR^A1@;v^MC*vo@=yf|z2Xx$P za2Cru?Gr%E+dE?}f)c)r!bwISi*ocOntu2*PMS$qW}(7Ln7~@XRCob}J^fdQjijrI zB56R`8Y5}pqd;-%!i8S}n1xxZ>XEeQbEFPTqADa^TZq&Ygyh#0nx$6*PbJuVf)t^T zizHy~*a3n;HAuc4kf)&>Yd1JdsyZJTn3&RG?)aJqlvp}NA_ct-do~TC2QcRIU+3tq zO@kn``GSh=+?2-IULeW54UcU~FEh-a&IRUaSd?BCkE}@lx?%1v01Hn;X?moh8nN4% zY{?MjAhDI{Wk`CdlnGan3OVO(yi2w)g5*`geRu7|URQ%$AfQyYg@gi8!F)l^#T+Bm!_8lgDRdK)@7 zo+I2yUT?#ZjTsPru&H8qZpw(1RT^d*H>bB@`=$|0t>cZGGN{FLbl0YHDVdG~>SQST z5uD%CkgKBSN^}V+n3Sz*G|jHj9FNLw?r1`nQ#G0}c#Y4as+k3L zT_bi~8!_srx)zue_BK4QNwrP^8xZL~gYCOSvr~nYib;ujb##74ezsw%7C~qXg~{pYu1y&sJR`B=FN#{qM2&kSev8ESZX!EhZ9WOH(E-q`KSpS%>Qm2A z@OIQ%Rs9~j>OOmDIEGPJRs9~R`ZlThJyP|}QuX_E)iY`$sNMZsb#DXYuc7{=aSJj_;v3dXM`07BN*yIdqa+=LqFI$X zt}W_&qPlxTmEV{61FXs)*sAPBL(<=%A0E5UU~!!6=WD6BfbruFj<95HZ^IkK3rP{TX$ zvVJrBEx3#$i1g~T%)DZ(r&vlN#n zBT`loLe&l@l|oKNG2ig;|U zb)?g(wbQK!C82DemBpD=wu=X8+~RuT+0U}%3jZeG|v?NKXJ%2AD39y z(?4cTP2urYdM>iHo8GsZ4?q@(1C2_@fbmpuAqPX>C`+Nw}dnBN+jw`_%h*;n4AiAIEG zUExx^ALFCj4tm1OZ#CdOlzank(*!w#eochB(rxq#P!z<|^CAXv6Bmk3nuxgb{Uv$% z1FsB~`1pqkAcDo$&iCg{oHEr&KnoqOGDU97D+))bG$X6Dsv?+Gv93HA&dRS@w&=Pn z)r;etawbkUuDWKqZ(dH0Z%XFm%xvGp?3}6DQ?qCICR9YCmBHEkZa`TfqVyKuY>XWf zrcU-vDDh1wUb0{we(}t_aPy~)t3ng-q7bB}cZcu>NwCO=*8oD$O*|a0lubjm zTZ$*%ELaW8UKkC9@twFi$MhRLBwx6oswQ4zXIruO zWt?tYHE-T!zOl;-qLq=T()NU@QI6$o%$b^*JvnpoI9DsE(KcP34D+_7hFOzpj_BXp z+K$ngX6AZ!&Npv!2BzNOnKvLg4+N4nOY-t9n@;x*_7VlAjsk%cJw}m2{pG+v!zy`iGLv^F}*;1j{E$XPs!WnPhy%&w1R5Ub<{` zb9fDVVwI5URX4>67)87WW+kqJ=Tc5wilTdI+>q0cI^;|fea7W#dA=l%#MxsL8-~8| z9w+!xx%lhbh$(`Nw|%5o!*-d`$QomW`8I`G zS@&s)A9CY(qDMz(4|s2}XPb{AKXYLZczF-_wjS`G^nkzC1OAfO1D$Bu;k3xpN4l^Z zFLB_*9rP_d;QgfCi4XN@&3}Ufcb0pk2fUsJ5FEtES?=i`@I^8XxXbM?U6|Ct?I`t~ z(*wSy2YhD_c(aT%?s9)1Lxf!}RR%{}4|p$G!gbS6>;dnPp~hXVsM8>^oTHImAts#q zxxSVRLYNMX-ywF)H`5M$H&dy$pdgWniE+v}{#AU`I;sM)9XORsFOtwPO`Ys=FOvA> zE}WKE=~$#rHvO}LU+2Pe1;4?C^Fk7^d>4L~#EV_HE)REmd}#gP7Ko1;b+YAoQE(bZ z>Cp5ys;IGD&Kkc+ly|=iUnG1Ua^bYTO~-5MWb>aV@poMKLE-a(3x87LCtUb9gq|A~ zX zEO+4(gnymjS`SZ(VeN3yYx$pa;adK^E<8o_{+f%wo=1M_qSx~1>!YsMucf_)$#qcU zuLvG?;UU3mUAXRFFS&3%KJF7->p{kBu%|+kdkQ*LKz6!gV_unc;O6k^BOjBO!Gz)uB+Z zJU=sn?^%pYUMI;c2#1Z#P?d^sYEiHtT7qv{imO1w;rxPvP;d>%D6>HLjtE~RBw$$4 z4C*ZOy;3H=QmLSCxH2oTI+2Nm4y;aKhAf$arTCbGK27;QJ$zt5ZKc~;^UIZhd-Yb# zMU(LZHR__8UMDnPs6u5L3s+dLYq&oZaPL3Y>WUZ}aCM zFY$ERB%(&Hlz+Y}!AFUXgXTwWnJD>Y=^!^qztUOUv@?*!vLSZFl9DO8IneLkE>lQ+;>&8-Ni{EhmC}e0i=q&v&)IE?=Lwfvmgy zm(xNC4qE?k9y*^sHy}}mopfQz@5CtVrv0&CE-{T7$$!elK-XWxk08*U{x*yLb_yZs zk4#$U*LtP<6;~5+jgX%GD{ce@CZm{2ZW!rSd~ zeJB?%@%!unrJJt>O&39AW4Jq_rEmjOd%hqb0XmitP-v z!1$9S7b}B|)c15C;f>`|$`YfkQRfK@8&6`$I zk?KPa%B`BYZaISVAqi=t+OB`K0?HL1D5P9~trR}Pl67` zc&-hb8kN6=A(pm|m1V@D9Y8x$UdpvnUTq^5$`0SdfFt=kh~KkVK+uE_&?jJpM2x%v zsTSGI+fH+_3t9pbw7=17@pnK%V%1EU831ejBw338L-j?Y*zG>f2yF_34txTKPuvbCeB0Tj zzHg+j2?8n4;$y~iywlvS-pQx2yhBU@r7k}u-Ftth4=?Q3`VWKj@J#=Q>mMb;y5;R` z7?90v7@gFn--C#@Hddj(K!ed;_%Li|Z1H1fe>8v(Rai5J!EP6a$K#s_`cB|2sgFWo zNTAr0vO71j&EG=ARM-(^FZc+irL!I3+6|8xkx8fnSs+mUhK%@ZZQgh;;GM+70TZ92 zm*6HB%1~WWdf=m&FrX2-Q1b-*+X|;1#)Uqq+K>3+k1u~*qd>~5&G_oU6R7Q^FCXd* z`p)Hzz#fu?#IQ&TX-KGV(#L4 zpOdnCIca83pzs&?$kqzf&2O`iy7SmMDkn*)b1qgn2~rA114q;Ck!hDw-GAX#QK-Oa zZ_q4{lXhd_#rpC1%!oen@B~cyKDbkvt#b$k#LDTUn!1&fiaZd6*>cFPIa`egNW%th#CF!;^HncK>4;z$?}!?e-Zy1ELI6 zn_^taQ@-;XYR{gHz+xl7H^p0CRD}OTsDG}KlxO{I;||0y+|$((qIYY2s$BYTs15xd zUveB#dU*qRAOfqL+XQ;?IQ0UhLoa4mV8($pNwpPixHPmGDO>10D=totHyCP`lPa`b z{rO9>$QFFn*BYpcq6kWPHxT=hx+ohxe{n0ls#BR+C2kKu*(H@w-63vN+)z{n`mnr} zl=z5J;y=vLR+n1)smWs*cU4t52JyurRop(+m4o#_pNY^w-&w3?Hr&J-+)3cEG5<`| zHZ`?&bsUt6fxT|=u0Y+bd`@|30VXPk#xFjM&z#0Dek)LTD6sz{^r6oJ7%F1#u)1pf zZ(;a-YbHK-{!R!_;4p}Z`1aV=&A7(n!BiwbL(~8cS~YNZ100g>uzJ>66yU{9SS4C#|)|vw4b+iCB!MGdvfg9)}O011Xx6R;cNfzpa%?_WP`03!_+k@F}=QjYF(7B3a9MR)T~?V1fa;}r)n!s z!gx;_>(rN>DEbSSn|+BQk=tWYy8hsca$Jk}`a|E~x2s`{r(YbdTYfk$n+VlTb-4)) zYd0J>Hl44t**911#kip`$-3K*`SEMdxu9lz-F-E_?p}PVZZJ*1jzdiF_%+dzB-CpU za~CIrY!`!U?^$wIw2~Y`wc^=b?S{j~raqMWXd{%bIb(VZ*6i(}UD?L*{wkH5VDWL( z)O<6cu4G7}gyRVb)G}15)6g}DxKaqKO5qE6+y%szAK%&>eIG^ImpEpXaET-ScGYsJ zQ7~_4i!H|oX>Zjwd+V2Y(eVQZ_Mh^^SRG34FG+6pYtco<)#5)%C-6GOZE2SWDP5OT zVoQd3{8%xOyKRrkP~c)1q;yOSigk-o{m;;i+t5!_cK1oy{aM}OuKgc*fBE~^XPAe> z!vQ&J=t_$AYw@#8wSL&2H14{4m@Qf-ghfKTx@?0~U8J_@fs$t*UA4`<>zDMFs(YPP zKZ7+XRdpUHTKvcV^{RJq)sGydM?iE<;5#7Hs10r>X3f|%%#Ee&Yp(6gJ~p&ld>Zv` zt*zy8>u{(Lpi_mN80PAtC*vyXgvvTCQke{T=nEA`03N|7);Hp+PyB6l`Sd7*Tlfwm zdL9xxX~=Z1D;#}8*@E+yusb^BcZ^hB$2P)@XzlgbYPe~D3B62D!DIV>`8&GW!YF8N zP9s%Uyd%^Z7vk0*9hT@p`YDl~4%G4U6D&&9ZaCd%tyQ=DbnSucW66A;22o<~tNQ98 z>btcSY(1zoIVX6P9?dX?U3a@@pu4rk79XS!o7MO#rt>b$f<6T1CT&gVVqzl4B4U}x z^3iqocX(euY^rGNP;7S14Jrn6vDHy`f32WO4gXHzs;YyTPA2>t!ndU$Y4 zksOHiXGx`swFi>n{lgwjwg+ktX5Tnxr8o_dRlHb~d#+q`-PK32a6H1-V@_JewLIl$ ztOSaL^4uxuBwLSJp*@G%6Y?VI>~iDFTB|S?>~Y*-&X4&UTl~$etU9^1aZJ{64}KUn zr>}l;xA!6*k6S@Tn-CVRZT2Mx++3F& z@tJ^odH7|Jul8#yO9fnBVQhyLEAjje>mmNzEuFJ4EZak& z4^0n?igsZrq$a|-rSlimlzcsC>3oC3lm;4D-yFXEmX6fY`7&;SZDvbsJBnM4ZX;C2 zY))7PsKs-Se_}9dGHF{wN5V*~o9A`0(|_J<-8QFcHl843r9zQ7S)!%7xTU%RSj>UI zF#LnG65($>+6#AbZ}?y1YlYJy#8O~EtqCnJI2DN-VZIEW3jC!lFw=i3oCHQRz{87H zGtx-eU6e*Q7`Q^U!e*RBNNt+~Gxn>j|Cq{*GlYrRg<-ma^_iadpI!CM8(uRa1LIc) zWN&l&zW5WYk=eb~y|^@;p(zqoutz#otRorPc63AOK4^|leaf2(_ZxWL_>|UTy1nya z!=DF(vu!oiHheMq-{3J8mCQ|`E~TTL#+{7}V8ioEX7?0lP;<>j6^6Yov8al4k;Yo} zMl87So3KZJ4kJZ^n_vSGptqkn`h*ZThDZz&Jaoe09M4}=e%xL0K!)Y$;|UhQ!%(WA zF27+|faoKl9Gmw)%NVANB;v8Y_6&Rr28TpV%0&?M?)$(@|H%ytNsSzgM_lUdKn4Y`uldH`2dy0Ie;51`?|;ObO5r@XY3R>$Q2 z7t1CGWY|!P0T9NP!-`)6X&~&BrzQ}EpN-v!vM}%=qWfwcN}zc%w{mA4J+PtKM`vtF zHOa-#dAfNbg~tk%tZMf<`pB`VuMR_lt7hd3#Sv8xjJ`aaDG}*$BW@RLdExUg9w9?J zh38xtgUGZ_1?>A}2!;noG?+lJa!Rusi>ryLIX#|MiwT>F>>sTx8axT7TDNr4;16$$ zn8)JL;V{a{4FiMR-_eVw?q=JuA@5e;$|tj0+_b*Ehs-BY1Y6Tw!TP{Rx;xvy|5Puu zC24}!E$9Mz0)d+Z}TK9heE8H(o zl;-g9*(yCJ@$2VJFCyGXg|+hRLOnOxtHO=k;&sbkG=DLpZQ~TpIAu46D+g1aZ>n;C z#w`YJXe{IC5X9hEr+x(u)hw5z*T?>wO8xO4=mx>xN@M}}g>uS^2{KKCqpeihoLH+p z6Ul}HC}hIb`9)>>ZK}Inub8#lc%#A}r0QUf%Cf*{P!xI$Tx-@v+nF~{bV!`{PQslW z3s$D`pu6ydsDtQi0jPFhh}I(}32T2_n`>}`&Ah2`yUPRm+Jh@@RJRt?bkpg2Lu+d6 zTd;$42(P772w6H@^BsZEhhb`XCb{X4bU#f!$4deeks3d7p<1#EC89^c#l2XFiu`_Vh8T**sA9dkJ-7zhWo3MjPJ!TuC8(r z)qZO6w3zw}_VYWq8nolm#$ zSUG>Wq`0^^*7}!E-~BSyy8qNj^#r05t2e$)Sb4>r71qZfn|eHT9Fq`r{b*I~_EQLg zQEkhYC>ET@`;YT%v`g0Q=#7kZ1N7>|a9Ti6vl_|1hO4Y+tN-WBn_8$4NC(Fv=h=!TzQSmJ?j|ED9(ws%jd1uhsOH9OxA@Bf{b zn;h1$SVV9G>2e^8ZpSA4%VNjZz;>he>Mlg{6OqNX(**nJA>G{}$jpeeF1M8W z;o~}6yeplxIMZD>vGth(7v8ZiHF_O49=%DyCn(aMlc3WNHtRcfs^XBPiHOg33by zHY3v8PEc~r1WFpo^d-o#szhqyCuA5smSdvetv&&ZuL%iOYNuxK0oHut7u6H@e6dt(-u?R{(W!#=$3 z?8~wFId-hLOtRWkc5X$@aODe}Vqgrduj zM1mF75nrUr7Yzq}`MN&Ep{fefmXCz@m6zcI?=ap-ptmv&1CO0>-~mbE@#e+xIKLt3 zX`c?nt3DG*QqIJ@$`P1XISccOqcP=L%&T0Bd6joCX5po`KL*b;)iC)5g`7VN%!cS2+RfYdb;bAKLC53$| z{5J}ZRpHYV&Q{^CC_G(-|4!jtT4jgMOo{|l#N@~l74dLng^DDZ)evu$iX@wB5Ghp= z%Oq*5Rir;hA}TV_tVT+WiVQZFA+lLT(##tXxm`ul&Gq0`t0Ke9I}zEYBBRW2fNZ;p zj5F&Ic|b)j;Yg#3jOWNs6}glnyHq68q?dB{s7Mye)~q5q=3OY~pz_L=bRW0Du%sPS zNu{F)DJbEGsJhYyk5X+@4YVn+WUC3W{?v*j_JBJOAe5St(ML53FC3KAD|<11RdCXk zc5oV*BFkVUPwPZ7%aA-HZU@PiQ8)>_>ATp0M8jNqU;VTlTu7e|sG9V?ZYkC`m`m^F z6qN9P6i`75|2l>Hs_+Wp-d}~UUjcfmVIQ26trIr?l?0^J^e#Awv!X4cpoD`I7T(1a zR+iek5pvE%|yzz zZkJkf8SPRPk^Zkv>FK=+I?Nq!+L`|nR%OhH zSPjSG_E46imnpo4l3se5ltS+Mm|JhoPI^kVMk1j%S&HJEp1?VSuNK7lxXn48Ig@uo zu+BG3mBZVxi{b_GI2?na0f+Li0+)uvSnv!}RclE`HL?yfsWW*RR%KKpqmGphm--mj zOCTd$ZkVGb>#~fHBeo)=a2@=j>BN<~9y1f_(a)~OK|Cx_8k*^<$1KhfuZNEB6i;ol z%pDNN+W>cHsMqDXUR;qY5-Or&rK-+X=sI^_ud5U4rDIYr9YwuHumW#RsMkQdUfVFT zse0Y)s+Y>4>SdTWb7|~Q?iRybCAFAORnn0~%1H9LBu~Q%Rf_@U5zooj}*qdL4Ngu?9p8sj!&mZq*RP|Q9?N%kd!#g9Y^hQ6op;R zB4;_*ILo=#S&ojBih)%ol=CN549W@NH3+4-N{<>Ir9PD&N`hNNRlQ0s$=d+0iCp_? z<_8O=>fUOL0i)6pF$^6o!oXSsj=jmI)WCXYf=uMYmJV~r#h8mLneI%K=}yls5I`nn zAK#H;S1FOc>lA6bq%9*m*AX#J9bIYnPI^R4M@D57edJ!rTcrJ0lE~^fEoXDblMqs= z=24Mq#ZWZ%qawr-(#vDEfDl4QitJKLgqf<%a~@@zrAmnBC0ee9c-5q%F%HilArGOPQB>hPWUn#|; z;nJxN^_+x^sUKb-Q^u6$m5GSbLYh}~*dpnPX!ts=;MRMi|$fNfKL;5ytFcvcy)|7MCQoQa)ub_sW>3n(_)S86cU7isy=edolc~ z4*Ot&is;6K4s*vwTSX6Q9V-o~44BO*1?lJtQTg);{GJjcF?ZaWs#X5HQ{`|Q%^7&Y z0mZy%3rPC>sl=c`=u^kw^_9n~-JFxO1|PRC*-Ara*`sx)YW*`&O0KQ6WRXiLZJ(sa zm8vgV8HI*<(5o()FTlAhbwsUUs7a~t(}XI^DhyQkyj|r_6IG}(K!w7r9l zI^K}8xg)GZphP7>=}_46cqvl%vnx1J=l;ab{Tk)wiTV{uGErCE<_cl3Ots`3&0LJA zBtapyHa{P}$xsYRBnMZzOpBwM`<5gbbyak=M9YQw<^<;G2z;13eqb}-teLB_R0dDO zGR5!qME12(c)3d5BB`sWHMVNOM8o&m8V=aSwxU?HDlSn;>h48PBOXssDq2b8{HxBO z2x!Ks<~JWDWSC`Vn1Qd5xdcUk3`60o(l9@=rBil%A|Zd1ZH9lR{M?EsxE0BxHS<#$ z*rD~UxI6hX=cmCYY*M;Y3pprPkU48EJ7viFB1v_>A5yQ! zrQ|PC3dUGm&rWe2$S=02nC^VlL3`cNfeBH%uE4py5++3F_EOi2`9n(})VaOL#94lD zK3~%Ks;?uhmZZ4n?OxWjSu}gN6o0CJTL{Gu=aYpvY8Y2xu%_cNIlm$2 z7CEcb`0qekz%u>-pnLb;P}`k2!s1RG*FD99b~P_oKE;Vla$xmX22G5=zr%`# zl>=Yiqpa&sEcEuxY&v0;K5N~5V^h=ISAI_Zpxfz(TzY%i=k;!c%;ejXzwxwp&3oQ{ zK5w7Qrl$9;w1pgaW$%qo&ueP>6;9s1vraU9U_JM76MThZhn&h4bG#`;{;{?2(88%F ztfnT$tw zU-F1&Zn|~3=i(vHc*dsTWG%E-d&Ug)_|r~8plmSqTsYLq+H2ixWqnK@#!V#{duKO2 zW0ZVZjZNN*Ge3qhx9lx_pDVhW1%JBHdU)aFk3ZR4dbjnab%?P$R0^UCz5Oy#!05Dg z&qe9acowHOl3Q|*ciq)QLJr;g6*qbNXP)>NH1C6kS{rqkMN}5{`bkQ%$oG3v@@)F` z%+?HQYzF-wTA1_aHCFUSs&e{W)@fyPB|&AQmi@}|zRu5a>8$*@YShdr03c~h;2tgNpu{HAB} zAnQWwE^nWQ(14x`hQq2(QXtLSZh=)&##Mbb=GaDjUZCXE0jWWG#H9XwI^>x!q}`J{*1dtdirT}xhYN2DB5ga zqqTPSo7YeI*mF^umA00>(6cxE%cS^ky+5VtnWh`}?!94N)81?=z_4fZ;N%Y$db2V= z-rN3j>b+L_(^eF^u`cjT8R8i;1YH9bzt%H3&3Xm)|H{Jk*6g*&>P_JN9LA1AFtKd1 ze%XSclx)^(eZ=Klo!o3?J?u@n9sT=y??CHn?o?iO@V|g5tnJCSc>7ydTU(mel-#qx zx^|0aT$;6T5s|=D$rhEZ+-{BX%t_mY)J2Z~RDxI^Q_wReMaY^@pv5LG@}_25u?CDV z=%28XEGum_J-yPC+9SEQyxqhvK#67XYX@dcqGb<@qIHBUn?Nhie$TF6U7uT~}h6 z2M_Xid!am9QE7mNJQO*c^%s;OtC2^p;j4;^;e#1rb;kDeMR^tZHF?Av;b0B2L1RW4 zHe?UwRp(sgRo^uRK^BQBAI<_W<*f~sMS^+N@SR6Bh=k|@ zjr|Q^V`N|D`31ppqlmUQV7K_)c;3gu4=8)7Qcon_dSHh#lnro6S1wrO=Ri0gZ<(-h zMnbrw10k6pS=m}>9~%~FOAy=3E3bkFKPo3GRsfp<@1TJx1ntNG4h8w4P%wfZ?7oN$ zWA1`H+PJ~qq5(9a{GzfNDMNYr2PoC0<|iq_EFoJd>4bI^m^v9fYa0ZePR8(OxDy~)aI@k#SBtfxkSx`tAjMzAP+^qrDNJbKdCW^x_!$@AF3Q9H# zQOk8kRj8~aFRE%_w=i#jfI?xz+03)Izy7L{Jsx{tuR=+De`80decV z9PB+Ss2ON2K$n+aRFt?60%Tz2ke1L%=>#bL))BuLWK@TOR4(>r$P1UlUh|~s^LU71 zrLo?1SB0f=qp;bKZp(uhDhl&4M#OE31_2bQ-&&$_9dAMz)R9R)s_(*vs0&Y0r^)Ix zMKvtHO%(4PJh((F@%mBGM57`V{d@P8h|)}7@6F(;=FKJOv7cU4 zs!2!>+vzI_$FYun?EDcseLdkg_@xG&UcY|NvxPTv?$-z({UXSyfX=KrCj z|0p57(M~@t>HJ!P<{yglKUbC=_+0~??kTeK&ysY0V?d{S2itpNtdw+q5^tv`+v$2u zil1oP>3!_<9g?4)7Tf8^dXWIHJXA&i|gB zey-ex@xw$r{Zl)AmZbB8J)Q2o#Fl@hq_duNy5}!;etOA^4u0Har~jVQeZY4}IzLj< z=~vz9txfVSr9wyt%|gS^gEWojfL%t1r1Rq*o$md@mXU5z>ELG_I^7en^ZO*7pIzv5 z?@#RgOL8Th7y5O2IcMiKS|#bcqNdZm>2~>>C7l=9b-HK2U4Ema^D?@f{yRIpS<-8% z5_Y=kB&44XN#~VqJN-60zq}%8@DjA0KF?0~$s#qcINRxkc6zR)&vKT(mXi%1uvL=I z3&=XZzt-!0j#a=kTZCpk*`t#tq-dxfJB5bVQ#Flu9k&CO(<0|o`1vc|nj=CSc*?|h zE zTKp0ImEihChdjYOyv&SU4@r?Ys_{qkS7X7A4*hJ9?3D07h#uIkf!!r|wbYmG8Q3F& zKP>fPI|N1#x`@wxJ_K;EZK)viiFLJZj{kdm=7`cz z=mw*{`rvCeB5n91n{Xe$2hbhf1)TWky#?k;#;*j|eEFIWtS^crdcEfWUyFfLKO}s- zjK6#h22OpiyK=|&fM*IHS_Gwo=Mp%d+XMYLPkTKOpK77kZxOB*{97{i=(qCL_P}SO&^L;S>Nmx<2|k9OLMr`I z{qF98&tpR0j^_+?@HHIgX9RD-6MZ`LOF4Uc;PaZ$ldC8?POFpgRuA;#gTFideAoj{ zADxljJ{MExxd6)equ{@hrE&dQ$zKJZiKlpU@O2;OUT8n!^A#Qt(ZSbqoCgX1g*@%& z>ojoM6QDaeFYW=)7Cs-yIHMnk&J=v`1ypMMd0#;A?R4S6!Ph06|3mP{M>EX*fkW|S z0{YScH;?wsfxa)M8v=XrC-Da1th+V_9BU2wCfd%g0lBO0X4Qk%KOAc-%#rTjdb(L- ziQ+3F-ELP!_tol_57hCyKtyn3gx&e_BSH6l8q#>hhgX@3jr;<-p#|u?=c8y9Zm)3% z>AXQ^D!Toz2v!s#8F9Kn#mQcrK?*JY0FqlR$|LI!XYHqjG+7`Z7V*^)1hJ$=Ow>}C zEJV=VA0#RyvGfhH+>ld#Svx?`zC%XXZXhC2t8Gvk?sm(us$d|9B^wGM*;H1OUc2$%I`AnDJ~QOv=BCe(>#Vl7msB;4QGyfwMGijLXO|C6|C)*# z3woe`TyW}FG?&tPe$zoe-GLu>;4>U}j$HTM^1tW6opx0q102!&9DE+{0sqi}k9W}1 z>rHeJpKSbT`6tMH!_7b6fnVUDuXW%~IUjW3PWpWg+)4i{2kxZ*n*(>!KPUHDZoQFH zXgUaY(jV&qZ^~eDrg!$!BQlS2^ZB0KZxVh5{JwE9L%9+tn{raYnx2#K$@A z6+3X}xL51Ia~%g7#zjENY4*D|=+*$6BQ6R!Wa{BP6 z`DZ!s%N_U}2R_GvhaI?cJb%oA(>M}Ng$;O9B`?04W!duVsyGadBD9JrI-B%{ZXgg+-f)Pc`Mny%Lb2kxYw@4%h) zTJFGSIr!u|a54?eKjOfhe7@BK{{0^CUpsK8J$E^9XT8#BQj3H1;KVO<;7&fX9k_Ge zvdn=y`*oEAciQK79Jtfo9(UkQ`d1yev)p8sUhSnRml{T7I%CkZj4l!Hn~G2_?>7E| z;5x6S|G=y0<>nMXnVOJgY=L_dr}>WAu1hvuW@Ae*E^SBDFKQ{u;6c&}axIOW1m3$8zC(d~Gn=s#8T zs_}I~PwRqoXq@KObkO=D9U4Dh;*(wY+rod23x7uVU*p0r5d20LPA`wsQR>2{O1nf| z_yI+3-0s2$3ZL(~a4p9U7k-JvA9vxirQF>vT&BAQt@F{L_2ZFp+g$h!690`0zhB~? zy722nKYwxIHwd02`qt&<3r_2HPI*cNKi`E96*=`fv*ze z|55a|!iBGuc##W#NBIBHh5uOOdB%m`A^d;l!Z!$?gD(6bkyEc%>-sJdJ|DX1e<0B99o#bqx1D~Vs}!f%v%<+<>~ z5)Zj>y;u827hWax`nC(dO5*pqaGC?r@u&;GSGS`JUm*28=)#W+?%Z>ju5lsVUM_kq zN2d#aO5%egpVt30!7p&(F=?+$1*fQpLe(;sy6A6V)G$`K=%a#fbkV1Y9`v(Y&HoQV zulFL>a=s*T{-=w-eophbi@(l)%0;iAOP#0f6y=dVXG;7+Ics_JbE$xfo+lW{ca4i) zk0al7(R)M=<;Wf{Izwx)AD4A+%+y-m-{WjwVWqJp4VOUJGK40==JmF z%Pl3BE?4s}5nS^hCUVDI^b>^tJuZ6v{Oo-fz1}-JrB7nHgGK)HUAXRdGhO&aD!XyD z3%5l7*SqkKM4!r!P27I=3Ec)4{TD)CFSypjdQudQhg|f!y>_|qPT|w!;-jDIce&{A zQ0$F!q#WHY`J$iEf@^v7djJbv^t1*v}aPG9%MPubFhEsA*GtbECJV0hpg)zG?Vy*XN@g(Efm6F{`Ac1Ro!C#6i@$!} z{FsYgj|1 zTzq~iH{1i{d4blm9&gWc;Vq({EEldyHH^yy*K+FT?wefn^zk(v-*(aK_kPmEuHEun zAh_oLsx00 z|8rdQ`hBd3i@r_lXOoLwzX$ds7rpK;2VHo9*uy(6KKebX-@E7oLhq61DO!GgUpmNz zuT{-xjB?>A!sk-KwSM$_TJv1=y4v7|Z3x7}S zCt02c>2mM$DS<8(T$iiwN5U?g90k&`(Zxr<*YdoJUbo|iE_{j9>q{4(*Dg@}hsijk z<+)n=%QzSQq9QjY3$E*>->13FMX%-go(pf3dhK-K-xa;>ap9W;e@$>*u6|!U9QG`5}@ixl^Dr&;ZcdNa^ZiF_+}Tb z@4p&dxW3P7cH#Pds>6lr`zC!~rRCK3M?R_$4vp*kpj;QO?{`+YaDAV$*@f%-h(;H# z=l{(vT+e$uT)3XcYUOG<^}N(4O4qoaXXd(aJr7*v!u5P?vkTYrrA8O7=OKFihmz?} z&nu3&==D4yN$gJ3>+AAGE?i%K=euxyeJpa}`Z~D9h3o6uV=i1@zYe-^eLXtj!u9nc zN&26bUysihxo|xW&v)T^ye)F!dR*P+!u2@$lndA6-diqQk3U^5T#pY%W_Vo%KC{9( z5>n?<9SQ}@^D`s#)nq1rM3-3*4jY-FDiz_>qF_O^1fTvCSAmAZ`2_``;2MxoW`RQa zl_f!BRZ$&tP?VS9tv5+V=|(2rX{(@5LNnnSI+%IYHOnW2Bls{$*al1S4qARikUHr9 z;o(Dm>RNi-)9i93;C785-B6RU^BPjErq>CjH>yxT?jL9@rMz-`Z$A^dSa2~fl?lIn z$JoJyfV=!lkxD%OxA}9Bmv~C|L`WT}Qa-(J>^!vm8lz{#E)q_6ll`mn>GQ*q-zJd2 zHzdCs*ZDO5A_9cD?SHf6PnG$erq}h?@n;d}PJd%Xe>DMs!sgwQdmcKjMiFo@`m8C}XPu+-~5xC1Io9wQ9>w1;{CYNH|uEYm+gxmDy)8|PM*vOIa4Ohn8=}3eK+|RUFk9798J8@5|63!>37xCcsQ4XxkiSO zZY&SPKE~D+*?Q*`*(O!CA;GQ%?SXo>pZKl{*e|7a!zm+r0jGAe^(=22b@WFl1r(=V zrrL88*ernRFm@Ngek0fd$KJGo_7A~sEVN;V+S@uIFNm>m3U3_N7O3kh`?S{28iWlS zz?63lqxyGJ9n~(vrk}Q4qs`5dX^)jndx^6y5B%agHWgvhP~O@b+X0=*X$IZNK#YwS zLG0_SgV?uP2m9+_J+>!n;ZnDQn05(QtP*z#$EJ>YdceEqh6(_l->P33XWsj`g>}hrd($2D|AZPM4NoahQ4vH+~Chi$N>C$!+Y^HhUZ9Is@C4^=)B7B1_rrKiy5&Rh(#FBBqq+ zDJz&5(RS!shRRe~|&!1{C*#ul)B zQpN?FQ^r-arHqSqq>S6p<>*jb1IUxp+_JSDZ0Um1vh_oR=u#Z0_hSo~tsRKMx|VhC3f$i@`$9#FTH1cyOP!Kr2IVf<32V`J(#%x1Bb zYKRS%upK$}zXR>1h}UwusmNwBm-Rn~C9?cI3^uYMmh44_4T+jt{QNE)Hio3@l^7%} zk9RVpot`k_VbDBEm7wi4*-G0*7Hoswu_@kPQg$bKw)sEVyy25GDO;XL288||O?$)t zi9x$bVOK0;UCPlzNI=k=vX!)hqV{(r#}2^yKIwyP0gux*RM;>(DO!Rt6Lu2AAkKxh zqEHO(`@c-39kn~njU##@u$aKJaai{R+ftp?q#d7|>kRDMx<2!mxt%xJ@^|ruy#3L@ zw0C!O7}L-;zfc#1#=dRak0os<@(rhrb^WC$a6{v=aOgE;adJ57$Jx}7?-99}mTx!z!N05%1pf0|8 zI;rre2RLYN=JOe%eTWseSFf>LNUwq~fN(H5I}J);p6$Iq+YXHR^j16lsPJEYL_Aga z6ope&_^%WmrovxR*r&pOqwrW2K270l75<9C(^dHI6wc+Rj&LYNk${Sr99g0w9*(R~ zktDMf;;mAVWRqTzD^(HM=|@FmrymuOoqkkAcKT5f+380`(#^x*R;wbzOj_02rXsS_ zkBW>le+WSzP?1YG(x@WiIkHnlF6GEB6_K5OR77_AQIQ<;Qyz3&*JTx8z|NLUGfk6>k* zeZT(_>qS>_ZR@U z3{EFkROVbtfYV%_g_-jyv!`LDiuqM+m5N=dVnr%;)!m$rc7aJoDA}T+h}TriQYw*- zpgN&+dJBnMH*XLgYMIHrLkJ9c$O_7@K&j-sgC42Et+K>)&f%2Dyj$m_`&T;59jfq$ zRTOtecGZ8#s<%lh za_|ghZ7OA@_~-sebGgvwLR;{td><)V?U4HuO-r){I?NrbK$~6)M{MRNWG|kEa#iu8 zl#_O#lH*)Dn|(!rct&lj@;Bf>ck7f&W&|(B8&tfXNzDai+Hqovy<#?;KN1xgAUl*C z+%S^&bs1<9E9i5>$b4up#r%q?TQ{gKPj6kZ#b0aqkN^+;oS%YpRM-N&j6r7vtgjz^Xl<}_vw&(kA8sv|2$LQgufY9w|f z(UGE&x5Xo+BjL<`x~cT}^^tIwW|%XCU-<B zR-)hKKFT?B-?+c!eugIH|*Xz%Wll*I1=%tu>EY*MDrWcUfyC9G-eS+2m{0LkM|gE^V3(pR%`mha7=7 z+Gnit7v?T{YpxaX4nAVde&3Uo<{3AHJR9F=HChv_EuIU9AfK0Yr9ppCThLu$r)0*=;0e4vCGKOTnMfz;P|ns z93Da0J!xbOyg?MAS;+kbd5vJ7nB-?rdDsLa?d;X|V5yxr;!&P&UQUj0O6KIuY~RG} zoT=GUvuF4wR79ec!PzB2_$)0eL^MBCSUS6A`qT+iC;KLp_$CxDSuhX3{1k9PbqG%d z3nNt_JQWPV6(RX>)HkN&=z?!dE9n6tKdMw!!v&dLpeiqi+QaOc{53$G5OSk*gAgu-&RC#SpP;J~BF1*i>EmTz&g&_}>Tnrz* z%I$I76m(mQ%UP-v>-2x+5Y)aWxoxRo)})#v;Kpw|u6s1E=D9V_d}pS8=XniwoJVQ1 z)TKb(JLz=KD%(%sN=fHCCY`=O`3a=_>m{9K(COF4(|1TZ-yZ37@6Wh=AJXH1+A-+AbC&p{?28GSM#=KBhr?ww-GkSpmt&9~D_|EY69 z%J%Q{El984nub?uuh-zzEuP6wTUCO?L8+&uzrC}6kLC+ zrSIrw0jF|(IMabU1U>@zHBs&=6*V@?nNB_X=Ieev)NAx}jQ{=NOs5nXFc$FQ~2B>D$=VhzZSeka6N84)B~SR zp}$k;^%Bd89_U}}0jH+wPX0bU;N%meJNol`z{mE0XZ3*308VQFL$_HgPXQ|_ae3<*(xz>H?bo&{TDKHKv9^ z4qgcddEkk8E1btgtF>D@0(iP@#2L~Y*fF(;PqDNwI;AnbJqdHT*jOWH_1s2J6WOO8 zj0(qSb>hWbtk9PG&-P*xJX&m4efaBGL027S2lqCwf{I)%4X4{2T|q-hq#B z;CDK3x;|?@PdRWWpIcHrkb@C#v|bddZctESI%;nF<}>W_42di{KBz6;mm z)wP0Cejolcf9iL15Izcj8s8{5@ux1Y@vRQ}iyXNArl0s+?7-i2@S!x#hkR(#LD(4l zX?(f^AM3yu3Qi{{pX(g-;~ez*+c~1W#DQ;d(2sZEJA2^2%RzssgZ`HeoNQ9d|9KC5 zl4abaWT*UNd%&|?IOU;ZzTgyhwpWP*r@o`*sdeB^JvRwXy2*0T>u<3L&vxKP9Q01S zOK@E;>XUSsA~509AEyzBqo3e(a`s34t-0nyeT@4?k2R#Kf|HXpSiQco-`n=9Xuj_lW;BLL$(gPmu0blRHo$ca$mz+qnoc9Smot$#| zdEHEn52S}&{L!&gaH5}tzyF`TZ-K9>xc1)XoFr_X34)66C_eB3gqPr}2ISNOf<_?< zhz)@R5{2+c!o$i#1D4!~f{zwktY~dZTeVnURM3L8fUULIdM#~jOIuMCYN^ngwp73W ze`c+nIg@h$>36?-`~B`f&YtoNT?8Ku0!rsiAYF~_ATFbE z1gVc$259J{tZGFeCj-$-zPMSJbZ`n*Y6pX z=OW3k`#t&}3;(Zq_+ZOE&@;J|&oM%`(W750e17cVx+eRV9==oP-|=wm|LphhpNKmq z=~H=lOD|0)55HU7CwTaGgij9-ud-}{0UrL5xQBT7Q{ukL!?`wtX1s@=CvNTMMDh#0 zxgQqc6#t{(x;I|&9}1rp9)E40R(km7#QlheH;Y^QOUhp>S3P@J@jr^*{^9W%Ah`CI zlzyhrb(VA}ezo8id$_)DDG%=;ZmnOH&#xrjM?Cs(3a#aNx4)0Ce!hwXYG(ol4`sz@aW%=0Hq$TXC+PY@DUR4Ob=fmZrz)z@@y6QFM9NP zHuY-3RZbm`dC8-{MAH95k6y=Je&^9&C-MHt!}ZLDk39SXq0fqvxFuG?#gJKgk^JUn&1zOM3N8D8-fk0*{aGnbtGllzyJX`;^eDoH`!! zBae^D`3nzMIrn?`TQ*t2-#z|1&e~ZzWGavD%`NnB{SG-(aFtWXWv}q)^?Uw0hn`td zDDsqh^lb&Na_Fgg9XDF&(SJ$wc9)0$R`@*V;aaZV_wZGczkd^4)1~7~mq`Cs^|MLh z{icVXBjxQ0!Ie)>aj*C2uM_$$4!sm9lY$){eW9dlk3%mkjL%UrAk274GQptGx8N%O zX2H*M=*>zf!7udaizJdyJM{d1QFE0?-%k>8y+hCMN;RTp(|&bS5KrxstKQV>c+t0y z7YYHhPqNS;#U8Hp)dUaMdTEh|YkjiX!}Y!1=;8XFzUATie&vY#DyP0Lr+c`TbL}50 zy_Um&bx$xZ+~oFO>=f>Wc|HsQx|@LycdzjOfZf4`&@)x1X6pO`Qfg@^GvaEZ9 zC!A(U^sFns6AUZG*e=?H`%J;zcNI{uSl&zboh0tNIo3p;e)!cA{&WU%Orc|^wGaL% z7t4ohH2hy(5cWdP{VBK^-j9E!BvjL@!F=}x@L-yXl|Y`U9@e7cCe$DENW&|BEilIK zo7F;Cp#g-zr@b0@ruZjF{5p`p_{mDyY5Ws``8)vyIs8b5In7h7Pg@TfA7i*PvB-_a zt?TIaX=eb-D8GF8YIw@e*+*Y~e!u%X0R`7e{Jjn#|69x!)%5qi#`YFfG7R9tAyq4pLJEE+V(QXc-^;4!ifb!_L`~XSUvArz!RqJx6vd z0${LZmw7Hru5FDr*?o50IkwE~(6hmv{iUrbl4~9BElarlixKP|)@1CdmHE#s&ZQ6y zd(UrtQNgA68cdz}&kW67+pu@MLogbE;edUlWP0g>$FUEv0JfGiEF)h*O==ubn(i|? zYFb8xMIm2p34EX7)nqp&wrnkoNL5iI*Jg!SZlv!^vp@)Zv*Gv1|M#f$Ya&6+ouu(e-4-7mAGICtYW{A z_MD(?$Pn#F(|$tE%(IX-8*eSGVy`3Tt`@JS-EPCnnLP*g6D>YxAm~pHj1aUMA##G; zN|0Qx?n`YVa_0UXX!|iapXVwG8-C@(fW&@3VY{~~=Zj?4&GNlV`N#sUoG)>8hslYU ze!oYTa>iD12)^UAT5KBWNo!)ouKAr9Nv!7({3cesHNWFcmDnpHzT3sOm-XGD&Xfte zZ9Z3&1+gLukyx>4fpzwwc-R^v&c4>UdSL#Oo!l`ikqRDO%R*QCok%9VF?ByYwYC8r1N+kdKk0xC?1 z6*-rq`$2}GKbISe4eP?)6M3fw!@BfFcd*UD_mt#=B?Gn_2zrzVcQ;6fX!Ap~*FyGG zbd;?RvWcUUY@`rpe#_J zU_heCnGkiJxdDy_s z1}}rW=7@sDk3~}JZZ4~+HLG`m5tTJl>Z;08)l;fuHNRa)d{bF9)`4Hvs_$67%_cLhLzD77E(vc$8Rc| zP8pFJcg;34qHJ2l0FxtFNnYMZ^CpUx75T6l-rreSQH`ZaWvOy3jgQu@4>GH%;g4g_ zqTLHENnz-;R6BbfWcfEm>~lWYpoS{r+I(4eZkU+xvZCKzHV-;vMetvrN~SDT`W zzOXg1gRHSOt`L$Z6Uzk2~cw4N?Z&9ksOHY;oN+xH^W;Z@q$69PGNNOn9#>^!zl; zM9;CDO!%-Y_^2#+1#rr*a_f`Ta3=n9v*3%f;QG2p6+z~8lX8!)T(rw|i`f@2wpt}= zc$>P#)O9ALvB}y;W4DVR)7B0$mvzm`WY}rgGj#E#2DLc#q4ZzRg6kRr@?jZJ`o8k2 z5ND4?@vF1oIz~-;H0Ke$&Kddq@6E#JJ6Z4_Ik?Mzhl8`OQ8~{?t4YInUHy#6g4Z~> ztG8uYaBd`~A%6}5XuRFzQ-Juf4zBl>_;`s!k1k8ZNAG{}`QPl&yZl#X!K1N#@OJrc zcIaKbnGY1uat=oAulqrw|3lI>&cYF{YhKDdT+6qclkef0PpUtqA0l)qkA8yix!%K%6?}?^>zeFZ4<9FP?*F3E zc=diVox@f9*On}JNa*>HD#7?{@%VgR+&ev7>rHoU5Z{+sLYEMx8n3R=KFY^Mo>M)1 zi{S2>9`b)%@KT{?bhK)Fs`q_qyej{F9)FeJU5n$&|D;E+^1tZgBF}3cuJUVLM0w13 ziO{pIrcwE=%kCY@gck|{qmif#QtaWXha;HFY&p32|D(A||07t6r)Vw6I#;>0lO>rU z%4T1JVYQBDn?!Ra{)kJnM93JPR+7p1@t+4G@;uV;=Oe7olksZ&@4JO118pB*6tx(C zu4$G6x>C}?^t1f>=^p|tQ~ZCIg8w&{X$IQT3>bs#lTVT&IvnH2RRX_E@-LT$T*Fg- z%I?e0cE{%lDCjPP+Aa{I@o6i7Wr}~J#INOq@v{!_+UzACI+cV@J z`@kPP+-P{3j+;(g>3N=w z^LK4deu%>-n;CrfC?4B51IK}u?t+c8ZX@EwbfqS3UOFOPK<^Yzu8q9wthW#kjTiL6 zIjtn$RJ^n6`3t_TG2EcXI1aU34%kQva0umx>Bm|2*%VPQ>d1jvzIegX zl1~*CS5O*9y6`C<5z3?#O(i8bbvCxGp}Ane(FQ0kF;jeJ zzu1TqHxKO2gEyW$(Ab=`xhu6S1%)GIaS6^WrF}~=Yf=-CnV*Mw%!c`I2Kjf5$8@6>gN8kYDn7#OK;)5> zOOyW)i1H#4rHqKVHu4|Hmtx6=`~^En#wfn>PfV544${=J;l-(@5*%C{q#9$X#;ako zRP&XpVI%U^QZ$W(1`QPiqtsc<*}X1%`Qh!i#4b61^h100=5?9)_1t|Mx76OT@}6^l zv0=n*KRo$M*IoS2*LNH0<=+fj{g1!gxxV-NH-DpQ-io8Y z)8^89Uo2>Be_Gk8ix%GS#c|8~o;Bc8ue|fU55JK3__(4cQ(t}hwV!|H?sFc!_M4lp zS~uvYpMPZjGqVre^!rtHIe$(*Fk@`R%+D3xe*I4>-|o34e!_$^9(#Q4cmI0gr^~DR z7ca;!z5FZPe|`10FZ}-azrFh058gZTyipx%mh@QM_GiES@&3WLj=bi^HwSK=y6Ibg zKmB)~4Ldyl#PGRG?`!(Qq+QeA{n3AZbWw291t0wB*-n$kYz|-g>HVQUl&X8wp6&HASF-x%4a=Hmdj>uU`@MI@+`hy(qY zjjd{q_|*x&0usgQ=z((q#bx=AU?UjBW?R=($odhej$$M>iOcCvqoWY9Rs4RkOqSD% z!|AN}%WZTe6#s5vm=8tVV@19R%xP=K7;Zv9qvemy5L^)Jy9h|jX>mtg59g82%cal4 z<)xqO)<$RHLOToB)}4iGr&D_EbxQB>=jHq((d4K!PSEj?GntXYJkCVVsjTEZ9sv%*Y zabcHmL{oF9g>O)>K~Jg<5~xB~yLD6Jhq&oT#x)R*BHut}JJbY|di z7#1asX4>2tHnKEB_5YT0Y^GAyIW~Jtk=eg{F-tCtse;u%aalA6r+aEmm8$;n=b|%$ zZn42_jTrggYY!O`KmUQZ2+ha;`#Cy(3iG_3$WRa%*55qOM;k6}j_8-^{2z5X>F8k^h`u&^G1-#Uw5ug)5m8fE?jAp2_FKSeDoX>ZC*!aq37oh z>CZFOVoPf&)oJv`y6<50b{%xSjZ`v87EQhBi_RrT*08U}aRQx_d0ude!`xR~&v)_h zH>6yUPgjTD^pD`yF;Q5J(f%ND+CMGfO?Lur#pP2rZEl40-SJ0roP9uZERQYbY_XD$ zJDgDD;N;UF?tvb@U)-Pa@cYC)!oziJdz6RYC~kLdgz@SaZMjF^NAytT;l~O--NSnb zuKhUG+wX<$R*zogTk7He6!$U@A1ZF`y(#}E1^=o?zee0Y@NkxUn%C?j%3pB?sz2qg z<>pmnaNSRLmf(E2EKv}*m~&S|i`sa~dfd|nqma~(c>-_>Y7FkZLz z);dq)Rr;I7;^T#aGa8A?AjKZ8dY<6ns?S9puIW93Ifo;^Q}N$mpOoLxmtrN_%Rcw8 zRVv&GLdo}yVKwiyyq_s}Lg@6N``*>9Pe1n@Ce*5vy z2gdkSPFRh3R|r>m!l_fAOF^9}{1R4lFazu(`qgmyTmc`oM?|nZC*fU;cAxfZf_cR( z*eKywdJHuE3O@u(CjAwO{w4?^^~bte!>eAI&HAbcsd+4y@M~QVc3*zFec2hrUI&9X z#gl!(Oz~%%yQq@-=QCvH7(afjH~mC&7k!Eb6xrJl4}YK1*6u9=6dS8EcOml@TZ)-N zj$Jo5m2~B!u>^y~$>uFVtb1~bu@&bue(T47vexjUH=kQ+tsQ2M?pu&~bRGm4UN6|R zE77pyQe3ko?xxZ=H~l`L!|IHNR2IEpTP^N1B+%8|pT>cA%0qw@@13OKx~^kl&gIQr z7}bCCqU3>FZnmTQyuWZ+%J5Caw!$hy;b~+0sbwX+@e0G>=AOQbkuwO58^LxLBH4D1 zU`NVECN$kZgSn4l_&034l-JY!=a%Gt>TP!$nf`zv=W;rSw=z!pp&gg+-?^z20u6^i zn6HWb5Y{l&_@YiUw9E`}Vq-h+(DQeN@n%RSXjyXab9@72L(6gK5g`fN92M`vrC|f- zv|BgGsAkvhaNS&M!=+=qG}3S~m4ePsrIwA{OW0+MAYeRl8}RM!J}KTkv>afzYaSc+ z%s>)wsb&50)=5~|go`OxBlOB9l%(V%))qD<*H~MJ#^j@jbU9LKx4KCxbCAlW+zpF+wujeMjXgC`%!B=<&@`|7<7?G7pTOCopfIh#Ls`61=rDsuPy z<9B~@-67?EMdkkZ#_z@tDfc#!J9qoaMb(Ft`*o4K=hfl*xTIc0A9a8SMRPJeaPJvDiQBHQL+_N^^KK77u?-99kPYs_M)>>{; zs!SPdDX}cyU;gFq+FH4Do$_to22%!2i8VRT^1X4y_fXYR?zT?(HgAJ@cT9;j8f5vt zdfaEuq}<6hot*M*-UjpTw7h97-`5Trc8rx9?@m;{J-JPZrQBcn)3&n@DYwaa$elZ? z>rm16LF6_XgxozB9`~8E4k@>J($v10drK+dp%3cG;pL`PrWooSR)XQ?IZr=AN{atv1@WOtR_A({oGjb5WsW%TrTA zDBB5>Pd_fZZ2Fq#HsA8_DcNN+Wtn>W(ld=&^6!G}=lSbr4W-wofnYlyOVhRJ?E0 zA4;(;cWE*j)v)^c{@Cj)4<@6@IO?#b-@X|KlhG6_%Gl7pz%;7KmQGBXjHb|2#@-Kq z_U41hXkJOmc-4Y6(+?)2$w10jc-+ro2b0khFUq)Q!$;!}rbkowSq>lS9A0@a8O^K7 zyk2nYqv%{_&ude0P{tp1{K1fe$!LlhE5Y?Y{rNculhM2c)Z_H?=5aRB6 z6Du3>DUe*5YS@^APXat&%;A;pkHmf$dEkr1c!cy=<9Kusj}G*BlpY7`khd(9lJ65) z6ZY0(ng66rIk$$#dk z{AYgJH1a^hrdZ>v_{cyK|D69!+x%x<-t@b$?Q76P!;5iz2paMaEcvG27l==yl~1>} zP`oea%~noIV9X+U9_eFy!j6q#)B_)$vJk~(b{$u9iiwsAnSrZ#=Cwy=P%hqjwNZw% z2m0Lx#=1;N&owY3>bY~^^L6}r2M)Xf$PCY9K5&2`+L6Yb4e*YJztkKEz^!N|Y|hFr zz(?%&6V?L(ehwH10x)tON@gOD4g?@Od?p4#>_-05TxB1)Q7lUXSE^b*$`vw2K{;Tz|x_PT+R@iHw47E6O?OvK1;dcD=PA_=I0iR zS8=>3a!o~?|B2A%Gyog%1N5i)zI`C#i!t0}My_HH(26Tytr!njF^VnA2YGsHe8mJt zyxK-Q#`=hByqq^+RDBJIjkemzEu>FNbis=D)`kQ}@jgv!V#U&hR*a{aVw@weFuy#A zJ#&1z)R-G3um@$cAG~Hgt+v6^!6*tOeqzIu`52)G<|J(Zh{{U`-SY zH_2JHr^GBl{0y zQx_boa6%`ZLr`!m67=7H(t<42@=sdGdL)CtrYn6Bmma#1zS66UzdlTkcjzj3bYZ3l zbF>7P%Q26E)43~CZ}t@5tP956s#5aaJUX)^9eTmo;T+_^q1;Ji8Z8Y&X*i5?9Nr6J z4dLw%KK9sSL&AQ4iJ#R4>$}E%doe9I03s*Rz#rVyZr5~u`<^-ReqDxq@NT$vpMfUh zH~wY(yFxb&=HIk;khX+f^cL=J8ddl5Z40^~iMn=Uh?)K(&Xu{|53mX6;13Gd=> zPyCSfd9zlId%9%>nYpJ@R?XQ1E^IbuT`L!zZ-M(}Cf)Q&*2uM9NtfXai=p;HLvLwZ z`sF#JaY0WlZ-5MvHRk%mv_*4ir&Tzs?V`nUGs$n)pZ$G%N@?~6w$F8 zICF!1O9l@eI_%2J|BKG6i1yjoUY$6eF^nXoZo6q z-S=5hsDJ#0D7>zzGflJlC+=uZf)f#B6~n=pW>Wp*uSDTDSZ~|FMgCtg{^Hf@!M68* z!kWBdk&L}suE`sTx|v41DNH}{-^kpWb``n{{%x7F*2bM-|DD(HodfyZHGJBm?I*ap zwcpCM0Hzy=r)x&TkqN&ZIQjnv3jmBMlXzC*FB3i1@Uex{_ZM$ktC~itr|2bgDyFQ9 z`zFn>*MQj?x7CRmLGV`!2g7+{cGYwZUxUc)<9`>N#fM)kN*|Zr$JvLO!xqsD za<<^)Bcd6k$ic~Hwzvm+_+P}$@_eRqu@>5r52mV5NN zMsTu+|6bg+9zIdroYADwc&`-x=G))Fw;8G+xI>;we}%a3@$fw1qxFZ?4w&Wr)Up<+r3u-@!9PE|o{ut`>Rt263M+Pd?moGSQ=d!o-Rb z$UJ(jS2lU{9|`@hJY3-5cODJbG>G#tKd{ zTD9HKedo%DPnv}upQMF@w>|u2!T;#-*Y+nTVF{GKo^Q~_!)FMe5gz^}!AA+M@@qSG zqerj&=XtpDf6>D~BYJz);m`U|jay%-Zs@1wPUTVhe|1fyma7TEkZR?hmXk#uuKBpy z!&UzqJzVwnziTM1Vv0pS{TrgT6vdv`JkRXh%!8#Lm;!@1$Wy}}y z)t3JB<3A7H$@yTX*va*4jt(>&u@>b`lpIZ-W#|!uVayQDr}VmZ?nf z&ye~@`>mE+>#{a$QvXl1hO+;_zH%J=;jf`w>vXJ(jUdH%p9}2y53*{nvGkQK$vyPk zlHAJ&X4kfFmPc{SI5FoJPhpYamgFu{>^_DQaOOOMW;4aMi_>4bVzt|50)Yr z5U%yJBJ8IKdt+dBQSy~ru&~jj#gQui&RMNzmj{Phl3pyC13De^K)F{5z_VGAnuM-lYX%`}5M0 z7$zY5q8!_*Jj;CC9_P*Ym*(Sg+_S(lPr^}&pX4lncq~!&7Q(cf8zjmr8M@s(vBla= zgN>f?pgp~qLmm3#=VP1R#6)(r%^MIq7dB)5DbLud#YlE1v(^7xS}|$W$sDkKE<1Md z6~(3*jh#CL0TL@Vm@~3_(t!>01(>A~`}l&JBKw2_%r*&LQ7|ot^}5fn;u!)Iu1(0Z z+RRj18|Pr{l!z4kNi4BdR<4wlYfL9|EO^SwRniGteuG%bvQAkkQ&zB{Jji>vwHpDh z5CIA>rF8{$gz2{e93n3EatbW=i3OM)6Z<68R!26|^NIKF=W=g7PvLHdeg3l1eh`|= z_PUk7gKp*T*m^!k=302BwzEe+KYixru+P*6H)x36y12;*t?-Q_aNiP(*xwKEIE<;7 z!`Zvf76Gb{re9E44r}lJxv`zUsBhT783D8LK0L+D3k=V@X9G^z?%oB*XrIO%_VENx zc((H~iFR9uhJ7D=%mgw&;S~&D&mSDj%|~c{6F0{P#WYmg=N^2_%rzW(BEby7x1Jn` z2KCK={z3e?Q{EZp_ofcgrUR_rqM3k}n91Xs%leyB0PL)UB1W&queP$Ten#f~^BE>G zFm?Ms@zCn7wk#fW?BCRU(b#%(H1>Y6gf+EKx& z^7y~Ezn!Cktxdu%;Yjmn1D87nuB{IHti;u=HGW`=Fw3efkF?n`YWQl3Io_dmdUP

)ARB9&*X;J148r-^&1hp!U1>Rb7+ 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

6wXF`{-qGoOlY7D3Gvp@Z`@NgBpQLnmcb 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%0ABU$bk(JyhKwPq&^PTVoRD5$qtWn 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 O>R-tx^b#dp*Z)5X@WBuO literal 0 HcmV?d00001 diff --git a/tools/sdk/include/crypto/bigint_impl.h b/tools/sdk/include/crypto/bigint_impl.h index fef6e0378b..8981f06b95 100644 --- a/tools/sdk/include/crypto/bigint_impl.h +++ b/tools/sdk/include/crypto/bigint_impl.h @@ -122,8 +122,8 @@ typedef struct /**< A big integer "session" context. */ } BI_CTX; #ifndef WIN32 -#define max(a,b) ((a)>(b)?(a):(b)) /**< Find the maximum of 2 numbers. */ -#define min(a,b) ((a)<(b)?(a):(b)) /**< Find the minimum of 2 numbers. */ +#define axtls_max(a,b) ((a)>(b)?(a):(b)) /**< Find the maximum of 2 numbers. */ +#define axtls_min(a,b) ((a)<(b)?(a):(b)) /**< Find the minimum of 2 numbers. */ #endif #define PERMANENT 0x7FFF55AA /**< A magic number for permanents. */ From 74a9b900b470a55e9ae6a330a17fda58925f9367 Mon Sep 17 00:00:00 2001 From: Myles Eftos Date: Thu, 13 Apr 2017 21:08:50 +1000 Subject: [PATCH 11/12] Adding tests/host/bin to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index a89e984662..8fbe2419aa 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ exclude.txt tools/sdk/lib/liblwip_src.a tools/sdk/lwip/src/build tools/sdk/lwip/src/liblwip_src.a +tests/host/bin *.o *.gc?? From 84b0005cfc5becd3f58813aeca9899b81bc857f0 Mon Sep 17 00:00:00 2001 From: Myles Eftos Date: Fri, 14 Jul 2017 07:30:05 +1000 Subject: [PATCH 12/12] Saving works a lot better when you actually hit save --- cores/esp8266/Updater.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/cores/esp8266/Updater.h b/cores/esp8266/Updater.h index faaeb29085..b1b18165ba 100644 --- a/cores/esp8266/Updater.h +++ b/cores/esp8266/Updater.h @@ -175,14 +175,9 @@ class UpdaterClass { bool _async; uint8_t _error; uint8_t *_buffer; -<<<<<<< HEAD size_t _bufferLen; // amount of data written into _buffer size_t _bufferSize; // total size of _buffer size_t _size; -======= - uint32_t _bufferLen; - uint32_t _size; ->>>>>>> 74a9b900b470a55e9ae6a330a17fda58925f9367 uint32_t _startAddress; uint32_t _currentAddress; uint32_t _command;