mirror of
https://github.com/esphome/esphome.git
synced 2026-09-29 07:50:21 +00:00
78 lines
3.1 KiB
C++
78 lines
3.1 KiB
C++
#pragma once
|
|
#include "api_frame_helper.h"
|
|
#ifdef USE_API
|
|
#ifdef USE_API_NOISE
|
|
#include "noise/protocol.h"
|
|
#include "esphome/components/noise/noise_handshake.h"
|
|
|
|
namespace esphome::api {
|
|
|
|
class APINoiseFrameHelper final : public APIFrameHelper {
|
|
public:
|
|
// Noise header structure:
|
|
// Pos 0: indicator (0x01)
|
|
// Pos 1-2: encrypted payload size (16-bit big-endian)
|
|
// Pos 3-6: encrypted type (16-bit) + data_len (16-bit)
|
|
// Pos 7+: actual payload data
|
|
static constexpr uint8_t HEADER_PADDING = noise::FRAME_HEADER_SIZE + 2 + 2; // frame header + type + data_len
|
|
|
|
APINoiseFrameHelper(std::unique_ptr<socket::Socket> socket, noise::NoiseContext &ctx)
|
|
: APIFrameHelper(std::move(socket)), ctx_(ctx) {
|
|
frame_header_padding_ = HEADER_PADDING;
|
|
}
|
|
~APINoiseFrameHelper() override;
|
|
APIError init() override;
|
|
#ifdef USE_API_PLAINTEXT
|
|
// Take over a connection whose first bytes were consumed by a plaintext
|
|
// helper on an unprovisioned device (see APIError::PROTOCOL_SWITCH_TO_NOISE).
|
|
// Seeds the already-read header bytes and pumps the handshake state machine
|
|
// until it would block.
|
|
APIError init_from_handoff(const uint8_t *header, uint8_t header_len);
|
|
#endif
|
|
APIError loop() override;
|
|
APIError read_packet(ReadPacketBuffer *buffer) override;
|
|
APIError write_protobuf_packet(uint16_t type, ProtoWriteBuffer buffer) override;
|
|
APIError write_protobuf_messages(ProtoWriteBuffer buffer, std::span<const MessageInfo> messages) override;
|
|
|
|
protected:
|
|
APIError pump_handshake_();
|
|
APIError state_action_();
|
|
APIError state_action_client_hello_();
|
|
APIError state_action_server_hello_();
|
|
APIError state_action_handshake_();
|
|
APIError state_action_handshake_read_();
|
|
APIError state_action_handshake_write_();
|
|
APIError try_read_frame_();
|
|
APIError write_frame_(const uint8_t *data, uint16_t len);
|
|
APIError encrypt_noise_message_(uint8_t *buf_start, uint16_t payload_size, uint16_t message_type,
|
|
uint16_t &encrypted_len_out);
|
|
APIError init_handshake_();
|
|
APIError check_handshake_finished_();
|
|
void send_explicit_handshake_reject_(const LogString *reason);
|
|
APIError handle_handshake_frame_error_(APIError aerr);
|
|
APIError handle_noise_error_(int err, const LogString *func_name, APIError api_err);
|
|
|
|
// Pointers first (4 bytes each; the handshake wrapper holds one pointer)
|
|
noise::NoiseResponderHandshake handshake_;
|
|
NoiseCipherState *send_cipher_{nullptr};
|
|
NoiseCipherState *recv_cipher_{nullptr};
|
|
|
|
// Reference to noise context (4 bytes on 32-bit)
|
|
noise::NoiseContext &ctx_;
|
|
|
|
// Buffer for noise handshake prologue (released after handshake)
|
|
APIBuffer prologue_;
|
|
|
|
// Group small types together
|
|
// Fixed-size header buffer for noise protocol:
|
|
// 1 byte for indicator + 2 bytes for message size (16-bit value, not varint)
|
|
// Note: Maximum message size is UINT16_MAX (65535), with a limit of 128 bytes during handshake phase
|
|
uint8_t rx_header_buf_[noise::FRAME_HEADER_SIZE];
|
|
uint8_t rx_header_buf_len_ = 0;
|
|
// 4 bytes total, no padding
|
|
};
|
|
|
|
} // namespace esphome::api
|
|
#endif // USE_API_NOISE
|
|
#endif // USE_API
|