diff --git a/Cargo.lock b/Cargo.lock index 65621bb61..9d2cc69d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3040,6 +3040,7 @@ dependencies = [ "android_logger", "arboard", "async-trait", + "base64", "cc", "cfg-if 1.0.0", "clap", diff --git a/Cargo.toml b/Cargo.toml index 57b31dd59..d5029532f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,7 @@ crc32fast = "1.3" uuid = { version = "0.8", features = ["v4"] } clap = "2.34" rpassword = "5.0" +base64 = "0.13" [target.'cfg(not(any(target_os = "android")))'.dependencies] cpal = { git = "https://github.com/open-trade/cpal" } diff --git a/libs/hbb_common/protos/message.proto b/libs/hbb_common/protos/message.proto index a8e8d34b5..24bc189b2 100644 --- a/libs/hbb_common/protos/message.proto +++ b/libs/hbb_common/protos/message.proto @@ -359,7 +359,6 @@ message PublicKey { message SignedId { bytes id = 1; - bytes pk = 2; } message AudioFormat { diff --git a/src/client.rs b/src/client.rs index 13571e585..c3096cb53 100644 --- a/src/client.rs +++ b/src/client.rs @@ -297,28 +297,51 @@ impl Client { } async fn secure_connection(peer_id: &str, pk: Vec, conn: &mut Stream) -> ResultType<()> { + let mut pk = pk; + const RS_PK: &[u8; 32] = &[ + 177, 155, 15, 73, 116, 147, 172, 11, 55, 38, 92, 168, 30, 116, 213, 196, 12, 134, 130, + 170, 181, 161, 192, 176, 132, 229, 139, 178, 17, 165, 150, 51, + ]; + if !pk.is_empty() { + let tmp = sign::PublicKey(*RS_PK); + if let Ok(data) = sign::verify(&pk, &tmp) { + pk = data; + } else { + log::error!("Handshake failed: invalid public key from rendezvous server"); + pk.clear(); + } + } if pk.len() != sign::PUBLICKEYBYTES { // send an empty message out in case server is setting up secure and waiting for first message conn.send(&Message::new()).await?; return Ok(()); } - let mut pk_ = [0u8; sign::PUBLICKEYBYTES]; - pk_[..].copy_from_slice(&pk); - let pk = sign::PublicKey(pk_); + let mut tmp = [0u8; sign::PUBLICKEYBYTES]; + tmp[..].copy_from_slice(&pk); + let sign_pk = sign::PublicKey(tmp); match timeout(CONNECT_TIMEOUT, conn.next()).await? { Some(res) => { let bytes = res?; if let Ok(msg_in) = Message::parse_from_bytes(&bytes) { if let Some(message::Union::signed_id(si)) = msg_in.union { - let their_pk_b = if si.pk.len() == box_::PUBLICKEYBYTES { - let mut pk_ = [0u8; box_::PUBLICKEYBYTES]; - pk_[..].copy_from_slice(&si.pk); - box_::PublicKey(pk_) - } else { - bail!("Handshake failed: invalid public box key length from peer"); - }; - if let Ok(id) = sign::verify(&si.id, &pk) { - if id == peer_id.as_bytes() { + if let Ok(data) = sign::verify(&si.id, &sign_pk) { + let s = String::from_utf8_lossy(&data); + let mut it = s.split("\0"); + let id = it.next().unwrap_or_default(); + let pk = + base64::decode(it.next().unwrap_or_default()).unwrap_or_default(); + let their_pk_b = if pk.len() == box_::PUBLICKEYBYTES { + let mut pk_ = [0u8; box_::PUBLICKEYBYTES]; + pk_[..].copy_from_slice(&pk); + box_::PublicKey(pk_) + } else { + log::error!( + "Handshake failed: invalid public box key length from peer" + ); + conn.send(&Message::new()).await?; + return Ok(()); + }; + if id == peer_id { let (our_pk_b, out_sk_b) = box_::gen_keypair(); let key = secretbox::gen_key(); let nonce = box_::Nonce([0u8; box_::NONCEBYTES]); @@ -332,7 +355,8 @@ impl Client { timeout(CONNECT_TIMEOUT, conn.send(&msg_out)).await??; conn.set_key(key); } else { - bail!("Handshake failed: sign failure"); + log::error!("Handshake failed: sign failure"); + conn.send(&Message::new()).await?; } } else { // fall back to non-secure connection in case pk mismatch @@ -342,10 +366,12 @@ impl Client { timeout(CONNECT_TIMEOUT, conn.send(&msg_out)).await??; } } else { - bail!("Handshake failed: invalid message type"); + log::error!("Handshake failed: invalid message type"); + conn.send(&Message::new()).await?; } } else { - bail!("Handshake failed: invalid message format"); + log::error!("Handshake failed: invalid message format"); + conn.send(&Message::new()).await?; } } None => { diff --git a/src/server.rs b/src/server.rs index 541d88f29..270b8075e 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,5 +1,5 @@ use crate::ipc::Data; -use connection::{ConnInner, Connection}; +pub use connection::*; use hbb_common::{ allow_err, anyhow::{anyhow, Context}, @@ -69,12 +69,12 @@ async fn accept_connection_(server: ServerPtr, socket: Stream, secure: bool) -> let listener = new_listener(local_addr, true).await?; log::info!("Server listening on: {}", &listener.local_addr()?); if let Ok((stream, addr)) = timeout(CONNECT_TIMEOUT, listener.accept()).await? { - create_tcp_connection_(server, Stream::from(stream), addr, secure).await?; + create_tcp_connection(server, Stream::from(stream), addr, secure).await?; } Ok(()) } -async fn create_tcp_connection_( +pub async fn create_tcp_connection( server: ServerPtr, stream: Stream, addr: SocketAddr, @@ -92,11 +92,13 @@ async fn create_tcp_connection_( sk_[..].copy_from_slice(&sk); let sk = sign::SecretKey(sk_); let mut msg_out = Message::new(); - let signed_id = sign::sign(Config::get_id().as_bytes(), &sk); let (our_pk_b, our_sk_b) = box_::gen_keypair(); + let signed_id = sign::sign( + format!("{}\0{}", Config::get_id(), base64::encode(our_pk_b.0)).as_bytes(), + &sk, + ); msg_out.set_signed_id(SignedId { id: signed_id, - pk: our_pk_b.0.into(), ..Default::default() }); timeout(CONNECT_TIMEOUT, stream.send(&msg_out)).await??; @@ -122,8 +124,8 @@ async fn create_tcp_connection_( key[..].copy_from_slice(&symmetric_key); stream.set_key(secretbox::Key(key)); } else if pk.asymmetric_value.is_empty() { - // force a trial to update_pk to rendezvous server Config::set_key_confirmed(false); + log::info!("Force to update pk"); } else { bail!("Handshake failed: invalid public sign key length from peer"); } @@ -193,7 +195,7 @@ async fn create_relay_connection_( ..Default::default() }); stream.send(&msg_out).await?; - create_tcp_connection_(server, stream, peer_addr, secure).await?; + create_tcp_connection(server, stream, peer_addr, secure).await?; Ok(()) }