cleanup, show tlv errors
This commit is contained in:
parent
3b9bc6c959
commit
7a49efe6f6
|
@ -159,12 +159,6 @@ impl AccessorySocket {
|
||||||
}
|
}
|
||||||
send_data.extend_from_slice("\r\n".as_bytes());
|
send_data.extend_from_slice("\r\n".as_bytes());
|
||||||
send_data.extend_from_slice(&body);
|
send_data.extend_from_slice(&body);
|
||||||
let mut visible = String::new();
|
|
||||||
for b in &send_data {
|
|
||||||
let part: Vec<u8> = std::ascii::escape_default(*b).collect();
|
|
||||||
visible.push_str(std::str::from_utf8(&part).unwrap());
|
|
||||||
}
|
|
||||||
log::info!("data as string: {visible}");
|
|
||||||
|
|
||||||
if let Some(encryption) = self.socket_encryption.as_mut() {
|
if let Some(encryption) = self.socket_encryption.as_mut() {
|
||||||
let mut packets = Vec::new();
|
let mut packets = Vec::new();
|
||||||
|
@ -201,9 +195,6 @@ impl AccessorySocket {
|
||||||
log::info!("encrypted {i} chunks!");
|
log::info!("encrypted {i} chunks!");
|
||||||
}
|
}
|
||||||
|
|
||||||
log::info!("data: {send_data:X?}");
|
|
||||||
log::info!("data len: {}", send_data.len());
|
|
||||||
|
|
||||||
self.socket.write_all(&send_data)?;
|
self.socket.write_all(&send_data)?;
|
||||||
|
|
||||||
let mut buf = [0; 1024];
|
let mut buf = [0; 1024];
|
||||||
|
|
|
@ -4,14 +4,14 @@ use hkdf::Hkdf;
|
||||||
use sha2::Sha512;
|
use sha2::Sha512;
|
||||||
use std::{collections::HashMap, path::PathBuf};
|
use std::{collections::HashMap, path::PathBuf};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tlv8::{TlvEncode, TlvType};
|
use tlv8::{HomekitState, TlvEncode, TlvType};
|
||||||
use x25519_dalek::{EphemeralSecret, PublicKey};
|
use x25519_dalek::{EphemeralSecret, PublicKey};
|
||||||
|
|
||||||
use pairing_data::DevicePairingData;
|
use pairing_data::DevicePairingData;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
homekit_http::AccessorySocket,
|
homekit_http::AccessorySocket,
|
||||||
tlv8::{decode, FormatTlv, TlvEncodableData},
|
tlv8::{decode, TlvEncodableData},
|
||||||
};
|
};
|
||||||
|
|
||||||
mod pairing_data;
|
mod pairing_data;
|
||||||
|
@ -198,8 +198,6 @@ impl DevicePairingData {
|
||||||
return Err(HomekitError::StateMismatch);
|
return Err(HomekitError::StateMismatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
log::info!("step3 response: {}", step3_response.as_tlv_string());
|
|
||||||
|
|
||||||
// 5.7.4 M4: Accessory -> iOS Device – ‘Verify Finish Responseʼ
|
// 5.7.4 M4: Accessory -> iOS Device – ‘Verify Finish Responseʼ
|
||||||
// When the accessory receives <M3>, it must perform the following steps:
|
// When the accessory receives <M3>, it must perform the following steps:
|
||||||
//
|
//
|
||||||
|
@ -233,14 +231,12 @@ impl DevicePairingData {
|
||||||
b"Control-Write-Encryption-Key",
|
b"Control-Write-Encryption-Key",
|
||||||
&mut controller_to_accessory_key,
|
&mut controller_to_accessory_key,
|
||||||
)?;
|
)?;
|
||||||
log::info!("c2a key: {controller_to_accessory_key:?}");
|
|
||||||
|
|
||||||
let mut accessory_to_controller_key = [0; 32];
|
let mut accessory_to_controller_key = [0; 32];
|
||||||
Hkdf::<Sha512>::new(Some(b"Control-Salt"), shared_secret.as_bytes()).expand(
|
Hkdf::<Sha512>::new(Some(b"Control-Salt"), shared_secret.as_bytes()).expand(
|
||||||
b"Control-Read-Encryption-Key",
|
b"Control-Read-Encryption-Key",
|
||||||
&mut accessory_to_controller_key,
|
&mut accessory_to_controller_key,
|
||||||
)?;
|
)?;
|
||||||
log::info!("a2c key: {accessory_to_controller_key:?}");
|
|
||||||
|
|
||||||
socket.set_encryption(controller_to_accessory_key, accessory_to_controller_key);
|
socket.set_encryption(controller_to_accessory_key, accessory_to_controller_key);
|
||||||
|
|
||||||
|
@ -265,15 +261,6 @@ impl DevicePairingData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum HomekitState {
|
|
||||||
M1 = 1,
|
|
||||||
M2 = 2,
|
|
||||||
M3 = 3,
|
|
||||||
M4 = 4,
|
|
||||||
M5 = 5,
|
|
||||||
M6 = 6,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum HomekitError {
|
pub enum HomekitError {
|
||||||
#[error("io")]
|
#[error("io")]
|
||||||
|
@ -283,7 +270,7 @@ pub enum HomekitError {
|
||||||
#[error("no device pairing data stored")]
|
#[error("no device pairing data stored")]
|
||||||
NoPairingData,
|
NoPairingData,
|
||||||
#[error("tlv error")]
|
#[error("tlv error")]
|
||||||
Tlv(#[from] tlv8::TlvError),
|
Tlv(#[from] tlv8::TlvCodecError),
|
||||||
#[error("mismatch with state response")]
|
#[error("mismatch with state response")]
|
||||||
StateMismatch,
|
StateMismatch,
|
||||||
#[error("Tlv not found")]
|
#[error("Tlv not found")]
|
||||||
|
|
|
@ -70,3 +70,79 @@ impl TryFrom<u8> for TlvType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum TlvError {
|
||||||
|
Reserved,
|
||||||
|
Unknown,
|
||||||
|
Authentication,
|
||||||
|
Backoff,
|
||||||
|
MaxPeers,
|
||||||
|
MaxTries,
|
||||||
|
Unavailable,
|
||||||
|
Busy,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<TlvError> for u8 {
|
||||||
|
fn from(value: TlvError) -> Self {
|
||||||
|
match value {
|
||||||
|
TlvError::Reserved => 0x00,
|
||||||
|
TlvError::Unknown => 0x01,
|
||||||
|
TlvError::Authentication => 0x02,
|
||||||
|
TlvError::Backoff => 0x03,
|
||||||
|
TlvError::MaxPeers => 0x04,
|
||||||
|
TlvError::MaxTries => 0x05,
|
||||||
|
TlvError::Unavailable => 0x06,
|
||||||
|
TlvError::Busy => 0x07,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct TlvErrorDecodeError(pub u8);
|
||||||
|
|
||||||
|
impl TryFrom<u8> for TlvError {
|
||||||
|
type Error = TlvErrorDecodeError;
|
||||||
|
|
||||||
|
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
0x00 => Ok(TlvError::Reserved),
|
||||||
|
0x01 => Ok(TlvError::Unknown),
|
||||||
|
0x02 => Ok(TlvError::Authentication),
|
||||||
|
0x03 => Ok(TlvError::Backoff),
|
||||||
|
0x04 => Ok(TlvError::MaxPeers),
|
||||||
|
0x05 => Ok(TlvError::MaxTries),
|
||||||
|
0x06 => Ok(TlvError::Unavailable),
|
||||||
|
0x07 => Ok(TlvError::Busy),
|
||||||
|
_ => Err(TlvErrorDecodeError(value)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum HomekitState {
|
||||||
|
M1 = 1,
|
||||||
|
M2 = 2,
|
||||||
|
M3 = 3,
|
||||||
|
M4 = 4,
|
||||||
|
M5 = 5,
|
||||||
|
M6 = 6,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct HomekitStateDecodeError(pub u8);
|
||||||
|
|
||||||
|
impl TryFrom<u8> for HomekitState {
|
||||||
|
type Error = HomekitStateDecodeError;
|
||||||
|
|
||||||
|
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
1 => Ok(Self::M1),
|
||||||
|
2 => Ok(Self::M2),
|
||||||
|
3 => Ok(Self::M3),
|
||||||
|
4 => Ok(Self::M4),
|
||||||
|
5 => Ok(Self::M5),
|
||||||
|
6 => Ok(Self::M6),
|
||||||
|
_ => Err(HomekitStateDecodeError(value)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
mod data_types;
|
use self::data_types::TlvError;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub use data_types::TlvType;
|
|
||||||
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
pub use data_types::{HomekitState, TlvType};
|
||||||
|
|
||||||
|
mod data_types;
|
||||||
|
|
||||||
pub trait FormatTlv {
|
pub trait FormatTlv {
|
||||||
fn as_tlv_string(&self) -> String;
|
fn as_tlv_string(&self) -> String;
|
||||||
}
|
}
|
||||||
|
@ -20,11 +20,38 @@ impl FormatTlv for (u8, Vec<u8>) {
|
||||||
impl FormatTlv for (&u8, &Vec<u8>) {
|
impl FormatTlv for (&u8, &Vec<u8>) {
|
||||||
fn as_tlv_string(&self) -> String {
|
fn as_tlv_string(&self) -> String {
|
||||||
let (tlv_type, data) = self;
|
let (tlv_type, data) = self;
|
||||||
let tlv_type = TlvType::try_from(**tlv_type).map_or_else(
|
let tlv_type =
|
||||||
|e| format!("Unknown TLV type: {}", e.0),
|
TlvType::try_from(**tlv_type).map_err(|e| format!("Unknown TLV type: {}", e.0));
|
||||||
|
match tlv_type {
|
||||||
|
Ok(tlv_type) => match tlv_type {
|
||||||
|
TlvType::Error => data
|
||||||
|
.first()
|
||||||
|
.map(|v| {
|
||||||
|
format!(
|
||||||
|
"Error: {}",
|
||||||
|
TlvError::try_from(*v).map_or_else(
|
||||||
|
|e| format!("Unknown error {:02X}", e.0),
|
||||||
|v| format!("{v:?}"),
|
|v| format!("{v:?}"),
|
||||||
);
|
)
|
||||||
format!("{tlv_type}: {data:?} (length: {})", data.len())
|
)
|
||||||
|
})
|
||||||
|
.unwrap_or(String::from("TLV error type with no data!")),
|
||||||
|
TlvType::State => data
|
||||||
|
.first()
|
||||||
|
.map(|v| {
|
||||||
|
format!(
|
||||||
|
"State: {}",
|
||||||
|
HomekitState::try_from(*v).map_or_else(
|
||||||
|
|e| format!("Unknown state {:02X}", e.0),
|
||||||
|
|v| format!("{v:?}"),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.unwrap_or(String::from("TLV error type with no data!")),
|
||||||
|
_ => format!("{tlv_type:?}: {data:?} (length: {})", data.len()),
|
||||||
|
},
|
||||||
|
Err(tlv_type) => format!("{tlv_type}: {data:?} (length: {})", data.len()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +62,14 @@ impl FormatTlv for HashMap<u8, Vec<u8>> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decode(data: &[u8]) -> Result<HashMap<u8, Vec<u8>>, TlvError> {
|
impl FormatTlv for Vec<(u8, Vec<u8>)> {
|
||||||
|
fn as_tlv_string(&self) -> String {
|
||||||
|
self.iter()
|
||||||
|
.fold(String::new(), |a, v| format!("{a}\n{}", v.as_tlv_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decode(data: &[u8]) -> Result<HashMap<u8, Vec<u8>>, TlvCodecError> {
|
||||||
let mut tlvs = HashMap::new();
|
let mut tlvs = HashMap::new();
|
||||||
let mut data = data;
|
let mut data = data;
|
||||||
|
|
||||||
|
@ -43,17 +77,17 @@ pub fn decode(data: &[u8]) -> Result<HashMap<u8, Vec<u8>>, TlvError> {
|
||||||
let tlv_len = (data[1] as usize) + 2;
|
let tlv_len = (data[1] as usize) + 2;
|
||||||
let current;
|
let current;
|
||||||
if tlv_len > data.len() {
|
if tlv_len > data.len() {
|
||||||
return Err(TlvError::WrongLength);
|
return Err(TlvCodecError::WrongLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
(current, data) = data.split_at(tlv_len);
|
(current, data) = data.split_at(tlv_len);
|
||||||
|
|
||||||
if current.len() < 2 {
|
if current.len() < 2 {
|
||||||
return Err(TlvError::TooShort);
|
return Err(TlvCodecError::TooShort);
|
||||||
}
|
}
|
||||||
|
|
||||||
if current.len() < tlv_len {
|
if current.len() < tlv_len {
|
||||||
return Err(TlvError::WrongLength);
|
return Err(TlvCodecError::WrongLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
let tlv_type = current[0];
|
let tlv_type = current[0];
|
||||||
|
@ -64,11 +98,12 @@ pub fn decode(data: &[u8]) -> Result<HashMap<u8, Vec<u8>>, TlvError> {
|
||||||
};
|
};
|
||||||
tlvs.insert(tlv_type, tlv_data);
|
tlvs.insert(tlv_type, tlv_data);
|
||||||
}
|
}
|
||||||
|
log::info!("{}", tlvs.as_tlv_string());
|
||||||
Ok(tlvs)
|
Ok(tlvs)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum TlvError {
|
pub enum TlvCodecError {
|
||||||
#[error("too short")]
|
#[error("too short")]
|
||||||
TooShort,
|
TooShort,
|
||||||
#[error("wrong length")]
|
#[error("wrong length")]
|
||||||
|
|
Loading…
Reference in a new issue