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
#[cfg(feature = "counter-galois-onion")]
36
pub(crate) mod cgo;
37
pub(crate) mod tor1;
38

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

            
47
use super::binding::CircuitBinding;
48

            
49
/// Type for the body of a relay cell.
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
4150
    fn as_mut(&mut self) -> &mut [u8] {
60
4150
        &mut self.0[..]
61
4150
    }
62
}
63

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

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

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

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

            
118
/// Represent a relay's view of the outbound crypto state on a given circuit.
119
#[allow(dead_code)]
120
pub(crate) trait OutboundRelayLayer {
121
    /// Decrypt a RelayCellBody that is moving towards the client.
122
    ///
123
    /// Return an authentication tag if it is addressed to us.
124
    fn decrypt_outbound(&mut self, cmd: ChanCmd, cell: &mut RelayCellBody) -> Option<SendmeTag>;
125
}
126

            
127
/// A client's view of the cryptographic state shared with a single relay on a
128
/// circuit, as used for outbound cells.
129
pub(crate) trait OutboundClientLayer {
130
    /// Prepare a RelayCellBody to be sent to the relay at this layer, and
131
    /// encrypt it.
132
    ///
133
    /// Return the authentication tag.
134
    fn originate_for(&mut self, cmd: ChanCmd, cell: &mut RelayCellBody) -> SendmeTag;
135
    /// Encrypt a RelayCellBody to be decrypted by this layer.
136
    fn encrypt_outbound(&mut self, cmd: ChanCmd, cell: &mut RelayCellBody);
137
}
138

            
139
/// A client's view of the crypto state shared with a single relay on a circuit,
140
/// as used for inbound cells.
141
pub(crate) trait InboundClientLayer {
142
    /// Decrypt a CellBody that passed through this layer.
143
    ///
144
    /// Return an authentication tag if this layer is the originator.
145
    fn decrypt_inbound(&mut self, cmd: ChanCmd, cell: &mut RelayCellBody) -> Option<SendmeTag>;
146
}
147

            
148
/// Type to store hop indices on a circuit.
149
///
150
/// Hop indices are zero-based: "0" denotes the first hop on the circuit.
151
#[derive(Copy, Clone, Eq, PartialEq, Debug, Deftly)]
152
#[derive_deftly(HasMemoryCost)]
153
pub struct HopNum(u8);
154

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

            
168
/// A helper for displaying [`HopNum`]s.
169
///
170
/// The [`Display`](std::fmt::Display) of this type displays the `HopNum` as a 1-based index
171
/// prefixed with the number sign (`#`). For example, the string representation of the first hop is
172
/// `"#1"`.
173
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
174
pub struct HopNumDisplay(HopNum);
175

            
176
impl std::fmt::Display for HopNumDisplay {
177
52
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
178
52
        let hop_num: u8 = self.0.into();
179
52

            
180
52
        write!(f, "#{}", hop_num + 1)
181
52
    }
182
}
183

            
184
impl From<HopNum> for u8 {
185
412
    fn from(hop: HopNum) -> u8 {
186
412
        hop.0
187
412
    }
188
}
189

            
190
impl From<u8> for HopNum {
191
12512
    fn from(v: u8) -> HopNum {
192
12512
        HopNum(v)
193
12512
    }
194
}
195

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

            
202
/// A client's view of the cryptographic state for an entire
203
/// constructed circuit, as used for sending cells.
204
pub(crate) struct OutboundClientCrypt {
205
    /// Vector of layers, one for each hop on the circuit, ordered from the
206
    /// closest hop to the farthest.
207
    layers: Vec<Box<dyn OutboundClientLayer + Send>>,
208
}
209

            
210
/// A client's view of the cryptographic state for an entire
211
/// constructed circuit, as used for receiving cells.
212
pub(crate) struct InboundClientCrypt {
213
    /// Vector of layers, one for each hop on the circuit, ordered from the
214
    /// closest hop to the farthest.
215
    layers: Vec<Box<dyn InboundClientLayer + Send>>,
216
}
217

            
218
impl OutboundClientCrypt {
219
    /// Return a new (empty) OutboundClientCrypt.
220
200
    pub(crate) fn new() -> Self {
221
200
        OutboundClientCrypt { layers: Vec::new() }
222
200
    }
223
    /// Prepare a cell body to sent away from the client.
224
    ///
225
    /// The cell is prepared for the `hop`th hop, and then encrypted with
226
    /// the appropriate keys.
227
    ///
228
    /// On success, returns a reference to tag that should be expected
229
    /// for an authenticated SENDME sent in response to this cell.
230
3874
    pub(crate) fn encrypt(
231
3874
        &mut self,
232
3874
        cmd: ChanCmd,
233
3874
        cell: &mut RelayCellBody,
234
3874
        hop: HopNum,
235
3874
    ) -> Result<SendmeTag> {
236
3874
        let hop: usize = hop.into();
237
3874
        if hop >= self.layers.len() {
238
2
            return Err(Error::NoSuchHop);
239
3872
        }
240
3872

            
241
3872
        let mut layers = self.layers.iter_mut().take(hop + 1).rev();
242
3872
        let first_layer = layers.next().ok_or(Error::NoSuchHop)?;
243
3872
        let tag = first_layer.originate_for(cmd, cell);
244
11358
        for layer in layers {
245
7486
            layer.encrypt_outbound(cmd, cell);
246
7486
        }
247
3872
        Ok(tag)
248
3874
    }
249

            
250
    /// Add a new layer to this OutboundClientCrypt
251
528
    pub(crate) fn add_layer(&mut self, layer: Box<dyn OutboundClientLayer + Send>) {
252
528
        assert!(self.layers.len() < u8::MAX as usize);
253
528
        self.layers.push(layer);
254
528
    }
255

            
256
    /// Return the number of layers configured on this OutboundClientCrypt.
257
50
    pub(crate) fn n_layers(&self) -> usize {
258
50
        self.layers.len()
259
50
    }
260
}
261

            
262
impl InboundClientCrypt {
263
    /// Return a new (empty) InboundClientCrypt.
264
172
    pub(crate) fn new() -> Self {
265
172
        InboundClientCrypt { layers: Vec::new() }
266
172
    }
267
    /// Decrypt an incoming cell that is coming to the client.
268
    ///
269
    /// On success, return which hop was the originator of the cell.
270
    // TODO(nickm): Use a real type for the tag, not just `&[u8]`.
271
1028
    pub(crate) fn decrypt(
272
1028
        &mut self,
273
1028
        cmd: ChanCmd,
274
1028
        cell: &mut RelayCellBody,
275
1028
    ) -> Result<(HopNum, SendmeTag)> {
276
2808
        for (hopnum, layer) in self.layers.iter_mut().enumerate() {
277
2808
            if let Some(tag) = layer.decrypt_inbound(cmd, cell) {
278
1026
                let hopnum = HopNum(u8::try_from(hopnum).expect("Somehow > 255 hops"));
279
1026
                return Ok((hopnum, tag));
280
1782
            }
281
        }
282
2
        Err(Error::BadCellAuth)
283
1028
    }
284
    /// Add a new layer to this InboundClientCrypt
285
444
    pub(crate) fn add_layer(&mut self, layer: Box<dyn InboundClientLayer + Send>) {
286
444
        assert!(self.layers.len() < u8::MAX as usize);
287
444
        self.layers.push(layer);
288
444
    }
289

            
290
    /// Return the number of layers configured on this InboundClientCrypt.
291
    ///
292
    /// TODO: use HopNum
293
    #[allow(dead_code)]
294
2
    pub(crate) fn n_layers(&self) -> usize {
295
2
        self.layers.len()
296
2
    }
297
}
298

            
299
/// Standard Tor relay crypto, as instantiated for RELAY cells.
300
pub(crate) type Tor1RelayCrypto =
301
    tor1::CryptStatePair<tor_llcrypto::cipher::aes::Aes128Ctr, tor_llcrypto::d::Sha1>;
302

            
303
/// Standard Tor relay crypto, as instantiated for the HSv3 protocol.
304
///
305
/// (The use of SHA3 is ridiculously overkill.)
306
#[cfg(feature = "hs-common")]
307
pub(crate) type Tor1Hsv3RelayCrypto =
308
    tor1::CryptStatePair<tor_llcrypto::cipher::aes::Aes256Ctr, tor_llcrypto::d::Sha3_256>;
309

            
310
#[cfg(test)]
311
mod test {
312
    // @@ begin test lint list maintained by maint/add_warning @@
313
    #![allow(clippy::bool_assert_comparison)]
314
    #![allow(clippy::clone_on_copy)]
315
    #![allow(clippy::dbg_macro)]
316
    #![allow(clippy::mixed_attributes_style)]
317
    #![allow(clippy::print_stderr)]
318
    #![allow(clippy::print_stdout)]
319
    #![allow(clippy::single_char_pattern)]
320
    #![allow(clippy::unwrap_used)]
321
    #![allow(clippy::unchecked_duration_subtraction)]
322
    #![allow(clippy::useless_vec)]
323
    #![allow(clippy::needless_pass_by_value)]
324
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
325

            
326
    use super::*;
327
    use rand::{seq::IndexedRandom as _, RngCore};
328
    use tor_basic_utils::{test_rng::testing_rng, RngExt as _};
329
    use tor_bytes::SecretBuf;
330
    use tor_cell::relaycell::RelayCellFormat;
331

            
332
    pub(crate) fn add_layers(
333
        cc_out: &mut OutboundClientCrypt,
334
        cc_in: &mut InboundClientCrypt,
335
        pair: Tor1RelayCrypto,
336
    ) {
337
        let (outbound, inbound, _) = pair.split_client_layer();
338
        cc_out.add_layer(Box::new(outbound));
339
        cc_in.add_layer(Box::new(inbound));
340
    }
341

            
342
    #[test]
343
    fn roundtrip() {
344
        // Take canned keys and make sure we can do crypto correctly.
345
        use crate::crypto::handshake::ShakeKeyGenerator as KGen;
346
        fn s(seed: &[u8]) -> SecretBuf {
347
            seed.to_vec().into()
348
        }
349

            
350
        let seed1 = s(b"hidden we are free");
351
        let seed2 = s(b"free to speak, to free ourselves");
352
        let seed3 = s(b"free to hide no more");
353

            
354
        let mut cc_out = OutboundClientCrypt::new();
355
        let mut cc_in = InboundClientCrypt::new();
356
        let pair = Tor1RelayCrypto::construct(KGen::new(seed1.clone())).unwrap();
357
        add_layers(&mut cc_out, &mut cc_in, pair);
358
        let pair = Tor1RelayCrypto::construct(KGen::new(seed2.clone())).unwrap();
359
        add_layers(&mut cc_out, &mut cc_in, pair);
360
        let pair = Tor1RelayCrypto::construct(KGen::new(seed3.clone())).unwrap();
361
        add_layers(&mut cc_out, &mut cc_in, pair);
362

            
363
        assert_eq!(cc_in.n_layers(), 3);
364
        assert_eq!(cc_out.n_layers(), 3);
365

            
366
        let (mut r1f, mut r1b, _) = Tor1RelayCrypto::construct(KGen::new(seed1))
367
            .unwrap()
368
            .split_relay_layer();
369
        let (mut r2f, mut r2b, _) = Tor1RelayCrypto::construct(KGen::new(seed2))
370
            .unwrap()
371
            .split_relay_layer();
372
        let (mut r3f, mut r3b, _) = Tor1RelayCrypto::construct(KGen::new(seed3))
373
            .unwrap()
374
            .split_relay_layer();
375
        let cmd = ChanCmd::RELAY;
376

            
377
        let mut rng = testing_rng();
378
        for _ in 1..300 {
379
            // outbound cell
380
            let mut cell = Box::new([0_u8; 509]);
381
            let mut cell_orig = [0_u8; 509];
382
            rng.fill_bytes(&mut cell_orig);
383
            cell.copy_from_slice(&cell_orig);
384
            let mut cell = cell.into();
385
            let _tag = cc_out.encrypt(cmd, &mut cell, 2.into()).unwrap();
386
            assert_ne!(&cell.as_ref()[9..], &cell_orig.as_ref()[9..]);
387
            assert!(r1f.decrypt_outbound(cmd, &mut cell).is_none());
388
            assert!(r2f.decrypt_outbound(cmd, &mut cell).is_none());
389
            assert!(r3f.decrypt_outbound(cmd, &mut cell).is_some());
390

            
391
            assert_eq!(&cell.as_ref()[9..], &cell_orig.as_ref()[9..]);
392

            
393
            // inbound cell
394
            let mut cell = Box::new([0_u8; 509]);
395
            let mut cell_orig = [0_u8; 509];
396
            rng.fill_bytes(&mut cell_orig);
397
            cell.copy_from_slice(&cell_orig);
398
            let mut cell = cell.into();
399

            
400
            r3b.originate(cmd, &mut cell);
401
            r2b.encrypt_inbound(cmd, &mut cell);
402
            r1b.encrypt_inbound(cmd, &mut cell);
403
            let (layer, _tag) = cc_in.decrypt(cmd, &mut cell).unwrap();
404
            assert_eq!(layer, 2.into());
405
            assert_eq!(&cell.as_ref()[9..], &cell_orig.as_ref()[9..]);
406

            
407
            // TODO: Test tag somehow.
408
        }
409

            
410
        // Try a failure: sending a cell to a nonexistent hop.
411
        {
412
            let mut cell = Box::new([0_u8; 509]).into();
413
            let err = cc_out.encrypt(cmd, &mut cell, 10.into());
414
            assert!(matches!(err, Err(Error::NoSuchHop)));
415
        }
416

            
417
        // Try a failure: A junk cell with no correct auth from any layer.
418
        {
419
            let mut cell = Box::new([0_u8; 509]).into();
420
            let err = cc_in.decrypt(cmd, &mut cell);
421
            assert!(matches!(err, Err(Error::BadCellAuth)));
422
        }
423
    }
424

            
425
    #[test]
426
    fn hop_num_display() {
427
        for i in 0..10 {
428
            let hop_num = HopNum::from(i);
429
            let expect = format!("#{}", i + 1);
430

            
431
            assert_eq!(expect, hop_num.display().to_string());
432
        }
433
    }
434

            
435
    /// Helper: Clear every field in the tor1 `cell` that is reserved for cryptography by relay cell
436
    /// format `version.
437
    ///
438
    /// We do this so that we can be sure that the _other_ fields have all been transmitted correctly.
439
    fn clean_cell_fields(cell: &mut RelayCellBody, format: RelayCellFormat) {
440
        use super::tor1;
441
        match format {
442
            RelayCellFormat::V0 => {
443
                cell.0[tor1::RECOGNIZED_RANGE].fill(0);
444
                cell.0[tor1::DIGEST_RANGE].fill(0);
445
            }
446
            RelayCellFormat::V1 => {
447
                cell.0[0..16].fill(0);
448
            }
449
            _ => {
450
                panic!("Unrecognized format!");
451
            }
452
        }
453
    }
454

            
455
    /// Helper: Test a single-hop message, forward from the client.
456
    fn test_fwd_one_hop<CS, RS, CF, CB, RF, RB>(format: RelayCellFormat)
457
    where
458
        CS: CryptInit + ClientLayer<CF, CB>,
459
        RS: CryptInit + RelayLayer<RF, RB>,
460
        CF: OutboundClientLayer,
461
        CB: InboundClientLayer,
462
        RF: OutboundRelayLayer,
463
        RB: InboundRelayLayer,
464
    {
465
        let mut rng = testing_rng();
466
        assert_eq!(CS::seed_len(), RS::seed_len());
467
        let mut seed = vec![0; CS::seed_len()];
468
        rng.fill_bytes(&mut seed[..]);
469
        let (mut client, _, _) = CS::initialize(&seed).unwrap().split_client_layer();
470
        let (mut relay, _, _) = RS::initialize(&seed).unwrap().split_relay_layer();
471

            
472
        for _ in 0..5 {
473
            let mut cell = RelayCellBody(Box::new([0_u8; 509]));
474
            rng.fill_bytes(&mut cell.0[..]);
475
            clean_cell_fields(&mut cell, format);
476
            let msg_orig = cell.clone();
477

            
478
            let ctag = client.originate_for(ChanCmd::RELAY, &mut cell);
479
            assert_ne!(cell.0[16..], msg_orig.0[16..]);
480
            let rtag = relay.decrypt_outbound(ChanCmd::RELAY, &mut cell);
481
            clean_cell_fields(&mut cell, format);
482
            assert_eq!(cell.0[..], msg_orig.0[..]);
483
            assert_eq!(rtag, Some(ctag));
484
        }
485
    }
486

            
487
    /// Helper: Test a single-hop message, backwards towards the client.
488
    fn test_rev_one_hop<CS, RS, CF, CB, RF, RB>(format: RelayCellFormat)
489
    where
490
        CS: CryptInit + ClientLayer<CF, CB>,
491
        RS: CryptInit + RelayLayer<RF, RB>,
492
        CF: OutboundClientLayer,
493
        CB: InboundClientLayer,
494
        RF: OutboundRelayLayer,
495
        RB: InboundRelayLayer,
496
    {
497
        let mut rng = testing_rng();
498
        assert_eq!(CS::seed_len(), RS::seed_len());
499
        let mut seed = vec![0; CS::seed_len()];
500
        rng.fill_bytes(&mut seed[..]);
501
        let (_, mut client, _) = CS::initialize(&seed).unwrap().split_client_layer();
502
        let (_, mut relay, _) = RS::initialize(&seed).unwrap().split_relay_layer();
503

            
504
        for _ in 0..5 {
505
            let mut cell = RelayCellBody(Box::new([0_u8; 509]));
506
            rng.fill_bytes(&mut cell.0[..]);
507
            clean_cell_fields(&mut cell, format);
508
            let msg_orig = cell.clone();
509

            
510
            let rtag = relay.originate(ChanCmd::RELAY, &mut cell);
511
            assert_ne!(cell.0[16..], msg_orig.0[16..]);
512
            let ctag = client.decrypt_inbound(ChanCmd::RELAY, &mut cell);
513
            clean_cell_fields(&mut cell, format);
514
            assert_eq!(cell.0[..], msg_orig.0[..]);
515
            assert_eq!(ctag, Some(rtag));
516
        }
517
    }
518

            
519
    fn test_fwd_three_hops_leaky<CS, RS, CF, CB, RF, RB>(format: RelayCellFormat)
520
    where
521
        CS: CryptInit + ClientLayer<CF, CB>,
522
        RS: CryptInit + RelayLayer<RF, RB>,
523
        CF: OutboundClientLayer + Send + 'static,
524
        CB: InboundClientLayer,
525
        RF: OutboundRelayLayer,
526
        RB: InboundRelayLayer,
527
    {
528
        let mut rng = testing_rng();
529
        assert_eq!(CS::seed_len(), RS::seed_len());
530
        let mut client = OutboundClientCrypt::new();
531
        let mut relays = Vec::new();
532
        for _ in 0..3 {
533
            let mut seed = vec![0; CS::seed_len()];
534
            rng.fill_bytes(&mut seed[..]);
535
            let (client_layer, _, _) = CS::initialize(&seed).unwrap().split_client_layer();
536
            let (relay_layer, _, _) = RS::initialize(&seed).unwrap().split_relay_layer();
537
            client.add_layer(Box::new(client_layer));
538
            relays.push(relay_layer);
539
        }
540

            
541
        'cell_loop: for _ in 0..32 {
542
            let mut cell = RelayCellBody(Box::new([0_u8; 509]));
543
            rng.fill_bytes(&mut cell.0[..]);
544
            clean_cell_fields(&mut cell, format);
545
            let msg_orig = cell.clone();
546
            let cmd = *[ChanCmd::RELAY, ChanCmd::RELAY_EARLY]
547
                .choose(&mut rng)
548
                .unwrap();
549
            let hop: u8 = rng.gen_range_checked(0_u8..=2).unwrap();
550

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

            
553
            for r_idx in 0..=hop {
554
                let rtag = relays[r_idx as usize].decrypt_outbound(cmd, &mut cell);
555
                if let Some(rtag) = rtag {
556
                    clean_cell_fields(&mut cell, format);
557
                    assert_eq!(cell.0[..], msg_orig.0[..]);
558
                    assert_eq!(rtag, ctag);
559
                    continue 'cell_loop;
560
                }
561
            }
562
            panic!("None of the relays thought that this cell was recognized!");
563
        }
564
    }
565

            
566
    fn test_rev_three_hops_leaky<CS, RS, CF, CB, RF, RB>(format: RelayCellFormat)
567
    where
568
        CS: CryptInit + ClientLayer<CF, CB>,
569
        RS: CryptInit + RelayLayer<RF, RB>,
570
        CF: OutboundClientLayer,
571
        CB: InboundClientLayer + Send + 'static,
572
        RF: OutboundRelayLayer,
573
        RB: InboundRelayLayer,
574
    {
575
        let mut rng = testing_rng();
576
        assert_eq!(CS::seed_len(), RS::seed_len());
577
        let mut client = InboundClientCrypt::new();
578
        let mut relays = Vec::new();
579
        for _ in 0..3 {
580
            let mut seed = vec![0; CS::seed_len()];
581
            rng.fill_bytes(&mut seed[..]);
582
            let (_, client_layer, _) = CS::initialize(&seed).unwrap().split_client_layer();
583
            let (_, relay_layer, _) = RS::initialize(&seed).unwrap().split_relay_layer();
584
            client.add_layer(Box::new(client_layer));
585
            relays.push(relay_layer);
586
        }
587

            
588
        for _ in 0..32 {
589
            let mut cell = RelayCellBody(Box::new([0_u8; 509]));
590
            rng.fill_bytes(&mut cell.0[..]);
591
            clean_cell_fields(&mut cell, format);
592
            let msg_orig = cell.clone();
593
            let cmd = *[ChanCmd::RELAY, ChanCmd::RELAY_EARLY]
594
                .choose(&mut rng)
595
                .unwrap();
596
            let hop: u8 = rng.gen_range_checked(0_u8..=2).unwrap();
597

            
598
            let rtag = relays[hop as usize].originate(cmd, &mut cell);
599
            for r_idx in (0..hop.into()).rev() {
600
                relays[r_idx as usize].encrypt_inbound(cmd, &mut cell);
601
            }
602

            
603
            let (observed_hop, ctag) = client.decrypt(cmd, &mut cell).unwrap();
604
            assert_eq!(observed_hop, hop.into());
605
            clean_cell_fields(&mut cell, format);
606
            assert_eq!(cell.0[..], msg_orig.0[..]);
607
            assert_eq!(ctag, rtag);
608
        }
609
    }
610

            
611
    macro_rules! integration_tests { { $modname:ident($fmt:expr, $ctype:ty, $rtype:ty) } => {
612
        mod $modname {
613
            use super::*;
614
            #[test]
615
            fn test_fwd_one_hop() {
616
                super::test_fwd_one_hop::<$ctype, $rtype, _, _, _, _>($fmt);
617
            }
618
            #[test]
619
            fn test_rev_one_hop() {
620
                super::test_rev_one_hop::<$ctype, $rtype, _, _, _, _>($fmt);
621
            }
622
            #[test]
623
            fn test_fwd_three_hops_leaky() {
624
                super::test_fwd_three_hops_leaky::<$ctype, $rtype, _, _, _, _>($fmt);
625
            }
626
            #[test]
627
            fn test_rev_three_hops_leaky() {
628
                super::test_rev_three_hops_leaky::<$ctype, $rtype, _, _, _, _>($fmt);
629
            }
630
        }
631
    }}
632

            
633
    integration_tests! { tor1(RelayCellFormat::V0, Tor1RelayCrypto, Tor1RelayCrypto) }
634
    #[cfg(feature = "hs-common")]
635
    integration_tests! { tor1_hs(RelayCellFormat::V0, Tor1Hsv3RelayCrypto, Tor1Hsv3RelayCrypto) }
636

            
637
    #[cfg(feature = "counter-galois-onion")]
638
    integration_tests! {
639
        cgo_aes128(RelayCellFormat::V1,
640
            cgo::CryptStatePair<aes::Aes128Dec, aes::Aes128Enc>,// client
641
            cgo::CryptStatePair<aes::Aes128Enc, aes::Aes128Enc> // relay
642
        )
643
    }
644
    #[cfg(feature = "counter-galois-onion")]
645
    integration_tests! {
646
        cgo_aes256(RelayCellFormat::V1,
647
            cgo::CryptStatePair<aes::Aes256Dec, aes::Aes256Enc>,// client
648
            cgo::CryptStatePair<aes::Aes256Enc, aes::Aes256Enc> // relay
649
        )
650
    }
651
}