13 static const char *
const TAG =
"api.socket";
18 return errno == EWOULDBLOCK || errno == EAGAIN;
30 return "BAD_HANDSHAKE_PACKET_LEN";
32 return "BAD_INDICATOR";
34 return "BAD_DATA_PACKET";
36 return "TCP_NODELAY_FAILED";
38 return "TCP_NONBLOCKING_FAILED";
40 return "CLOSE_FAILED";
42 return "SHUTDOWN_FAILED";
48 return "SOCKET_READ_FAILED";
50 return "SOCKET_WRITE_FAILED";
52 return "HANDSHAKESTATE_READ_FAILED";
54 return "HANDSHAKESTATE_WRITE_FAILED";
56 return "HANDSHAKESTATE_BAD_STATE";
58 return "CIPHERSTATE_DECRYPT_FAILED";
60 return "CIPHERSTATE_ENCRYPT_FAILED";
62 return "OUT_OF_MEMORY";
64 return "HANDSHAKESTATE_SETUP_FAILED";
66 return "HANDSHAKESTATE_SPLIT_FAILED";
68 return "BAD_HANDSHAKE_ERROR_BYTE";
70 return "CONNECTION_CLOSED";
75 #define HELPER_LOG(msg, ...) ESP_LOGVV(TAG, "%s: " msg, info_.c_str(), ##__VA_ARGS__) 80 static const char *
const PROLOGUE_INIT =
"NoiseAPIInit";
84 if (err == NOISE_ERROR_NO_MEMORY)
86 if (err == NOISE_ERROR_UNKNOWN_ID)
88 if (err == NOISE_ERROR_UNKNOWN_NAME)
89 return "UNKNOWN_NAME";
90 if (err == NOISE_ERROR_MAC_FAILURE)
92 if (err == NOISE_ERROR_NOT_APPLICABLE)
93 return "NOT_APPLICABLE";
94 if (err == NOISE_ERROR_SYSTEM)
96 if (err == NOISE_ERROR_REMOTE_KEY_REQUIRED)
97 return "REMOTE_KEY_REQUIRED";
98 if (err == NOISE_ERROR_LOCAL_KEY_REQUIRED)
99 return "LOCAL_KEY_REQUIRED";
100 if (err == NOISE_ERROR_PSK_REQUIRED)
101 return "PSK_REQUIRED";
102 if (err == NOISE_ERROR_INVALID_LENGTH)
103 return "INVALID_LENGTH";
104 if (err == NOISE_ERROR_INVALID_PARAM)
105 return "INVALID_PARAM";
106 if (err == NOISE_ERROR_INVALID_STATE)
107 return "INVALID_STATE";
108 if (err == NOISE_ERROR_INVALID_NONCE)
109 return "INVALID_NONCE";
110 if (err == NOISE_ERROR_INVALID_PRIVATE_KEY)
111 return "INVALID_PRIVATE_KEY";
112 if (err == NOISE_ERROR_INVALID_PUBLIC_KEY)
113 return "INVALID_PUBLIC_KEY";
114 if (err == NOISE_ERROR_INVALID_FORMAT)
115 return "INVALID_FORMAT";
116 if (err == NOISE_ERROR_INVALID_SIGNATURE)
117 return "INVALID_SIGNATURE";
124 HELPER_LOG(
"Bad state for init %d", (
int)
state_);
127 int err =
socket_->setblocking(
false);
130 HELPER_LOG(
"Setting nonblocking failed with errno %d", errno);
135 err =
socket_->setsockopt(IPPROTO_TCP, TCP_NODELAY, &enable,
sizeof(
int));
138 HELPER_LOG(
"Setting nodelay failed with errno %d", errno);
143 prologue_.insert(
prologue_.end(), PROLOGUE_INIT, PROLOGUE_INIT + strlen(PROLOGUE_INIT));
179 if (frame ==
nullptr) {
180 HELPER_LOG(
"Bad argument for try_read_frame_");
189 if (received == -1) {
190 if (errno == EWOULDBLOCK || errno == EAGAIN) {
194 HELPER_LOG(
"Socket read failed with errno %d", errno);
196 }
else if (received == 0) {
198 HELPER_LOG(
"Connection closed");
201 rx_header_buf_len_ += received;
202 if ((
size_t) received != to_read) {
212 if (indicator != 0x01) {
214 HELPER_LOG(
"Bad indicator byte %u", indicator);
223 HELPER_LOG(
"Bad packet len for handshake: %d", msg_size);
228 if (
rx_buf_.size() != msg_size) {
236 if (received == -1) {
237 if (errno == EWOULDBLOCK || errno == EAGAIN) {
241 HELPER_LOG(
"Socket read failed with errno %d", errno);
243 }
else if (received == 0) {
245 HELPER_LOG(
"Connection closed");
248 rx_buf_len_ += received;
249 if ((
size_t) received != to_read) {
256 #ifdef HELPER_LOG_PACKETS 280 HELPER_LOG(
"Bad state for method: %d", (
int)
state_);
306 std::vector<uint8_t> msg;
312 const uint8_t *name_ptr =
reinterpret_cast<const uint8_t *
>(name.c_str());
313 msg.insert(msg.end(), name_ptr, name_ptr + name.size() + 1);
327 int action = noise_handshakestate_get_action(
handshake_);
328 if (action == NOISE_ACTION_READ_MESSAGE) {
343 if (frame.
msg.empty()) {
346 }
else if (frame.
msg[0] != 0x00) {
347 HELPER_LOG(
"Bad handshake error byte: %u", frame.
msg[0]);
353 noise_buffer_init(mbuf);
354 noise_buffer_set_input(mbuf, frame.
msg.data() + 1, frame.
msg.size() - 1);
355 err = noise_handshakestate_read_message(
handshake_, &mbuf,
nullptr);
358 HELPER_LOG(
"noise_handshakestate_read_message failed: %s",
noise_err_to_str(err).c_str());
359 if (err == NOISE_ERROR_MAC_FAILURE) {
370 }
else if (action == NOISE_ACTION_WRITE_MESSAGE) {
373 noise_buffer_init(mbuf);
374 noise_buffer_set_output(mbuf, buffer + 1,
sizeof(buffer) - 1);
376 err = noise_handshakestate_write_message(
handshake_, &mbuf,
nullptr);
379 HELPER_LOG(
"noise_handshakestate_write_message failed: %s",
noise_err_to_str(err).c_str());
393 HELPER_LOG(
"Bad action for handshake: %d", action);
403 std::vector<uint8_t> data;
404 data.resize(reason.length() + 1);
406 for (
size_t i = 0; i < reason.length(); i++) {
407 data[i + 1] = (uint8_t) reason[i];
434 noise_buffer_init(mbuf);
435 noise_buffer_set_inout(mbuf, frame.
msg.data(), frame.
msg.size(), frame.
msg.size());
439 HELPER_LOG(
"noise_cipherstate_decrypt failed: %s",
noise_err_to_str(err).c_str());
443 size_t msg_size = mbuf.size;
444 uint8_t *msg_data = frame.
msg.data();
447 HELPER_LOG(
"Bad data packet: size %d too short", msg_size);
455 uint16_t
type = (((uint16_t) msg_data[0]) << 8) | msg_data[1];
456 uint16_t data_len = (((uint16_t) msg_data[2]) << 8) | msg_data[3];
457 if (data_len > msg_size - 4) {
459 HELPER_LOG(
"Bad data packet: data_len %u greater than msg_size %u", data_len, msg_size);
483 size_t msg_len = 4 + payload_len + padding;
484 size_t frame_len = 3 + msg_len + noise_cipherstate_get_mac_length(
send_cipher_);
485 auto tmpbuf = std::unique_ptr<uint8_t[]>{
new (std::nothrow) uint8_t[frame_len]};
486 if (tmpbuf ==
nullptr) {
487 HELPER_LOG(
"Could not allocate for writing packet");
493 const uint8_t msg_offset = 3;
494 const uint8_t payload_offset = msg_offset + 4;
495 tmpbuf[msg_offset + 0] = (uint8_t) (type >> 8);
496 tmpbuf[msg_offset + 1] = (uint8_t) type;
497 tmpbuf[msg_offset + 2] = (uint8_t) (payload_len >> 8);
498 tmpbuf[msg_offset + 3] = (uint8_t) payload_len;
500 std::copy(payload, payload + payload_len, &tmpbuf[payload_offset]);
502 std::fill(&tmpbuf[payload_offset + payload_len], &tmpbuf[frame_len], 0);
505 noise_buffer_init(mbuf);
506 noise_buffer_set_inout(mbuf, &tmpbuf[msg_offset], msg_len, frame_len - msg_offset);
510 HELPER_LOG(
"noise_cipherstate_encrypt failed: %s",
noise_err_to_str(err).c_str());
514 size_t total_len = 3 + mbuf.size;
515 tmpbuf[1] = (uint8_t) (mbuf.size >> 8);
516 tmpbuf[2] = (uint8_t) mbuf.size;
520 iov.iov_len = total_len;
530 if (errno == EWOULDBLOCK || errno == EAGAIN)
533 HELPER_LOG(
"Socket write failed with errno %d", errno);
535 }
else if (sent == 0) {
555 size_t total_write_len = 0;
556 for (
int i = 0; i < iovcnt; i++) {
557 #ifdef HELPER_LOG_PACKETS 558 ESP_LOGVV(TAG,
"Sending raw: %s",
559 format_hex_pretty(reinterpret_cast<uint8_t *>(iov[i].iov_base), iov[i].iov_len).c_str());
561 total_write_len += iov[i].
iov_len;
573 for (
int i = 0; i < iovcnt; i++) {
575 reinterpret_cast<uint8_t *>(iov[i].iov_base) + iov[i].
iov_len);
580 ssize_t sent =
socket_->writev(iov, iovcnt);
583 for (
int i = 0; i < iovcnt; i++) {
585 reinterpret_cast<uint8_t *>(iov[i].iov_base) + iov[i].
iov_len);
588 }
else if (sent == -1) {
591 HELPER_LOG(
"Socket write failed with errno %d", errno);
593 }
else if ((
size_t) sent != total_write_len) {
595 size_t to_consume = sent;
596 for (
int i = 0; i < iovcnt; i++) {
597 if (to_consume >= iov[i].iov_len) {
601 reinterpret_cast<uint8_t *>(iov[i].iov_base) + iov[i].
iov_len);
613 header[1] = (uint8_t) (len >> 8);
614 header[2] = (uint8_t) len;
622 iov[1].
iov_base =
const_cast<uint8_t *
>(data);
637 nid_.pattern_id = NOISE_PATTERN_NN;
638 nid_.cipher_id = NOISE_CIPHER_CHACHAPOLY;
639 nid_.dh_id = NOISE_DH_CURVE25519;
640 nid_.prefix_id = NOISE_PREFIX_STANDARD;
641 nid_.hybrid_id = NOISE_DH_NONE;
642 nid_.hash_id = NOISE_HASH_SHA256;
643 nid_.modifier_ids[0] = NOISE_MODIFIER_PSK0;
645 err = noise_handshakestate_new_by_id(&
handshake_, &
nid_, NOISE_ROLE_RESPONDER);
648 HELPER_LOG(
"noise_handshakestate_new_by_id failed: %s",
noise_err_to_str(err).c_str());
652 const auto &psk =
ctx_->get_psk();
653 err = noise_handshakestate_set_pre_shared_key(
handshake_, psk.data(), psk.size());
656 HELPER_LOG(
"noise_handshakestate_set_pre_shared_key failed: %s",
noise_err_to_str(err).c_str());
663 HELPER_LOG(
"noise_handshakestate_set_prologue failed: %s",
noise_err_to_str(err).c_str());
672 HELPER_LOG(
"noise_handshakestate_start failed: %s",
noise_err_to_str(err).c_str());
681 int action = noise_handshakestate_get_action(
handshake_);
682 if (action == NOISE_ACTION_READ_MESSAGE || action == NOISE_ACTION_WRITE_MESSAGE)
684 if (action != NOISE_ACTION_SPLIT) {
686 HELPER_LOG(
"Bad action for handshake: %d", action);
692 HELPER_LOG(
"noise_handshakestate_split failed: %s",
noise_err_to_str(err).c_str());
696 HELPER_LOG(
"Handshake complete!");
726 int err =
socket_->shutdown(how);
729 if (how == SHUT_RDWR) {
738 ESP_LOGE(TAG,
"Failed to acquire random bytes, rebooting!");
743 #endif // USE_API_NOISE 745 #ifdef USE_API_PLAINTEXT 750 HELPER_LOG(
"Bad state for init %d", (
int)
state_);
753 int err =
socket_->setblocking(
false);
756 HELPER_LOG(
"Setting nonblocking failed with errno %d", errno);
760 err =
socket_->setsockopt(IPPROTO_TCP, TCP_NODELAY, &enable,
sizeof(
int));
763 HELPER_LOG(
"Setting nodelay failed with errno %d", errno);
795 if (frame ==
nullptr) {
796 HELPER_LOG(
"Bad argument for try_read_frame_");
801 while (!rx_header_parsed_) {
803 ssize_t received =
socket_->read(&data, 1);
804 if (received == -1) {
805 if (errno == EWOULDBLOCK || errno == EAGAIN) {
809 HELPER_LOG(
"Socket read failed with errno %d", errno);
811 }
else if (received == 0) {
813 HELPER_LOG(
"Connection closed");
826 uint32_t consumed = 0;
828 if (!msg_size_varint.has_value()) {
834 rx_header_parsed_len_ = msg_size_varint->as_uint32();
837 if (!msg_type_varint.has_value()) {
841 rx_header_parsed_type_ = msg_type_varint->as_uint32();
842 rx_header_parsed_ =
true;
847 if (
rx_buf_.size() != rx_header_parsed_len_) {
848 rx_buf_.resize(rx_header_parsed_len_);
853 size_t to_read = rx_header_parsed_len_ -
rx_buf_len_;
855 if (received == -1) {
856 if (errno == EWOULDBLOCK || errno == EAGAIN) {
860 HELPER_LOG(
"Socket read failed with errno %d", errno);
862 }
else if (received == 0) {
864 HELPER_LOG(
"Connection closed");
867 rx_buf_len_ += received;
868 if ((
size_t) received != to_read) {
875 #ifdef HELPER_LOG_PACKETS 883 rx_header_parsed_ =
false;
901 buffer->
data_len = rx_header_parsed_len_;
902 buffer->
type = rx_header_parsed_type_;
911 std::vector<uint8_t> header;
912 header.push_back(0x00);
918 iov[0].
iov_len = header.size();
919 if (payload_len == 0) {
922 iov[1].
iov_base =
const_cast<uint8_t *
>(payload);
933 }
else if (sent == -1) {
935 HELPER_LOG(
"Socket write failed with errno %d", errno);
955 size_t total_write_len = 0;
956 for (
int i = 0; i < iovcnt; i++) {
957 #ifdef HELPER_LOG_PACKETS 958 ESP_LOGVV(TAG,
"Sending raw: %s",
961 total_write_len += iov[i].
iov_len;
973 for (
int i = 0; i < iovcnt; i++) {
980 ssize_t sent =
socket_->writev(iov, iovcnt);
983 for (
int i = 0; i < iovcnt; i++) {
988 }
else if (sent == -1) {
991 HELPER_LOG(
"Socket write failed with errno %d", errno);
993 }
else if ((
size_t) sent != total_write_len) {
995 size_t to_consume = sent;
996 for (
int i = 0; i < iovcnt; i++) {
997 if (to_consume >= iov[i].
iov_len) {
1019 int err =
socket_->shutdown(how);
1022 if (how == SHUT_RDWR) {
1027 #endif // USE_API_PLAINTEXT
~APINoiseFrameHelper() override
APIError write_frame_(const uint8_t *data, size_t len)
std::shared_ptr< APINoiseContext > ctx_
std::string format_hex_pretty(const uint8_t *data, size_t length)
Format the byte array data of length len in pretty-printed, human-readable hex.
std::vector< uint8_t > msg
APIError close() override
Representation of a VarInt - in ProtoBuf should be 64bit but we only use 32bit.
const char * api_error_to_str(APIError err)
APIError write_packet(uint16_t type, const uint8_t *payload, size_t len) override
static optional< ProtoVarInt > parse(const uint8_t *buffer, uint32_t len, uint32_t *consumed)
NoiseCipherState * recv_cipher_
APIError init() override
Initialize the frame helper, returns OK if successful.
APIError write_raw_(const struct iovec *iov, int iovcnt)
Write the data to the socket, or buffer it a write would block.
std::vector< uint8_t > tx_buf_
bool random_bytes(uint8_t *data, size_t len)
Generate len number of random bytes.
std::unique_ptr< socket::Socket > socket_
APIError loop() override
Run through handshake messages (if in that phase)
APIError try_read_frame_(ParsedFrame *frame)
Read a packet into the rx_buf_.
NoiseHandshakeState * handshake_
bool is_would_block(ssize_t ret)
Is the given return value (from write syscalls) a wouldblock error?
std::vector< uint8_t > prologue_
void encode(std::vector< uint8_t > &out)
APIError loop() override
Not used for plaintext.
APIError try_read_frame_(ParsedFrame *frame)
Read a packet into the rx_buf_.
APIError shutdown(int how) override
std::string noise_err_to_str(int err)
Convert a noise error code to a readable error.
Application App
Global storage of Application pointer - only one Application can exist.
APIError shutdown(int how) override
uint8_t rx_header_buf_[3]
APIError read_packet(ReadPacketBuffer *buffer) override
const std::string & get_name() const
Get the name of this Application set by pre_setup().
void send_explicit_handshake_reject_(const std::string &reason)
APIError read_packet(ReadPacketBuffer *buffer) override
enum esphome::api::APINoiseFrameHelper::State state_
std::vector< uint8_t > msg
APIError init() override
Initialize the frame helper, returns OK if successful.
size_t rx_header_buf_len_
std::string to_string(int value)
APIError state_action_()
To be called from read/write methods.
APIError write_raw_(const struct iovec *iov, int iovcnt)
Write the data to the socket, or buffer it a write would block.
APIError init_handshake_()
Initiate the data structures for the handshake.
std::vector< uint8_t > rx_buf_
APIError write_packet(uint16_t type, const uint8_t *payload, size_t len) override
Implementation of SPI Controller mode.
APIError close() override
APIError try_send_tx_buf_()
void noise_rand_bytes(void *output, size_t len)
APIError try_send_tx_buf_()
std::vector< uint8_t > container
bool can_write_without_blocking() override
bool can_write_without_blocking() override
NoiseCipherState * send_cipher_
APIError check_handshake_finished_()