diff --git a/Cargo.toml b/Cargo.toml index 3ba0156c..33eb31be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,39 +20,46 @@ exclude = [ "rustfmt.toml", ] +#[features] +#not-embedded = ["ed25519-dalek", "get_if_addrs", "hyper"] + [dependencies] -aead = "0.4" +aead = "0.5" async-trait = "0.1" byteorder = "1.3" bytes = "1.0" -chacha20poly1305 = "0.8" -ed25519-dalek = { version = "1.0", features = ["std", "serde"] } +chacha20poly1305 = "0.10.1" erased-serde = "0.3" macaddr = { version = "1.0.1", features = ["serde"] } futures = "0.3" -get_if_addrs = "0.5" hkdf = "0.11" -hyper = { version = "0.14", features = ["server", "http1"] } -libmdns = "0.6" log = "0.4" num = "0.2" -rand = "0.7" serde = { version = "1.0", features = ["rc", "derive"] } serde_json = "1.0" sha2 = "0.9" -signature = "1.1" +signature = "2.1.0" srp = "0.5" thiserror = "1.0" -tokio = "1.8" +tokio = { version = "1.28.1", features = ["rt"] } url = "2.1" -uuid = { version = "0.8", features = ["v4", "serde"] } -x25519-dalek = "0.6" +uuid = { version = "1.3", features = ["serde", "v4"] } +rand = "0.8.5" + +ed25519-dalek = { version = "2.0.0-rc.2", features = ["serde", "std"] } +x25519-dalek = "2.0.0-rc.2" + +hyper = { version = "0.14", features = ["server", "http1"] } +get_if_addrs = { version = "0.5", optional = true } +libmdns = { version = "0.6", optional = true } + +cfg-if = "0.1" [build-dependencies] handlebars = "2.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -uuid = { version = "0.8", features = ["v4", "serde"] } +uuid = { version = "1.3", features = ["v4", "serde"] } [dev-dependencies] env_logger = "0.8" diff --git a/src/config.rs b/src/config.rs index 4a7be014..499cb1ec 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,6 +1,6 @@ -use ed25519_dalek::Keypair as Ed25519Keypair; -//use eui48::MacAddress; +use crate::Ed25519Keypair; use macaddr::MacAddr6 as MacAddress; + use rand::{rngs::OsRng, Rng}; use serde::{Deserialize, Serialize}; use std::net::IpAddr; @@ -120,15 +120,18 @@ fn generate_random_mac_address() -> MacAddress { /// Generates an Ed25519 keypair. fn generate_ed25519_keypair() -> Ed25519Keypair { let mut csprng = OsRng {}; - Ed25519Keypair::generate(&mut csprng) + todo!() + //Ed25519Keypair::generate(&mut csprng) } /// Returns the IP of the system's first non-loopback network interface or defaults to `127.0.0.1`. fn get_local_ip() -> IpAddr { +#[cfg(get_if_addrs)] for iface in get_if_addrs::get_if_addrs().unwrap() { if !iface.is_loopback() { return iface.ip(); } } +#[cfg(not(get_if_addrs))] "127.0.0.1".parse().unwrap() } diff --git a/src/error.rs b/src/error.rs index 053313a1..de0c5e23 100644 --- a/src/error.rs +++ b/src/error.rs @@ -49,8 +49,10 @@ pub enum Error { Hyper(#[from] hyper::Error), #[error("Task Join Error: {0}")] TaskJoin(#[from] tokio::task::JoinError), - #[error("AEAD Error")] - Aead, + + #[error("Chacha Error")] + Chacha, + #[error("HKDF Invalid Length Error")] HkdfInvalidLength, #[error("UTF-8 Error: {0}")] @@ -63,6 +65,6 @@ pub enum Error { MpscSend(#[from] mpsc::SendError<()>), } -impl From for Error { - fn from(_: aead::Error) -> Self { Error::Aead } +impl From for Error { + fn from(_: chacha20poly1305::Error) -> Self { Error::Chacha } } diff --git a/src/hap_type.rs b/src/hap_type.rs index 97735621..4eea727b 100644 --- a/src/hap_type.rs +++ b/src/hap_type.rs @@ -322,7 +322,7 @@ impl ToString for HapType { fn to_string(&self) -> String { match self { HapType::Unknown => "unknown".into(), - HapType::Custom(uuid) => uuid.to_hyphenated().to_string(), + HapType::Custom(uuid) => uuid.hyphenated().to_string(), HapType::AccessCodeControlPoint => "262".into(), HapType::AccessCodeSupportedConfiguration => "261".into(), HapType::AccessControlLevel => "E5".into(), diff --git a/src/lib.rs b/src/lib.rs index c1233860..bf13c10a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -pub use ed25519_dalek::Keypair as Ed25519Keypair; +pub use ed25519_dalek::SigningKey as Ed25519Keypair; pub use futures; pub use macaddr::MacAddr6 as MacAddress; pub use serde_json; diff --git a/src/tlv.rs b/src/tlv.rs index e02ce900..f45972d6 100644 --- a/src/tlv.rs +++ b/src/tlv.rs @@ -240,8 +240,8 @@ impl From for Error { } } -impl From for Error { - fn from(err: aead::Error) -> Self { +impl From for Error { + fn from(err: chacha20poly1305::Error) -> Self { error!("{:?}", err); Error::Authentication } diff --git a/src/transport/http/handler/pair_setup.rs b/src/transport/http/handler/pair_setup.rs index 69545285..9434c941 100644 --- a/src/transport/http/handler/pair_setup.rs +++ b/src/transport/http/handler/pair_setup.rs @@ -1,12 +1,18 @@ -use aead::{generic_array::GenericArray, AeadInPlace, NewAead}; -use chacha20poly1305::ChaCha20Poly1305; +use aead::{generic_array::GenericArray}; +use chacha20poly1305::{ + ChaCha20Poly1305, + KeyInit, + AeadInPlace, +}; use futures::future::{BoxFuture, FutureExt}; -use hyper::{body::Buf, Body}; use log::{debug, info}; use num::BigUint; + +use hyper::{body::Buf, Body}; use rand::{rngs::OsRng, RngCore}; + use sha2::{digest::Digest, Sha512}; -use signature::{Signer, Verifier}; +use ed25519_dalek::{Signer, Verifier}; use srp::{ client::{srp_private_key, SrpClient}, groups::G_3072, @@ -276,12 +282,25 @@ async fn handle_exchange( let sub_tlv = tlv::decode(&decrypted_data); let device_pairing_id = sub_tlv.get(&(Type::Identifier as u8)).ok_or(tlv::Error::Unknown)?; - let device_ltpk = ed25519_dalek::PublicKey::from_bytes( - sub_tlv.get(&(Type::PublicKey as u8)).ok_or(tlv::Error::Unknown)?, + + let device_ltpk = ed25519_dalek::VerifyingKey::from_bytes( + &TryInto::<[u8; 32]>::try_into( + sub_tlv.get(&(Type::PublicKey as u8)).ok_or(tlv::Error::Unknown)?.clone(), + ).map_err(|_| tlv::Error::Unknown)? )?; + /* + let device_ltpk = x25519_dalek::PublicKey::from( + TryInto::<[u8; 32]>::try_into( + sub_tlv.get(&(Type::PublicKey as u8)).ok_or(tlv::Error::Unknown)?.clone(), + ).map_err(|_| tlv::Error::Unknown)? + ); + */ + let device_signature = ed25519_dalek::Signature::from_bytes( - sub_tlv.get(&(Type::Signature as u8)).ok_or(tlv::Error::Unknown)?, - )?; + &TryInto::<[u8; 64]>::try_into( + sub_tlv.get(&(Type::Signature as u8)).ok_or(tlv::Error::Unknown)?.clone() + ).map_err(|_| tlv::Error::Unknown)? + ); let device_x = hkdf_extract_and_expand( b"Pair-Setup-Controller-Sign-Salt", @@ -326,12 +345,12 @@ async fn handle_exchange( let mut accessory_info: Vec = Vec::new(); accessory_info.extend(&accessory_x); accessory_info.extend(device_id.as_bytes()); - accessory_info.extend(config.device_ed25519_keypair.public.as_bytes()); + accessory_info.extend(config.device_ed25519_keypair.verifying_key().as_bytes()); let accessory_signature = config.device_ed25519_keypair.sign(&accessory_info); let encoded_sub_tlv = vec![ Value::Identifier(device_id), - Value::PublicKey(config.device_ed25519_keypair.public.as_bytes().to_vec()), + Value::PublicKey(config.device_ed25519_keypair.verifying_key().as_bytes().to_vec()), Value::Signature(accessory_signature.to_bytes().to_vec()), ] .encode(); diff --git a/src/transport/http/handler/pair_verify.rs b/src/transport/http/handler/pair_verify.rs index 752d60ca..e2d73143 100644 --- a/src/transport/http/handler/pair_verify.rs +++ b/src/transport/http/handler/pair_verify.rs @@ -1,5 +1,5 @@ -use aead::{generic_array::GenericArray, AeadInPlace, NewAead}; -use chacha20poly1305::ChaCha20Poly1305; +use aead::generic_array::GenericArray; +use chacha20poly1305::{ChaCha20Poly1305, KeyInit, AeadInPlace}; use futures::{ channel::oneshot, future::{BoxFuture, FutureExt}, @@ -11,6 +11,7 @@ use signature::{Signer, Verifier}; use std::str; use uuid::Uuid; use x25519_dalek::{EphemeralSecret, PublicKey}; +use ed25519_dalek::VerifyingKey; use crate::{ pointer, @@ -217,8 +218,10 @@ async fn handle_finish( let device_pairing_id = sub_tlv.get(&(Type::Identifier as u8)).ok_or(tlv::Error::Unknown)?; debug!("raw device pairing ID: {:?}", &device_pairing_id); let device_signature = ed25519_dalek::Signature::from_bytes( - sub_tlv.get(&(Type::Signature as u8)).ok_or(tlv::Error::Unknown)?, - )?; + &TryInto::<[u8; 64]>::try_into( + sub_tlv.get(&(Type::Signature as u8)).ok_or(tlv::Error::Unknown)?.clone() + ).map_err(|_| tlv::Error::Unknown)? + ); debug!("device signature: {:?}", &device_signature); let uuid_str = str::from_utf8(device_pairing_id)?; @@ -232,7 +235,7 @@ async fn handle_finish( device_info.extend(device_pairing_id); device_info.extend(session.b_pub.as_bytes()); - if ed25519_dalek::PublicKey::from_bytes(&pairing.public_key)? + if VerifyingKey::from_bytes(&pairing.public_key)? .verify(&device_info, &device_signature) .is_err() { diff --git a/src/transport/http/handler/pairings.rs b/src/transport/http/handler/pairings.rs index 67403e8e..9a1b6a7e 100644 --- a/src/transport/http/handler/pairings.rs +++ b/src/transport/http/handler/pairings.rs @@ -157,8 +157,8 @@ async fn handle_add( let mut s = storage.lock().await; match s.load_pairing(&pairing_uuid).await { Ok(mut pairing) => { - if ed25519_dalek::PublicKey::from_bytes(&pairing.public_key)? - != ed25519_dalek::PublicKey::from_bytes(<pk)? + if x25519_dalek::PublicKey::from(pairing.public_key) + != x25519_dalek::PublicKey::from(TryInto::<[u8; 32]>::try_into(ltpk).map_err(|_| tlv::Error::Unknown)?) { return Err(tlv::Error::Unknown); } @@ -240,7 +240,7 @@ async fn handle_list( let pairings = storage.lock().await.list_pairings().await?; let mut list = vec![Value::State(StepNumber::Res as u8)]; for (i, pairing) in pairings.iter().enumerate() { - list.push(Value::Identifier(pairing.id.to_hyphenated().to_string())); + list.push(Value::Identifier(pairing.id.hyphenated().to_string())); list.push(Value::PublicKey(pairing.public_key.to_vec())); list.push(Value::Permissions(pairing.permissions.clone())); if i < pairings.len() { diff --git a/src/transport/http/server.rs b/src/transport/http/server.rs index b9554568..fc1802a6 100644 --- a/src/transport/http/server.rs +++ b/src/transport/http/server.rs @@ -11,7 +11,7 @@ use std::{ sync::Arc, task::{Context, Poll}, }; -use tokio::net::TcpListener; +use std::net::TcpListener; use crate::{ event::Event, @@ -186,12 +186,12 @@ impl Server { drop(config_lock); info!("binding TCP listener on {}", &socket_addr); - let listener = TcpListener::bind(socket_addr).await?; + let listener = TcpListener::bind(socket_addr)?; mdns_responder.lock().await.update_records().await; loop { - let (stream, _socket_addr) = listener.accept().await?; + let (stream, _socket_addr) = listener.accept()?; debug!("incoming TCP stream from {}", stream.peer_addr()?); @@ -255,7 +255,7 @@ impl Server { http.http1_keep_alive(true); http.http1_preserve_header_case(true); - tokio::spawn(encrypted_stream.map_err(|e| error!("{:?}", e)).map(|_| ())); + //tokio::spawn(encrypted_stream.map_err(|e| error!("{:?}", e)).map(|_| ())); tokio::spawn( http.serve_connection(stream_wrapper, api) .map_err(|e| error!("{:?}", e)) diff --git a/src/transport/mdns.rs b/src/transport/mdns.rs index 2d4afa8f..2cda14dc 100644 --- a/src/transport/mdns.rs +++ b/src/transport/mdns.rs @@ -1,4 +1,13 @@ -use libmdns::{Responder, Service}; + +cfg_if::cfg_if! { + if #[cfg(libmdns)] { + use libmdns::{Responder, Service}; + } else { + type Responder = (); + type Service= (); + } +} + use log::debug; use crate::pointer; @@ -14,7 +23,14 @@ pub struct MdnsResponder { impl MdnsResponder { /// Creates a new mDNS Responder. pub async fn new(config: pointer::Config) -> Self { - let (responder, task) = libmdns::Responder::with_default_handle().expect("creating mDNS responder"); + cfg_if::cfg_if! { + if #[cfg(libmdns)] { + let (responder, task) = libmdns::Responder::with_default_handle().expect("creating mDNS responder"); + } else { + let (responder, task) = todo!(); + } + } + MdnsResponder { config, @@ -38,9 +54,12 @@ impl MdnsResponder { drop(c); + todo!(); + /* self.service = Some(self.responder.register("_hap._tcp".into(), name, port, &[ &tr[0], &tr[1], &tr[2], &tr[3], &tr[4], &tr[5], &tr[6], &tr[7], ])); + */ debug!("setting mDNS records: {:?}", &tr); } @@ -51,7 +70,14 @@ impl MdnsResponder { Some(task) => task, // if the task handle is gone, recreate the whole responder None => { - let (responder, task) = libmdns::Responder::with_default_handle().expect("creating mDNS responder"); + cfg_if::cfg_if! { + if #[cfg(libmdns)] { + let (responder, task) = libmdns::Responder::with_default_handle().expect("creating mDNS responder"); + + } else { + let (responder, task) = todo!(); + } + } self.responder = responder; task diff --git a/src/transport/tcp.rs b/src/transport/tcp.rs index 32bf4e18..c3c06cd8 100644 --- a/src/transport/tcp.rs +++ b/src/transport/tcp.rs @@ -1,7 +1,7 @@ -use aead::{generic_array::GenericArray, AeadInPlace, NewAead}; +use aead::generic_array::GenericArray; use byteorder::{ByteOrder, LittleEndian}; use bytes::{Buf, BytesMut}; -use chacha20poly1305::{ChaCha20Poly1305, Nonce, Tag}; +use chacha20poly1305::{ChaCha20Poly1305, Nonce, Tag, KeyInit, AeadInPlace}; use futures::{ channel::{ mpsc::{self, UnboundedReceiver, UnboundedSender}, @@ -19,10 +19,8 @@ use std::{ sync::{Arc, Mutex, RwLock}, task::{Context, Poll, Waker}, }; -use tokio::{ - io::{AsyncRead, AsyncWrite, ReadBuf}, - net::TcpStream, -}; +use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; +use std::net::TcpStream; use uuid::Uuid; use crate::Result; @@ -278,6 +276,7 @@ impl EncryptedStream { Poll::Pending } + /* fn read_stream(&mut self, cx: &mut Context, buf: &mut ReadBuf) -> Poll> { debug!("reading from TCP stream"); @@ -329,7 +328,9 @@ impl EncryptedStream { } } } + */ + /* fn poll_outgoing(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { let encrypted_stream = Pin::into_inner(self); loop { @@ -360,7 +361,9 @@ impl EncryptedStream { } } } + */ + /* fn poll_incoming(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { let encrypted_stream = Pin::into_inner(self); @@ -400,8 +403,10 @@ impl EncryptedStream { } } } + */ } +/* impl Future for EncryptedStream { type Output = std::result::Result<(), io::Error>; @@ -412,7 +417,8 @@ impl Future for EncryptedStream { EncryptedStream::poll_incoming(Pin::new(encrypted_stream), cx) } } - +*/ +/* impl AsyncRead for EncryptedStream { fn poll_read( self: Pin<&mut Self>, @@ -445,7 +451,9 @@ impl AsyncRead for EncryptedStream { } } } +*/ +/* impl AsyncWrite for EncryptedStream { #[allow(unused_must_use)] fn poll_write(self: Pin<&mut Self>, cx: &mut Context, buf: &[u8]) -> Poll> { @@ -486,6 +494,7 @@ impl AsyncWrite for EncryptedStream { Poll::Ready(Ok(())) } } +*/ fn decrypt_chunk( shared_secret: &[u8; 32],