Merge branch 'cell-introduce1' into 'main'

Implement onion service Introduce1

See merge request tpo/core/arti!724
This commit is contained in:
Nick Mathewson 2022-09-20 13:02:02 +00:00
commit 7715b9c8d6
3 changed files with 130 additions and 6 deletions

View File

@ -72,6 +72,9 @@ pub enum RelayMsg {
/// Establish Rendezvous
#[cfg(feature = "onion-service")]
EstablishRendezvous(onion_service::EstablishRendezvous),
/// Introduce1
#[cfg(feature = "onion-service")]
Introduce1(onion_service::Introduce1),
/// An unrecognized command.
Unrecognized(Unrecognized),
@ -123,6 +126,8 @@ impl RelayMsg {
EstablishIntro(_) => RelayCmd::ESTABLISH_INTRO,
#[cfg(feature = "onion-service")]
EstablishRendezvous(_) => RelayCmd::ESTABLISH_RENDEZVOUS,
#[cfg(feature = "onion-service")]
Introduce1(_) => RelayCmd::INTRODUCE1,
Unrecognized(u) => u.cmd(),
}
}
@ -160,6 +165,10 @@ impl RelayMsg {
RelayCmd::ESTABLISH_RENDEZVOUS => RelayMsg::EstablishRendezvous(
onion_service::EstablishRendezvous::decode_from_reader(r)?,
),
#[cfg(feature = "onion-service")]
RelayCmd::INTRODUCE1 => {
RelayMsg::Introduce1(onion_service::Introduce1::decode_from_reader(r)?)
}
_ => RelayMsg::Unrecognized(Unrecognized::decode_with_cmd(c, r)?),
})
}
@ -192,6 +201,8 @@ impl RelayMsg {
EstablishIntro(b) => b.encode_onto(w),
#[cfg(feature = "onion-service")]
EstablishRendezvous(b) => b.encode_onto(w),
#[cfg(feature = "onion-service")]
Introduce1(b) => b.encode_onto(w),
Unrecognized(b) => b.encode_onto(w),
}
}

View File

@ -5,7 +5,7 @@
use super::msg;
use caret::caret_int;
use tor_bytes::{EncodeError, EncodeResult, Readable, Result, Writeable};
use tor_bytes::{EncodeError, EncodeResult, Error as BytesError, Readable, Result, Writeable};
use tor_bytes::{Reader, Writer};
use tor_units::BoundedInt32;
@ -251,3 +251,65 @@ impl msg::Body for EstablishRendezvous {
w.write(&self.cookie)
}
}
/// A message sent from client to introduction point.
#[derive(Debug, Clone)]
pub struct Introduce1 {
/// Introduction point auth key type and the type of
/// the MAC used in `handshake_auth`.
auth_key_type: AuthKeyType,
/// The public introduction point auth key.
auth_key: Vec<u8>,
/// Up to end of relay payload.
encrypted: Vec<u8>,
}
impl msg::Body for Introduce1 {
fn into_message(self) -> msg::RelayMsg {
msg::RelayMsg::Introduce1(self)
}
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
let legacy_key_id: [u8; 20] = r.extract()?;
if legacy_key_id.iter().any(|b| *b != 0_u8) {
return Err(BytesError::BadMessage("legacy key id in Introduce1."));
}
let auth_key_type = r.take_u8()?.into();
let auth_key_len = r.take_u16()?;
let auth_key = r.take(auth_key_len as usize)?.into();
let n_ext = r.take_u8()?;
for _ in 0..n_ext {
let _ext_type = r.take_u8()?;
r.read_nested_u8len(|r| {
r.take_rest();
Ok(())
})?;
}
let encrypted = r.take_rest().into();
Ok(Self {
auth_key_type,
auth_key,
encrypted,
})
}
fn encode_onto(self, w: &mut Vec<u8>) -> EncodeResult<()> {
w.write_all(&[0_u8; 20]);
w.write_u8(self.auth_key_type.get());
w.write_u16(u16::try_from(self.auth_key.len()).map_err(|_| EncodeError::BadLengthValue)?);
w.write_all(&self.auth_key[..]);
// No Introduce1 extension for now.
w.write_u8(0_u8);
w.write_all(&self.encrypted[..]);
Ok(())
}
}
impl Introduce1 {
/// All arguments constructor
pub fn new(auth_key_type: AuthKeyType, auth_key: Vec<u8>, encrypted: Vec<u8>) -> Self {
Self {
auth_key_type,
auth_key,
encrypted,
}
}
}

View File

@ -670,7 +670,7 @@ fn test_establish_intro() {
let sig = vec![0, 1, 2, 3];
assert_eq!(Into::<u8>::into(cmd), 32);
// Establish intro with one recognzied extention
// Establish intro with one recognzied extension
let mut es_intro = EstablishIntro::new(auth_key_type, auth_key, handshake_auth, sig);
es_intro.set_extension_dos(extension_dos);
msg(
@ -682,7 +682,7 @@ fn test_establish_intro() {
&es_intro.into(),
);
// Establish intro with no extention
// Establish intro with no extension
let auth_key = vec![0, 1, 2, 3];
let sig = vec![0, 1, 2, 3];
msg(
@ -694,11 +694,10 @@ fn test_establish_intro() {
&EstablishIntro::new(auth_key_type, auth_key, handshake_auth, sig).into(),
);
// Establish intro with one recognzied extention
// and one unknown extention
// Establish intro with one recognzied extension
// and one unknown extension
let auth_key = vec![0, 1, 2, 3];
let sig = vec![0, 1, 2, 3];
let extension_dos = EstIntroExtDoS::new(Some(1_i32), Some(2_i32))
.expect("invalid EST_INTRO_DOS_EXT parameter(s)");
@ -721,6 +720,58 @@ fn test_establish_intro() {
assert_eq!(actual_bytes, expect_bytes);
}
#[cfg(feature = "onion-service")]
#[test]
fn test_introduce1() {
use tor_cell::relaycell::{
msg::RelayMsg,
onion_service::{AuthKeyType, Introduce1},
};
let cmd = RelayCmd::INTRODUCE1;
let auth_key_type = AuthKeyType::ED25519_SHA3_256;
let auth_key = vec![0, 1, 2, 3];
let encrypted = vec![1, 9, 8, 4];
assert_eq!(Into::<u8>::into(cmd), 34);
// Introduce1 with no extension
let intro1 = Introduce1::new(auth_key_type, auth_key, encrypted);
msg(
cmd,
"0000000000000000000000000000000000000000
02 0004 00010203
00
01090804",
&intro1.clone().into(),
);
// Introduce1 with unknown extensions
let body = "0000000000000000000000000000000000000000
02 0004 00010203
02 01 01 00 02 01 00
01090804";
let actual_msg = decode(cmd, &unhex(body)[..]).unwrap();
let mut actual_bytes = vec![];
let mut expect_bytes = vec![];
actual_msg
.encode_onto(&mut actual_bytes)
.expect("Encode msg onto byte vector");
let expected_msg: RelayMsg = intro1.into();
expected_msg
.encode_onto(&mut expect_bytes)
.expect("Encode msg onto byte vector");
assert_eq!(actual_bytes, expect_bytes);
// Introduce1 with legacy key id
msg_error(
cmd,
"1000000000000000000000000000000000000000
02 0004 00010203
00
01090804",
BytesError::BadMessage("legacy key id in Introduce1."),
);
}
// TODO: need to add tests for:
// - unrecognized
// - data