1
//! Relay cell cryptography
2
//!
3
//! The Tor protocol centers around "RELAY cells", which are transmitted through
4
//! the network along circuits.  The client that creates a circuit shares two
5
//! different sets of keys and state with each of the relays on the circuit: one
6
//! for "outbound" traffic, and one for "inbound" traffic.
7
//!
8
//! So for example, if a client creates a 3-hop circuit with relays R1, R2, and
9
//! R3, the client has:
10
//!   * An "inbound" cryptographic state shared with R1.
11
//!   * An "inbound" cryptographic state shared with R2.
12
//!   * An "inbound" cryptographic state shared with R3.
13
//!   * An "outbound" cryptographic state shared with R1.
14
//!   * An "outbound" cryptographic state shared with R2.
15
//!   * An "outbound" cryptographic state shared with R3.
16
//!
17
//! In this module at least, we'll call each of these state objects a "layer" of
18
//! the circuit's encryption.
19
//!
20
//! The Tor specification does not describe these layer objects very explicitly.
21
//! In the current relay cryptography protocol, each layer contains:
22
//!    * A keyed AES-CTR state. (AES-128 or AES-256)  This cipher uses a key
23
//!      called `Kf` or `Kb` in the spec, where `Kf` is a "forward" key used in
24
//!      the outbound direction, and `Kb` is a "backward" key used in the
25
//!      inbound direction.
26
//!    * A running digest. (SHA1 or SHA3)  This digest is initialized with a
27
//!      value called `Df` or `Db` in the spec.
28
//!
29
//! This `crypto::cell` module itself provides traits and implementations that
30
//! should work for all current future versions of the relay cell crypto design.
31
//! The current Tor protocols are instantiated in a `tor1` submodule.
32

            
33
#[cfg(feature = "bench")]
34
pub(crate) mod bench_utils;
35
pub(crate) mod cgo;
36
pub(crate) mod tor1;
37

            
38
use crate::{Error, Result};
39
use derive_deftly::Deftly;
40
use tor_cell::{
41
    chancell::{BoxedCellBody, ChanCmd},
42
    relaycell::msg::SendmeTag,
43
};
44
use tor_memquota::derive_deftly_template_HasMemoryCost;
45

            
46
use super::binding::CircuitBinding;
47

            
48
/// Type for the body of a relay cell.
49
#[cfg_attr(feature = "bench", visibility::make(pub))]
50
#[derive(Clone, derive_more::From, derive_more::Into)]
51
pub(crate) struct RelayCellBody(BoxedCellBody);
52

            
53
impl AsRef<[u8]> for RelayCellBody {
54
1810
    fn as_ref(&self) -> &[u8] {
55
1810
        &self.0[..]
56
1810
    }
57
}
58
impl AsMut<[u8]> for RelayCellBody {
59
4170
    fn as_mut(&mut self) -> &mut [u8] {
60
4170
        &mut self.0[..]
61
4170
    }
62
}
63

            
64
/// Represents the ability for one hop of a circuit's cryptographic state to be
65
/// initialized from a given seed.
66
#[cfg_attr(feature = "bench", visibility::make(pub))]
67
pub(crate) trait CryptInit: Sized {
68
    /// Return the number of bytes that this state will require.
69
    fn seed_len() -> usize;
70
    /// Construct this state from a seed of the appropriate length.
71
    fn initialize(seed: &[u8]) -> Result<Self>;
72
    /// Initialize this object from a key generator.
73
114
    fn construct<K: super::handshake::KeyGenerator>(keygen: K) -> Result<Self> {
74
114
        let seed = keygen.expand(Self::seed_len())?;
75
114
        Self::initialize(&seed[..])
76
114
    }
77
}
78

            
79
/// A paired object containing the inbound and outbound cryptographic layers
80
/// used by a client to communicate with a single hop on one of its circuits.
81
///
82
/// TODO: Maybe we should fold this into CryptInit.
83
#[cfg_attr(feature = "bench", visibility::make(pub))]
84
pub(crate) trait ClientLayer<F, B>
85
where
86
    F: OutboundClientLayer,
87
    B: InboundClientLayer,
88
{
89
    /// Consume this ClientLayer and return a paired forward and reverse
90
    /// crypto layer, and a [`CircuitBinding`] object
91
    fn split_client_layer(self) -> (F, B, CircuitBinding);
92
}
93

            
94
/// A paired object containing the inbound and outbound cryptographic layers
95
/// used by a relay to implement a client's circuits.
96
///
97
#[allow(dead_code)] // To be used by relays.
98
#[cfg_attr(feature = "bench", visibility::make(pub))]
99
pub(crate) trait RelayLayer<F, B>
100
where
101
    F: OutboundRelayLayer,
102
    B: InboundRelayLayer,
103
{
104
    /// Consume this ClientLayer and return a paired forward and reverse
105
    /// crypto layers, and a [`CircuitBinding`] object
106
    fn split_relay_layer(self) -> (F, B, CircuitBinding);
107
}
108

            
109
/// Represents a relay's view of the inbound crypto state on a given circuit.
110
#[allow(dead_code)] // Relays are not yet implemented.
111
#[cfg_attr(feature = "bench", visibility::make(pub))]
112
pub(crate) trait InboundRelayLayer {
113
    /// Prepare a RelayCellBody to be sent towards the client,
114
    /// and encrypt it.
115
    ///
116
    /// Return the authentication tag.
117
    fn originate(&mut self, cmd: ChanCmd, cell: &mut RelayCellBody) -> SendmeTag;
118
    /// Encrypt a RelayCellBody that is moving towards the client.
119
    fn encrypt_inbound(&mut self, cmd: ChanCmd, cell: &mut RelayCellBody);
120
}
121

            
122
/// Represent a relay's view of the outbound crypto state on a given circuit.
123
#[allow(dead_code)]
124
#[cfg_attr(feature = "bench", visibility::make(pub))]
125
pub(crate) trait OutboundRelayLayer {
126
    /// Decrypt a RelayCellBody that is coming from the client.
127
    ///
128
    /// Return an authentication tag if it is addressed to us.
129
    fn decrypt_outbound(&mut self, cmd: ChanCmd, cell: &mut RelayCellBody) -> Option<SendmeTag>;
130
}
131

            
132
/// A client's view of the cryptographic state shared with a single relay on a
133
/// circuit, as used for outbound cells.
134
#[cfg_attr(feature = "bench", visibility::make(pub))]
135
pub(crate) trait OutboundClientLayer {
136
    /// Prepare a RelayCellBody to be sent to the relay at this layer, and
137
    /// encrypt it.
138
    ///
139
    /// Return the authentication tag.
140
    fn originate_for(&mut self, cmd: ChanCmd, cell: &mut RelayCellBody) -> SendmeTag;
141
    /// Encrypt a RelayCellBody to be decrypted by this layer.
142
    fn encrypt_outbound(&mut self, cmd: ChanCmd, cell: &mut RelayCellBody);
143
}
144

            
145
/// A client's view of the crypto state shared with a single relay on a circuit,
146
/// as used for inbound cells.
147
#[cfg_attr(feature = "bench", visibility::make(pub))]
148
pub(crate) trait InboundClientLayer {
149
    /// Decrypt a CellBody that passed through this layer.
150
    ///
151
    /// Return an authentication tag if this layer is the originator.
152
    fn decrypt_inbound(&mut self, cmd: ChanCmd, cell: &mut RelayCellBody) -> Option<SendmeTag>;
153
}
154

            
155
/// Type to store hop indices on a circuit.
156
///
157
/// Hop indices are zero-based: "0" denotes the first hop on the circuit.
158
#[derive(Copy, Clone, Eq, PartialEq, Debug, Deftly, Ord, PartialOrd)]
159
#[derive_deftly(HasMemoryCost)]
160
pub struct HopNum(u8);
161

            
162
impl HopNum {
163
    /// Return an object that implements [`Display`](std::fmt::Display) for printing `HopNum`s.
164
    ///
165
    /// This will display the `HopNum` as a 1-indexed value (the string representation of the first
166
    /// hop is `"#1"`).
167
    ///
168
    /// To display the zero-based underlying representation of the `HopNum`, use
169
    /// [`Debug`](std::fmt::Debug).
170
96
    pub fn display(&self) -> HopNumDisplay {
171
96
        HopNumDisplay(*self)
172
96
    }
173

            
174
    /// Return true if this is  the first hop of a circuit.
175
    pub(crate) fn is_first_hop(&self) -> bool {
176
        self.0 == 0
177
    }
178
}
179

            
180
/// A helper for displaying [`HopNum`]s.
181
///
182
/// The [`Display`](std::fmt::Display) of this type displays the `HopNum` as a 1-based index
183
/// prefixed with the number sign (`#`). For example, the string representation of the first hop is
184
/// `"#1"`.
185
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
186
pub struct HopNumDisplay(HopNum);
187

            
188
impl std::fmt::Display for HopNumDisplay {
189
96
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
190
96
        let hop_num: u8 = self.0.into();
191

            
192
96
        write!(f, "#{}", hop_num + 1)
193
96
    }
194
}
195

            
196
impl From<HopNum> for u8 {
197
1044
    fn from(hop: HopNum) -> u8 {
198
1044
        hop.0
199
1044
    }
200
}
201

            
202
impl From<u8> for HopNum {
203
34275
    fn from(v: u8) -> HopNum {
204
34275
        HopNum(v)
205
34275
    }
206
}
207

            
208
impl From<HopNum> for usize {
209
32879
    fn from(hop: HopNum) -> usize {
210
32879
        hop.0 as usize
211
32879
    }
212
}
213

            
214
/// A client's view of the cryptographic state for an entire
215
/// constructed circuit, as used for sending cells.
216
#[cfg_attr(feature = "bench", visibility::make(pub), derive(Default))]
217
pub(crate) struct OutboundClientCrypt {
218
    /// Vector of layers, one for each hop on the circuit, ordered from the
219
    /// closest hop to the farthest.
220
    layers: Vec<Box<dyn OutboundClientLayer + Send>>,
221
}
222

            
223
/// A client's view of the cryptographic state for an entire
224
/// constructed circuit, as used for receiving cells.
225
#[cfg_attr(feature = "bench", visibility::make(pub), derive(Default))]
226
pub(crate) struct InboundClientCrypt {
227
    /// Vector of layers, one for each hop on the circuit, ordered from the
228
    /// closest hop to the farthest.
229
    layers: Vec<Box<dyn InboundClientLayer + Send>>,
230
}
231

            
232
impl OutboundClientCrypt {
233
    /// Return a new (empty) OutboundClientCrypt.
234
446
    #[cfg_attr(feature = "bench", visibility::make(pub))]
235
446
    pub(crate) fn new() -> Self {
236
446
        OutboundClientCrypt { layers: Vec::new() }
237
446
    }
238
    /// Prepare a cell body to sent away from the client.
239
    ///
240
    /// The cell is prepared for the `hop`th hop, and then encrypted with
241
    /// the appropriate keys.
242
    ///
243
    /// On success, returns a reference to tag that should be expected
244
    /// for an authenticated SENDME sent in response to this cell.
245
5574
    #[cfg_attr(feature = "bench", visibility::make(pub))]
246
5574
    pub(crate) fn encrypt(
247
5574
        &mut self,
248
5574
        cmd: ChanCmd,
249
5574
        cell: &mut RelayCellBody,
250
5574
        hop: HopNum,
251
5574
    ) -> Result<SendmeTag> {
252
5574
        let hop: usize = hop.into();
253
5574
        if hop >= self.layers.len() {
254
2
            return Err(Error::NoSuchHop);
255
5572
        }
256

            
257
5572
        let mut layers = self.layers.iter_mut().take(hop + 1).rev();
258
5572
        let first_layer = layers.next().ok_or(Error::NoSuchHop)?;
259
5572
        let tag = first_layer.originate_for(cmd, cell);
260
10890
        for layer in layers {
261
10890
            layer.encrypt_outbound(cmd, cell);
262
10890
        }
263
5572
        Ok(tag)
264
5574
    }
265

            
266
    /// Add a new layer to this OutboundClientCrypt
267
1154
    pub(crate) fn add_layer(&mut self, layer: Box<dyn OutboundClientLayer + Send>) {
268
1154
        assert!(self.layers.len() < u8::MAX as usize);
269
1154
        self.layers.push(layer);
270
1154
    }
271

            
272
    /// Return the number of layers configured on this OutboundClientCrypt.
273
74
    pub(crate) fn n_layers(&self) -> usize {
274
74
        self.layers.len()
275
74
    }
276
}
277

            
278
impl InboundClientCrypt {
279
    /// Return a new (empty) InboundClientCrypt.
280
418
    #[cfg_attr(feature = "bench", visibility::make(pub))]
281
418
    pub(crate) fn new() -> Self {
282
418
        InboundClientCrypt { layers: Vec::new() }
283
418
    }
284
    /// Decrypt an incoming cell that is coming to the client.
285
    ///
286
    /// On success, return which hop was the originator of the cell.
287
    // TODO(nickm): Use a real type for the tag, not just `&[u8]`.
288
1356
    #[cfg_attr(feature = "bench", visibility::make(pub))]
289
1356
    pub(crate) fn decrypt(
290
1356
        &mut self,
291
1356
        cmd: ChanCmd,
292
1356
        cell: &mut RelayCellBody,
293
1356
    ) -> Result<(HopNum, SendmeTag)> {
294
3812
        for (hopnum, layer) in self.layers.iter_mut().enumerate() {
295
3812
            if let Some(tag) = layer.decrypt_inbound(cmd, cell) {
296
1354
                let hopnum = HopNum(u8::try_from(hopnum).expect("Somehow > 255 hops"));
297
1354
                return Ok((hopnum, tag));
298
2458
            }
299
        }
300
2
        Err(Error::BadCellAuth)
301
1356
    }
302
    /// Add a new layer to this InboundClientCrypt
303
1070
    pub(crate) fn add_layer(&mut self, layer: Box<dyn InboundClientLayer + Send>) {
304
1070
        assert!(self.layers.len() < u8::MAX as usize);
305
1070
        self.layers.push(layer);
306
1070
    }
307

            
308
    /// Return the number of layers configured on this InboundClientCrypt.
309
    ///
310
    /// TODO: use HopNum
311
    #[allow(dead_code)]
312
2
    pub(crate) fn n_layers(&self) -> usize {
313
2
        self.layers.len()
314
2
    }
315
}
316

            
317
/// Standard Tor relay crypto, as instantiated for RELAY cells.
318
pub(crate) type Tor1RelayCrypto =
319
    tor1::CryptStatePair<tor_llcrypto::cipher::aes::Aes128Ctr, tor_llcrypto::d::Sha1>;
320

            
321
/// Standard Tor relay crypto, as instantiated for the HSv3 protocol.
322
///
323
/// (The use of SHA3 is ridiculously overkill.)
324
#[cfg(feature = "hs-common")]
325
pub(crate) type Tor1Hsv3RelayCrypto =
326
    tor1::CryptStatePair<tor_llcrypto::cipher::aes::Aes256Ctr, tor_llcrypto::d::Sha3_256>;
327

            
328
/// Counter galois onion relay crypto.
329
//
330
// We use `aes` directly here instead of tor_llcrypto::aes, which may or may not be OpenSSL:
331
// the OpenSSL implementations have bad performance when it comes to re-keying
332
// or changing IVs.
333
pub(crate) type CgoRelayCrypto = cgo::CryptStatePair<aes::Aes128, aes::Aes128Enc>;
334

            
335
#[cfg(test)]
336
mod test {
337
    // @@ begin test lint list maintained by maint/add_warning @@
338
    #![allow(clippy::bool_assert_comparison)]
339
    #![allow(clippy::clone_on_copy)]
340
    #![allow(clippy::dbg_macro)]
341
    #![allow(clippy::mixed_attributes_style)]
342
    #![allow(clippy::print_stderr)]
343
    #![allow(clippy::print_stdout)]
344
    #![allow(clippy::single_char_pattern)]
345
    #![allow(clippy::unwrap_used)]
346
    #![allow(clippy::unchecked_time_subtraction)]
347
    #![allow(clippy::useless_vec)]
348
    #![allow(clippy::needless_pass_by_value)]
349
    #![allow(clippy::string_slice)] // See arti#2571
350
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
351

            
352
    use super::*;
353
    use rand::{Rng, seq::IndexedRandom as _};
354
    use tor_basic_utils::{RngExt as _, test_rng::testing_rng};
355
    use tor_bytes::SecretBuf;
356
    use tor_cell::relaycell::RelayCellFormat;
357

            
358
    pub(crate) fn add_layers(
359
        cc_out: &mut OutboundClientCrypt,
360
        cc_in: &mut InboundClientCrypt,
361
        pair: Tor1RelayCrypto,
362
    ) {
363
        let (outbound, inbound, _) = pair.split_client_layer();
364
        cc_out.add_layer(Box::new(outbound));
365
        cc_in.add_layer(Box::new(inbound));
366
    }
367

            
368
    #[test]
369
    fn roundtrip() {
370
        // Take canned keys and make sure we can do crypto correctly.
371
        use crate::crypto::handshake::ShakeKeyGenerator as KGen;
372
        fn s(seed: &[u8]) -> SecretBuf {
373
            seed.to_vec().into()
374
        }
375

            
376
        let seed1 = s(b"hidden we are free");
377
        let seed2 = s(b"free to speak, to free ourselves");
378
        let seed3 = s(b"free to hide no more");
379

            
380
        let mut cc_out = OutboundClientCrypt::new();
381
        let mut cc_in = InboundClientCrypt::new();
382
        let pair = Tor1RelayCrypto::construct(KGen::new(seed1.clone())).unwrap();
383
        add_layers(&mut cc_out, &mut cc_in, pair);
384
        let pair = Tor1RelayCrypto::construct(KGen::new(seed2.clone())).unwrap();
385
        add_layers(&mut cc_out, &mut cc_in, pair);
386
        let pair = Tor1RelayCrypto::construct(KGen::new(seed3.clone())).unwrap();
387
        add_layers(&mut cc_out, &mut cc_in, pair);
388

            
389
        assert_eq!(cc_in.n_layers(), 3);
390
        assert_eq!(cc_out.n_layers(), 3);
391

            
392
        let (mut r1f, mut r1b, _) = Tor1RelayCrypto::construct(KGen::new(seed1))
393
            .unwrap()
394
            .split_relay_layer();
395
        let (mut r2f, mut r2b, _) = Tor1RelayCrypto::construct(KGen::new(seed2))
396
            .unwrap()
397
            .split_relay_layer();
398
        let (mut r3f, mut r3b, _) = Tor1RelayCrypto::construct(KGen::new(seed3))
399
            .unwrap()
400
            .split_relay_layer();
401
        let cmd = ChanCmd::RELAY;
402

            
403
        let mut rng = testing_rng();
404
        for _ in 1..300 {
405
            // outbound cell
406
            let mut cell = Box::new([0_u8; 509]);
407
            let mut cell_orig = [0_u8; 509];
408
            rng.fill_bytes(&mut cell_orig);
409
            cell.copy_from_slice(&cell_orig);
410
            let mut cell = cell.into();
411
            let _tag = cc_out.encrypt(cmd, &mut cell, 2.into()).unwrap();
412
            assert_ne!(&cell.as_ref()[9..], &cell_orig.as_ref()[9..]);
413
            assert!(r1f.decrypt_outbound(cmd, &mut cell).is_none());
414
            assert!(r2f.decrypt_outbound(cmd, &mut cell).is_none());
415
            assert!(r3f.decrypt_outbound(cmd, &mut cell).is_some());
416

            
417
            assert_eq!(&cell.as_ref()[9..], &cell_orig.as_ref()[9..]);
418

            
419
            // inbound cell
420
            let mut cell = Box::new([0_u8; 509]);
421
            let mut cell_orig = [0_u8; 509];
422
            rng.fill_bytes(&mut cell_orig);
423
            cell.copy_from_slice(&cell_orig);
424
            let mut cell = cell.into();
425

            
426
            r3b.originate(cmd, &mut cell);
427
            r2b.encrypt_inbound(cmd, &mut cell);
428
            r1b.encrypt_inbound(cmd, &mut cell);
429
            let (layer, _tag) = cc_in.decrypt(cmd, &mut cell).unwrap();
430
            assert_eq!(layer, 2.into());
431
            assert_eq!(&cell.as_ref()[9..], &cell_orig.as_ref()[9..]);
432

            
433
            // TODO: Test tag somehow.
434
        }
435

            
436
        // Try a failure: sending a cell to a nonexistent hop.
437
        {
438
            let mut cell = Box::new([0_u8; 509]).into();
439
            let err = cc_out.encrypt(cmd, &mut cell, 10.into());
440
            assert!(matches!(err, Err(Error::NoSuchHop)));
441
        }
442

            
443
        // Try a failure: A junk cell with no correct auth from any layer.
444
        {
445
            let mut cell = Box::new([0_u8; 509]).into();
446
            let err = cc_in.decrypt(cmd, &mut cell);
447
            assert!(matches!(err, Err(Error::BadCellAuth)));
448
        }
449
    }
450

            
451
    #[test]
452
    fn hop_num_display() {
453
        for i in 0..10 {
454
            let hop_num = HopNum::from(i);
455
            let expect = format!("#{}", i + 1);
456

            
457
            assert_eq!(expect, hop_num.display().to_string());
458
        }
459
    }
460

            
461
    /// Helper: Clear every field in the tor1 `cell` that is reserved for cryptography by relay cell
462
    /// format `version.
463
    ///
464
    /// We do this so that we can be sure that the _other_ fields have all been transmitted correctly.
465
    fn clean_cell_fields(cell: &mut RelayCellBody, format: RelayCellFormat) {
466
        use super::tor1;
467
        match format {
468
            RelayCellFormat::V0 => {
469
                cell.0[tor1::RECOGNIZED_RANGE].fill(0);
470
                cell.0[tor1::DIGEST_RANGE].fill(0);
471
            }
472
            RelayCellFormat::V1 => {
473
                cell.0[0..16].fill(0);
474
            }
475
            _ => {
476
                panic!("Unrecognized format!");
477
            }
478
        }
479
    }
480

            
481
    /// Helper: Test a single-hop message, forward from the client.
482
    fn test_fwd_one_hop<CS, RS, CF, CB, RF, RB>(format: RelayCellFormat)
483
    where
484
        CS: CryptInit + ClientLayer<CF, CB>,
485
        RS: CryptInit + RelayLayer<RF, RB>,
486
        CF: OutboundClientLayer,
487
        CB: InboundClientLayer,
488
        RF: OutboundRelayLayer,
489
        RB: InboundRelayLayer,
490
    {
491
        let mut rng = testing_rng();
492
        assert_eq!(CS::seed_len(), RS::seed_len());
493
        let mut seed = vec![0; CS::seed_len()];
494
        rng.fill_bytes(&mut seed[..]);
495
        let (mut client, _, _) = CS::initialize(&seed).unwrap().split_client_layer();
496
        let (mut relay, _, _) = RS::initialize(&seed).unwrap().split_relay_layer();
497

            
498
        for _ in 0..5 {
499
            let mut cell = RelayCellBody(Box::new([0_u8; 509]));
500
            rng.fill_bytes(&mut cell.0[..]);
501
            clean_cell_fields(&mut cell, format);
502
            let msg_orig = cell.clone();
503

            
504
            let ctag = client.originate_for(ChanCmd::RELAY, &mut cell);
505
            assert_ne!(cell.0[16..], msg_orig.0[16..]);
506
            let rtag = relay.decrypt_outbound(ChanCmd::RELAY, &mut cell);
507
            clean_cell_fields(&mut cell, format);
508
            assert_eq!(cell.0[..], msg_orig.0[..]);
509
            assert_eq!(rtag, Some(ctag));
510
        }
511
    }
512

            
513
    /// Helper: Test a single-hop message, backwards towards the client.
514
    fn test_rev_one_hop<CS, RS, CF, CB, RF, RB>(format: RelayCellFormat)
515
    where
516
        CS: CryptInit + ClientLayer<CF, CB>,
517
        RS: CryptInit + RelayLayer<RF, RB>,
518
        CF: OutboundClientLayer,
519
        CB: InboundClientLayer,
520
        RF: OutboundRelayLayer,
521
        RB: InboundRelayLayer,
522
    {
523
        let mut rng = testing_rng();
524
        assert_eq!(CS::seed_len(), RS::seed_len());
525
        let mut seed = vec![0; CS::seed_len()];
526
        rng.fill_bytes(&mut seed[..]);
527
        let (_, mut client, _) = CS::initialize(&seed).unwrap().split_client_layer();
528
        let (_, mut relay, _) = RS::initialize(&seed).unwrap().split_relay_layer();
529

            
530
        for _ in 0..5 {
531
            let mut cell = RelayCellBody(Box::new([0_u8; 509]));
532
            rng.fill_bytes(&mut cell.0[..]);
533
            clean_cell_fields(&mut cell, format);
534
            let msg_orig = cell.clone();
535

            
536
            let rtag = relay.originate(ChanCmd::RELAY, &mut cell);
537
            assert_ne!(cell.0[16..], msg_orig.0[16..]);
538
            let ctag = client.decrypt_inbound(ChanCmd::RELAY, &mut cell);
539
            clean_cell_fields(&mut cell, format);
540
            assert_eq!(cell.0[..], msg_orig.0[..]);
541
            assert_eq!(ctag, Some(rtag));
542
        }
543
    }
544

            
545
    fn test_fwd_three_hops_leaky<CS, RS, CF, CB, RF, RB>(format: RelayCellFormat)
546
    where
547
        CS: CryptInit + ClientLayer<CF, CB>,
548
        RS: CryptInit + RelayLayer<RF, RB>,
549
        CF: OutboundClientLayer + Send + 'static,
550
        CB: InboundClientLayer,
551
        RF: OutboundRelayLayer,
552
        RB: InboundRelayLayer,
553
    {
554
        let mut rng = testing_rng();
555
        assert_eq!(CS::seed_len(), RS::seed_len());
556
        let mut client = OutboundClientCrypt::new();
557
        let mut relays = Vec::new();
558
        for _ in 0..3 {
559
            let mut seed = vec![0; CS::seed_len()];
560
            rng.fill_bytes(&mut seed[..]);
561
            let (client_layer, _, _) = CS::initialize(&seed).unwrap().split_client_layer();
562
            let (relay_layer, _, _) = RS::initialize(&seed).unwrap().split_relay_layer();
563
            client.add_layer(Box::new(client_layer));
564
            relays.push(relay_layer);
565
        }
566

            
567
        'cell_loop: for _ in 0..32 {
568
            let mut cell = RelayCellBody(Box::new([0_u8; 509]));
569
            rng.fill_bytes(&mut cell.0[..]);
570
            clean_cell_fields(&mut cell, format);
571
            let msg_orig = cell.clone();
572
            let cmd = *[ChanCmd::RELAY, ChanCmd::RELAY_EARLY]
573
                .choose(&mut rng)
574
                .unwrap();
575
            let hop: u8 = rng.gen_range_checked(0_u8..=2).unwrap();
576

            
577
            let ctag = client.encrypt(cmd, &mut cell, hop.into()).unwrap();
578

            
579
            for r_idx in 0..=hop {
580
                let rtag = relays[r_idx as usize].decrypt_outbound(cmd, &mut cell);
581
                if let Some(rtag) = rtag {
582
                    clean_cell_fields(&mut cell, format);
583
                    assert_eq!(cell.0[..], msg_orig.0[..]);
584
                    assert_eq!(rtag, ctag);
585
                    continue 'cell_loop;
586
                }
587
            }
588
            panic!("None of the relays thought that this cell was recognized!");
589
        }
590
    }
591

            
592
    fn test_rev_three_hops_leaky<CS, RS, CF, CB, RF, RB>(format: RelayCellFormat)
593
    where
594
        CS: CryptInit + ClientLayer<CF, CB>,
595
        RS: CryptInit + RelayLayer<RF, RB>,
596
        CF: OutboundClientLayer,
597
        CB: InboundClientLayer + Send + 'static,
598
        RF: OutboundRelayLayer,
599
        RB: InboundRelayLayer,
600
    {
601
        let mut rng = testing_rng();
602
        assert_eq!(CS::seed_len(), RS::seed_len());
603
        let mut client = InboundClientCrypt::new();
604
        let mut relays = Vec::new();
605
        for _ in 0..3 {
606
            let mut seed = vec![0; CS::seed_len()];
607
            rng.fill_bytes(&mut seed[..]);
608
            let (_, client_layer, _) = CS::initialize(&seed).unwrap().split_client_layer();
609
            let (_, relay_layer, _) = RS::initialize(&seed).unwrap().split_relay_layer();
610
            client.add_layer(Box::new(client_layer));
611
            relays.push(relay_layer);
612
        }
613

            
614
        for _ in 0..32 {
615
            let mut cell = RelayCellBody(Box::new([0_u8; 509]));
616
            rng.fill_bytes(&mut cell.0[..]);
617
            clean_cell_fields(&mut cell, format);
618
            let msg_orig = cell.clone();
619
            let cmd = *[ChanCmd::RELAY, ChanCmd::RELAY_EARLY]
620
                .choose(&mut rng)
621
                .unwrap();
622
            let hop: u8 = rng.gen_range_checked(0_u8..=2).unwrap();
623

            
624
            let rtag = relays[hop as usize].originate(cmd, &mut cell);
625
            for r_idx in (0..hop.into()).rev() {
626
                relays[r_idx as usize].encrypt_inbound(cmd, &mut cell);
627
            }
628

            
629
            let (observed_hop, ctag) = client.decrypt(cmd, &mut cell).unwrap();
630
            assert_eq!(observed_hop, hop.into());
631
            clean_cell_fields(&mut cell, format);
632
            assert_eq!(cell.0[..], msg_orig.0[..]);
633
            assert_eq!(ctag, rtag);
634
        }
635
    }
636

            
637
    macro_rules! integration_tests { { $modname:ident($fmt:expr, $ctype:ty, $rtype:ty) } => {
638
        mod $modname {
639
            use super::*;
640
            #[test]
641
            fn test_fwd_one_hop() {
642
                super::test_fwd_one_hop::<$ctype, $rtype, _, _, _, _>($fmt);
643
            }
644
            #[test]
645
            fn test_rev_one_hop() {
646
                super::test_rev_one_hop::<$ctype, $rtype, _, _, _, _>($fmt);
647
            }
648
            #[test]
649
            fn test_fwd_three_hops_leaky() {
650
                super::test_fwd_three_hops_leaky::<$ctype, $rtype, _, _, _, _>($fmt);
651
            }
652
            #[test]
653
            fn test_rev_three_hops_leaky() {
654
                super::test_rev_three_hops_leaky::<$ctype, $rtype, _, _, _, _>($fmt);
655
            }
656
        }
657
    }}
658

            
659
    integration_tests! { tor1(RelayCellFormat::V0, Tor1RelayCrypto, Tor1RelayCrypto) }
660
    #[cfg(feature = "hs-common")]
661
    integration_tests! { tor1_hs(RelayCellFormat::V0, Tor1Hsv3RelayCrypto, Tor1Hsv3RelayCrypto) }
662

            
663
    integration_tests! {
664
        cgo_aes128(RelayCellFormat::V1,
665
            cgo::CryptStatePair<aes::Aes128Dec, aes::Aes128Enc>,// client
666
            cgo::CryptStatePair<aes::Aes128Enc, aes::Aes128Enc> // relay
667
        )
668
    }
669
    integration_tests! {
670
        cgo_aes256(RelayCellFormat::V1,
671
            cgo::CryptStatePair<aes::Aes256Dec, aes::Aes256Enc>,// client
672
            cgo::CryptStatePair<aes::Aes256Enc, aes::Aes256Enc> // relay
673
        )
674
    }
675
}