tor_cell/relaycell/
hs.rs

1//! Encoding and decoding for relay messages related to onion services.
2
3use super::msg::{self, Body};
4use crate::relaycell::extlist::{decl_extension_group, ExtList};
5use caret::caret_int;
6use derive_deftly::Deftly;
7use tor_bytes::{EncodeError, EncodeResult, Error as BytesError, Result};
8use tor_bytes::{Reader, Writer};
9use tor_hscrypto::RendCookie;
10use tor_llcrypto::pk::rsa::RsaIdentity;
11use tor_memquota::derive_deftly_template_HasMemoryCost;
12
13pub mod est_intro;
14pub mod intro_payload;
15pub mod pow;
16
17pub use crate::relaycell::extlist::UnrecognizedExt;
18
19caret_int! {
20    /// The type of the introduction point auth key
21    #[derive(Deftly)]
22    #[derive_deftly(HasMemoryCost)]
23    pub struct AuthKeyType(u8) {
24        /// Ed25519; SHA3-256
25        ED25519_SHA3_256 = 2,
26    }
27}
28
29/// A message sent from client to rendezvous point.
30#[derive(Debug, Clone, Deftly)]
31#[derive_deftly(HasMemoryCost)]
32pub struct EstablishRendezvous {
33    /// A rendezvous cookie is an arbitrary 20-byte value,
34    /// chosen randomly by the client.
35    cookie: RendCookie,
36}
37impl EstablishRendezvous {
38    /// Construct a new establish rendezvous cell.
39    pub fn new(cookie: RendCookie) -> Self {
40        Self { cookie }
41    }
42}
43impl msg::Body for EstablishRendezvous {
44    fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
45        let cookie = r.extract()?;
46        r.take_rest();
47        Ok(Self { cookie })
48    }
49    fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
50        w.write(&self.cookie)
51    }
52}
53
54#[derive(Debug, Clone, Deftly)]
55#[derive_deftly(HasMemoryCost)]
56/// A message sent from client to introduction point.
57pub struct Introduce1(Introduce);
58
59impl msg::Body for Introduce1 {
60    fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
61        let (intro, _) = Introduce::decode_from_reader(r)?;
62        Ok(Self(intro))
63    }
64    fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
65        self.0.encode_onto(w)
66    }
67}
68
69impl Introduce1 {
70    /// All arguments constructor
71    pub fn new(auth_key_type: AuthKeyType, auth_key: Vec<u8>, encrypted: Vec<u8>) -> Self {
72        Self(Introduce::new(auth_key_type, auth_key, encrypted))
73    }
74}
75
76#[derive(Debug, Clone, Deftly)]
77#[derive_deftly(HasMemoryCost)]
78/// A message sent from introduction point to hidden service host.
79pub struct Introduce2 {
80    /// A copy of the encoded header that we'll use to finish the hs_ntor handshake.
81    encoded_header: Vec<u8>,
82    /// The decoded message itself.
83    msg: Introduce,
84}
85
86impl msg::Body for Introduce2 {
87    fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
88        let (msg, header) = Introduce::decode_from_reader(r)?;
89        let encoded_header = header.to_vec();
90
91        Ok(Self {
92            encoded_header,
93            msg,
94        })
95    }
96    fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
97        self.msg.encode_onto(w)
98    }
99}
100
101impl Introduce2 {
102    /// All arguments constructor.
103    ///
104    /// This is only useful for testing, since in reality the only time this
105    /// message type is created is when an introduction point is forwarding an
106    /// INTRODUCE1 message.
107    #[cfg(test)] // Don't expose this generally without dealing somehow with the `expect` below
108    pub fn new(auth_key_type: AuthKeyType, auth_key: Vec<u8>, encrypted: Vec<u8>) -> Self {
109        use tor_bytes::Writeable as _;
110        let msg = Introduce::new(auth_key_type, auth_key, encrypted);
111        let mut encoded_header = Vec::new();
112        msg.header
113            .write_onto(&mut encoded_header)
114            .expect("Generated a header that we could not encode");
115        Self {
116            encoded_header,
117            msg,
118        }
119    }
120
121    /// Return the bytes used to transmit `header`.
122    ///
123    /// (This data is used as part of the handshake.)
124    pub fn encoded_header(&self) -> &[u8] {
125        &self.encoded_header[..]
126    }
127    /// Return the parsed header of this message.
128    pub fn header(&self) -> &IntroduceHeader {
129        &self.msg.header
130    }
131    /// Return the encrypted body of this message.
132    ///
133    /// (This body is decrypted as part of the handshake.)
134    pub fn encrypted_body(&self) -> &[u8] {
135        &self.msg.encrypted[..]
136    }
137}
138
139caret_int! {
140    /// The recognized unencrypted extension types for an `Introduce1` or `Introduce2` message.
141    #[derive(Ord,PartialOrd)]
142    pub struct IntroduceExtType(u8) {
143    }
144}
145
146decl_extension_group! {
147    /// An unencrypted extension to an `Introduce` or `Introduce2` message.
148    ///
149    /// (Currently, no extensions of this type are recognized)
150    #[derive(Debug,Clone,Deftly)]
151    #[derive_deftly(HasMemoryCost)]
152    enum IntroduceExt [ IntroduceExtType ] {
153    }
154}
155
156/// The unencrypted header portion of an `Introduce1` or `Introduce2` message.
157///
158/// This is a separate type because the `hs_ntor` handshake requires access to the
159/// encoded format of the header, only.
160#[derive(Debug, Clone, Deftly)]
161#[derive_deftly(HasMemoryCost)]
162pub struct IntroduceHeader {
163    /// Introduction point auth key type and the type of
164    /// the MAC used in `handshake_auth`.
165    auth_key_type: AuthKeyType,
166    /// The public introduction point auth key.
167    auth_key: Vec<u8>,
168    /// A list of extensions
169    extensions: ExtList<IntroduceExt>,
170}
171
172impl tor_bytes::Readable for IntroduceHeader {
173    fn take_from(r: &mut Reader<'_>) -> Result<Self> {
174        let legacy_key_id: RsaIdentity = r.extract()?;
175        if !legacy_key_id.is_zero() {
176            return Err(BytesError::InvalidMessage(
177                "legacy key id in Introduce1.".into(),
178            ));
179        }
180        let auth_key_type = r.take_u8()?.into();
181        let auth_key_len = r.take_u16()?;
182        let auth_key = r.take(auth_key_len as usize)?.into();
183        let extensions = r.extract()?;
184        Ok(Self {
185            auth_key_type,
186            auth_key,
187            extensions,
188        })
189    }
190}
191
192impl tor_bytes::Writeable for IntroduceHeader {
193    fn write_onto<W: Writer + ?Sized>(&self, w: &mut W) -> EncodeResult<()> {
194        w.write_all(&[0_u8; 20]);
195        w.write_u8(self.auth_key_type.get());
196        w.write_u16(u16::try_from(self.auth_key.len()).map_err(|_| EncodeError::BadLengthValue)?);
197        w.write_all(&self.auth_key[..]);
198        w.write(&self.extensions)?;
199        Ok(())
200    }
201}
202
203#[derive(Debug, Clone, Deftly)]
204#[derive_deftly(HasMemoryCost)]
205/// A message body shared by Introduce1 and Introduce2
206struct Introduce {
207    /// The unencrypted header portion of the message.
208    header: IntroduceHeader,
209    /// Up to end of relay payload.
210    encrypted: Vec<u8>,
211}
212
213impl Introduce {
214    /// All arguments constructor
215    fn new(auth_key_type: AuthKeyType, auth_key: Vec<u8>, encrypted: Vec<u8>) -> Self {
216        Self {
217            header: IntroduceHeader {
218                auth_key_type,
219                auth_key,
220                extensions: Default::default(),
221            },
222            encrypted,
223        }
224    }
225    /// Decode an Introduce message body from the given reader.
226    ///
227    /// Return the Introduce message body itself, and the text of the body's header.
228    fn decode_from_reader<'a>(r: &mut Reader<'a>) -> Result<(Self, &'a [u8])> {
229        let header_start = r.cursor();
230        let header = r.extract()?;
231        let header_end = r.cursor();
232        let encrypted = r.take_rest().into();
233        Ok((
234            Self { header, encrypted },
235            r.range(header_start, header_end),
236        ))
237    }
238    /// Encode an Introduce message body onto the given writer
239    fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
240        w.write(&self.header)?;
241        w.write_all(&self.encrypted[..]);
242        Ok(())
243    }
244}
245
246/// A message sent from an onion service to a rendezvous point, telling it to
247/// make a connection to the client.
248#[derive(Debug, Clone, Deftly)]
249#[derive_deftly(HasMemoryCost)]
250pub struct Rendezvous1 {
251    /// The cookie originally sent by the client in its ESTABLISH_REND message.
252    cookie: RendCookie,
253    /// The message to send the client.
254    handshake_info: Vec<u8>,
255}
256
257impl Body for Rendezvous1 {
258    fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
259        let cookie = r.extract()?;
260        let handshake_info = r.take_rest().into();
261        Ok(Self {
262            cookie,
263            handshake_info,
264        })
265    }
266
267    fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
268        w.write(&self.cookie)?;
269        w.write_all(&self.handshake_info[..]);
270        Ok(())
271    }
272}
273
274impl Rendezvous1 {
275    /// Create a new Rendezvous1 message, to handshake with a client identified
276    /// by a given RendCookie, and send it a given message.
277    pub fn new(cookie: RendCookie, handshake_info: impl Into<Vec<u8>>) -> Self {
278        Self {
279            cookie,
280            handshake_info: handshake_info.into(),
281        }
282    }
283}
284
285/// A message sent from the rendezvous point to the client, telling it about the
286/// onion service's message.
287#[derive(Debug, Clone, Deftly)]
288#[derive_deftly(HasMemoryCost)]
289pub struct Rendezvous2 {
290    /// The handshake message from the onion service.
291    handshake_info: Vec<u8>,
292}
293
294impl Rendezvous2 {
295    /// Construct a new Rendezvous2 cell containing a given handshake message.
296    pub fn new(handshake_info: impl Into<Vec<u8>>) -> Self {
297        Self {
298            handshake_info: handshake_info.into(),
299        }
300    }
301
302    /// Return the body of this Rendezvous2 cell. (That is, the handshake
303    /// message from the onion service.)
304    pub fn handshake_info(&self) -> &[u8] {
305        &self.handshake_info
306    }
307}
308
309impl From<Rendezvous1> for Rendezvous2 {
310    fn from(value: Rendezvous1) -> Self {
311        Self {
312            handshake_info: value.handshake_info,
313        }
314    }
315}
316
317impl Body for Rendezvous2 {
318    fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
319        let handshake_info = r.take_rest().into();
320        Ok(Self { handshake_info })
321    }
322
323    fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
324        w.write_all(&self.handshake_info[..]);
325        Ok(())
326    }
327}
328
329caret_int! {
330    /// The recognized extension types for an `IntroEstablished` message.
331    #[derive(Ord, PartialOrd)]
332    pub struct IntroEstablishedExtType(u8) {
333    }
334}
335
336decl_extension_group! {
337    /// An extension to an IntroEstablished message.
338    ///
339    /// (Currently, no extensions of this type are recognized)
340    #[derive(Debug,Clone,Deftly)]
341    #[derive_deftly(HasMemoryCost)]
342    #[non_exhaustive]
343    pub enum IntroEstablishedExt [ IntroEstablishedExtType ] {
344    }
345}
346
347/// Reply sent from the introduction point to the onion service, telling it that
348/// an introduction point is now established.
349#[derive(Debug, Clone, Default, Deftly)]
350#[derive_deftly(HasMemoryCost)]
351pub struct IntroEstablished {
352    /// The extensions included in this cell.
353    extensions: ExtList<IntroEstablishedExt>,
354}
355
356impl IntroEstablished {
357    /// Create a new IntroEstablished message.
358    pub fn new() -> Self {
359        Self::default()
360    }
361
362    /// Return an iterator over the extensions declared in this message.
363    pub fn iter_extensions(&self) -> impl Iterator<Item = &IntroEstablishedExt> {
364        self.extensions.iter()
365    }
366}
367
368impl Body for IntroEstablished {
369    fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
370        let extensions = r.extract()?;
371        Ok(Self { extensions })
372    }
373
374    fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
375        w.write(&self.extensions)?;
376        Ok(())
377    }
378}
379
380caret_int! {
381    /// A status code returned in response to an INTRODUCE1 message.
382    #[derive(Deftly)]
383    #[derive_deftly(HasMemoryCost)]
384    pub struct IntroduceAckStatus(u16) {
385        /// The message was relayed successfully.
386        SUCCESS = 0x0000,
387        /// The introduction point does not have a live circuit from the
388        /// identified service.
389        NOT_RECOGNIZED = 0x0001,
390        /// There was a failure while parsing the INTRODUCE1 message.
391        BAD_MESSAGE_FORMAT = 0x0002,
392        /// The introduction point was unable to deliver the message to the service.
393        CANT_RELAY = 0x0003,
394    }
395}
396caret_int! {
397    /// The recognized extension types for an `IntroEstablished` message.
398    #[derive(Ord, PartialOrd, Deftly)]
399    #[derive_deftly(HasMemoryCost)]
400    pub struct IntroduceAckExtType(u8) {
401    }
402}
403decl_extension_group! {
404    /// An extension to an IntroduceAct message.
405    ///
406    /// (Currently, no extensions of this type are recognized.)
407    #[derive(Debug,Clone,Deftly)]
408    #[derive_deftly(HasMemoryCost)]
409    enum IntroduceAckExt [ IntroduceAckExtType ] {
410    }
411}
412
413/// A reply from the introduction point to the client, telling it that its
414/// introduce1 was received.
415#[derive(Clone, Debug, Deftly)]
416#[derive_deftly(HasMemoryCost)]
417pub struct IntroduceAck {
418    /// The status reported for the Introduce1 message.
419    status_code: IntroduceAckStatus,
420    /// The extensions on this message.
421    extensions: ExtList<IntroduceAckExt>,
422}
423impl IntroduceAck {
424    /// Create a new IntroduceAck message with a provided status code.
425    pub fn new(status_code: IntroduceAckStatus) -> Self {
426        Self {
427            status_code,
428            extensions: Default::default(),
429        }
430    }
431
432    /// Return the status code from this message.
433    pub fn status(&self) -> IntroduceAckStatus {
434        self.status_code
435    }
436
437    /// Checks whether the introduction was a success
438    ///
439    /// If introduction was forwarded successfully,
440    /// returns an `Ok<IntroduceAck>`, whose `.status()` can safely be ignored.
441    /// (The extension list may still be of interest.)
442    ///
443    /// Otherwise, returns `Err<IntroduceAckStatus>`,
444    /// which is suitable for error reporting purposes.
445    pub fn success(self) -> std::result::Result<IntroduceAck, IntroduceAckStatus> {
446        if self.status() == IntroduceAckStatus::SUCCESS {
447            Ok(self)
448        } else {
449            Err(self.status())
450        }
451    }
452}
453
454impl Body for IntroduceAck {
455    fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
456        let status_code = r.take_u16()?.into();
457        let extensions = r.extract()?;
458        Ok(IntroduceAck {
459            status_code,
460            extensions,
461        })
462    }
463
464    fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
465        w.write_u16(self.status_code.into());
466        w.write(&self.extensions)?;
467        Ok(())
468    }
469}
470
471/// When to maybe retry introduction to the *same service* at the *same introduction point*.
472///
473/// (Using this on `IntroduceAckStatus::SUCCESS` is a mistake;
474/// if you do that you'll not get a meaningful retry time, but it won't panic.)
475impl tor_error::HasRetryTime for IntroduceAckStatus {
476    fn retry_time(&self) -> tor_error::RetryTime {
477        use tor_error::RetryTime as RT;
478        use IntroduceAckStatus as S;
479        match *self {
480            S::SUCCESS => RT::Never, // this is a bug
481            S::NOT_RECOGNIZED => RT::AfterWaiting,
482            S::BAD_MESSAGE_FORMAT => RT::Never,
483            S::CANT_RELAY => RT::AfterWaiting,
484            _ => RT::AfterWaiting, // who knows?
485        }
486    }
487}
488
489super::msg::empty_body! {
490    /// Acknowledges an EstablishRendezvous message.
491    pub struct RendezvousEstablished {}
492}