1
//! Encoding and decoding for relay messages related to onion services.
2

            
3
use super::msg::{self, Body};
4
use crate::relaycell::extlist::{decl_extension_group, ExtList};
5
use caret::caret_int;
6
use derive_deftly::Deftly;
7
use tor_bytes::{EncodeError, EncodeResult, Error as BytesError, Result};
8
use tor_bytes::{Reader, Writer};
9
use tor_hscrypto::RendCookie;
10
use tor_llcrypto::pk::rsa::RsaIdentity;
11
use tor_memquota::derive_deftly_template_HasMemoryCost;
12

            
13
pub mod est_intro;
14
pub mod intro_payload;
15
pub mod pow;
16

            
17
pub use crate::relaycell::extlist::UnrecognizedExt;
18

            
19
caret_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)]
32
pub struct EstablishRendezvous {
33
    /// A rendezvous cookie is an arbitrary 20-byte value,
34
    /// chosen randomly by the client.
35
    cookie: RendCookie,
36
}
37
impl EstablishRendezvous {
38
    /// Construct a new establish rendezvous cell.
39
55
    pub fn new(cookie: RendCookie) -> Self {
40
55
        Self { cookie }
41
55
    }
42
}
43
impl msg::Body for EstablishRendezvous {
44
165
    fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
45
165
        let cookie = r.extract()?;
46
110
        r.take_rest();
47
110
        Ok(Self { cookie })
48
165
    }
49
6
    fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
50
6
        w.write(&self.cookie)
51
6
    }
52
}
53

            
54
#[derive(Debug, Clone, Deftly)]
55
#[derive_deftly(HasMemoryCost)]
56
/// A message sent from client to introduction point.
57
pub struct Introduce1(Introduce);
58

            
59
impl msg::Body for Introduce1 {
60
165
    fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
61
165
        let (intro, _) = Introduce::decode_from_reader(r)?;
62
110
        Ok(Self(intro))
63
165
    }
64
6
    fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
65
6
        self.0.encode_onto(w)
66
6
    }
67
}
68

            
69
impl Introduce1 {
70
    /// All arguments constructor
71
55
    pub fn new(auth_key_type: AuthKeyType, auth_key: Vec<u8>, encrypted: Vec<u8>) -> Self {
72
55
        Self(Introduce::new(auth_key_type, auth_key, encrypted))
73
55
    }
74
}
75

            
76
#[derive(Debug, Clone, Deftly)]
77
#[derive_deftly(HasMemoryCost)]
78
/// A message sent from introduction point to hidden service host.
79
pub 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

            
86
impl 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

            
101
impl 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

            
139
caret_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

            
146
decl_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)]
162
pub 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

            
172
impl tor_bytes::Readable for IntroduceHeader {
173
165
    fn take_from(r: &mut Reader<'_>) -> Result<Self> {
174
165
        let legacy_key_id: RsaIdentity = r.extract()?;
175
165
        if !legacy_key_id.is_zero() {
176
55
            return Err(BytesError::InvalidMessage(
177
55
                "legacy key id in Introduce1.".into(),
178
55
            ));
179
110
        }
180
110
        let auth_key_type = r.take_u8()?.into();
181
110
        let auth_key_len = r.take_u16()?;
182
110
        let auth_key = r.take(auth_key_len as usize)?.into();
183
110
        let extensions = r.extract()?;
184
110
        Ok(Self {
185
110
            auth_key_type,
186
110
            auth_key,
187
110
            extensions,
188
110
        })
189
165
    }
190
}
191

            
192
impl tor_bytes::Writeable for IntroduceHeader {
193
6
    fn write_onto<W: Writer + ?Sized>(&self, w: &mut W) -> EncodeResult<()> {
194
6
        w.write_all(&[0_u8; 20]);
195
6
        w.write_u8(self.auth_key_type.get());
196
6
        w.write_u16(u16::try_from(self.auth_key.len()).map_err(|_| EncodeError::BadLengthValue)?);
197
6
        w.write_all(&self.auth_key[..]);
198
6
        w.write(&self.extensions)?;
199
6
        Ok(())
200
6
    }
201
}
202

            
203
#[derive(Debug, Clone, Deftly)]
204
#[derive_deftly(HasMemoryCost)]
205
/// A message body shared by Introduce1 and Introduce2
206
struct 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

            
213
impl Introduce {
214
    /// All arguments constructor
215
55
    fn new(auth_key_type: AuthKeyType, auth_key: Vec<u8>, encrypted: Vec<u8>) -> Self {
216
55
        Self {
217
55
            header: IntroduceHeader {
218
55
                auth_key_type,
219
55
                auth_key,
220
55
                extensions: Default::default(),
221
55
            },
222
55
            encrypted,
223
55
        }
224
55
    }
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
165
    fn decode_from_reader<'a>(r: &mut Reader<'a>) -> Result<(Self, &'a [u8])> {
229
165
        let header_start = r.cursor();
230
165
        let header = r.extract()?;
231
110
        let header_end = r.cursor();
232
110
        let encrypted = r.take_rest().into();
233
110
        Ok((
234
110
            Self { header, encrypted },
235
110
            r.range(header_start, header_end),
236
110
        ))
237
165
    }
238
    /// Encode an Introduce message body onto the given writer
239
6
    fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
240
6
        w.write(&self.header)?;
241
6
        w.write_all(&self.encrypted[..]);
242
6
        Ok(())
243
6
    }
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)]
250
pub 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

            
257
impl Body for Rendezvous1 {
258
55
    fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
259
55
        let cookie = r.extract()?;
260
55
        let handshake_info = r.take_rest().into();
261
55
        Ok(Self {
262
55
            cookie,
263
55
            handshake_info,
264
55
        })
265
55
    }
266

            
267
4
    fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
268
4
        w.write(&self.cookie)?;
269
4
        w.write_all(&self.handshake_info[..]);
270
4
        Ok(())
271
4
    }
272
}
273

            
274
impl 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
2
    pub fn new(cookie: RendCookie, handshake_info: impl Into<Vec<u8>>) -> Self {
278
2
        Self {
279
2
            cookie,
280
2
            handshake_info: handshake_info.into(),
281
2
        }
282
2
    }
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)]
289
pub struct Rendezvous2 {
290
    /// The handshake message from the onion service.
291
    handshake_info: Vec<u8>,
292
}
293

            
294
impl 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

            
309
impl From<Rendezvous1> for Rendezvous2 {
310
55
    fn from(value: Rendezvous1) -> Self {
311
55
        Self {
312
55
            handshake_info: value.handshake_info,
313
55
        }
314
55
    }
315
}
316

            
317
impl Body for Rendezvous2 {
318
55
    fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
319
55
        let handshake_info = r.take_rest().into();
320
55
        Ok(Self { handshake_info })
321
55
    }
322

            
323
4
    fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
324
4
        w.write_all(&self.handshake_info[..]);
325
4
        Ok(())
326
4
    }
327
}
328

            
329
caret_int! {
330
    /// The recognized extension types for an `IntroEstablished` message.
331
    #[derive(Ord, PartialOrd)]
332
    pub struct IntroEstablishedExtType(u8) {
333
    }
334
}
335

            
336
decl_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)]
351
pub struct IntroEstablished {
352
    /// The extensions included in this cell.
353
    extensions: ExtList<IntroEstablishedExt>,
354
}
355

            
356
impl IntroEstablished {
357
    /// Create a new IntroEstablished message.
358
55
    pub fn new() -> Self {
359
55
        Self::default()
360
55
    }
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

            
368
impl Body for IntroEstablished {
369
55
    fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
370
55
        let extensions = r.extract()?;
371
55
        Ok(Self { extensions })
372
55
    }
373

            
374
4
    fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
375
4
        w.write(&self.extensions)?;
376
4
        Ok(())
377
4
    }
378
}
379

            
380
caret_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
}
396
caret_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
}
403
decl_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)]
417
pub 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
}
423
impl IntroduceAck {
424
    /// Create a new IntroduceAck message with a provided status code.
425
55
    pub fn new(status_code: IntroduceAckStatus) -> Self {
426
55
        Self {
427
55
            status_code,
428
55
            extensions: Default::default(),
429
55
        }
430
55
    }
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

            
454
impl Body for IntroduceAck {
455
55
    fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
456
55
        let status_code = r.take_u16()?.into();
457
55
        let extensions = r.extract()?;
458
55
        Ok(IntroduceAck {
459
55
            status_code,
460
55
            extensions,
461
55
        })
462
55
    }
463

            
464
4
    fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
465
4
        w.write_u16(self.status_code.into());
466
4
        w.write(&self.extensions)?;
467
4
        Ok(())
468
4
    }
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.)
475
impl 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

            
489
super::msg::empty_body! {
490
    /// Acknowledges an EstablishRendezvous message.
491
    pub struct RendezvousEstablished {}
492
}