3#ifdef USE_OTA_ENCRYPTION
20static constexpr char OTA_NOISE_PROLOGUE_INIT[]
PROGMEM =
"NoiseOTAInit";
22static constexpr char OTA_NOISE_PROLOGUE_INIT[] =
"NoiseOTAInit";
24static constexpr size_t OTA_NOISE_PROLOGUE_INIT_LEN =
sizeof(OTA_NOISE_PROLOGUE_INIT) - 1;
50 static constexpr size_t PROLOGUE_ACK_LEN = 2;
51 static constexpr size_t PROLOGUE_CLIENT_FEATURES_LEN = 1;
52 static constexpr size_t PROLOGUE_FEATURE_ACK_LEN = 2;
53 uint8_t prologue[OTA_NOISE_PROLOGUE_INIT_LEN +
sizeof(
MAGIC_BYTES) + PROLOGUE_ACK_LEN + PROLOGUE_CLIENT_FEATURES_LEN +
54 PROLOGUE_FEATURE_ACK_LEN];
55 progmem_memcpy(prologue, OTA_NOISE_PROLOGUE_INIT, OTA_NOISE_PROLOGUE_INIT_LEN);
56 uint8_t *p = prologue + OTA_NOISE_PROLOGUE_INIT_LEN;
62 *p++ = USE_OTA_VERSION;
67 *p++ = server_feature_flags;
70 int err = this->
noise_ ==
nullptr ? NOISE_ERROR_NO_MEMORY
75 ESP_LOGW(TAG,
"Session init: %d", err);
103 const uint16_t payload_len = s.
frame_len - noise::FRAME_HEADER_SIZE;
106 if (s.
frame_buf[noise::FRAME_HEADER_SIZE] != noise::HANDSHAKE_STATUS_OK) {
107 ESP_LOGW(TAG,
"Client rejected the handshake: %u", s.
frame_buf[noise::FRAME_HEADER_SIZE]);
115 ESP_LOGW(TAG,
"Handshake read: %s (%d)", LOG_STR_ARG(reason), err);
127 ESP_LOGW(TAG,
"Handshake write: %d", err);
131 const uint16_t payload_len = msg_len + 1;
133 s.
frame_buf[noise::FRAME_HEADER_SIZE] = noise::HANDSHAKE_STATUS_OK;
134 s.
frame_len = noise::FRAME_HEADER_SIZE + payload_len;
142 ESP_LOGW(TAG,
"Handshake split: %d", err);
146 ESP_LOGD(TAG,
"Noise handshake complete");
150 ESP_LOGW(TAG,
"Bad handshake state");
161 const size_t payload_len =
encode_uint16(header[1], header[2]);
162 if (header[0] != noise::FRAME_INDICATOR || payload_len < min_len || payload_len > max_len) {
163 ESP_LOGW(TAG,
"Bad frame: 0x%02X, %zu bytes", header[0], payload_len);
187 if (payload_len == 0) {
191 s.
frame_len = noise::FRAME_HEADER_SIZE + payload_len;
212 uint8_t data[noise::FRAME_HEADER_SIZE + noise::MAC_FAILURE_PAYLOAD_SIZE];
213 const size_t payload_len =
216 this->
client_->write(data, noise::FRAME_HEADER_SIZE + payload_len);
222 noise_buffer_init(mbuf);
223 noise_buffer_set_inout(mbuf, buf,
len,
len);
224 int err = noise_cipherstate_decrypt(this->
noise_->recv_cipher, &mbuf);
226 ESP_LOGW(TAG,
"Decrypt: %d", err);
237 uint8_t header[noise::FRAME_HEADER_SIZE];
238 if (!this->
readall_(header,
sizeof(header))) {
242 if (ciphertext_len == 0) {
245 if (!this->
readall_(buf, ciphertext_len)) {
274 memcpy(frame + noise::FRAME_HEADER_SIZE, data,
len);
276 noise_buffer_init(mbuf);
277 noise_buffer_set_inout(mbuf, frame + noise::FRAME_HEADER_SIZE,
len,
len + noise::MAC_SIZE);
278 int err = noise_cipherstate_encrypt(this->
noise_->send_cipher, &mbuf);
280 ESP_LOGW(TAG,
"Encrypt: %d", err);
284 return this->
writeall_(frame, noise::FRAME_HEADER_SIZE + mbuf.size);
static constexpr size_t OTA_BUFFER_SIZE
bool handle_noise_handshake_()
Drive the non-blocking handshake from loop(); returns true once the transport ciphers are ready.
bool noise_write_(const uint8_t *data, size_t len)
Blocking write of a short response (at most NOISE_MAX_RESPONSE bytes) as one encrypted frame.
static constexpr uint8_t MAGIC_BYTES[5]
bool writeall_(const uint8_t *buf, size_t len)
ssize_t noise_decrypt_(uint8_t *buf, size_t len)
Decrypt a ciphertext in place; returns the plaintext size or -1.
bool noise_readall_(uint8_t *buf, size_t len)
Blocking read of one frame whose plaintext must be exactly len bytes (control units are one unit per ...
bool noise_start_session_(uint8_t server_feature_flags)
Start the responder handshake, on the session reserved at offer time.
bool noise_try_read_frame_()
Non-blocking read of one handshake frame into the session buffer.
RAMUniquePtr< NoiseSession > noise_
bool handle_write_error_(ssize_t written, const LogString *desc)
ssize_t noise_read_frame_blocking_(uint8_t *buf, size_t min_ciphertext, size_t max_ciphertext)
Blocking read of one frame whose ciphertext size must be within the given bounds, decrypted in place;...
size_t noise_frame_payload_len_(const uint8_t *header, size_t min_len, size_t max_len)
Payload length from a frame header, or 0 (logged) when the indicator or the length is out of range.
bool handle_read_error_(ssize_t read, const LogString *desc)
ssize_t noise_read_data_(uint8_t *buf, size_t capacity)
Blocking read of one data-phase frame, decrypted in place; returns the plaintext size,...
bool readall_(uint8_t *buf, size_t len)
void noise_send_reject_(const LogString *reason)
Best-effort explicit reject frame so the client can log a readable reason.
const noise::NoiseContext & noise_context_() const
bool noise_try_write_frame_()
Non-blocking write of the pending session-buffer frame.
void cleanup_connection_()
void noise_reserve_session_()
std::unique_ptr< socket::Socket > client_
static constexpr size_t NOISE_MAX_RESPONSE
An STL allocator that uses SPI or internal RAM.
RAMUniquePtr< T > make_unique(Args &&...args)
Value initialize one T; empty on exhaustion.
int write_message(uint8_t *out, size_t capacity, size_t &out_len)
Produce the next handshake message into out; out_len receives its size and is zero on error.
Action action() const
ACTION_FAILED is the catch-all: returned before init(), after split() has released the state,...
int read_message(uint8_t *data, size_t len)
Process one received handshake message.
int split(NoiseCipherState *&send_cipher, NoiseCipherState *&recv_cipher)
Hand out the transport ciphers and free the handshake state.
constexpr float BME680_GAS_LOOKUP_TABLE_1[16] PROGMEM
ESPHOME_LOG_TAG(TAG, CRASH_LOG_TAG)
void write_frame_header(uint8_t *buf, uint16_t payload_len)
size_t format_reject_payload(uint8_t *buf, size_t capacity, const LogString *reason)
Fill buf with a handshake reject payload (status byte plus the reason text, PROGMEM aware); returns t...
const LogString * reject_reason_for(int err)
Reject reason for a failed handshake read.
@ OTA_RESPONSE_FEATURE_FLAGS
void progmem_memcpy(void *dst, const void *src, size_t len)
constexpr uint16_t encode_uint16(uint8_t msb, uint8_t lsb)
Encode a 16-bit value given the most and least significant byte.
uint16_t uint16_t & capacity
NoiseCipherState * recv_cipher
uint8_t frame_buf[noise::FRAME_HEADER_SIZE+1+noise::MAX_HANDSHAKE_SIZE]
NoiseCipherState * send_cipher
noise::NoiseResponderHandshake handshake