[TLS] Update TLS to be able to use ECDHE_ECDSA_AES_128_GCM_SHA256 cipher

This commit is contained in:
TD-er
2025-10-10 20:52:28 +02:00
parent 6f5be97fe9
commit af56ce7fb6
28 changed files with 1909 additions and 495 deletions
+2 -2
View File
@@ -10,8 +10,8 @@ BUILD = esp8266
# C compiler, linker, and static library builder.
TOOLCHAIN_PREFIX := xtensa-lx106-elf-
CC := $(TOOLCHAIN_PREFIX)gcc
CFLAGS = -W -Wall -g -O2 -Wpointer-arith -Wl,-EL -nostdlib -mlongcalls -mno-text-section-literals -ffunction-sections -fdata-sections -Werror -free -fipa-pta -mextra-l32r-costs=5
CFLAGS += -D__ets__ -DICACHE_FLASH -DESP8266 -DBR_SLOW_MUL15=1 -DPGM_READ_UNALIGNED=0
CFLAGS = -W -Wall -g -O2 -Wpointer-arith -Wl,-EL -nostdlib -mlongcalls -mno-text-section-literals -ffunction-sections -fdata-sections -Werror
CFLAGS += -D__ets__ -DICACHE_FLASH -DESP8266 -DBR_SLOW_MUL15=1
LD := $(TOOLCHAIN_PREFIX)ld
AR := $(TOOLCHAIN_PREFIX)ar
@@ -412,7 +412,7 @@ br_pem_decoder_run(void *t0ctx)
break;
case 17: {
/* co */
T0_CO();
T0_CO();
}
break;
case 18: {
@@ -425,12 +425,12 @@ br_pem_decoder_run(void *t0ctx)
break;
case 19: {
/* drop */
(void)T0_POP();
(void)T0_POP();
}
break;
case 20: {
/* dup */
T0_PUSH(T0_PEEK(0));
T0_PUSH(T0_PEEK(0));
}
break;
case 21: {
@@ -474,7 +474,7 @@ br_pem_decoder_run(void *t0ctx)
break;
case 24: {
/* over */
T0_PUSH(T0_PEEK(1));
T0_PUSH(T0_PEEK(1));
}
break;
case 25: {
@@ -506,7 +506,7 @@ br_pem_decoder_run(void *t0ctx)
break;
case 27: {
/* swap */
T0_SWAP();
T0_SWAP();
}
break;
case 28: {
@@ -0,0 +1,308 @@
/*
* _ec_c25519_m15.c — BearSSL Curve25519 (X25519) implementation using ESP32 ROM-backed Montgomery arithmetic
*
* This file provides a fast Montgomery ladder implementation for Curve25519 scalar
* multiplication (X25519), leveraging the ESP32's ROM bigint accelerator for modular
* multiplication in the prime field p = 2^255 - 19.
*
* Key features:
* - Field arithmetic in the normal domain using single-step ROM-backed multiply/square.
* - 8×32-bit little-endian limb representation for all field elements.
* - Constant-time Montgomery ladder for scalar multiplication.
* - RFC 7748compliant clamping of scalar inputs.
* - Supports multiplication by arbitrary ucoordinates and basepoint generation.
* - Fully compatible with BearSSL's ec_impl API.
*
* Internal operations avoid heap allocation and use fixed-size buffers.
*
* Requires: ESP32 platform with SOC_MPI_SUPPORTED enabled.
*
* Author: Christian Baars
*/
#if defined(USE_SHA_ROM)
#if defined(ESP_PLATFORM) && !defined(ESP8266) && !defined(CONFIG_IDF_TARGET_ESP32)
#if __has_include("soc/sha_caps.h")
# include "soc/sha_caps.h"
#elif __has_include("soc/soc_caps.h")
# include "soc/soc_caps.h"
#else
# error "No ESP capability header found"
#endif
#if SOC_MPI_SUPPORTED
#include "rom/bigint.h"
#include "t_inner.h"
#define WORDS 8 /* 8×32-bit limbs */
/* Prime p = 2^255 - 19 (little-endian 32-bit limbs) */
static const uint32_t P_LE[WORDS] = {
0xFFFFFFED, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x7FFFFFFF
};
/* R^2 mod p (with R = 2^256 mod p = 38) */
static const uint32_t RR_LE[WORDS] = { 1444, 0,0,0,0,0,0,0 };
/* A24 = 121665 (normal-domain constant) */
static const uint32_t A24_LE[WORDS] = { 121665, 0,0,0,0,0,0,0 };
static const uint32_t MPRIME = 0x286BCA1B;
/* ---------- limb utilities ---------- */
static inline void zclear(uint32_t *a) { memset(a, 0, WORDS * sizeof(uint32_t)); }
static inline void zcopy(uint32_t *dst, const uint32_t *src) { memcpy(dst, src, WORDS * sizeof(uint32_t)); }
/* ct compare: return 1 if a >= b, else 0 */
static inline uint32_t ge_ct(const uint32_t *a, const uint32_t *b) {
uint32_t gt = 0, eq = 1;
for (int i = WORDS - 1; i >= 0; i--) {
uint32_t ai = a[i], bi = b[i];
uint32_t gt_i = (ai > bi);
uint32_t lt_i = (ai < bi);
gt |= (eq & gt_i);
eq &= ~(gt_i | lt_i);
}
return gt | eq;
}
static inline void add_mod(uint32_t *d, const uint32_t *a, const uint32_t *b) {
uint64_t c = 0;
for (int i = 0; i < WORDS; i++) {
c = (uint64_t)a[i] + b[i] + (c >> 32);
d[i] = (uint32_t)c;
}
uint32_t need_sub = (uint32_t)(c >> 32);
need_sub |= ge_ct(d, P_LE);
uint32_t borrow = 0, tmp[WORDS];
for (int i = 0; i < WORDS; i++) {
uint64_t t = (uint64_t)d[i] - P_LE[i] - borrow;
tmp[i] = (uint32_t)t;
borrow = (uint32_t)(t >> 63);
}
for (int i = 0; i < WORDS; i++) d[i] = need_sub ? tmp[i] : d[i];
}
static inline void sub_mod(uint32_t *d, const uint32_t *a, const uint32_t *b) {
uint32_t borrow = 0;
for (int i = 0; i < WORDS; i++) {
uint64_t t = (uint64_t)a[i] - b[i] - borrow;
d[i] = (uint32_t)t;
borrow = (uint32_t)(t >> 63);
}
uint64_t c = 0, tmp[WORDS];
for (int i = 0; i < WORDS; i++) {
c = (uint64_t)d[i] + P_LE[i] + (c >> 32);
tmp[i] = (uint32_t)c;
}
for (int i = 0; i < WORDS; i++) d[i] = borrow ? tmp[i] : d[i];
}
static inline void field_mul(uint32_t *dst, const uint32_t *a, const uint32_t *b) {
ets_bigint_enable();
ets_bigint_modmult(a, b, P_LE, MPRIME, RR_LE, WORDS);
ets_bigint_wait_finish();
ets_bigint_getz(dst, WORDS);
ets_bigint_disable();
}
static inline void field_sqr(uint32_t *dst, const uint32_t *a) {
field_mul(dst, a, a);
}
/* Fermat inversion: a^(p-2) in normal domain */
static void field_inv(uint32_t *out, const uint32_t *a) {
static const uint32_t EXP_P_MINUS_2[WORDS] = {
0xFFFFFFEB, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x7FFFFFFF
};
uint32_t res[WORDS], base[WORDS];
zclear(res); res[0] = 1;
zcopy(base, a);
for (int wi = WORDS - 1; wi >= 0; wi--) {
uint32_t w = EXP_P_MINUS_2[wi];
for (int b = 31; b >= 0; b--) {
field_sqr(res, res);
if ((w >> b) & 1U) field_mul(res, res, base);
}
}
zcopy(out, res);
}
/* Conditional swap */
static inline void cswap(uint32_t *a, uint32_t *b, uint32_t ctl) {
uint32_t mask = -ctl;
for (int i = 0; i < WORDS; i++) {
uint32_t t = (a[i] ^ b[i]) & mask;
a[i] ^= t; b[i] ^= t;
}
}
/* ---------- X25519 ladder (normal domain) ---------- */
static const unsigned char GEN[] PROGMEM = {
0x09, 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
};
static const unsigned char ORDER[] PROGMEM = {
0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
static const unsigned char *
api_generator(int curve, size_t *len)
{
(void)curve;
*len = 32;
return GEN;
}
static const unsigned char *
api_order(int curve, size_t *len)
{
(void)curve;
*len = 32;
return ORDER;
}
static size_t
api_xoff(int curve, size_t *len)
{
(void)curve;
*len = 32;
return 0;
}
static uint32_t
api_mul(unsigned char *G, size_t Glen,
const unsigned char *kb, size_t kblen, int curve)
{
(void)curve;
if (Glen != 32 || kblen > 32) {
return 0;
}
/* Clamp scalar per RFC 7748 */
unsigned char k[32];
memset(k, 0, 32 - kblen);
memcpy(k + (32 - kblen), kb, kblen);
k[31] &= 0xF8;
k[0] &= 0x7F;
k[0] |= 0x40;
/* Load u and clear high bit per RFC 7748 */
unsigned char u_bytes[32];
memcpy(u_bytes, G, 32);
u_bytes[31] &= 0x7F;
uint32_t x1[WORDS], x2[WORDS], z2[WORDS], x3[WORDS], z3[WORDS];
br_range_dec32le(x1, WORDS, u_bytes);
/* Initialize:
* (x2:z2) = (1:0)
* (x3:z3) = (u:1)
*/
zclear(z2);
zclear(x2); x2[0] = 1;
zcopy(x3, x1);
zclear(z3); z3[0] = 1;
uint32_t a[WORDS], aa[WORDS], b[WORDS], bb[WORDS];
uint32_t c[WORDS], d[WORDS], e[WORDS], da[WORDS], cb[WORDS];
uint32_t t[WORDS];
uint32_t swap = 0;
for (int i = 254; i >= 0; i--) {
uint32_t kt = (k[31 - (i >> 3)] >> (i & 7)) & 1U;
swap ^= kt;
cswap(x2, x3, swap);
cswap(z2, z3, swap);
swap = kt;
/* Ladder step */
add_mod(a, x2, z2); /* a = x2 + z2 */
sub_mod(b, x2, z2); /* b = x2 - z2 */
field_sqr(aa, a); /* aa = a^2 */
field_sqr(bb, b); /* bb = b^2 */
sub_mod(e, aa, bb); /* e = aa - bb */
add_mod(c, x3, z3); /* c = x3 + z3 */
sub_mod(d, x3, z3); /* d = x3 - z3 */
field_mul(da, d, a); /* da = d * a */
field_mul(cb, c, b); /* cb = c * b */
add_mod(x3, da, cb); /* x3 = (da + cb)^2 */
field_sqr(x3, x3);
sub_mod(z3, da, cb); /* z3 = (da - cb)^2 * x1 */
field_sqr(z3, z3);
field_mul(z3, z3, x1);
field_mul(x2, aa, bb); /* x2 = aa * bb */
/* z2 = e * (aa + A24 * e) */
field_mul(t, A24_LE, e); /* t = A24 * e */
add_mod(t, t, aa); /* t = aa + A24*e */
field_mul(z2, e, t); /* z2 = e * t */
}
cswap(x2, x3, swap);
cswap(z2, z3, swap);
/* u = x2 / z2 */
uint32_t z2i[WORDS], unorm[WORDS];
field_inv(z2i, z2);
field_mul(unorm, x2, z2i);
/* Final reduction if needed and serialize */
if (ge_ct(unorm, P_LE)) {
sub_mod(unorm, unorm, P_LE);
}
br_range_enc32le(G, unorm, WORDS);
return 1;
}
static size_t
api_mulgen(unsigned char *R,
const unsigned char *x, size_t xlen, int curve)
{
const unsigned char *G0;
size_t Glen;
G0 = api_generator(curve, &Glen);
memcpy_P(R, G0, Glen);
api_mul(R, Glen, x, xlen, curve);
return Glen;
}
static uint32_t
api_muladd(unsigned char *A, const unsigned char *B, size_t len,
const unsigned char *x, size_t xlen,
const unsigned char *y, size_t ylen, int curve)
{
(void)A; (void)B; (void)len; (void)x; (void)xlen; (void)y; (void)ylen; (void)curve;
/* Not applicable for Curve25519 (no ECDSA). */
return 0;
}
/* see bearssl_ec.h */
const br_ec_impl br_ec_c25519_m15 PROGMEM = {
(uint32_t)0x20000000,
&api_generator,
&api_order,
&api_xoff,
&api_mul,
&api_mulgen,
&api_muladd
};
#endif /* SOC_MPI_SUPPORTED */
#endif /* ESP_PLATFORM && !ESP8266 */
#endif /* USE_SHA_ROM */
@@ -0,0 +1,468 @@
/*
* _ec_p256_m15.c — BearSSL P-256 implementation using ESP32 ROM-backed Montgomery arithmetic
*
* This file provides a fast elliptic curve implementation for secp256r1 (P-256),
* leveraging the ESP32's ROM bigint accelerator for modular multiplication.
*
* Key features:
* - Field arithmetic in normal domain using Montgomery-backed multiply/square.
* - Jacobian point representation with full group law (point add/double).
* - Scalar multiplication via double-and-add, supporting arbitrary base points.
* - Conversion between affine and Jacobian coordinates.
* - Compact encoding/decoding of uncompressed points (04 || X || Y).
* - Fully compatible with BearSSL's ec_impl API.
*
* All field elements are stored as 8×32-bit little-endian limbs.
* Internal operations avoid heap allocation and use fixed-size buffers.
*
* Requires: ESP32 platform with SOC_MPI_SUPPORTED enabled.
*
* Author: Christian Baars
*/
#if defined(USE_SHA_ROM)
#if defined(ESP_PLATFORM) && !defined(ESP8266) && !defined(CONFIG_IDF_TARGET_ESP32)
#if __has_include("soc/sha_caps.h")
# include "soc/sha_caps.h"
#elif __has_include("soc/soc_caps.h")
# include "soc/soc_caps.h"
#else
# error "No ESP capability header found"
#endif
#if SOC_MPI_SUPPORTED
#include <stdint.h>
#include "rom/bigint.h"
#include "t_inner.h"
#define WORDS 8
/* ESP32 ROM Montgomery parameters (little-endian).*/
static const uint32_t P_LE[8] = {
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
0x00000000, 0x00000000, 0x00000001, 0xFFFFFFFF
};
static const uint32_t RR_LE[8] = {
0x03000000, 0x00000000, 0xFFFFFFFF, 0xFBFFFFFF,
0xFEFFFFFF, 0xFFFFFFFF, 0xFDFFFFFF, 0x04000000
};
/* -p^{-1} mod 2^32 */
static const uint32_t MPRIME = 0x00000001;
/* Factor to convert ROM Montgomery output back to normal domain (8 limbs) */
static const uint32_t CINV2_LE[8] = {
0xB15F7DC9, 0x21BC7192, 0xF82DEBEB, 0xF2086906,
0x8AD3BB54, 0xE34453E4, 0xB2B4EF16, 0x5FF55809
};
/* Generator point G in little-endian 32-bit limbs (LSW first) */
static const uint32_t Gx[WORDS] = {
0xD898C296, 0xF4A13945, 0x2DEB33A0, 0x77037D81,
0x63A440F2, 0xF8BCE6E5, 0xE12C4247, 0x6B17D1F2
};
static const uint32_t Gy[WORDS] = {
0x37BF51F5, 0xCBB64068, 0x6B315ECE, 0x2BCE3357,
0x7C0F9E16, 0x8EE7EB4A, 0xFE1A7F9B, 0x4FE342E2
};
typedef struct {
uint32_t X[WORDS];
uint32_t Y[WORDS];
uint32_t Z[WORDS];
} p256_pt;
/* ---------- small utilities ---------- */
static inline void zclear(uint32_t *dst) {
memset(dst, 0, WORDS * sizeof(uint32_t));
}
static inline void zcopy(uint32_t *dst, const uint32_t *src) {
memcpy(dst, src, WORDS * sizeof(uint32_t));
}
static inline int is_zero(const uint32_t *a) {
uint32_t acc = 0;
for (int i = 0; i < WORDS; i++) acc |= a[i];
return acc == 0;
}
/* big-endian bytes -> internal little-endian limbs (reverse word order) */
static void be32_to_le32(const uint8_t *src, uint32_t *dst) {
for (int i = 0; i < WORDS; i++) {
int j = WORDS - 1 - i;
dst[i] = ((uint32_t)src[4*j] << 24)
| ((uint32_t)src[4*j + 1] << 16)
| ((uint32_t)src[4*j + 2] << 8)
| ((uint32_t)src[4*j + 3]);
}
}
/* internal little-endian limbs -> big-endian bytes (reverse word order) */
static void le32_to_be32(const uint32_t *src, uint8_t *dst) {
for (int i = 0; i < WORDS; i++) {
int j = WORDS - 1 - i;
dst[4*j] = (uint8_t)(src[i] >> 24);
dst[4*j + 1] = (uint8_t)(src[i] >> 16);
dst[4*j + 2] = (uint8_t)(src[i] >> 8);
dst[4*j + 3] = (uint8_t)(src[i]);
}
}
/* ---------- field arithmetic modulo p (normal domain) ---------- */
static inline const uint32_t *Pmod(void) { return P_LE; }
static int ge_mod_p(const uint32_t *a) {
const uint32_t *P = Pmod();
for (int i = WORDS - 1; i >= 0; i--) {
if (a[i] > P[i]) return 1;
if (a[i] < P[i]) return 0;
}
return 1; /* equal */
}
static void field_add_mod(uint32_t *dst, const uint32_t *a, const uint32_t *b) {
const uint32_t *P = Pmod();
uint64_t carry = 0;
for (int i = 0; i < WORDS; i++) {
uint64_t sum = (uint64_t)a[i] + b[i] + carry;
dst[i] = (uint32_t)sum;
carry = sum >> 32;
}
if (carry || ge_mod_p(dst)) {
uint64_t borrow = 0;
for (int i = 0; i < WORDS; i++) {
uint64_t diff = (uint64_t)dst[i] - P[i] - borrow;
dst[i] = (uint32_t)diff;
borrow = (diff >> 63) & 1;
}
}
}
static void field_sub_mod(uint32_t *dst, const uint32_t *a, const uint32_t *b) {
const uint32_t *P = Pmod();
uint64_t borrow = 0;
for (int i = 0; i < WORDS; i++) {
uint64_t diff = (uint64_t)a[i] - b[i] - borrow;
dst[i] = (uint32_t)diff;
borrow = (diff >> 63) & 1;
}
if (borrow) {
uint64_t carry = 0;
for (int i = 0; i < WORDS; i++) {
uint64_t sum = (uint64_t)dst[i] + P[i] + carry;
dst[i] = (uint32_t)sum;
carry = sum >> 32;
}
}
}
/* ROM-backed modular multiply returning normal-domain result (8 limbs) */
static void rom_field_mul(uint32_t *dst, const uint32_t *a, const uint32_t *b) {
uint32_t tmp[WORDS];
ets_bigint_enable();
/* Montgomery multiply in ROM (returns Montgomery residue) */
ets_bigint_modmult(a, b, P_LE, MPRIME, RR_LE, WORDS);
ets_bigint_wait_finish();
ets_bigint_getz(tmp, WORDS);
/* Convert out of Montgomery domain using the proven CINV2_LE */
ets_bigint_modmult(tmp, CINV2_LE, P_LE, MPRIME, RR_LE, WORDS);
ets_bigint_wait_finish();
ets_bigint_getz(dst, WORDS);
ets_bigint_disable();
}
static inline void field_mul(uint32_t *dst, const uint32_t *a, const uint32_t *b) {
rom_field_mul(dst, a, b);
}
static inline void field_sqr(uint32_t *dst, const uint32_t *a) {
rom_field_mul(dst, a, a);
}
/* Square-and-multiply exponentiation for p-2 (normal domain throughout) */
static void field_inv(uint32_t *out, const uint32_t *a) {
static const uint32_t EXP_P_MINUS_2[WORDS] = {
0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
0x00000000, 0x00000000, 0x00000001, 0xFFFFFFFF
};
uint32_t res[WORDS], base[WORDS];
zclear(res); res[0] = 1; /* res = 1 */
zcopy(base, a); /* base = a */
for (int wi = WORDS - 1; wi >= 0; wi--) {
uint32_t w = EXP_P_MINUS_2[wi];
for (int b = 31; b >= 0; b--) {
field_sqr(res, res);
if ((w >> b) & 1U) {
field_mul(res, res, base);
}
}
}
zcopy(out, res);
}
/* ---------- point utilities ---------- */
static inline void load_generator(p256_pt *Pp) {
zcopy(Pp->X, Gx);
zcopy(Pp->Y, Gy);
zclear(Pp->Z);
Pp->Z[0] = 1;
}
static void to_affine(p256_pt *Pp) {
uint32_t zi[WORDS], zi2[WORDS], xi[WORDS], yi[WORDS];
uint32_t z0 = 0;
for (int i = 0; i < WORDS; i++) z0 |= Pp->Z[i];
if (z0 == 0) {
zclear(Pp->X); zclear(Pp->Y); zclear(Pp->Z);
return;
}
field_inv(zi, Pp->Z);
field_sqr(zi2, zi);
field_mul(xi, Pp->X, zi2);
field_mul(yi, Pp->Y, zi2);
field_mul(yi, yi, zi);
zcopy(Pp->X, xi);
zcopy(Pp->Y, yi);
zclear(Pp->Z); Pp->Z[0] = 1;
}
/* ---------- group law (Jacobian, a = -3) ---------- */
__attribute__((noinline))
static void p256_point_double(p256_pt *Q) {
if (is_zero(Q->Y)) { zclear(Q->X); zclear(Q->Y); zclear(Q->Z); return; }
uint32_t Z2[WORDS], M[WORDS], Mtmp[WORDS], S[WORDS], T1[WORDS], T2[WORDS], X3[WORDS], Y3[WORDS];
/* Z2 = Z^2 */
field_sqr(Z2, Q->Z);
/* T1 = X - Z^2 ; T2 = X + Z^2 */
field_sub_mod(T1, Q->X, Z2);
field_add_mod(T2, Q->X, Z2);
/* M = (X - Z^2) * (X + Z^2) */
field_mul(M, T1, T2);
/* M = 3 * M */
zcopy(Mtmp, M);
field_add_mod(M, M, M); /* 2*M */
field_add_mod(M, M, Mtmp); /* 3*M */
/* S = 4 * X * Y^2 */
field_sqr(S, Q->Y); /* Y^2 */
field_mul(S, S, Q->X); /* X*Y^2 */
field_add_mod(S, S, S); /* 2*X*Y^2 */
field_add_mod(S, S, S); /* 4*X*Y^2 */
/* X3 = M^2 - 2*S */
field_sqr(X3, M);
field_sub_mod(X3, X3, S);
field_sub_mod(X3, X3, S);
/* Y3 = M*(S - X3) - 8*Y^4 */
field_sub_mod(Y3, S, X3);
field_mul(Y3, Y3, M);
field_sqr(T1, Q->Y); /* Y^2 */
field_sqr(T1, T1); /* Y^4 */
field_add_mod(T1, T1, T1); /* 2*Y^4 */
field_add_mod(T1, T1, T1); /* 4*Y^4 */
field_add_mod(T1, T1, T1); /* 8*Y^4 */
field_sub_mod(Y3, Y3, T1);
/* Z3 = 2*Y*Z */
field_mul(Q->Z, Q->Y, Q->Z);
field_add_mod(Q->Z, Q->Z, Q->Z);
zcopy(Q->X, X3);
zcopy(Q->Y, Y3);
}
__attribute__((noinline))
static void p256_point_add(p256_pt *R, const p256_pt *Pp, const p256_pt *Qp) {
if (is_zero(Pp->Z)) { zcopy(R->X, Qp->X); zcopy(R->Y, Qp->Y); zcopy(R->Z, Qp->Z); return; }
if (is_zero(Qp->Z)) { zcopy(R->X, Pp->X); zcopy(R->Y, Pp->Y); zcopy(R->Z, Pp->Z); return; }
uint32_t Z1Z1[WORDS], Z2Z2[WORDS], U1[WORDS], U2[WORDS];
uint32_t S1[WORDS], S2[WORDS], H[WORDS], RR[WORDS];
uint32_t H2[WORDS], H3[WORDS], U1H2[WORDS], X3[WORDS], Y3[WORDS], Z3[WORDS], t[WORDS];
field_sqr(Z1Z1, Pp->Z);
field_sqr(Z2Z2, Qp->Z);
field_mul(U1, Pp->X, Z2Z2);
field_mul(U2, Qp->X, Z1Z1);
field_mul(t, Qp->Z, Z2Z2); /* Z2^3 */
field_mul(S1, Pp->Y, t);
field_mul(t, Pp->Z, Z1Z1); /* Z1^3 */
field_mul(S2, Qp->Y, t);
field_sub_mod(H, U2, U1);
field_sub_mod(RR, S2, S1);
if (is_zero(H)) {
if (is_zero(RR)) {
p256_pt D = *Pp;
p256_point_double(&D);
zcopy(R->X, D.X);
zcopy(R->Y, D.Y);
zcopy(R->Z, D.Z);
} else {
zclear(R->X); zclear(R->Y); zclear(R->Z); /* infinity */
}
return;
}
field_sqr(H2, H);
field_mul(H3, H, H2);
field_mul(U1H2, U1, H2);
field_sqr(X3, RR);
field_sub_mod(X3, X3, H3);
field_sub_mod(X3, X3, U1H2);
field_sub_mod(X3, X3, U1H2); /* -2*U1H2 */
field_sub_mod(Y3, U1H2, X3);
field_mul(Y3, Y3, RR);
field_mul(t, S1, H3);
field_sub_mod(Y3, Y3, t);
field_mul(t, Pp->Z, Qp->Z);
field_mul(Z3, t, H);
zcopy(R->X, X3);
zcopy(R->Y, Y3);
zcopy(R->Z, Z3);
}
/* ---------- shared scalar multiply helpers (reduce duplication) ---------- */
static void scalar_mul_point(p256_pt *R, const p256_pt *Base, const uint8_t *k, size_t klen) {
zclear(R->X); zclear(R->Y); zclear(R->Z); /* R = O */
for (size_t bi = 0; bi < klen * 8; bi++) {
p256_point_double(R);
if ((k[bi >> 3] >> (7 - (bi & 7))) & 1) {
p256_point_add(R, R, Base);
}
}
}
/* Load uncompressed point (04 || X || Y) into Jacobian with Z=1 */
static int load_point_uncompressed(p256_pt *Pp, const unsigned char *buf, size_t len) {
if (len != 65 || buf[0] != 0x04) return 0;
be32_to_le32(buf + 1, Pp->X);
be32_to_le32(buf + 33, Pp->Y);
zclear(Pp->Z); Pp->Z[0] = 1;
return 1;
}
static void store_point_uncompressed(unsigned char *buf, const p256_pt *Pp) {
buf[0] = 0x04;
le32_to_be32(Pp->X, buf + 1);
le32_to_be32(Pp->Y, buf + 33);
}
/* ---------- BearSSL ec_impl API ---------- */
static const unsigned char *api_generator(int curve, size_t *len) {
(void)curve;
*len = br_secp256r1.generator_len;
return br_secp256r1.generator;
}
static const unsigned char *api_order(int curve, size_t *len) {
(void)curve;
*len = br_secp256r1.order_len;
return br_secp256r1.order;
}
static size_t api_xoff(int curve, size_t *len) {
(void)curve;
*len = 32;
return 1;
}
static uint32_t api_mul(unsigned char *G, size_t Glen,
const unsigned char *x, size_t xlen,
int curve) {
(void)curve;
p256_pt Pp, R;
if (!load_point_uncompressed(&Pp, G, Glen)) return 0;
scalar_mul_point(&R, &Pp, x, xlen);
to_affine(&R);
store_point_uncompressed(G, &R);
return 1;
}
static size_t api_mulgen(unsigned char *Rbuf,
const unsigned char *x, size_t xlen,
int curve) {
(void)curve;
p256_pt Gp, R;
load_generator(&Gp);
scalar_mul_point(&R, &Gp, x, xlen);
to_affine(&R);
store_point_uncompressed(Rbuf, &R);
return 65;
}
static uint32_t api_muladd(unsigned char *A, const unsigned char *B,
size_t Glen,
const unsigned char *x, size_t xlen,
const unsigned char *y, size_t ylen,
int curve) {
(void)curve;
p256_pt Pp, Qp, R, T;
if (!load_point_uncompressed(&Pp, A, Glen)) return 0;
scalar_mul_point(&R, &Pp, x, xlen);
if (B) {
if (!load_point_uncompressed(&Qp, B, Glen)) return 0;
} else {
load_generator(&Qp);
}
scalar_mul_point(&T, &Qp, y, ylen);
p256_point_add(&R, &R, &T);
to_affine(&R);
store_point_uncompressed(A, &R);
return 1;
}
const br_ec_impl br_ec_p256_m15 PROGMEM = {
(uint32_t)0x00800000,
&api_generator,
&api_order,
&api_xoff,
&api_mul,
&api_mulgen,
&api_muladd
};
#endif // SOC_MPI_SUPPORTED
#endif // defined(ESP_PLATFORM) && !defined(ESP8266)
#endif // USE_SHA_ROM
@@ -1475,4 +1475,4 @@ const br_ec_impl br_ec_c25519_m15 PROGMEM = {
&api_mul,
&api_mulgen,
&api_muladd
};
};
@@ -0,0 +1,754 @@
/*
* _sha_hal_idf5x.c BearSSL dropin with ESP32 HAL SHA acceleration
*
* This file provides hardware-accelerated implementations of BearSSL-compatible
* hash functions (SHA-1, SHA-224, SHA-256, SHA-384, SHA-512) using the ESP-IDF 5.x
* SHA HAL. It replaces the software digest core with direct access to the ESP32's
* SHA engine, preserving BearSSL's context structure and API semantics.
*
* Each hash context uses a minimal layout:
* - val[] holds the midstate as a raw little-endian byte image.
* - buf[] holds the partial block (64 or 128 bytes).
* - count tracks the total input length in bytes.
*
* Endianness is preserved across state() and set_state() calls, allowing seamless
* serialization and restoration of midstate snapshots. All conversions for hardware
* interaction are localized to update() and out().
*
* This module is designed for drop-in replacement with no changes to BearSSL clients.
* It supports multihash, midstate injection, and digest resumption.
*
* Author: Christian Baars
*/
#include "t_inner.h"
#if defined(USE_SHA_ROM)
#if defined(ESP_PLATFORM) && !defined(ESP8266)
#include <stdint.h>
#include "freertos/FreeRTOS.h"
#if __has_include("soc/sha_caps.h")
# include "soc/sha_caps.h"
#elif __has_include("soc/soc_caps.h")
# include "soc/soc_caps.h"
#else
# error "No SHA capability header found"
#endif
#if SOC_SHA_SUPPORT_RESUME
#if __has_include("hal/sha_ll.h")
# include "hal/sha_ll.h"
# define HAVE_SHA_LL 1
#else
# define HAVE_SHA_LL 0
#endif
#define HAVE_HAL_SHA1 (SOC_SHA_SUPPORT_SHA1)
#define HAVE_HAL_SHA224 (SOC_SHA_SUPPORT_SHA224)
#define HAVE_HAL_SHA256 (SOC_SHA_SUPPORT_SHA256)
#define HAVE_HAL_SHA384 (SOC_SHA_SUPPORT_SHA384)
#define HAVE_HAL_SHA512 (SOC_SHA_SUPPORT_SHA512)
static portMUX_TYPE s_sha_mux = portMUX_INITIALIZER_UNLOCKED;
#define SHA_ENTER() {portENTER_CRITICAL(&s_sha_mux); int __DECLARE_RCC_ATOMIC_ENV; sha_ll_enable_bus_clock(true); sha_ll_reset_register();}
#define SHA_EXIT() {portEXIT_CRITICAL(&s_sha_mux); int __DECLARE_RCC_ATOMIC_ENV; sha_ll_enable_bus_clock(false);}
#define SHA_WAIT() {while (sha_ll_busy()) { } }
/* ================================================================
* SHA-1 (HAL path, no save/restore) - needs char buf[112];
* ================================================================ */
#if HAVE_HAL_SHA1
static void __attribute__((noinline))
sha_hal_process_block(void *state_buf, const void *blk,
esp_sha_type type, size_t digest_words,
size_t block_words, bool first)
{
SHA_ENTER();
if (!first) {
sha_ll_write_digest(type, state_buf, digest_words);
}
sha_ll_fill_text_block(blk, block_words);
if (first) {
sha_ll_start_block(type);
} else {
sha_ll_continue_block(type);
}
SHA_WAIT();
sha_ll_read_digest(type, state_buf, digest_words);
SHA_EXIT();
}
static const uint8_t S1_IV_BYTES[20] PROGMEM = {
0x67,0x45,0x23,0x01, 0xEF,0xCD,0xAB,0x89,
0x98,0xBA,0xDC,0xFE, 0x10,0x32,0x54,0x76,
0xC3,0xD2,0xE1,0xF0
};
void br_sha1_init(br_sha1_context *cc)
{
cc->vtable = &br_sha1_vtable;
cc->count = 0;
memset(cc->buf, 0, sizeof cc->buf);
/* Store IV bytes exactly as given (LE words) into cc->val */
memcpy(cc->val, S1_IV_BYTES, sizeof S1_IV_BYTES);
}
void br_sha1_update(br_sha1_context *cc, const void *data, size_t len)
{
const uint8_t *src = data;
size_t used = (size_t)(cc->count & 63U);
if (!len) return;
cc->count += len;
if (used) {
size_t take = 64 - used;
if (take > len) take = len;
memcpy(cc->buf + used, src, take);
src += take;
len -= take;
used += take;
if (used == 64) {
sha_hal_process_block(cc->val, cc->buf, SHA1, 5, 16, cc->count == 64);
used = 0;
}
}
while (len >= 64) {
sha_hal_process_block(cc->val, src, SHA1, 5, 16,
(cc->count - len == 0) && !used);
src += 64;
len -= 64;
}
if (len) {
memcpy(cc->buf, src, len);
}
}
void br_sha1_out(const br_sha1_context *cc, void *out)
{
br_sha1_context ctx = *cc;
size_t used = (size_t)(ctx.count & 63U);
uint64_t bit_len = (uint64_t)ctx.count << 3;
ctx.buf[used++] = 0x80;
if (used > 56) {
memset(ctx.buf + used, 0, 64 - used);
sha_hal_process_block(ctx.val, ctx.buf, SHA1, 5, 16, ctx.count <= 64);
used = 0;
}
memset(ctx.buf + used, 0, 56 - used);
br_enc64be(ctx.buf + 56, bit_len);
sha_hal_process_block(ctx.val, ctx.buf, SHA1, 5, 16, ctx.count <= 64);
memcpy(out, ctx.val, 20);
}
uint64_t br_sha1_state(const br_sha1_context *cc, void *dst)
{
/* Export raw 20-byte LE midstate image exactly as stored */
memcpy(dst, cc->val, 20);
return cc->count;
}
void br_sha1_set_state(br_sha1_context *cc, const void *src, uint64_t count)
{
if (!(cc->vtable == &br_sha1_vtable)) {
cc->vtable = &br_sha1_vtable;
}
/* Import raw 20-byte LE midstate image exactly as provided */
memcpy(cc->val, src, 20);
cc->count = count;
memset(cc->buf, 0, sizeof cc->buf);
}
const br_hash_class br_sha1_vtable PROGMEM = {
sizeof(br_sha1_context),
BR_HASHDESC_ID(br_sha1_ID)
| BR_HASHDESC_OUT(20)
| BR_HASHDESC_LBLEN(6)
| BR_HASHDESC_MD_PADDING
| BR_HASHDESC_MD_PADDING_BE
| BR_HASHDESC_STATE(32),
(void (*)(const br_hash_class **)) &br_sha1_init,
(void (*)(const br_hash_class **, const void *, size_t)) &br_sha1_update,
(void (*)(const br_hash_class *const *, void *)) &br_sha1_out,
(uint64_t (*)(const br_hash_class *const *, void *)) &br_sha1_state,
(void (*)(const br_hash_class **, const void *, uint64_t)) &br_sha1_set_state
};
#endif /* HAVE_HAL_SHA1 */
/* ================================================================
* SHA-224 (HAL path, no save/restore)
* ================================================================ */
#if HAVE_HAL_SHA224
/* SHA-224 IV as 32-bit words (FIPS 180-4) */
static const uint32_t S224_IV_WORDS[8] = {
0xc1059ed8U, 0x367cd507U, 0x3070dd17U, 0xf70e5939U,
0xffc00b31U, 0x68581511U, 0x64f98fa7U, 0xbefa4fa4U
};
void br_sha224_init(br_sha224_context *cc) {
cc->vtable = &br_sha224_vtable;
cc->count = 0;
memset(cc->buf, 0, sizeof cc->buf);
/* Internal state is LE; encode IV directly in LE form into cc->val */
br_range_enc32le(cc->val, S224_IV_WORDS, 8);
}
/* Reuse SHA-256 out, then truncate to 28 bytes */
void br_sha224_out(const br_sha224_context *cc, void *out) {
uint8_t full[32];
br_sha256_out((const br_sha256_context *)cc, full);
memcpy(out, full, 28);
}
const br_hash_class br_sha224_vtable PROGMEM = {
sizeof(br_sha224_context),
BR_HASHDESC_ID(br_sha224_ID)
| BR_HASHDESC_OUT(28)
| BR_HASHDESC_LBLEN(6)
| BR_HASHDESC_MD_PADDING
| BR_HASHDESC_MD_PADDING_BE
| BR_HASHDESC_STATE(32),
(void (*)(const br_hash_class **)) &br_sha224_init,
(void (*)(const br_hash_class **, const void *, size_t)) &br_sha224_update,
(void (*)(const br_hash_class *const *, void *)) &br_sha224_out,
(uint64_t (*)(const br_hash_class *const *, void *)) &br_sha224_state,
(void (*)(const br_hash_class **, const void *, uint64_t)) &br_sha224_set_state
};
#endif /* HAVE_HAL_SHA224 */
/* ================================================================
* SHA-256 (HAL path, save/restore)
* ================================================================ */
#if HAVE_HAL_SHA256 && defined(SOC_SHA_SUPPORT_RESUME)
/* Fixed SHA-256 IV in big-endian bytes (spec-defined) */
static const uint8_t S256_IV_BYTES[32] PROGMEM = {
0x6a, 0x09, 0xe6, 0x67, 0xbb, 0x67, 0xae, 0x85,
0x3c, 0x6e, 0xf3, 0x72, 0xa5, 0x4f, 0xf5, 0x3a,
0x51, 0x0e, 0x52, 0x7f, 0x9b, 0x05, 0x68, 0x8c,
0x1f, 0x83, 0xd9, 0xab, 0x5b, 0xe0, 0xcd, 0x19
};
/* Maintain the partial block in cc->buf[] (64 bytes) */
static inline void s256_update_partial(br_sha256_context *cc,
const uint8_t *data_ptr,
size_t data_len,
size_t prev_partial_len)
{
size_t new_partial_len = (prev_partial_len + data_len) & 63U;
if (new_partial_len == 0) {
/* Exact block boundary: clear partial buffer */
memset(cc->buf, 0, sizeof cc->buf);
return;
}
if (data_len >= new_partial_len) {
/* Tail entirely from current input */
memcpy(cc->buf, data_ptr + (data_len - new_partial_len), new_partial_len);
} else {
/* Need some bytes from previous partial tail */
size_t need_prev = new_partial_len - data_len;
if (need_prev && need_prev <= prev_partial_len) {
memmove(cc->buf, cc->buf + (prev_partial_len - need_prev), need_prev);
} else if (need_prev) {
memset(cc->buf, 0, need_prev);
}
memcpy(cc->buf + need_prev, data_ptr, data_len);
}
if (new_partial_len < sizeof cc->buf) {
memset(cc->buf + new_partial_len, 0, sizeof cc->buf - new_partial_len);
}
}
void br_sha256_init(br_sha256_context *cc)
{
cc->vtable = &br_sha256_vtable;
cc->count = 0;
memset(cc->buf, 0, sizeof cc->buf);
/* Keep midstate bytes exactly as IV (BE byte image), as in the original */
memcpy(cc->val, S256_IV_BYTES, 32);
}
void br_sha224_update(br_sha224_context *cc, const void *data, size_t len)
{
if (!len) return;
/* Embedded mode selection by vtable pointer (no desc, no tags) */
const int mode = (cc->vtable == &br_sha256_vtable) ? SHA2_256 : SHA2_224;
const uint8_t *data_ptr = (const uint8_t *)data;
const uint8_t *orig_ptr = data_ptr;
size_t orig_len = len;
size_t prev_partial_len = (size_t)(cc->count & 63U);
bool starting_from_iv = (cc->count == 0) && (prev_partial_len == 0);
size_t stitch_take = 0;
if (prev_partial_len && len >= (64 - prev_partial_len))
stitch_take = 64 - prev_partial_len;
if (stitch_take || len >= 64) {
size_t block_count_in_run = 0;
SHA_ENTER();
/* Complete the partial block (stitch) if needed */
if (stitch_take) {
uint32_t midstate_words[8];
/* Original semantics: decode state from LE words before seeding HW */
br_range_dec32le(midstate_words, 8, cc->val);
sha_ll_load(mode);
sha_ll_write_digest(mode, midstate_words, 8);
uint8_t first_block[64];
memcpy(first_block, cc->buf, prev_partial_len);
memcpy(first_block + prev_partial_len, data_ptr, stitch_take);
sha_ll_fill_text_block(first_block, 16);
sha_ll_continue_block(mode);
SHA_WAIT();
data_ptr += stitch_take;
len -= stitch_take;
block_count_in_run = 1;
}
/* Process full 64-byte blocks */
if (len >= 64) {
if (starting_from_iv && stitch_take == 0) {
/* Start from IV directly */
sha_ll_fill_text_block(data_ptr, 16);
sha_ll_start_block(mode);
SHA_WAIT();
data_ptr += 64;
len -= 64;
block_count_in_run = 1;
} else if (block_count_in_run == 0) {
/* Seed from current midstate once before the run */
uint32_t midstate_words2[8];
br_range_dec32le(midstate_words2, 8, cc->val);
sha_ll_load(mode);
sha_ll_write_digest(mode, midstate_words2, 8);
}
#if defined(CONFIG_IDF_TARGET_ARCH_RISCV) /* RISC-V: enforce 8-block (512B) window with checkpointing */
while (len >= 64) {
sha_ll_fill_text_block(data_ptr, 16);
sha_ll_continue_block(mode);
SHA_WAIT();
data_ptr += 64;
len -= 64;
block_count_in_run++;
if (block_count_in_run == 8 && len >= 64) {
uint32_t midstate_words3[8];
sha_ll_load(mode);
sha_ll_read_digest(mode, midstate_words3, 8);
sha_ll_load(mode);
sha_ll_write_digest(mode, midstate_words3, 8);
block_count_in_run = 0;
}
}
#else /* Xtensa: simple per-block processing, no extra checkpointing */
while (len >= 64) {
sha_ll_fill_text_block(data_ptr, 16);
sha_ll_continue_block(mode);
SHA_WAIT();
data_ptr += 64;
len -= 64;
}
#endif
}
/* Commit midstate back; keep the same on-wire format as before: LE words in cc->val */
{
uint32_t tmp_words[8];
sha_ll_load(mode);
SHA_WAIT();
sha_ll_read_digest(mode, tmp_words, 8);
br_range_enc32le(cc->val, tmp_words, 8);
}
SHA_EXIT();
}
/* Bookkeeping and partial buffer maintenance */
cc->count += orig_len;
s256_update_partial((br_sha256_context *)cc, orig_ptr, orig_len, prev_partial_len);
}
void br_sha256_out(const br_sha256_context *cc, void *out)
{
uint8_t saved_partial[sizeof cc->buf];
uint64_t saved_count = cc->count;
uint8_t saved_state[32];
memcpy(saved_partial, cc->buf, sizeof cc->buf);
memcpy(saved_state, cc->val, 32);
uint8_t partial_len = (uint8_t)(saved_count & 63U);
const int mode = (cc->vtable == &br_sha256_vtable) ? SHA2_256 : SHA2_224;
bool midstate_is_iv = (memcmp(saved_state, S256_IV_BYTES, 32) == 0);
bool no_full_blocks_done = (saved_count < 64);
bool must_start_from_iv = midstate_is_iv && no_full_blocks_done;
SHA_ENTER();
if (!must_start_from_iv) {
uint32_t midstate_words[8];
/* Original semantics: state stored as LE words in cc->val */
br_range_dec32le(midstate_words, 8, saved_state);
sha_ll_load(mode);
sha_ll_write_digest(mode, midstate_words, 8);
}
uint8_t final_blocks[128];
memcpy(final_blocks, saved_partial, partial_len);
final_blocks[partial_len] = 0x80;
size_t zero_len = (partial_len < 56) ? (56 - partial_len - 1)
: (120 - partial_len - 1);
if (zero_len) {
memset(final_blocks + partial_len + 1, 0, zero_len);
}
uint64_t bit_length = saved_count * 8;
size_t len_pos = partial_len + 1 + zero_len;
for (int i = 0; i < 8; i++) {
final_blocks[len_pos + i] = (uint8_t)(bit_length >> (56 - 8 * i));
}
size_t total_final_len = len_pos + 8;
if (total_final_len == 64) {
sha_ll_fill_text_block(final_blocks, 16);
if (must_start_from_iv)
sha_ll_start_block(mode);
else
sha_ll_continue_block(mode);
SHA_WAIT();
} else {
sha_ll_fill_text_block(final_blocks, 16);
if (must_start_from_iv)
sha_ll_start_block(mode);
else
sha_ll_continue_block(mode);
SHA_WAIT();
sha_ll_fill_text_block(final_blocks + 64, 16);
sha_ll_continue_block(mode);
SHA_WAIT();
}
{
uint32_t tmp_words[8];
sha_ll_load(mode);
sha_ll_read_digest(mode, tmp_words, 8);
SHA_EXIT();
/* Final digest serialization remains LE as in your original */
br_range_enc32le(out, tmp_words, 8);
}
/* Non-destructive out(): restore snapshot */
memcpy(((br_sha256_context *)cc)->buf, saved_partial, sizeof cc->buf);
((br_sha256_context *)cc)->count = saved_count;
/* cc->val was never modified in out() */
}
uint64_t br_sha224_state(const br_sha256_context *cc, void *dst)
{
/* Export midstate bytes exactly as stored (LE words image), unchanged */
memcpy(dst, cc->val, 32);
return cc->count;
}
void br_sha224_set_state(br_sha256_context *cc, const void *src, uint64_t count)
{
if( !(cc->vtable == &br_sha256_vtable) && !(cc->vtable == &br_sha224_vtable)){
cc->vtable = &br_sha256_vtable; /* safety for multihash fresh gen context */
}
/* Reset partial, set count, and import state bytes exactly as provided */
memset(cc->buf, 0, sizeof cc->buf);
memcpy(cc->val, src, 32);
cc->count = count;
}
const br_hash_class br_sha256_vtable PROGMEM = {
sizeof(br_sha256_context),
BR_HASHDESC_ID(br_sha256_ID)
| BR_HASHDESC_OUT(32)
| BR_HASHDESC_STATE(32)
| BR_HASHDESC_LBLEN(6)
| BR_HASHDESC_MD_PADDING
| BR_HASHDESC_MD_PADDING_BE,
(void (*)(const br_hash_class **))&br_sha256_init,
(void (*)(const br_hash_class **,
const void *, size_t))&br_sha256_update,
(void (*)(const br_hash_class *const *, void *))&br_sha256_out,
(uint64_t (*)(const br_hash_class *const *, void *))&br_sha256_state,
(void (*)(const br_hash_class **, const void *, uint64_t))
&br_sha256_set_state
};
#endif /* HAVE_HAL_SHA256 && SOC_SHA_SUPPORT_RESUME */
/* ================================================================
* SHA-384 (HAL path, no save/restore)
* ================================================================ */
#if HAVE_HAL_SHA384
static const uint64_t S384_IV_WORDS[8] = {
0xcbbb9d5dc1059ed8ULL, 0x629a292a367cd507ULL,
0x9159015a3070dd17ULL, 0x152fecd8f70e5939ULL,
0x67332667ffc00b31ULL, 0x8eb44a8768581511ULL,
0xdb0c2e0d64f98fa7ULL, 0x47b5481dbefa4fa4ULL
};
void br_sha384_init(br_sha384_context *cc) {
cc->vtable = &br_sha384_vtable;
cc->count = 0;
memset(cc->buf, 0, sizeof cc->buf);
/* Internal state is LE; encode IV directly in LE form into cc->val */
br_range_enc64le(cc->val, S384_IV_WORDS, 8);
}
void br_sha384_update(br_sha384_context *cc, const void *data, size_t len) {
if (!len) return;
const uint8_t *src = (const uint8_t *)data;
size_t used = (size_t)(cc->count & 127U);
uint64_t prior_count = cc->count;
cc->count += len;
if (used) {
size_t take = 128 - used;
if (take > len) take = len;
memcpy(cc->buf + used, src, take);
src += take;
len -= take;
used += take;
if (used == 128) {
uint64_t st_be[8];
br_range_dec64le(st_be, 8, cc->val);
br_range_enc64be(st_be, st_be, 8);
SHA_ENTER();
sha_ll_load(SHA2_512);
sha_ll_write_digest(SHA2_512, st_be, 16);
sha_ll_fill_text_block(cc->buf, 32);
sha_ll_continue_block(SHA2_512);
SHA_WAIT();
sha_ll_read_digest(SHA2_512, st_be, 16);
SHA_EXIT();
br_range_dec64be(st_be, 8, st_be);
br_range_enc64le(cc->val, st_be, 8);
prior_count += 128;
used = 0;
}
}
if (len >= 128) {
uint64_t st_be[8];
br_range_dec64le(st_be, 8, cc->val);
br_range_enc64be(st_be, st_be, 8);
bool first = (prior_count == 0);
SHA_ENTER();
sha_ll_load(SHA2_512);
sha_ll_write_digest(SHA2_512, st_be, 16);
while (len >= 128) {
sha_ll_fill_text_block(src, 32);
if (first) {
sha_ll_start_block(SHA2_512);
first = false;
} else {
sha_ll_continue_block(SHA2_512);
}
SHA_WAIT();
src += 128;
len -= 128;
}
sha_ll_read_digest(SHA2_512, st_be, 16);
SHA_EXIT();
br_range_dec64be(st_be, 8, st_be);
br_range_enc64le(cc->val, st_be, 8);
}
if (len) memcpy(cc->buf, src, len);
}
void br_sha384_out(const br_sha384_context *cc, void *out) {
br_sha384_context ctx = *cc;
size_t used = (size_t)(ctx.count & 127U);
uint64_t bit_hi = (uint64_t)(ctx.count >> 61);
uint64_t bit_lo = (uint64_t)(ctx.count << 3);
ctx.buf[used++] = 0x80;
if (used > 112) {
memset(ctx.buf + used, 0, 128 - used);
uint64_t st_be[8];
br_range_dec64le(st_be, 8, ctx.val);
br_range_enc64be(st_be, st_be, 8);
SHA_ENTER();
sha_ll_load(SHA2_512);
sha_ll_write_digest(SHA2_512, st_be, 16);
sha_ll_fill_text_block(ctx.buf, 32);
sha_ll_continue_block(SHA2_512);
SHA_WAIT();
sha_ll_read_digest(SHA2_512, st_be, 16);
SHA_EXIT();
br_range_dec64be(st_be, 8, st_be);
br_range_enc64le(ctx.val, st_be, 8);
used = 0;
}
memset(ctx.buf + used, 0, 112 - used);
br_enc64be(ctx.buf + 112, bit_hi);
br_enc64be(ctx.buf + 120, bit_lo);
uint64_t st_be2[8];
br_range_dec64le(st_be2, 8, ctx.val);
br_range_enc64be(st_be2, st_be2, 8);
SHA_ENTER();
sha_ll_load(SHA2_512);
sha_ll_write_digest(SHA2_512, st_be2, 16);
sha_ll_fill_text_block(ctx.buf, 32);
sha_ll_continue_block(SHA2_512);
SHA_WAIT();
sha_ll_read_digest(SHA2_512, st_be2, 16);
SHA_EXIT();
br_range_dec64be(st_be2, 8, st_be2);
br_range_enc64be(out, st_be2, 6);
}
uint64_t br_sha384_state(const br_sha384_context *cc, void *dst) {
/* Export raw 64-byte LE midstate image exactly as stored */
memcpy(dst, cc->val, 64);
return cc->count;
}
void br_sha384_set_state(br_sha384_context *cc, const void *src, uint64_t count) {
if (!(cc->vtable == &br_sha384_vtable)) {
cc->vtable = &br_sha384_vtable;
}
/* Import raw 64-byte LE midstate image exactly as provided */
memcpy(cc->val, src, 64);
cc->count = count;
memset(cc->buf, 0, sizeof cc->buf);
}
const br_hash_class br_sha384_vtable PROGMEM = {
sizeof(br_sha384_context),
BR_HASHDESC_ID(br_sha384_ID)
| BR_HASHDESC_OUT(48)
| BR_HASHDESC_STATE(64)
| BR_HASHDESC_LBLEN(7)
| BR_HASHDESC_MD_PADDING
| BR_HASHDESC_MD_PADDING_BE
| BR_HASHDESC_MD_PADDING_128,
(void (*)(const br_hash_class **)) &br_sha384_init,
(void (*)(const br_hash_class **, const void *, size_t)) &br_sha384_update,
(void (*)(const br_hash_class *const *, void *)) &br_sha384_out,
(uint64_t (*)(const br_hash_class *const *, void *)) &br_sha384_state,
(void (*)(const br_hash_class **, const void *, uint64_t)) &br_sha384_set_state
};
#endif /* HAVE_HAL_SHA384 */
/* ================================================================
* SHA-512 (HAL path, no save/restore)
* Uses SHA-384 update/state/set_state
* ================================================================ */
#if HAVE_HAL_SHA512
static const uint64_t S512_IV_WORDS[8] = {
0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL,
0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,
0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL,
0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL
};
void br_sha512_init(br_sha512_context *cc) {
cc->vtable = &br_sha512_vtable;
cc->count = 0;
memset(cc->buf, 0, sizeof cc->buf);
/* Internal state is LE; encode IV directly in LE form into cc->val */
br_range_enc64le(cc->val, S512_IV_WORDS, 8);
}
void br_sha512_out(const br_sha512_context *cc, void *out) {
br_sha512_context ctx = *cc;
size_t used = (size_t)(ctx.count & 127U);
uint64_t bit_hi = (uint64_t)(ctx.count >> 61);
uint64_t bit_lo = (uint64_t)(ctx.count << 3);
ctx.buf[used++] = 0x80;
if (used > 112) {
memset(ctx.buf + used, 0, 128 - used);
uint64_t st_be[8];
br_range_dec64le(st_be, 8, ctx.val);
br_range_enc64be(st_be, st_be, 8);
SHA_ENTER();
sha_ll_load(SHA2_512);
sha_ll_write_digest(SHA2_512, st_be, 16);
sha_ll_fill_text_block(ctx.buf, 32);
sha_ll_continue_block(SHA2_512);
SHA_WAIT();
sha_ll_read_digest(SHA2_512, st_be, 16);
SHA_EXIT();
br_range_dec64be(st_be, 8, st_be);
br_range_enc64le(ctx.val, st_be, 8);
used = 0;
}
memset(ctx.buf + used, 0, 112 - used);
br_enc64be(ctx.buf + 112, bit_hi);
br_enc64be(ctx.buf + 120, bit_lo);
uint64_t st_be2[8];
br_range_dec64le(st_be2, 8, ctx.val);
br_range_enc64be(st_be2, st_be2, 8);
SHA_ENTER();
sha_ll_load(SHA2_512);
sha_ll_write_digest(SHA2_512, st_be2, 16);
sha_ll_fill_text_block(ctx.buf, 32);
sha_ll_continue_block(SHA2_512);
SHA_WAIT();
sha_ll_read_digest(SHA2_512, st_be2, 16);
SHA_EXIT();
/* Output digest in bigendian bytes as BearSSL expects */
br_range_dec64be(st_be2, 8, st_be2);
br_range_enc64be(out, st_be2, 8);
}
const br_hash_class br_sha512_vtable PROGMEM = {
sizeof(br_sha512_context),
BR_HASHDESC_ID(br_sha512_ID)
| BR_HASHDESC_OUT(64)
| BR_HASHDESC_STATE(64)
| BR_HASHDESC_LBLEN(7)
| BR_HASHDESC_MD_PADDING
| BR_HASHDESC_MD_PADDING_BE
| BR_HASHDESC_MD_PADDING_128,
(void (*)(const br_hash_class **)) &br_sha512_init,
(void (*)(const br_hash_class **, const void *, size_t)) &br_sha384_update, /* reuse SHA-384 update */
(void (*)(const br_hash_class *const *, void *)) &br_sha512_out,
(uint64_t (*)(const br_hash_class *const *, void *)) &br_sha512_state,
(void (*)(const br_hash_class **, const void *, uint64_t)) &br_sha512_set_state
};
#endif /* HAVE_HAL_SHA512 */
#else
/* ===== ESP8266 - leave it unchanged ===== */
#endif // SOC_SHA_SUPPORT_RESUME
#endif // defined(ESP_PLATFORM) && !defined(ESP8266)
#endif //USE_SHA_ROM
+4 -5
View File
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
@@ -9,12 +9,12 @@
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
@@ -22,7 +22,6 @@
* SOFTWARE.
*/
#include <pgmspace_bearssl.h>
#include "t_inner.h"
#define F(B, C, D) ((((C) ^ (D)) & (B)) ^ (D))
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
@@ -9,12 +9,12 @@
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
@@ -9,12 +9,12 @@
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
@@ -9,12 +9,12 @@
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
@@ -9,12 +9,12 @@
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+4 -112
View File
@@ -25,10 +25,6 @@
#define BR_ENABLE_INTRINSICS 1
#include "t_inner.h"
#if BR_USE_GETENTROPY
#include <unistd.h>
#endif
#if BR_USE_URANDOM
#include <sys/types.h>
#include <unistd.h>
@@ -42,9 +38,6 @@
#pragma comment(lib, "advapi32")
#endif
/*
* Seeder that uses the RDRAND opcodes (on x86 CPU).
*/
#if BR_RDRAND
BR_TARGETS_X86_UP
BR_TARGET("rdrnd")
@@ -64,24 +57,9 @@ seeder_rdrand(const br_prng_class **ctx)
*
* Intel recommends trying at least 10 times in case of
* failure.
*
* AMD bug: there are reports that some AMD processors
* have a bug that makes them fail silently after a
* suspend/resume cycle, in which case RDRAND will report
* a success but always return 0xFFFFFFFF.
* see: https://bugzilla.kernel.org/show_bug.cgi?id=85911
*
* As a mitigation, if the 32-bit value is 0 or -1, then
* it is considered a failure and tried again. This should
* reliably detect the buggy case, at least. This also
* implies that the selected seed values can never be
* 0x00000000 or 0xFFFFFFFF, which is not a problem since
* we are generating a seed for a PRNG, and we overdo it
* a bit (we generate 32 bytes of randomness, and 256 bits
* of entropy are really overkill).
*/
for (j = 0; j < 10; j ++) {
if (_rdrand32_step(&x) && x != 0 && x != (uint32_t)-1) {
if (_rdrand32_step(&x)) {
goto next_word;
}
}
@@ -102,11 +80,9 @@ rdrand_supported(void)
*/
return br_cpuid(0, 0, 0x40000000, 0);
}
#endif
/*
* Seeder that uses /dev/urandom (on Unix-like systems).
*/
#if BR_USE_URANDOM
static int
seeder_urandom(const br_prng_class **ctx)
@@ -140,32 +116,6 @@ seeder_urandom(const br_prng_class **ctx)
}
#endif
/*
* Seeder that uses getentropy() (backed by getrandom() on some systems,
* e.g. Linux). On failure, it will use the /dev/urandom seeder (if
* enabled).
*/
#if BR_USE_GETENTROPY
static int
seeder_getentropy(const br_prng_class **ctx)
{
unsigned char tmp[32];
if (getentropy(tmp, sizeof tmp) == 0) {
(*ctx)->update(ctx, tmp, sizeof tmp);
return 1;
}
#if BR_USE_URANDOM
return seeder_urandom(ctx);
#else
return 0;
#endif
}
#endif
/*
* Seeder that uses CryptGenRandom() (on Windows).
*/
#if BR_USE_WIN32_RAND
static int
seeder_win32(const br_prng_class **ctx)
@@ -221,56 +171,12 @@ seeder_esp8266(const br_prng_class **ctx)
}
(*ctx)->update(ctx, tmp, sizeof tmp);
return 1;
}
#endif
#endif
#ifdef BR_USE_PICO_RAND
extern uint32_t __picoRand();
static int
seeder_pico(const br_prng_class **ctx)
{
uint32_t tmp[32 / sizeof(uint32_t)];
size_t i;
for (i=0; i<sizeof(tmp)/sizeof(tmp[0]); i++) {
tmp[i] = __picoRand();
}
(*ctx)->update(ctx, tmp, sizeof tmp);
return 1;
}
#endif
/*
* An aggregate seeder that uses RDRAND, and falls back to an OS-provided
* source if RDRAND fails.
*/
#if BR_RDRAND && (BR_USE_GETENTROPY || BR_USE_URANDOM || BR_USE_WIN32_RAND)
static int
seeder_rdrand_with_fallback(const br_prng_class **ctx)
{
if (!seeder_rdrand(ctx)) {
#if BR_USE_PICO
return seeder_pico(ctx);
#elif BR_USE_GETENTROPY
return seeder_getentropy(ctx);
#elif BR_USE_URANDOM
return seeder_urandom(ctx);
#elif BR_USE_WIN32_RAND
return seeder_win32(ctx);
#elif BR_USE_ESP8266_RAND
return seeder_esp8266(ctx);
#else
#error "macro selection has gone wrong"
#endif
}
return 1;
}
#endif
/* see bearssl_rand.h */
br_prng_seeder
@@ -281,24 +187,10 @@ br_prng_seeder_system(const char **name)
if (name != NULL) {
*name = "rdrand";
}
#if BR_USE_GETENTROPY || BR_USE_URANDOM || BR_USE_WIN32_RAND
return &seeder_rdrand_with_fallback;
#else
return &seeder_rdrand;
#endif
}
#endif
#if BR_USE_PICO_RAND
if (name != NULL) {
*name = "pico";
}
return &seeder_pico;
#elif BR_USE_GETENTROPY
if (name != NULL) {
*name = "getentropy";
}
return &seeder_getentropy;
#elif BR_USE_URANDOM
#if BR_USE_URANDOM
if (name != NULL) {
*name = "urandom";
}
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
@@ -9,12 +9,12 @@
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
@@ -69,7 +69,6 @@ cc_choose(const br_ssl_client_certificate_class **pctx,
choices->hash_id = -1;
choices->chain = zc->chain;
choices->chain_len = zc->chain_len;
return;
}
}
@@ -395,9 +395,6 @@ make_client_sign(br_ssl_client_context *ctx)
ctx->eng.pad, sizeof ctx->eng.pad);
}
/* State machine should be squeezed for size, not performance critical */
#pragma GCC optimize ("Os")
static const unsigned char t0_datablock[] PROGMEM = {
@@ -1202,7 +1199,7 @@ br_ssl_hs_client_run(void *t0ctx)
break;
case 27: {
/* co */
T0_CO();
T0_CO();
}
break;
case 28: {
@@ -1330,12 +1327,12 @@ br_ssl_hs_client_run(void *t0ctx)
break;
case 37: {
/* drop */
(void)T0_POP();
(void)T0_POP();
}
break;
case 38: {
/* dup */
T0_PUSH(T0_PEEK(0));
T0_PUSH(T0_PEEK(0));
}
break;
case 39: {
@@ -1511,7 +1508,7 @@ br_ssl_hs_client_run(void *t0ctx)
break;
case 56: {
/* over */
T0_PUSH(T0_PEEK(1));
T0_PUSH(T0_PEEK(1));
}
break;
case 57: {
@@ -1652,7 +1649,7 @@ br_ssl_hs_client_run(void *t0ctx)
break;
case 69: {
/* swap */
T0_SWAP();
T0_SWAP();
}
break;
case 70: {
@@ -426,9 +426,6 @@ verify_CV_sig(br_ssl_server_context *ctx, size_t sig_len)
return 0;
}
/* State machine should be squeezed for size, not performance critical */
#pragma GCC optimize ("Os")
static const unsigned char t0_datablock[] PROGMEM = {
@@ -1067,7 +1064,7 @@ br_ssl_hs_server_run(void *t0ctx)
break;
case 10: {
/* -rot */
T0_NROT();
T0_NROT();
}
break;
case 11: {
@@ -1241,7 +1238,7 @@ br_ssl_hs_server_run(void *t0ctx)
break;
case 27: {
/* co */
T0_CO();
T0_CO();
}
break;
case 28: {
@@ -1405,12 +1402,12 @@ br_ssl_hs_server_run(void *t0ctx)
break;
case 41: {
/* drop */
(void)T0_POP();
(void)T0_POP();
}
break;
case 42: {
/* dup */
T0_PUSH(T0_PEEK(0));
T0_PUSH(T0_PEEK(0));
}
break;
case 43: {
@@ -1547,12 +1544,12 @@ br_ssl_hs_server_run(void *t0ctx)
break;
case 58: {
/* over */
T0_PUSH(T0_PEEK(1));
T0_PUSH(T0_PEEK(1));
}
break;
case 59: {
/* pick */
T0_PICK(T0_POP());
T0_PICK(T0_POP());
}
break;
case 60: {
@@ -1693,7 +1690,7 @@ br_ssl_hs_server_run(void *t0ctx)
break;
case 71: {
/* swap */
T0_SWAP();
T0_SWAP();
}
break;
case 72: {
@@ -625,52 +625,6 @@ typedef struct {
} br_name_element;
/**
* \brief Callback for validity date checks.
*
* The function receives as parameter an arbitrary user-provided context,
* and the notBefore and notAfter dates specified in an X.509 certificate,
* both expressed as a number of days and a number of seconds:
*
* - Days are counted in a proleptic Gregorian calendar since
* January 1st, 0 AD. Year "0 AD" is the one that preceded "1 AD";
* it is also traditionally known as "1 BC".
*
* - Seconds are counted since midnight, from 0 to 86400 (a count of
* 86400 is possible only if a leap second happened).
*
* Each date and time is understood in the UTC time zone. The "Unix
* Epoch" (January 1st, 1970, 00:00 UTC) corresponds to days=719528 and
* seconds=0; the "Windows Epoch" (January 1st, 1601, 00:00 UTC) is
* days=584754, seconds=0.
*
* This function must return -1 if the current date is strictly before
* the "notBefore" time, or +1 if the current date is strictly after the
* "notAfter" time. If neither condition holds, then the function returns
* 0, which means that the current date falls within the validity range of
* the certificate. If the function returns a value distinct from -1, 0
* and +1, then this is interpreted as an unavailability of the current
* time, which normally ends the validation process with a
* `BR_ERR_X509_TIME_UNKNOWN` error.
*
* During path validation, this callback will be invoked for each
* considered X.509 certificate. Validation fails if any of the calls
* returns a non-zero value.
*
* The context value is an abritrary pointer set by the caller when
* configuring this callback.
*
* \param tctx context pointer.
* \param not_before_days notBefore date (days since Jan 1st, 0 AD).
* \param not_before_seconds notBefore time (seconds, at most 86400).
* \param not_after_days notAfter date (days since Jan 1st, 0 AD).
* \param not_after_seconds notAfter time (seconds, at most 86400).
* \return -1, 0 or +1.
*/
typedef int (*br_x509_time_check)(void *tctx,
uint32_t not_before_days, uint32_t not_before_seconds,
uint32_t not_after_days, uint32_t not_after_seconds);
/**
* \brief The "minimal" X.509 engine structure.
*
@@ -693,8 +647,8 @@ typedef struct {
uint32_t *rp;
const unsigned char *ip;
} cpu;
uint32_t dp_stack[31];
uint32_t rp_stack[31];
uint32_t dp_stack[32];
uint32_t rp_stack[32];
int err;
/* Server name to match with the SAN / CN of the EE certificate. */
@@ -776,12 +730,6 @@ typedef struct {
br_name_element *name_elts;
size_t num_name_elts;
/*
* Callback function (and context) to get the current date.
*/
void *itime_ctx;
br_x509_time_check itime;
/*
* Public key cryptography implementations (signature verification).
*/
@@ -963,28 +911,6 @@ br_x509_minimal_set_time(br_x509_minimal_context *ctx,
{
ctx->days = days;
ctx->seconds = seconds;
ctx->itime = 0;
}
/**
* \brief Set the validity range callback function for the X.509
* "minimal" engine.
*
* The provided function will be invoked to check whether the validation
* date is within the validity range for a given X.509 certificate; a
* call will be issued for each considered certificate. The provided
* context pointer (itime_ctx) will be passed as first parameter to the
* callback.
*
* \param tctx context for callback invocation.
* \param cb callback function.
*/
static inline void
br_x509_minimal_set_time_callback(br_x509_minimal_context *ctx,
void *itime_ctx, br_x509_time_check itime)
{
ctx->itime_ctx = itime_ctx;
ctx->itime = itime;
}
/**
+6 -24
View File
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
@@ -9,12 +9,12 @@
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
@@ -111,27 +111,9 @@
#define BR_RDRAND 1
*/
/*
* When BR_USE_GETENTROPY is enabled, the SSL engine will use the
* getentropy() function to obtain quality randomness for seeding its
* internal PRNG. On Linux and FreeBSD, getentropy() is implemented by
* the standard library with the system call getrandom(); on OpenBSD,
* getentropy() is the system call, and there is no getrandom() wrapper,
* hence the use of the getentropy() function for maximum portability.
*
* If the getentropy() call fails, and BR_USE_URANDOM is not explicitly
* disabled, then /dev/urandom will be used as a fallback mechanism. On
* FreeBSD and OpenBSD, this does not change much, since /dev/urandom
* will block if not enough entropy has been obtained since last boot.
* On Linux, /dev/urandom might not block, which can be troublesome in
* early boot stages, which is why getentropy() is preferred.
*
#define BR_USE_GETENTROPY 1
*/
/*
* When BR_USE_URANDOM is enabled, the SSL engine will use /dev/urandom
* to automatically obtain quality randomness for seeding its internal
* to automatically obtain quality randomness for seedings its internal
* PRNG.
*
#define BR_USE_URANDOM 1
@@ -147,7 +129,7 @@
/*
* When BR_USE_WIN32_RAND is enabled, the SSL engine will use the Win32
* (CryptoAPI) functions (CryptAcquireContext(), CryptGenRandom()...) to
* automatically obtain quality randomness for seeding its internal PRNG.
* automatically obtain quality randomness for seedings its internal PRNG.
*
* Note: if both BR_USE_URANDOM and BR_USE_WIN32_RAND are defined, the
* former takes precedence.
+4 -4
View File
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
@@ -9,12 +9,12 @@
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
@@ -100,9 +100,6 @@ br_pkey_decoder_push(br_pkey_decoder_context *ctx,
br_pkey_decoder_run(&ctx->cpu);
}
/* State machine should be squeezed for size, not performance critical */
#pragma GCC optimize ("Os")
static const unsigned char t0_datablock[] PROGMEM = {
@@ -386,7 +383,7 @@ br_pkey_decoder_run(void *t0ctx)
break;
case 9: {
/* -rot */
T0_NROT();
T0_NROT();
}
break;
case 10: {
@@ -454,17 +451,17 @@ br_pkey_decoder_run(void *t0ctx)
break;
case 17: {
/* co */
T0_CO();
T0_CO();
}
break;
case 18: {
/* drop */
(void)T0_POP();
(void)T0_POP();
}
break;
case 19: {
/* dup */
T0_PUSH(T0_PEEK(0));
T0_PUSH(T0_PEEK(0));
}
break;
case 20: {
@@ -501,7 +498,7 @@ br_pkey_decoder_run(void *t0ctx)
break;
case 23: {
/* over */
T0_PUSH(T0_PEEK(1));
T0_PUSH(T0_PEEK(1));
}
break;
case 24: {
@@ -537,7 +534,7 @@ br_pkey_decoder_run(void *t0ctx)
break;
case 26: {
/* rot */
T0_ROT();
T0_ROT();
}
break;
case 27: {
@@ -574,7 +571,7 @@ br_pkey_decoder_run(void *t0ctx)
break;
case 30: {
/* swap */
T0_SWAP();
T0_SWAP();
}
break;
}
@@ -100,9 +100,6 @@ br_skey_decoder_push(br_skey_decoder_context *ctx,
br_skey_decoder_run(&ctx->cpu);
}
/* State machine should be squeezed for size, not performance critical */
#pragma GCC optimize ("Os")
static const unsigned char t0_datablock[] PROGMEM = {
@@ -411,7 +408,7 @@ br_skey_decoder_run(void *t0ctx)
break;
case 9: {
/* -rot */
T0_NROT();
T0_NROT();
}
break;
case 10: {
@@ -488,17 +485,17 @@ br_skey_decoder_run(void *t0ctx)
break;
case 18: {
/* co */
T0_CO();
T0_CO();
}
break;
case 19: {
/* drop */
(void)T0_POP();
(void)T0_POP();
}
break;
case 20: {
/* dup */
T0_PUSH(T0_PEEK(0));
T0_PUSH(T0_PEEK(0));
}
break;
case 21: {
@@ -543,7 +540,7 @@ br_skey_decoder_run(void *t0ctx)
break;
case 25: {
/* over */
T0_PUSH(T0_PEEK(1));
T0_PUSH(T0_PEEK(1));
}
break;
case 26: {
@@ -579,7 +576,7 @@ br_skey_decoder_run(void *t0ctx)
break;
case 28: {
/* rot */
T0_ROT();
T0_ROT();
}
break;
case 29: {
@@ -632,7 +629,7 @@ br_skey_decoder_run(void *t0ctx)
break;
case 32: {
/* swap */
T0_SWAP();
T0_SWAP();
}
break;
case 33: {
@@ -113,9 +113,6 @@ br_x509_decoder_push(br_x509_decoder_context *ctx,
br_x509_decoder_run(&ctx->cpu);
}
/* State machine should be squeezed for size, not performance critical */
#pragma GCC optimize ("Os")
static const unsigned char t0_datablock[] PROGMEM = {
@@ -523,7 +520,7 @@ br_x509_decoder_run(void *t0ctx)
break;
case 11: {
/* -rot */
T0_NROT();
T0_NROT();
}
break;
case 12: {
@@ -618,7 +615,7 @@ br_x509_decoder_run(void *t0ctx)
break;
case 22: {
/* co */
T0_CO();
T0_CO();
}
break;
case 23: {
@@ -656,12 +653,12 @@ br_x509_decoder_run(void *t0ctx)
break;
case 26: {
/* drop */
(void)T0_POP();
(void)T0_POP();
}
break;
case 27: {
/* dup */
T0_PUSH(T0_PEEK(0));
T0_PUSH(T0_PEEK(0));
}
break;
case 28: {
@@ -707,7 +704,7 @@ br_x509_decoder_run(void *t0ctx)
break;
case 32: {
/* over */
T0_PUSH(T0_PEEK(1));
T0_PUSH(T0_PEEK(1));
}
break;
case 33: {
@@ -756,7 +753,7 @@ br_x509_decoder_run(void *t0ctx)
break;
case 35: {
/* rot */
T0_ROT();
T0_ROT();
}
break;
case 36: {
@@ -777,7 +774,7 @@ br_x509_decoder_run(void *t0ctx)
break;
case 38: {
/* swap */
T0_SWAP();
T0_SWAP();
}
break;
}
@@ -489,8 +489,6 @@ static int check_single_trust_anchor_CA(br_x509_minimal_context *ctx,
return 0;
}
/* State machine should be squeezed for size, not performance critical */
#pragma GCC optimize ("Os")
@@ -1088,7 +1086,7 @@ br_x509_minimal_run(void *t0ctx)
break;
case 11: {
/* -rot */
T0_NROT();
T0_NROT();
}
break;
case 12: {
@@ -1271,43 +1269,35 @@ br_x509_minimal_run(void *t0ctx)
uint32_t nas = T0_POP();
uint32_t nad = T0_POP();
int r;
if (CTX->itime != 0) {
r = CTX->itime(CTX->itime_ctx, nbd, nbs, nad, nas);
if (r < -1 || r > 1) {
CTX->err = BR_ERR_X509_TIME_UNKNOWN;
T0_CO();
}
} else {
uint32_t vd = CTX->days;
uint32_t vs = CTX->seconds;
if (vd == 0 && vs == 0) {
uint32_t vd = CTX->days;
uint32_t vs = CTX->seconds;
if (vd == 0 && vs == 0) {
#if BR_USE_UNIX_TIME
time_t x = time(NULL);
time_t x = time(NULL);
vd = (uint32_t)(x / 86400) + 719528;
vs = (uint32_t)(x % 86400);
vd = (uint32_t)(x / 86400) + 719528;
vs = (uint32_t)(x % 86400);
#elif BR_USE_WIN32_TIME
FILETIME ft;
uint64_t x;
FILETIME ft;
uint64_t x;
GetSystemTimeAsFileTime(&ft);
x = ((uint64_t)ft.dwHighDateTime << 32)
+ (uint64_t)ft.dwLowDateTime;
x = (x / 10000000);
vd = (uint32_t)(x / 86400) + 584754;
vs = (uint32_t)(x % 86400);
GetSystemTimeAsFileTime(&ft);
x = ((uint64_t)ft.dwHighDateTime << 32)
+ (uint64_t)ft.dwLowDateTime;
x = (x / 10000000);
vd = (uint32_t)(x / 86400) + 584754;
vs = (uint32_t)(x % 86400);
#else
CTX->err = BR_ERR_X509_TIME_UNKNOWN;
CTX->err = BR_ERR_X509_TIME_UNKNOWN;
T0_CO();
#endif
}
if (vd < nbd || (vd == nbd && vs < nbs)) {
r = -1;
} else if (vd > nad || (vd == nad && vs > nas)) {
r = 1;
} else {
r = 0;
}
}
if (vd < nbd || (vd == nbd && vs < nbs)) {
r = -1;
} else if (vd > nad || (vd == nad && vs > nas)) {
r = 1;
} else {
r = 0;
}
T0_PUSHi(r);
@@ -1315,7 +1305,7 @@ br_x509_minimal_run(void *t0ctx)
break;
case 26: {
/* co */
T0_CO();
T0_CO();
}
break;
case 27: {
@@ -1463,12 +1453,12 @@ br_x509_minimal_run(void *t0ctx)
break;
case 37: {
/* drop */
(void)T0_POP();
(void)T0_POP();
}
break;
case 38: {
/* dup */
T0_PUSH(T0_PEEK(0));
T0_PUSH(T0_PEEK(0));
}
break;
case 39: {
@@ -1609,7 +1599,7 @@ br_x509_minimal_run(void *t0ctx)
break;
case 48: {
/* over */
T0_PUSH(T0_PEEK(1));
T0_PUSH(T0_PEEK(1));
}
break;
case 49: {
@@ -1659,7 +1649,7 @@ br_x509_minimal_run(void *t0ctx)
break;
case 51: {
/* rot */
T0_ROT();
T0_ROT();
}
break;
case 52: {
@@ -1711,7 +1701,7 @@ br_x509_minimal_run(void *t0ctx)
break;
case 58: {
/* swap */
T0_SWAP();
T0_SWAP();
}
break;
case 59: {
@@ -1785,5 +1775,3 @@ verify_signature(br_x509_minimal_context *ctx, const br_x509_pkey *pk)
return BR_ERR_X509_UNSUPPORTED;
}
}
+156 -138
View File
@@ -54,7 +54,9 @@
#include "c_types.h"
#endif
#include <core_version.h>
#if __has_include("core_version.h") // ESP32 Stage has no core_version.h file. Disable include via PlatformIO Option
#include <core_version.h> // Arduino_Esp8266 version information (ARDUINO_ESP8266_RELEASE and ARDUINO_ESP8266_RELEASE_2_7_1)
#endif // ESP32_STAGE
#undef DEBUG_TLS
#ifdef DEBUG_TLS
@@ -75,6 +77,9 @@ void _Log_heap_size(const char *msg) {
#define LOG_HEAP_SIZE(a)
#endif
// get UTC time from Tasmota
//extern uint32_t UtcTime(void);
//extern uint32_t CfgTime(void);
#ifdef ESP8266 // Stack thunk is not needed with ESP32
// Stack thunked versions of calls
@@ -196,7 +201,8 @@ void WiFiClientSecure_light::_clear() {
_last_error = 0;
_recvapp_buf = nullptr;
_recvapp_len = 0;
_insecure = false; // set to true when calling setPubKeyFingerprint()
_insecure = true; // set to true when calling setPubKeyFingerprint()
_rsa_only = false; // for now we disable ECDSA by default
_fingerprint_any = true; // by default accept all fingerprints
_fingerprint1 = nullptr;
_fingerprint2 = nullptr;
@@ -298,16 +304,6 @@ void WiFiClientSecure_light::flush(void) {
#ifdef ESP32
int WiFiClientSecure_light::connect(IPAddress ip, uint16_t port)
{
return connect(ip, port, _timeout);
}
int WiFiClientSecure_light::connect(const char* name, uint16_t port)
{
return connect(name, port, _timeout);
}
int WiFiClientSecure_light::connect(IPAddress ip, uint16_t port, int32_t timeout) {
DEBUG_BSSL("connect(%s,%d)", ip.toString().c_str(), port);
@@ -316,7 +312,9 @@ int WiFiClientSecure_light::connect(IPAddress ip, uint16_t port, int32_t timeout
setLastError(ERR_TCP_CONNECT);
return 0;
}
return _connectSSL(_domain.isEmpty() ? nullptr : _domain.c_str());
bool success = _connectSSL(_domain.isEmpty() ? nullptr : _domain.c_str());
if (!success) { stop(); }
return success;
}
#else // ESP32
int WiFiClientSecure_light::connect(IPAddress ip, uint16_t port) {
@@ -326,7 +324,9 @@ int WiFiClientSecure_light::connect(IPAddress ip, uint16_t port) {
setLastError(ERR_TCP_CONNECT);
return 0;
}
return _connectSSL(_domain.isEmpty() ? nullptr : _domain.c_str());
bool success = _connectSSL(_domain.isEmpty() ? nullptr : _domain.c_str());
if (!success) { stop(); }
return success;
}
#endif
@@ -335,7 +335,7 @@ int WiFiClientSecure_light::connect(const char* name, uint16_t port, int32_t tim
DEBUG_BSSL("connect(%s,%d)\n", name, port);
IPAddress remote_addr;
clearLastError();
if (WiFi.hostByName(name, remote_addr) != 1) {
if (!WiFi.hostByName(name, remote_addr)) {
DEBUG_BSSL("connect: Name loopup failure\n");
setLastError(ERR_CANT_RESOLVE_IP);
return 0;
@@ -354,7 +354,7 @@ int WiFiClientSecure_light::connect(const char* name, uint16_t port) {
DEBUG_BSSL("connect(%s,%d)\n", name, port);
IPAddress remote_addr;
clearLastError();
if (WiFi.hostByName(name, remote_addr, 1000) != 1) {
if (!WiFi.hostByName(name, remote_addr)) {
DEBUG_BSSL("connect: Name loopup failure\n");
setLastError(ERR_CANT_RESOLVE_IP);
return 0;
@@ -587,6 +587,7 @@ int WiFiClientSecure_light::_run_until(unsigned target, bool blocking) {
if (((int32_t)(millis() - (t + this->_loopTimeout)) >= 0)){
DEBUG_BSSL("_run_until: Timeout\n");
setLastError(ERR_TLS_TIMEOUT);
return -1;
}
@@ -606,72 +607,66 @@ int WiFiClientSecure_light::_run_until(unsigned target, bool blocking) {
}
#endif
/*
If there is some record data to send, do it. This takes
precedence over everything else.
*/
if (state & BR_SSL_SENDREC) {
unsigned char *buf;
size_t len;
int wlen;
/*
If there is some record data to send, do it. This takes
precedence over everything else.
*/
if (state & BR_SSL_SENDREC) {
unsigned char *buf;
size_t len;
int wlen;
buf = br_ssl_engine_sendrec_buf(_eng, &len);
wlen = WiFiClient::write(buf, len);
if (wlen < 0) {
/*
If we received a close_notify and we
still send something, then we have our
own response close_notify to send, and
the peer is allowed by RFC 5246 not to
wait for it.
*/
if (!_eng->shutdown_recv) {
// br_ssl_engine_fail(_eng, BR_ERR_IO);
}
return -1;
}
if (wlen > 0) {
br_ssl_engine_sendrec_ack(_eng, wlen);
}
buf = br_ssl_engine_sendrec_buf(_eng, &len);
wlen = WiFiClient::write(buf, len);
if (wlen <= 0) {
/*
If we received a close_notify and we
still send something, then we have our
own response close_notify to send, and
the peer is allowed by RFC 5246 not to
wait for it.
*/
return -1;
}
if (wlen > 0) {
br_ssl_engine_sendrec_ack(_eng, wlen);
}
no_work = 0;
continue;
}
continue;
}
/*
If we reached our target, then we are finished.
*/
if (state & target) {
return 0;
}
/*
If some application data must be read, and we did not
exit, then this means that we are trying to write data,
and that's not possible until the application data is
read. This may happen if using a shared in/out buffer,
and the underlying protocol is not strictly half-duplex.
This is unrecoverable here, so we report an error.
*/
if (state & BR_SSL_RECVAPP) {
DEBUG_BSSL("_run_until: Fatal protocol state\n");
return -1;
}
/*
If we reached that point, then either we are trying
to read data and there is some, or the engine is stuck
until a new record is obtained.
*/
if (state & BR_SSL_RECVREC) {
if (WiFiClient::available()) {
/*
If we reached our target, then we are finished.
*/
if (state & target) {
return 0;
}
/*
If some application data must be read, and we did not
exit, then this means that we are trying to write data,
and that's not possible until the application data is
read. This may happen if using a shared in/out buffer,
and the underlying protocol is not strictly half-duplex.
This is unrecoverable here, so we report an error.
*/
if (state & BR_SSL_RECVAPP) {
DEBUG_BSSL("_run_until: Fatal protocol state\n");
return -1;
}
/*
If we reached that point, then either we are trying
to read data and there is some, or the engine is stuck
until a new record is obtained.
*/
if (state & BR_SSL_RECVREC) {
if (WiFiClient::available()) {
unsigned char *buf;
size_t len;
int rlen;
buf = br_ssl_engine_recvrec_buf(_eng, &len);
rlen = WiFiClient::read(buf, len);
rlen = WiFiClient::read(buf, len);
if (rlen < 0) {
// br_ssl_engine_fail(_eng, BR_ERR_IO);
return -1;
}
if (rlen > 0) {
@@ -680,16 +675,15 @@ int WiFiClientSecure_light::_run_until(unsigned target, bool blocking) {
no_work = 0;
continue;
}
}
/*
We can reach that point if the target RECVAPP, and
the state contains SENDAPP only. This may happen with
a shared in/out buffer. In that case, we must flush
the buffered data to "make room" for a new incoming
record.
*/
br_ssl_engine_flush(_eng, 0);
}
/*
We can reach that point if the target RECVAPP, and
the state contains SENDAPP only. This may happen with
a shared in/out buffer. In that case, we must flush
the buffered data to "make room" for a new incoming
record.
*/
br_ssl_engine_flush(_eng, 0);
no_work++; // We didn't actually advance here
}
@@ -792,59 +786,69 @@ extern "C" {
xc->done_cert = true; // first cert already processed
}
// **** Start patch Castellucci
/*
static void pubkeyfingerprint_pubkey_fingerprint(br_sha1_context *shactx, br_rsa_public_key rsakey) {
br_sha1_init(shactx);
br_sha1_update(shactx, "ssh-rsa", 7); // tag
br_sha1_update(shactx, rsakey.e, rsakey.elen); // exponent
br_sha1_update(shactx, rsakey.n, rsakey.nlen); // modulus
}
*/
// If `compat` id false, adds a u32be length prefixed value to the sha1 state.
// If `compat` is true, the length will be omitted for compatibility with
// data from older versions of Tasmota.
static void sha1_update_len(br_sha1_context *shactx, const void *msg, uint32_t len, bool compat) {
// Add a data element with a u32be length prefix to the sha1 state.
static void sha1_update_len(br_sha1_context *shactx, const void *msg, uint32_t len) {
uint8_t buf[] = {0, 0, 0, 0};
if (!compat) {
buf[0] = (len >> 24) & 0xff;
buf[1] = (len >> 16) & 0xff;
buf[2] = (len >> 8) & 0xff;
buf[3] = (len >> 0) & 0xff;
br_sha1_update(shactx, buf, 4); // length
}
buf[0] = (len >> 24) & 0xff;
buf[1] = (len >> 16) & 0xff;
buf[2] = (len >> 8) & 0xff;
buf[3] = (len >> 0) & 0xff;
br_sha1_update(shactx, buf, 4); // length
br_sha1_update(shactx, msg, len); // message
}
// Update the received fingerprint based on the certificate's public key.
// If `compat` is true, an insecure version of the fingerprint will be
// calcualted for compatibility with older versions of Tasmota. Normally,
// `compat` should be false.
static void pubkeyfingerprint_pubkey_fingerprint(br_x509_pubkeyfingerprint_context *xc, bool compat) {
br_rsa_public_key rsakey = xc->ctx.pkey.key.rsa;
// Calculate the received fingerprint based on the certificate's public key.
// The public exponent and modulus are length prefixed to avoid security
// vulnerabilities related to ambiguous serialization. Without this, an
// attacker can generate alternative public keys which result in the same
// fingerprint, but are trivial to crack. This works because RSA keys can be
// created with more than two primes, and most numbers, even large ones, can
// be easily factored.
static void pubkeyfingerprint_pubkey_fingerprint(br_x509_pubkeyfingerprint_context *xc) {
if (xc->ctx.pkey.key_type == BR_KEYTYPE_RSA) {
br_rsa_public_key rsakey = xc->ctx.pkey.key.rsa;
br_sha1_context shactx;
br_sha1_context shactx;
br_sha1_init(&shactx);
br_sha1_init(&shactx);
sha1_update_len(&shactx, "ssh-rsa", 7, compat); // tag
sha1_update_len(&shactx, rsakey.e, rsakey.elen, compat); // exponent
sha1_update_len(&shactx, rsakey.n, rsakey.nlen, compat); // modulus
// The tag string doesn't really matter, but it should differ depending on
// key type. For RSA it's a fixed string.
sha1_update_len(&shactx, "ssh-rsa", 7); // tag
sha1_update_len(&shactx, rsakey.e, rsakey.elen); // exponent
sha1_update_len(&shactx, rsakey.n, rsakey.nlen); // modulus
br_sha1_out(&shactx, xc->pubkey_recv_fingerprint); // copy to fingerprint
br_sha1_out(&shactx, xc->pubkey_recv_fingerprint); // copy to fingerprint
}
#ifndef ESP8266
else if (xc->ctx.pkey.key_type == BR_KEYTYPE_EC) {
br_ec_public_key eckey = xc->ctx.pkey.key.ec;
br_sha1_context shactx;
br_sha1_init(&shactx);
// The tag string doesn't really matter, but it should differ depending on
// key type. For ECDSA it's a fixed string.
sha1_update_len(&shactx, "ecdsa", 5); // tag
int32_t curve = htonl(eckey.curve);
sha1_update_len(&shactx, &curve, 4); // curve id as int32be
sha1_update_len(&shactx, eckey.q, eckey.qlen); // public point
}
#endif
else {
// We don't support anything else, so just set the fingerprint to all zeros.
memset(xc->pubkey_recv_fingerprint, 0, 20);
}
}
// **** End patch Castellucci
// Callback when complete chain has been parsed.
// Return 0 on validation success, !0 on validation error
static unsigned pubkeyfingerprint_end_chain(const br_x509_class **ctx) {
br_x509_pubkeyfingerprint_context *xc = (br_x509_pubkeyfingerprint_context *)ctx;
// set fingerprint status byte to zero
// FIXME: find a better way to pass this information
xc->pubkey_recv_fingerprint[20] = 0;
// Try matching using the the new fingerprint algorithm
pubkeyfingerprint_pubkey_fingerprint(xc, false);
pubkeyfingerprint_pubkey_fingerprint(xc);
if (!xc->fingerprint_all) {
if (0 == memcmp_P(xc->pubkey_recv_fingerprint, xc->fingerprint1, 20)) {
return 0;
@@ -857,7 +861,6 @@ extern "C" {
// Default (no validation at all) or no errors in prior checks = success.
return 0;
}
// **** End patch Castellucci
}
// Return the public key from the validator (set by x509_minimal)
@@ -894,20 +897,39 @@ extern "C" {
ctx->fingerprint_all = fingerprint_all;
}
#ifdef ESP8266
// We limit to a single cipher to reduce footprint
// we reference it, don't put in PROGMEM
static const uint16_t suites[] = {
BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
};
#else
// add more flexibility on ESP32
static const uint16_t suites[] = {
BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
};
static const uint16_t suites_RSA_ONLY[] = {
BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
};
#endif
// Default initializion for our SSL clients
static void br_ssl_client_base_init(br_ssl_client_context *cc) {
static void br_ssl_client_base_init(br_ssl_client_context *cc, bool _rsa_only) {
br_ssl_client_zero(cc);
// forbid SSL renegotiation, as we free the Private Key after handshake
br_ssl_engine_add_flags(&cc->eng, BR_OPT_NO_RENEGOTIATION);
br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12);
#ifdef ESP8266
br_ssl_engine_set_suites(&cc->eng, suites, (sizeof suites) / (sizeof suites[0]));
#else
if (_rsa_only) {
br_ssl_engine_set_suites(&cc->eng, suites_RSA_ONLY, (sizeof suites_RSA_ONLY) / (sizeof suites_RSA_ONLY[0]));
} else {
br_ssl_engine_set_suites(&cc->eng, suites, (sizeof suites) / (sizeof suites[0]));
}
#endif
br_ssl_client_set_default_rsapub(cc);
br_ssl_engine_set_default_rsavrfy(&cc->eng);
@@ -922,6 +944,9 @@ extern "C" {
// we support only P256 EC curve for AWS IoT, no EC curve for Letsencrypt unless forced
br_ssl_engine_set_ec(&cc->eng, &br_ec_p256_m15); // TODO
#ifndef ESP8266
br_ssl_engine_set_ecdsa(&cc->eng, &br_ecdsa_i15_vrfy_asn1);
#endif
}
}
@@ -935,8 +960,6 @@ bool WiFiClientSecure_light::_connectSSL(const char* hostName) {
LOG_HEAP_SIZE("_connectSSL.start");
bool OOM_error_occured = true;
do { // used to exit on Out of Memory error and keep all cleanup code at the same place
// ============================================================
// allocate Thunk stack, move to alternate stack and initialize
@@ -954,7 +977,7 @@ bool WiFiClientSecure_light::_connectSSL(const char* hostName) {
_ctx_present = true;
_eng = &_sc->eng; // Allocation/deallocation taken care of by the _sc shared_ptr
br_ssl_client_base_init(_sc.get());
br_ssl_client_base_init(_sc.get(), _rsa_only);
if (_alpn_names && _alpn_num > 0) {
br_ssl_engine_set_protocol_names(_eng, _alpn_names, _alpn_num);
}
@@ -989,23 +1012,20 @@ bool WiFiClientSecure_light::_connectSSL(const char* hostName) {
br_ssl_engine_set_buffers_bidi(_eng, _iobuf_in.get(), _iobuf_in_size, _iobuf_out.get(), _iobuf_out_size);
// ============================================================
// allocate Private key if needed, only if USE_MQTT_AWS_IOT
// allocate Private key if needed, only if USE_MQTT_CLIENT_CERT
LOG_HEAP_SIZE("_connectSSL before PrivKey allocation");
#ifdef USE_MQTT_AWS_IOT
#if defined(USE_MQTT_CLIENT_CERT)
// ============================================================
// Set the EC Private Key, only USE_MQTT_AWS_IOT
// Set the EC Private Key, only USE_MQTT_CLIENT_CERT
// limited to P256 curve
br_ssl_client_set_single_ec(_sc.get(), _chain_P, 1,
_sk_ec_P, _allowed_usages,
_cert_issuer_key_type, &br_ec_p256_m15, br_ecdsa_sign_asn1_get_default());
#endif // USE_MQTT_AWS_IOT
#endif // USE_MQTT_CLIENT_CERT
// ============================================================
// Start TLS connection, ALL
if (!br_ssl_client_reset(_sc.get(), hostName, 0)) {
OOM_error_occured = false;
break;
}
if (!br_ssl_client_reset(_sc.get(), hostName, 0)) break;
auto ret = _wait_for_handshake();
#ifdef DEBUG_ESP_SSL
@@ -1031,10 +1051,8 @@ bool WiFiClientSecure_light::_connectSSL(const char* hostName) {
// ============================================================
// if we arrived here, this means we had an OOM error, cleaning up
if (OOM_error_occured) {
setLastError(ERR_OOM);
DEBUG_BSSL("_connectSSL: Out of memory\n");
}
setLastError(ERR_OOM);
DEBUG_BSSL("_connectSSL: Out of memory\n");
#ifdef ESP8266
stack_thunk_light_del_ref();
#endif
+16 -16
View File
@@ -20,7 +20,9 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <core_version.h>
#if __has_include("core_version.h") // ESP32 Stage has no core_version.h file. Disable include via PlatformIO Option
#include <core_version.h> // Arduino_Esp8266 version information (ARDUINO_ESP8266_RELEASE and ARDUINO_ESP8266_RELEASE_2_7_1)
#endif // ESP32_STAGE
#ifndef wificlientlightbearssl_h
#define wificlientlightbearssl_h
@@ -29,27 +31,24 @@
#include "NetworkClient.h"
#include <t_bearssl.h>
namespace BearSSL {
class WiFiClientSecure_light : public NetworkClient {
public:
typedef std::function<uint32_t()> UtcTime_fcn;
typedef std::function<uint32_t()> CfgTime_fcn;
WiFiClientSecure_light(int recv, int xmit);
~WiFiClientSecure_light() override;
// Set function pointers to call to get UTC time or build time.
typedef std::function<uint32_t()> UtcTime_fcn;
typedef std::function<uint32_t()> CfgTime_fcn;
void setUtcTime_fcn(UtcTime_fcn fcn) { _UtcTime = fcn; }
void setCfgTime_fcn(CfgTime_fcn fcn) { _CfgTime = fcn; }
void allocateBuffers(void);
#ifdef ESP32 // the method to override in ESP32 has timeout argument default #define WIFI_CLIENT_DEF_CONN_TIMEOUT_MS (3000)
int connect(IPAddress ip, uint16_t port) override;
int connect(const char* name, uint16_t port) override;
int connect(IPAddress ip, uint16_t port, int32_t timeout);
int connect(const char* name, uint16_t port, int32_t timeout);
int connect(IPAddress ip, uint16_t port, int32_t timeout = 3000) override;
int connect(const char* name, uint16_t port, int32_t timeout = 3000) override;
#else
int connect(IPAddress ip, uint16_t port) override;
int connect(const char* name, uint16_t port) override;
@@ -93,6 +92,10 @@ class WiFiClientSecure_light : public NetworkClient {
_fingerprint2 = f2;
_fingerprint_any = f_any;
_insecure = true;
_rsa_only = true; // if fingerprint, we limit to RSA only
}
void setRSAOnly(bool rsa_only) {
_rsa_only = rsa_only;
}
const uint8_t * getRecvPubKeyFingerprint(void) {
return _recv_fingerprint;
@@ -141,7 +144,7 @@ class WiFiClientSecure_light : public NetworkClient {
}
private:
uint32_t _loopTimeout=5000;
uint32_t _loopTimeout=10000;
void _clear();
bool _ctx_present;
std::shared_ptr<br_ssl_client_context> _sc;
@@ -158,14 +161,10 @@ class WiFiClientSecure_light : public NetworkClient {
bool _fingerprint_any; // accept all fingerprints
bool _insecure; // force fingerprint
bool _rsa_only; // restrict to RSA only key exchange (no ECDSA - enabled to force RSA fingerprints)
const uint8_t *_fingerprint1; // fingerprint1 to be checked against
const uint8_t *_fingerprint2; // fingerprint2 to be checked against
// **** Start patch Castellucci
/*
uint8_t _recv_fingerprint[20]; // fingerprint received
*/
uint8_t _recv_fingerprint[21]; // fingerprint received
// **** End patch Castellucci
unsigned char *_recvapp_buf;
size_t _recvapp_len;
@@ -207,7 +206,8 @@ class WiFiClientSecure_light : public NetworkClient {
#define ERR_CANT_RESOLVE_IP -1001
#define ERR_TCP_CONNECT -1002
// #define ERR_MISSING_EC_KEY -1003 // deprecated, AWS IoT is not called if the private key is not present
#define ERR_MISSING_CA -1004
// #define ERR_MISSING_CA -1004 // deprecated
#define ERR_TLS_TIMEOUT -1005
// For reference, BearSSL error codes:
// #define BR_ERR_OK 0
+3 -1
View File
@@ -331,6 +331,7 @@ bool MQTTConnect_prepareClient(controllerIndex_t controller_idx) {
mqtt_rootCA.clear();
if (mqtt_tls != nullptr) {
mqtt_tls->setTrustAnchor(Tasmota_TA, Tasmota_TA_size);
mqtt_tls->setInsecure();
}
break;
@@ -500,7 +501,8 @@ bool MQTTConnect_wrapUpConnect(controllerIndex_t controller_idx, bool MQTTresult
if (mqtt_tls_last_error == ERR_OOM) mqtt_tls_last_errorstr = F("OutOfMemory");
if (mqtt_tls_last_error == ERR_CANT_RESOLVE_IP) mqtt_tls_last_errorstr = F("Can't resolve IP");
if (mqtt_tls_last_error == ERR_TCP_CONNECT) mqtt_tls_last_errorstr = F("TCP Connect error");
if (mqtt_tls_last_error == ERR_MISSING_CA) mqtt_tls_last_errorstr = F("Missing CA");
// if (mqtt_tls_last_error == ERR_MISSING_CA) mqtt_tls_last_errorstr = F("Missing CA");
if (mqtt_tls_last_error == ERR_TLS_TIMEOUT) mqtt_tls_last_errorstr = F("TLS Timeout");
}
# ifdef ESP32
+1 -1
View File
@@ -11,7 +11,7 @@ String mqtt_tls_last_errorstr;
int32_t mqtt_tls_last_error = 0;
# ifdef ESP32
BearSSL::WiFiClientSecure_light*mqtt_tls;
BearSSL::WiFiClientSecure_light*mqtt_tls{};
# endif // ifdef ESP32
# ifdef ESP8266
BearSSL::WiFiClientSecure*mqtt_tls;
+93
View File
@@ -512,6 +512,99 @@ void handle_controllers_ControllerSettingsPage(controllerIndex_t controllerindex
addHtmlInt(mqtt_tls_last_error);
addHtml(F(": "));
addHtml(mqtt_tls_last_errorstr);
/*
getLastError codes as documented in lib\lib_ssl\bearssl-esp8266\src\t_bearssl_ssl.h
SSL-level error codes
| Receive Fatal Alert
| | Send Fatal Alert
| | |
0 : 256 : 512 : BR_ERR_OK
1 : 257 : 513 : BR_ERR_BAD_PARAM - caller-provided parameter is incorrect
2 : 258 : 514 : BR_ERR_BAD_STATE - operation requested by the caller cannot be applied with the current context state (e.g. reading data while outgoing data is waiting to be sent)
3 : 259 : 515 : BR_ERR_UNSUPPORTED_VERSION - incoming protocol or record version is unsupported
4 : 260 : 516 : BR_ERR_BAD_VERSION - incoming record version does not match the expected version
5 : 261 : 517 : BR_ERR_BAD_LENGTH - incoming record length is invalid
6 : 262 : 518 : BR_ERR_TOO_LARGE - incoming record is too large to be processed, or buffer is too small for the handshake message to send
7 : 263 : 519 : BR_ERR_BAD_MAC - decryption found an invalid padding, or the record MAC is not correct
8 : 264 : 520 : BR_ERR_NO_RANDOM - no initial entropy was provided, and none can be obtained from the OS
9 : 265 : 521 : BR_ERR_UNKNOWN_TYPE - incoming record type is unknown
10 : 266 : 522 : BR_ERR_UNEXPECTED - incoming record or message has wrong type with regards to the current engine state
12 : 268 : 524 : BR_ERR_BAD_CCS - ChangeCipherSpec message from the peer has invalid contents
13 : 269 : 525 : BR_ERR_BAD_ALERT - alert message from the peer has invalid contents (odd length)
14 : 270 : 526 : BR_ERR_BAD_HANDSHAKE - incoming handshake message decoding failed
15 : 271 : 527 : BR_ERR_OVERSIZED_ID - ServerHello contains a session ID which is larger than 32 bytes
16 : 272 : 528 : BR_ERR_BAD_CIPHER_SUITE - server wants to use a cipher suite that we did not claim to support. This is also reported if we tried to advertise a cipher suite that we do not support
17 : 273 : 529 : BR_ERR_BAD_COMPRESSION - server wants to use a compression that we did not claim to support
18 : 274 : 530 : BR_ERR_BAD_FRAGLEN - server's max fragment length does not match client's
19 : 275 : 531 : BR_ERR_BAD_SECRENEG - secure renegotiation failed
20 : 276 : 532 : BR_ERR_EXTRA_EXTENSION - server sent an extension type that we did not announce, or used the same extension type several times in a single ServerHello
21 : 277 : 533 : BR_ERR_BAD_SNI - invalid Server Name Indication contents (when used by the server, this extension shall be empty)
22 : 278 : 534 : BR_ERR_BAD_HELLO_DONE - invalid ServerHelloDone from the server (length is not 0)
23 : 279 : 535 : BR_ERR_LIMIT_EXCEEDED - internal limit exceeded (e.g. server's public key is too large)
24 : 280 : 536 : BR_ERR_BAD_FINISHED - Finished message from peer does not match the expected value
25 : 281 : 537 : BR_ERR_RESUME_MISMATCH - session resumption attempt with distinct version or cipher suite
26 : 282 : 538 : BR_ERR_INVALID_ALGORITHM - unsupported or invalid algorithm (ECDHE curve, signature algorithm, hash function)
27 : 283 : 539 : BR_ERR_BAD_SIGNATURE - invalid signature (on ServerKeyExchange from server, or in CertificateVerify from client)
28 : 284 : 540 : BR_ERR_WRONG_KEY_USAGE - peer's public key does not have the proper type or is not allowed for requested operation
29 : 285 : 541 : BR_ERR_NO_CLIENT_AUTH - client did not send a certificate upon request, or the client certificate could not be validated
31 : 287 : 543 : BR_ERR_IO - I/O error or premature close on underlying transport stream. This error code is set only by the simplified I/O API ("br_sslio_*")
getLastError codes as documented in lib\lib_ssl\bearssl-esp8266\src\t_bearssl_x509.h
32 : BR_ERR_X509_OK - validation was successful; this is not actually an error
33 : BR_ERR_X509_INVALID_VALUE - invalid value in an ASN.1 structure
34 : BR_ERR_X509_TRUNCATED - truncated certificate
35 : BR_ERR_X509_EMPTY_CHAIN - empty certificate chain (no certificate at all)
36 : BR_ERR_X509_INNER_TRUNC - decoding error: inner element extends beyond outer element size
37 : BR_ERR_X509_BAD_TAG_CLASS - decoding error: unsupported tag class (application or private)
38 : BR_ERR_X509_BAD_TAG_VALUE - decoding error: unsupported tag value
39 : BR_ERR_X509_INDEFINITE_LENGTH - decoding error: indefinite length
40 : BR_ERR_X509_EXTRA_ELEMENT - decoding error: extraneous element
41 : BR_ERR_X509_UNEXPECTED - decoding error: unexpected element
42 : BR_ERR_X509_NOT_CONSTRUCTED - decoding error: expected constructed element, but is primitive
43 : BR_ERR_X509_NOT_PRIMITIVE - decoding error: expected primitive element, but is constructed
44 : BR_ERR_X509_PARTIAL_BYTE - decoding error: BIT STRING length is not multiple of 8
45 : BR_ERR_X509_BAD_BOOLEAN - decoding error: BOOLEAN value has invalid length
46 : BR_ERR_X509_OVERFLOW - decoding error: value is off-limits
47 : BR_ERR_X509_BAD_DN - invalid distinguished name
48 : BR_ERR_X509_BAD_TIME - invalid date/time representation
49 : BR_ERR_X509_UNSUPPORTED - certificate contains unsupported features that cannot be ignored
50 : BR_ERR_X509_LIMIT_EXCEEDED - key or signature size exceeds internal limits
51 : BR_ERR_X509_WRONG_KEY_TYPE - key type does not match that which was expected
52 : BR_ERR_X509_BAD_SIGNATURE - signature is invalid
53 : BR_ERR_X509_TIME_UNKNOWN - validation time is unknown
54 : BR_ERR_X509_EXPIRED - certificate is expired or not yet valid
55 : BR_ERR_X509_DN_MISMATCH - issuer/subject DN mismatch in the chain
56 : BR_ERR_X509_BAD_SERVER_NAME - expected server name was not found in the chain
57 : BR_ERR_X509_CRITICAL_EXTENSION - unknown critical extension in certificate
58 : BR_ERR_X509_NOT_CA - not a CA, or path length constraint violation
59 : BR_ERR_X509_FORBIDDEN_KEY_USAGE - Key Usage extension prohibits intended usage
60 : BR_ERR_X509_WEAK_PUBLIC_KEY - public key found in certificate is too small
62 : BR_ERR_X509_NOT_TRUSTED - chain could not be linked to a trust anchor
getLastError codes as documented in lib\lib_ssl\bearssl-esp8266\src\t_bearssl_ssl.h
10 : 266 : BR_ALERT_UNEXPECTED_MESSAGE
20 : 276 : BR_ALERT_BAD_RECORD_MAC
22 : 278 : BR_ALERT_RECORD_OVERFLOW
30 : 286 : BR_ALERT_DECOMPRESSION_FAILURE
40 : 296 : BR_ALERT_HANDSHAKE_FAILURE
42 : 298 : BR_ALERT_BAD_CERTIFICATE
43 : 299 : BR_ALERT_UNSUPPORTED_CERTIFICATE
44 : 300 : BR_ALERT_CERTIFICATE_REVOKED
45 : 301 : BR_ALERT_CERTIFICATE_EXPIRED
46 : 302 : BR_ALERT_CERTIFICATE_UNKNOWN
47 : 303 : BR_ALERT_ILLEGAL_PARAMETER
48 : 304 : BR_ALERT_UNKNOWN_CA
49 : 305 : BR_ALERT_ACCESS_DENIED
50 : 306 : BR_ALERT_DECODE_ERROR
51 : 307 : BR_ALERT_DECRYPT_ERROR
70 : 326 : BR_ALERT_PROTOCOL_VERSION
71 : 327 : BR_ALERT_INSUFFICIENT_SECURITY
80 : 336 : BR_ALERT_INTERNAL_ERROR
90 : 346 : BR_ALERT_USER_CANCELED
100 : 356 : BR_ALERT_NO_RENEGOTIATION
110 : 366 : BR_ALERT_UNSUPPORTED_EXTENSION
120 : 376 : BR_ALERT_NO_APPLICATION_PROTOCOL
*/
# ifdef ESP32