mirror of
https://github.com/esphome/esphome.git
synced 2026-09-07 21:46:09 +00:00
Share the spare ephemeral key size and note the key stays in RAM until consumed
This commit is contained in:
@@ -27,9 +27,8 @@ void NoiseContext::load_psk(psk_t &out) const {
|
||||
}
|
||||
|
||||
#ifdef USE_NOISE_SPARE_EPHEMERAL
|
||||
static constexpr size_t PRIVATE_KEY_SIZE = 32;
|
||||
static constexpr size_t PUBLIC_KEY_SIZE = 32;
|
||||
static_assert(PRIVATE_KEY_SIZE + PUBLIC_KEY_SIZE == SPARE_EPHEMERAL_SIZE);
|
||||
static constexpr size_t PRIVATE_KEY_SIZE = SPARE_EPHEMERAL_KEY_SIZE;
|
||||
static constexpr size_t PUBLIC_KEY_SIZE = SPARE_EPHEMERAL_KEY_SIZE;
|
||||
uint8_t spare_ephemeral[SPARE_EPHEMERAL_SIZE]; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
|
||||
void prepare_spare_ephemeral() {
|
||||
|
||||
@@ -45,13 +45,14 @@ const LogString *noise_err_to_logstr(int err);
|
||||
// One responder ephemeral key pair generated ahead of time (about 60 ms on
|
||||
// ESP8266), refilled by the api server while idle and consumed by the next
|
||||
// handshake of any noise transport; an empty slot means the handshake
|
||||
// generates its own key.
|
||||
// generates its own key. The private key stays in RAM until consumed.
|
||||
// Private key then public key; zero when empty
|
||||
static constexpr size_t SPARE_EPHEMERAL_SIZE = 64;
|
||||
static constexpr size_t SPARE_EPHEMERAL_KEY_SIZE = 32;
|
||||
static constexpr size_t SPARE_EPHEMERAL_SIZE = 2 * SPARE_EPHEMERAL_KEY_SIZE;
|
||||
extern uint8_t spare_ephemeral[SPARE_EPHEMERAL_SIZE]; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
// Polled every api loop tick, so it must inline. A clamped X25519 private key
|
||||
// always has bit 254 set, so that byte doubles as the ready flag.
|
||||
inline bool has_spare_ephemeral() { return (spare_ephemeral[31] & 0x40) != 0; }
|
||||
inline bool has_spare_ephemeral() { return (spare_ephemeral[SPARE_EPHEMERAL_KEY_SIZE - 1] & 0x40) != 0; }
|
||||
/// Fill the slot; blocks for the base point multiply
|
||||
void prepare_spare_ephemeral();
|
||||
/// Hand the slot's key pair to a handshake that has not started and wipe the
|
||||
|
||||
@@ -161,7 +161,7 @@ TEST(NoiseResponderHandshakeTest, FullHandshakeAndTransportRoundTrip) {
|
||||
// responder_e receives the ephemeral public key the responder put on the
|
||||
// wire (the clear text start of its message, taken before the initiator
|
||||
// consumes the buffer in place)
|
||||
static void run_handshake(NoiseResponderHandshake &responder, uint8_t responder_e[32]) {
|
||||
static void run_handshake(NoiseResponderHandshake &responder, uint8_t responder_e[SPARE_EPHEMERAL_KEY_SIZE]) {
|
||||
const psk_t psk = make_psk(7);
|
||||
ASSERT_EQ(responder.init(ctx_for(psk), PROLOGUE, sizeof(PROLOGUE)), 0);
|
||||
Initiator initiator(psk, PROLOGUE, sizeof(PROLOGUE));
|
||||
@@ -170,8 +170,8 @@ static void run_handshake(NoiseResponderHandshake &responder, uint8_t responder_
|
||||
ASSERT_EQ(responder.read_message(msg, msg_len), 0);
|
||||
size_t reply_len = 0;
|
||||
ASSERT_EQ(responder.write_message(msg, sizeof(msg), reply_len), 0);
|
||||
ASSERT_GE(reply_len, 32u);
|
||||
std::memcpy(responder_e, msg, 32);
|
||||
ASSERT_GE(reply_len, SPARE_EPHEMERAL_KEY_SIZE);
|
||||
std::memcpy(responder_e, msg, SPARE_EPHEMERAL_KEY_SIZE);
|
||||
ASSERT_EQ(initiator.read_message(msg, reply_len), 0);
|
||||
ASSERT_EQ(responder.action(), Action::ACTION_SPLIT);
|
||||
}
|
||||
@@ -179,7 +179,7 @@ static void run_handshake(NoiseResponderHandshake &responder, uint8_t responder_
|
||||
TEST(SpareEphemeralTest, EmptySlotLeavesHandshakeToGenerate) {
|
||||
ASSERT_FALSE(has_spare_ephemeral());
|
||||
NoiseResponderHandshake responder;
|
||||
uint8_t responder_e[32];
|
||||
uint8_t responder_e[SPARE_EPHEMERAL_KEY_SIZE];
|
||||
run_handshake(responder, responder_e);
|
||||
EXPECT_FALSE(has_spare_ephemeral());
|
||||
}
|
||||
@@ -209,11 +209,11 @@ TEST(SpareEphemeralTest, ConsumeHandsTheKeyToANewState) {
|
||||
TEST(SpareEphemeralTest, SlotKeyIsOnTheWireAndConsumedOnce) {
|
||||
prepare_spare_ephemeral();
|
||||
ASSERT_TRUE(has_spare_ephemeral());
|
||||
uint8_t expected_pub[32];
|
||||
std::memcpy(expected_pub, spare_ephemeral + 32, sizeof(expected_pub));
|
||||
uint8_t expected_pub[SPARE_EPHEMERAL_KEY_SIZE];
|
||||
std::memcpy(expected_pub, spare_ephemeral + SPARE_EPHEMERAL_KEY_SIZE, sizeof(expected_pub));
|
||||
|
||||
NoiseResponderHandshake first;
|
||||
uint8_t responder_e[32];
|
||||
uint8_t responder_e[SPARE_EPHEMERAL_KEY_SIZE];
|
||||
run_handshake(first, responder_e);
|
||||
// The spare, not a generated key, went out; and it went out once
|
||||
EXPECT_EQ(std::memcmp(responder_e, expected_pub, sizeof(expected_pub)), 0);
|
||||
|
||||
Reference in New Issue
Block a user