mirror of
https://github.com/letscontrolit/ESPEasy.git
synced 2026-07-27 19:57:38 +00:00
[TLS] Update TLS to be able to use ECDHE_ECDSA_AES_128_GCM_SHA256 cipher
This commit is contained in:
@@ -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 7748–compliant clamping of scalar inputs.
|
||||
* - Supports multiplication by arbitrary u‑coordinates 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 drop‑in 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 big‑endian 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
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Regular → Executable
+156
-138
@@ -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
|
||||
|
||||
Regular → Executable
+16
-16
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user