tor_cell/relaycell/
hs.rs

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