20static const char *
const TAG =
"api.noise";
22static constexpr char PROLOGUE_INIT[] PROGMEM =
"NoiseAPIInit";
24static const char *
const PROLOGUE_INIT =
"NoiseAPIInit";
26static constexpr size_t PROLOGUE_INIT_LEN = 12;
29static constexpr size_t API_MAX_LOG_BYTES = 168;
31#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
32#define HELPER_LOG(msg, ...) \
34 char peername_buf[socket::SOCKADDR_STR_LEN]; \
35 this->get_peername_to(peername_buf); \
36 ESP_LOGVV(TAG, "%s (%s): " msg, this->client_name_, peername_buf, ##__VA_ARGS__); \
39#define HELPER_LOG(msg, ...) ((void) 0)
42#ifdef HELPER_LOG_PACKETS
43#define LOG_PACKET_RECEIVED(buffer) \
45 char hex_buf_[format_hex_pretty_size(API_MAX_LOG_BYTES)]; \
46 ESP_LOGVV(TAG, "Received frame: %s", \
47 format_hex_pretty_to(hex_buf_, (buffer).data(), \
48 (buffer).size() < API_MAX_LOG_BYTES ? (buffer).size() : API_MAX_LOG_BYTES)); \
51#define LOG_PACKET_RECEIVED(buffer) ((void) 0)
56 if (err == NOISE_ERROR_NO_MEMORY)
57 return LOG_STR(
"NO_MEMORY");
58 if (err == NOISE_ERROR_UNKNOWN_ID)
59 return LOG_STR(
"UNKNOWN_ID");
60 if (err == NOISE_ERROR_UNKNOWN_NAME)
61 return LOG_STR(
"UNKNOWN_NAME");
62 if (err == NOISE_ERROR_MAC_FAILURE)
63 return LOG_STR(
"MAC_FAILURE");
64 if (err == NOISE_ERROR_NOT_APPLICABLE)
65 return LOG_STR(
"NOT_APPLICABLE");
66 if (err == NOISE_ERROR_SYSTEM)
67 return LOG_STR(
"SYSTEM");
68 if (err == NOISE_ERROR_REMOTE_KEY_REQUIRED)
69 return LOG_STR(
"REMOTE_KEY_REQUIRED");
70 if (err == NOISE_ERROR_LOCAL_KEY_REQUIRED)
71 return LOG_STR(
"LOCAL_KEY_REQUIRED");
72 if (err == NOISE_ERROR_PSK_REQUIRED)
73 return LOG_STR(
"PSK_REQUIRED");
74 if (err == NOISE_ERROR_INVALID_LENGTH)
75 return LOG_STR(
"INVALID_LENGTH");
76 if (err == NOISE_ERROR_INVALID_PARAM)
77 return LOG_STR(
"INVALID_PARAM");
78 if (err == NOISE_ERROR_INVALID_STATE)
79 return LOG_STR(
"INVALID_STATE");
80 if (err == NOISE_ERROR_INVALID_NONCE)
81 return LOG_STR(
"INVALID_NONCE");
82 if (err == NOISE_ERROR_INVALID_PRIVATE_KEY)
83 return LOG_STR(
"INVALID_PRIVATE_KEY");
84 if (err == NOISE_ERROR_INVALID_PUBLIC_KEY)
85 return LOG_STR(
"INVALID_PUBLIC_KEY");
86 if (err == NOISE_ERROR_INVALID_FORMAT)
87 return LOG_STR(
"INVALID_FORMAT");
88 if (err == NOISE_ERROR_INVALID_SIGNATURE)
89 return LOG_STR(
"INVALID_SIGNATURE");
90 return LOG_STR(
"UNKNOWN");
104 memcpy_P(
prologue_.
data() + old_size, PROLOGUE_INIT, PROLOGUE_INIT_LEN);
106 std::memcpy(
prologue_.
data() + old_size, PROLOGUE_INIT, PROLOGUE_INIT_LEN);
126 HELPER_LOG(
"%s failed: %s", LOG_STR_ARG(func_name), LOG_STR_ARG(
noise_err_to_logstr(err)));
138 bool socket_ready = this->
socket_->ready();
175 if (
static_cast<uint8_t
>(received) != to_read) {
193 uint16_t limit = is_data ? MAX_MESSAGE_SIZE : MAX_HANDSHAKE_SIZE;
194 if (msg_size > limit) {
196 HELPER_LOG(
"Bad packet: message size %u exceeds maximum %u", msg_size, limit);
204 uint16_t alloc_size = msg_size + (is_data ? RX_BUF_NULL_TERMINATOR : 0);
216 if (
static_cast<uint16_t
>(received) != to_read) {
222 LOG_PACKET_RECEIVED(this->
rx_buf_);
247 HELPER_LOG(
"Bad state for method: %d", (
int) this->
state_);
273 this->
prologue_[old_size] = (uint8_t) (rx_size >> 8);
274 this->
prologue_[old_size + 1] = (uint8_t) rx_size;
276 std::memcpy(this->
prologue_.
data() + old_size + 2, this->rx_buf_.data(), rx_size);
285 char mac[MAC_ADDRESS_BUFFER_SIZE];
289 size_t name_len = name.size() + 1;
290 size_t name_offset = 1;
291 size_t mac_offset = name_offset + name_len;
292 size_t total_size = 1 + name_len + MAC_ADDRESS_BUFFER_SIZE;
296 constexpr size_t max_msg_size = 1 + ESPHOME_DEVICE_NAME_MAX_LEN + 1 + MAC_ADDRESS_BUFFER_SIZE;
297 uint8_t msg[max_msg_size];
303 std::memcpy(msg + name_offset, name.c_str(), name_len);
305 std::memcpy(msg + mac_offset, mac, MAC_ADDRESS_BUFFER_SIZE);
320 int action = noise_handshakestate_get_action(this->
handshake_);
321 if (action == NOISE_ACTION_READ_MESSAGE) {
323 }
else if (action == NOISE_ACTION_WRITE_MESSAGE) {
328 HELPER_LOG(
"Bad action for handshake: %d", action);
340 }
else if (this->
rx_buf_[0] != 0x00) {
341 HELPER_LOG(
"Bad handshake error byte: %u", this->
rx_buf_[0]);
347 noise_buffer_init(mbuf);
348 noise_buffer_set_input(mbuf, this->
rx_buf_.
data() + 1, this->rx_buf_.size() - 1);
349 int err = noise_handshakestate_read_message(this->
handshake_, &mbuf,
nullptr);
353 : LOG_STR(
"Handshake error"));
363 noise_buffer_init(mbuf);
364 noise_buffer_set_output(mbuf, buffer + 1,
sizeof(buffer) - 1);
366 int err = noise_handshakestate_write_message(this->
handshake_, &mbuf,
nullptr);
383#ifdef USE_STORE_LOG_STR_IN_FLASH
385 size_t reason_len = strlen_P(
reinterpret_cast<PGM_P
>(reason));
386 reason_len = std::min(reason_len,
sizeof(data) - 1);
387 if (reason_len > 0) {
388 memcpy_P(data + 1,
reinterpret_cast<PGM_P
>(reason), reason_len);
392 const char *reason_str = LOG_STR_ARG(reason);
393 size_t reason_len = strlen(reason_str);
394 reason_len = std::min(reason_len,
sizeof(data) - 1);
395 if (reason_len > 0) {
397 std::memcpy(data + 1, reason_str, reason_len);
401 size_t data_size = reason_len + 1;
419 noise_buffer_init(mbuf);
424#ifdef ESPHOME_DEBUG_API
430 size_t encrypted_size = this->
rx_buf_.
size() - RX_BUF_NULL_TERMINATOR;
431 noise_buffer_set_inout(mbuf, this->
rx_buf_.
data(), encrypted_size, encrypted_size);
432 int err = noise_cipherstate_decrypt(this->
recv_cipher_, &mbuf);
439 uint16_t msg_size = mbuf.size;
443 HELPER_LOG(
"Bad data packet: size %d too short", msg_size);
447 uint16_t
type = (((uint16_t) msg_data[0]) << 8) | msg_data[1];
448 uint16_t data_len = (((uint16_t) msg_data[2]) << 8) | msg_data[3];
449 if (data_len > msg_size - 4) {
451 HELPER_LOG(
"Bad data packet: data_len %u greater than msg_size %u", data_len, msg_size);
455 buffer->
data = msg_data + 4;
463 uint16_t &encrypted_len_out) {
469 constexpr uint8_t msg_offset = 3;
470 buf_start[msg_offset] =
static_cast<uint8_t
>(message_type >> 8);
471 buf_start[msg_offset + 1] =
static_cast<uint8_t
>(message_type);
472 buf_start[msg_offset + 2] =
static_cast<uint8_t
>(
payload_size >> 8);
473 buf_start[msg_offset + 3] =
static_cast<uint8_t
>(
payload_size);
478 noise_buffer_init(mbuf);
481 int err = noise_cipherstate_encrypt(this->
send_cipher_, &mbuf);
488 buf_start[1] =
static_cast<uint8_t
>(mbuf.size >> 8);
489 buf_start[2] =
static_cast<uint8_t
>(mbuf.size);
491 encrypted_len_out =
static_cast<uint16_t
>(3 + mbuf.size);
496#ifdef ESPHOME_DEBUG_API
507 uint16_t encrypted_len;
515#ifdef ESPHOME_DEBUG_API
517 assert(!messages.empty());
524 uint8_t *write_start = buffer_data + messages[0].offset;
525 uint16_t total_write_len = 0;
527 for (
const auto &msg : messages) {
528 uint8_t *buf_start = buffer_data + msg.offset;
529 uint16_t encrypted_len;
533 total_write_len += encrypted_len;
542 header[1] = (uint8_t) (
len >> 8);
543 header[2] = (uint8_t)
len;
551 iov[1].
iov_base =
const_cast<uint8_t *
>(data);
566 nid_.pattern_id = NOISE_PATTERN_NN;
567 nid_.cipher_id = NOISE_CIPHER_CHACHAPOLY;
568 nid_.dh_id = NOISE_DH_CURVE25519;
569 nid_.prefix_id = NOISE_PREFIX_STANDARD;
570 nid_.hybrid_id = NOISE_DH_NONE;
571 nid_.hash_id = NOISE_HASH_SHA256;
572 nid_.modifier_ids[0] = NOISE_MODIFIER_PSK0;
574 err = noise_handshakestate_new_by_id(&
handshake_, &
nid_, NOISE_ROLE_RESPONDER);
581 err = noise_handshakestate_set_pre_shared_key(
handshake_, psk.data(), psk.size());
602#ifdef ESPHOME_DEBUG_API
606 int action = noise_handshakestate_get_action(
handshake_);
607 if (action == NOISE_ACTION_READ_MESSAGE || action == NOISE_ACTION_WRITE_MESSAGE)
609 if (action != NOISE_ACTION_SPLIT) {
611 HELPER_LOG(
"Bad action for handshake: %d", action);
622 HELPER_LOG(
"Handshake complete!");
648 ESP_LOGE(TAG,
"Acquiring random bytes failed; rebooting");
const StringRef & get_name() const
Get the name of this Application set by pre_setup().
void release()
Release all memory (equivalent to std::vector swap trick).
void resize(size_t n) ESPHOME_ALWAYS_INLINE
APIError handle_socket_read_result_(ssize_t received)
APIError ESPHOME_ALWAYS_INLINE write_raw_fast_buf_(const void *data, uint16_t len)
APIError write_raw_buf_(const void *data, uint16_t len, ssize_t sent=WRITE_NOT_ATTEMPTED)
APIError write_raw_iov_(const struct iovec *iov, int iovcnt, uint16_t total_write_len, ssize_t sent=WRITE_NOT_ATTEMPTED)
APIOverflowBuffer overflow_buf_
std::unique_ptr< socket::Socket > socket_
uint8_t frame_footer_size_
APIError ESPHOME_ALWAYS_INLINE check_data_state_() const
APIError drain_overflow_and_handle_errors_()
const psk_t & get_psk() const
APIError write_protobuf_packet(uint8_t type, ProtoWriteBuffer buffer) override
uint8_t rx_header_buf_len_
NoiseCipherState * send_cipher_
APIError state_action_handshake_()
APIError read_packet(ReadPacketBuffer *buffer) override
NoiseCipherState * recv_cipher_
~APINoiseFrameHelper() override
APIError handle_noise_error_(int err, const LogString *func_name, APIError api_err)
APIError write_protobuf_messages(ProtoWriteBuffer buffer, std::span< const MessageInfo > messages) override
APIError state_action_()
To be called from read/write methods.
APIError state_action_handshake_write_()
APIError try_read_frame_()
Read a packet into the rx_buf_.
APIError loop() override
Run through handshake messages (if in that phase)
APIError encrypt_noise_message_(uint8_t *buf_start, uint16_t payload_size, uint8_t message_type, uint16_t &encrypted_len_out)
NoiseHandshakeState * handshake_
uint8_t rx_header_buf_[3]
static constexpr uint8_t HEADER_PADDING
APIError handle_handshake_frame_error_(APIError aerr)
void send_explicit_handshake_reject_(const LogString *reason)
APIError write_frame_(const uint8_t *data, uint16_t len)
APIError state_action_handshake_read_()
APIError state_action_server_hello_()
APIError init() override
Initialize the frame helper, returns OK if successful.
APIError state_action_client_hello_()
APIError check_handshake_finished_()
APIError init_handshake_()
Initiate the data structures for the handshake.
bool empty() const
True when no backlogged data is waiting.
APIBuffer * get_buffer() const
void noise_rand_bytes(void *output, size_t len)
@ HANDSHAKESTATE_READ_FAILED
@ HANDSHAKESTATE_BAD_STATE
@ HANDSHAKESTATE_SPLIT_FAILED
@ BAD_HANDSHAKE_PACKET_LEN
@ BAD_HANDSHAKE_ERROR_BYTE
@ HANDSHAKESTATE_SETUP_FAILED
@ CIPHERSTATE_ENCRYPT_FAILED
@ CIPHERSTATE_DECRYPT_FAILED
@ HANDSHAKESTATE_WRITE_FAILED
const LogString * noise_err_to_logstr(int err)
Convert a noise error code to a readable error.
bool random_bytes(uint8_t *data, size_t len)
Generate len random bytes using the platform's secure RNG (hardware RNG or OS CSPRNG).
void get_mac_address_into_buffer(std::span< char, MAC_ADDRESS_BUFFER_SIZE > buf)
Get the device MAC address into the given buffer, in lowercase hex notation.
Application App
Global storage of Application pointer - only one Application can exist.