tor_proto/crypto/handshake/
ntor_v3.rs

1//! Implements the ntor v3 key exchange, as described in proposal 332.
2//!
3//! The main difference between the ntor v3r handshake and the
4//! original ntor handshake is that this this one allows each party to
5//! encrypt data (without forward secrecy) after it sends the first
6//! message.
7
8// TODO:
9//    Remove the "allow" item for dead_code.
10//    Make terminology and variable names consistent with spec.
11
12// This module is still unused: so allow some dead code for now.
13#![allow(dead_code)]
14
15use std::borrow::Borrow;
16
17use super::{RelayHandshakeError, RelayHandshakeResult};
18use crate::util::ct;
19use crate::{Error, Result};
20use tor_bytes::{EncodeResult, Reader, SecretBuf, Writeable, Writer};
21use tor_error::into_internal;
22use tor_llcrypto::d::{Sha3_256, Shake256, Shake256Reader};
23use tor_llcrypto::pk::{curve25519, ed25519::Ed25519Identity};
24use tor_llcrypto::util::ct::ct_lookup;
25
26use cipher::{KeyIvInit, StreamCipher};
27
28use crate::crypto::handshake::KeyGenerator;
29use rand_core::{CryptoRng, RngCore};
30use subtle::{Choice, ConstantTimeEq};
31use tor_cell::relaycell::extend::{CircRequestExt, CircResponseExt};
32use tor_llcrypto::cipher::aes::Aes256Ctr;
33use zeroize::Zeroizing;
34
35/// The verification string to be used for circuit extension.
36const NTOR3_CIRC_VERIFICATION: &[u8] = b"circuit extend";
37
38/// The size of an encryption key in bytes.
39const ENC_KEY_LEN: usize = 32;
40/// The size of a MAC key in bytes.
41const MAC_KEY_LEN: usize = 32;
42/// The size of a curve25519 public key in bytes.
43const PUB_KEY_LEN: usize = 32;
44/// The size of a digest output in bytes.
45const DIGEST_LEN: usize = 32;
46/// The length of a MAC output in bytes.
47const MAC_LEN: usize = 32;
48/// The length of a node identity in bytes.
49const ID_LEN: usize = 32;
50
51/// The output of the digest, as an array.
52type DigestVal = [u8; DIGEST_LEN];
53/// The output of the MAC.
54type MacVal = [u8; MAC_LEN];
55/// A key for symmetric encryption or decryption.
56//
57// TODO (nickm): Any move operations applied to this key could subvert the zeroizing.
58type EncKey = Zeroizing<[u8; ENC_KEY_LEN]>;
59/// A key for message authentication codes.
60type MacKey = [u8; MAC_KEY_LEN];
61
62/// Opaque wrapper type for NtorV3's hash reader.
63struct NtorV3XofReader(Shake256Reader);
64
65impl digest::XofReader for NtorV3XofReader {
66    fn read(&mut self, buffer: &mut [u8]) {
67        self.0.read(buffer);
68    }
69}
70
71/// An encapsulated value for passing as input to a MAC, digest, or
72/// KDF algorithm.
73///
74/// This corresponds to the ENCAP() function in proposal 332.
75struct Encap<'a>(&'a [u8]);
76
77impl<'a> Writeable for Encap<'a> {
78    fn write_onto<B: Writer + ?Sized>(&self, b: &mut B) -> EncodeResult<()> {
79        b.write_u64(self.0.len() as u64);
80        b.write(self.0)
81    }
82}
83
84impl<'a> Encap<'a> {
85    /// Return the length of the underlying data in bytes.
86    fn len(&self) -> usize {
87        self.0.len()
88    }
89    /// Return the underlying data
90    fn data(&self) -> &'a [u8] {
91        self.0
92    }
93}
94
95/// Helper to define a set of tweak values as instances of `Encap`.
96macro_rules! define_tweaks {
97    {
98        $(#[$pid_meta:meta])*
99        PROTOID = $protoid:expr;
100        $( $(#[$meta:meta])* $name:ident <= $suffix:expr ; )*
101    } => {
102        $(#[$pid_meta])*
103        const PROTOID: &'static [u8] = $protoid.as_bytes();
104        $(
105            $(#[$meta])*
106            const $name : Encap<'static> =
107                Encap(concat!($protoid, ":", $suffix).as_bytes());
108        )*
109    }
110}
111
112define_tweaks! {
113    /// Protocol ID: concatenated with other things in the protocol to
114    /// prevent hash confusion.
115    PROTOID =  "ntor3-curve25519-sha3_256-1";
116
117    /// Message MAC tweak: used to compute the MAC of an encrypted client
118    /// message.
119    T_MSGMAC <= "msg_mac";
120    /// Message KDF tweak: used when deriving keys for encrypting and MACing
121    /// client message.
122    T_MSGKDF <= "kdf_phase1";
123    /// Key seeding tweak: used to derive final KDF input from secret_input.
124    T_KEY_SEED <= "key_seed";
125    /// Verifying tweak: used to derive 'verify' value from secret_input.
126    T_VERIFY <= "verify";
127    /// Final KDF tweak: used to derive keys for encrypting relay message
128    /// and for the actual tor circuit.
129    T_FINAL <= "kdf_final";
130    /// Authentication tweak: used to derive the final authentication
131    /// value for the handshake.
132    T_AUTH <= "auth_final";
133}
134
135/// Compute a tweaked hash.
136fn hash(t: &Encap<'_>, data: &[u8]) -> DigestVal {
137    use digest::Digest;
138    let mut d = Sha3_256::new();
139    d.update((t.len() as u64).to_be_bytes());
140    d.update(t.data());
141    d.update(data);
142    d.finalize().into()
143}
144
145/// Perform a symmetric encryption operation and return the encrypted data.
146///
147/// (This isn't safe to do more than once with the same key, but we never
148/// do that in this protocol.)
149fn encrypt(key: &EncKey, m: &[u8]) -> Vec<u8> {
150    let mut d = m.to_vec();
151    let zero_iv = Default::default();
152    let mut cipher = Aes256Ctr::new(key.as_ref().into(), &zero_iv);
153    cipher.apply_keystream(&mut d);
154    d
155}
156/// Perform a symmetric decryption operation and return the encrypted data.
157fn decrypt(key: &EncKey, m: &[u8]) -> Vec<u8> {
158    encrypt(key, m)
159}
160
161/// Wrapper around a Digest or ExtendedOutput object that lets us use it
162/// as a tor_bytes::Writer.
163struct DigestWriter<U>(U);
164impl<U: digest::Update> tor_bytes::Writer for DigestWriter<U> {
165    fn write_all(&mut self, bytes: &[u8]) {
166        self.0.update(bytes);
167    }
168}
169impl<U> DigestWriter<U> {
170    /// Consume this wrapper and return the underlying object.
171    fn take(self) -> U {
172        self.0
173    }
174}
175
176/// Hash tweaked with T_KEY_SEED
177fn h_key_seed(d: &[u8]) -> DigestVal {
178    hash(&T_KEY_SEED, d)
179}
180/// Hash tweaked with T_VERIFY
181fn h_verify(d: &[u8]) -> DigestVal {
182    hash(&T_VERIFY, d)
183}
184
185/// Helper: compute the encryption key and mac_key for the client's
186/// encrypted message.
187///
188/// Takes as inputs `xb` (the shared secret derived from
189/// diffie-hellman as Bx or Xb), the relay's public key information,
190/// the client's public key (B), and the shared verification string.
191fn kdf_msgkdf(
192    xb: &curve25519::SharedSecret,
193    relay_public: &NtorV3PublicKey,
194    client_public: &curve25519::PublicKey,
195    verification: &[u8],
196) -> EncodeResult<(EncKey, DigestWriter<Sha3_256>)> {
197    // secret_input_phase1 = Bx | ID | X | B | PROTOID | ENCAP(VER)
198    // phase1_keys = KDF_msgkdf(secret_input_phase1)
199    // (ENC_K1, MAC_K1) = PARTITION(phase1_keys, ENC_KEY_LEN, MAC_KEY_LEN
200    use digest::{ExtendableOutput, XofReader};
201    let mut msg_kdf = DigestWriter(Shake256::default());
202    msg_kdf.write(&T_MSGKDF)?;
203    msg_kdf.write(xb)?;
204    msg_kdf.write(&relay_public.id)?;
205    msg_kdf.write(client_public)?;
206    msg_kdf.write(&relay_public.pk)?;
207    msg_kdf.write(PROTOID)?;
208    msg_kdf.write(&Encap(verification))?;
209    let mut r = msg_kdf.take().finalize_xof();
210    let mut enc_key = Zeroizing::new([0; ENC_KEY_LEN]);
211    let mut mac_key = Zeroizing::new([0; MAC_KEY_LEN]);
212
213    r.read(&mut enc_key[..]);
214    r.read(&mut mac_key[..]);
215    let mut mac = DigestWriter(Sha3_256::default());
216    {
217        mac.write(&T_MSGMAC)?;
218        mac.write(&Encap(&mac_key[..]))?;
219        mac.write(&relay_public.id)?;
220        mac.write(&relay_public.pk)?;
221        mac.write(client_public)?;
222    }
223
224    Ok((enc_key, mac))
225}
226
227/// Client side of the ntor v3 handshake.
228pub(crate) struct NtorV3Client;
229
230impl super::ClientHandshake for NtorV3Client {
231    type KeyType = NtorV3PublicKey;
232    type StateType = NtorV3HandshakeState;
233    type KeyGen = NtorV3KeyGenerator;
234    type ClientAuxData = [CircRequestExt];
235    type ServerAuxData = Vec<CircResponseExt>;
236
237    /// Generate a new client onionskin for a relay with a given onion key.
238    /// If any `extensions` are provided, encode them into to the onionskin.
239    ///
240    /// On success, return a state object that will be used to complete the handshake, along
241    /// with the message to send.
242    fn client1<R: RngCore + CryptoRng, M: Borrow<[CircRequestExt]>>(
243        rng: &mut R,
244        key: &NtorV3PublicKey,
245        extensions: &M,
246    ) -> Result<(Self::StateType, Vec<u8>)> {
247        let mut message = Vec::new();
248        CircRequestExt::write_many_onto(extensions.borrow(), &mut message)
249            .map_err(|e| Error::from_bytes_enc(e, "ntor3 handshake extensions"))?;
250        Ok(
251            client_handshake_ntor_v3(rng, key, &message, NTOR3_CIRC_VERIFICATION)
252                .map_err(into_internal!("Can't encode ntor3 client handshake."))?,
253        )
254    }
255
256    /// Handle an onionskin from a relay, and produce a key generator.
257    ///
258    /// The state object must match the one that was used to make the
259    /// client onionskin that the server is replying to.
260    fn client2<T: AsRef<[u8]>>(
261        state: Self::StateType,
262        msg: T,
263    ) -> Result<(Vec<CircResponseExt>, Self::KeyGen)> {
264        let (message, xofreader) =
265            client_handshake_ntor_v3_part2(&state, msg.as_ref(), NTOR3_CIRC_VERIFICATION)?;
266        let extensions = CircResponseExt::decode(&message).map_err(|err| Error::CellDecodeErr {
267            object: "ntor v3 extensions",
268            err,
269        })?;
270        let keygen = NtorV3KeyGenerator { reader: xofreader };
271
272        Ok((extensions, keygen))
273    }
274}
275
276/// Server side of the ntor v3 handshake.
277pub(crate) struct NtorV3Server;
278
279impl super::ServerHandshake for NtorV3Server {
280    type KeyType = NtorV3SecretKey;
281    type KeyGen = NtorV3KeyGenerator;
282    type ClientAuxData = [CircRequestExt];
283    type ServerAuxData = Vec<CircResponseExt>;
284
285    fn server<R: RngCore + CryptoRng, REPLY: super::AuxDataReply<Self>, T: AsRef<[u8]>>(
286        rng: &mut R,
287        reply_fn: &mut REPLY,
288        key: &[Self::KeyType],
289        msg: T,
290    ) -> RelayHandshakeResult<(Self::KeyGen, Vec<u8>)> {
291        let mut bytes_reply_fn = |bytes: &[u8]| -> Option<Vec<u8>> {
292            let client_exts = CircRequestExt::decode(bytes).ok()?;
293            let reply_exts = reply_fn.reply(&client_exts)?;
294            let mut out = vec![];
295            CircResponseExt::write_many_onto(&reply_exts, &mut out).ok()?;
296            Some(out)
297        };
298
299        let (res, reader) = server_handshake_ntor_v3(
300            rng,
301            &mut bytes_reply_fn,
302            msg.as_ref(),
303            key,
304            NTOR3_CIRC_VERIFICATION,
305        )?;
306        Ok((NtorV3KeyGenerator { reader }, res))
307    }
308}
309
310/// Key information about a relay used for the ntor v3 handshake.
311///
312/// Contains a single curve25519 ntor onion key, and the relay's ed25519
313/// identity.
314#[derive(Clone, Debug)]
315pub(crate) struct NtorV3PublicKey {
316    /// The relay's identity.
317    pub(crate) id: Ed25519Identity,
318    /// The relay's onion key.
319    pub(crate) pk: curve25519::PublicKey,
320}
321
322/// Secret key information used by a relay for the ntor v3 handshake.
323pub(crate) struct NtorV3SecretKey {
324    /// The relay's public key information
325    pk: NtorV3PublicKey,
326    /// The secret onion key.
327    sk: curve25519::StaticSecret,
328}
329
330impl NtorV3SecretKey {
331    /// Construct a new NtorV3SecretKey from its components.
332    #[allow(unused)]
333    pub(crate) fn new(
334        sk: curve25519::StaticSecret,
335        pk: curve25519::PublicKey,
336        id: Ed25519Identity,
337    ) -> Self {
338        Self {
339            pk: NtorV3PublicKey { id, pk },
340            sk,
341        }
342    }
343
344    /// Generate a key using the given `rng`, suitable for testing.
345    #[cfg(test)]
346    pub(crate) fn generate_for_test<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
347        let mut id = [0_u8; 32];
348        // Random bytes will work for testing, but aren't necessarily actually a valid id.
349        rng.fill_bytes(&mut id);
350
351        let sk = curve25519::StaticSecret::random_from_rng(rng);
352
353        let pk = NtorV3PublicKey {
354            pk: (&sk).into(),
355            id: id.into(),
356        };
357        Self { pk, sk }
358    }
359
360    /// Checks whether `id` and `pk` match this secret key.
361    ///
362    /// Used to perform a constant-time secret key lookup.
363    fn matches(&self, id: Ed25519Identity, pk: curve25519::PublicKey) -> Choice {
364        // TODO: use similar pattern in ntor_v1!
365        id.as_bytes().ct_eq(self.pk.id.as_bytes()) & pk.as_bytes().ct_eq(self.pk.pk.as_bytes())
366    }
367}
368
369/// Client state for the ntor v3 handshake.
370///
371/// The client needs to hold this state between when it sends its part
372/// of the handshake and when it receives the relay's reply.
373pub(crate) struct NtorV3HandshakeState {
374    /// The public key of the relay we're communicating with.
375    relay_public: NtorV3PublicKey, // B, ID.
376    /// Our ephemeral secret key for this handshake.
377    my_sk: curve25519::StaticSecret, // x
378    /// Our ephemeral public key for this handshake.
379    my_public: curve25519::PublicKey, // X
380
381    /// The shared secret generated as Bx or Xb.
382    shared_secret: curve25519::SharedSecret, // Bx
383    /// The MAC of our original encrypted message.
384    msg_mac: MacVal, // msg_mac
385}
386
387/// A key generator returned from an ntor v3 handshake.
388pub(crate) struct NtorV3KeyGenerator {
389    /// The underlying `digest::XofReader`.
390    reader: NtorV3XofReader,
391}
392
393impl KeyGenerator for NtorV3KeyGenerator {
394    fn expand(mut self, keylen: usize) -> Result<SecretBuf> {
395        use digest::XofReader;
396        let mut ret: SecretBuf = vec![0; keylen].into();
397        self.reader.read(ret.as_mut());
398        Ok(ret)
399    }
400}
401
402/// Client-side Ntor version 3 handshake, part one.
403///
404/// Given a secure `rng`, a relay's public key, a secret message to send,
405/// and a shared verification string, generate a new handshake state
406/// and a message to send to the relay.
407fn client_handshake_ntor_v3<R: RngCore + CryptoRng>(
408    rng: &mut R,
409    relay_public: &NtorV3PublicKey,
410    client_msg: &[u8],
411    verification: &[u8],
412) -> EncodeResult<(NtorV3HandshakeState, Vec<u8>)> {
413    let my_sk = curve25519::StaticSecret::random_from_rng(rng);
414    client_handshake_ntor_v3_no_keygen(relay_public, client_msg, verification, my_sk)
415}
416
417/// As `client_handshake_ntor_v3`, but don't generate an ephemeral DH
418/// key: instead take that key an arguments `my_sk`.
419fn client_handshake_ntor_v3_no_keygen(
420    relay_public: &NtorV3PublicKey,
421    client_msg: &[u8],
422    verification: &[u8],
423    my_sk: curve25519::StaticSecret,
424) -> EncodeResult<(NtorV3HandshakeState, Vec<u8>)> {
425    let my_public = curve25519::PublicKey::from(&my_sk);
426    let bx = my_sk.diffie_hellman(&relay_public.pk);
427
428    let (enc_key, mut mac) = kdf_msgkdf(&bx, relay_public, &my_public, verification)?;
429
430    //encrypted_msg = ENC(ENC_K1, CM)
431    // msg_mac = MAC_msgmac(MAC_K1, ID | B | X | encrypted_msg)
432    let encrypted_msg = encrypt(&enc_key, client_msg);
433    let msg_mac: DigestVal = {
434        use digest::Digest;
435        mac.write(&encrypted_msg)?;
436        mac.take().finalize().into()
437    };
438
439    let mut message = Vec::new();
440    message.write(&relay_public.id)?;
441    message.write(&relay_public.pk)?;
442    message.write(&my_public)?;
443    message.write(&encrypted_msg)?;
444    message.write(&msg_mac)?;
445
446    let state = NtorV3HandshakeState {
447        relay_public: relay_public.clone(),
448        my_sk,
449        my_public,
450        shared_secret: bx,
451        msg_mac,
452    };
453
454    Ok((state, message))
455}
456
457/// Trait for an object that handle and incoming client message and
458/// return a server's reply.
459///
460/// This is implemented for `FnMut(&[u8]) -> Option<Vec<u8>>` automatically.
461pub(crate) trait MsgReply {
462    /// Given a message received from a client, parse it and decide
463    /// how (and whether) to reply.
464    ///
465    /// Return None if the handshake should fail.
466    fn reply(&mut self, msg: &[u8]) -> Option<Vec<u8>>;
467}
468
469impl<F> MsgReply for F
470where
471    F: FnMut(&[u8]) -> Option<Vec<u8>>,
472{
473    fn reply(&mut self, msg: &[u8]) -> Option<Vec<u8>> {
474        self(msg)
475    }
476}
477
478/// Complete an ntor v3 handshake as a server.
479///
480/// Use the provided `rng` to generate keys; use the provided
481/// `reply_fn` to handle incoming client secret message and decide how
482/// to reply.  The client's handshake is in `message`.  Our private
483/// key(s) are in `keys`.  The `verification` string must match the
484/// string provided by the client.
485///
486/// On success, return the server handshake message to send, and an XofReader
487/// to use in generating circuit keys.
488fn server_handshake_ntor_v3<RNG: CryptoRng + RngCore, REPLY: MsgReply>(
489    rng: &mut RNG,
490    reply_fn: &mut REPLY,
491    message: &[u8],
492    keys: &[NtorV3SecretKey],
493    verification: &[u8],
494) -> RelayHandshakeResult<(Vec<u8>, NtorV3XofReader)> {
495    let secret_key_y = curve25519::StaticSecret::random_from_rng(rng);
496    server_handshake_ntor_v3_no_keygen(reply_fn, &secret_key_y, message, keys, verification)
497}
498
499/// As `server_handshake_ntor_v3`, but take a secret key instead of an RNG.
500fn server_handshake_ntor_v3_no_keygen<REPLY: MsgReply>(
501    reply_fn: &mut REPLY,
502    secret_key_y: &curve25519::StaticSecret,
503    message: &[u8],
504    keys: &[NtorV3SecretKey],
505    verification: &[u8],
506) -> RelayHandshakeResult<(Vec<u8>, NtorV3XofReader)> {
507    // Decode the message.
508    let mut r = Reader::from_slice(message);
509    let id: Ed25519Identity = r.extract()?;
510    let requested_pk: curve25519::PublicKey = r.extract()?;
511    let client_pk: curve25519::PublicKey = r.extract()?;
512    let client_msg = r.take_all_but(MAC_LEN)?;
513    let msg_mac: MacVal = r.extract()?;
514    r.should_be_exhausted()?;
515
516    // See if we recognize the provided (id,requested_pk) pair.
517    let keypair = ct_lookup(keys, |key| key.matches(id, requested_pk));
518    let keypair = match keypair {
519        Some(k) => k,
520        None => return Err(RelayHandshakeError::MissingKey),
521    };
522
523    let xb = keypair.sk.diffie_hellman(&client_pk);
524    let (enc_key, mut mac) = kdf_msgkdf(&xb, &keypair.pk, &client_pk, verification)
525        .map_err(into_internal!("Can't apply ntor3 kdf."))?;
526    // Verify the message we received.
527    let computed_mac: DigestVal = {
528        use digest::Digest;
529        mac.write(client_msg)
530            .map_err(into_internal!("Can't compute MAC input."))?;
531        mac.take().finalize().into()
532    };
533    let y_pk: curve25519::PublicKey = (secret_key_y).into();
534    let xy = secret_key_y.diffie_hellman(&client_pk);
535
536    let mut okay = computed_mac.ct_eq(&msg_mac)
537        & ct::bool_to_choice(xy.was_contributory())
538        & ct::bool_to_choice(xb.was_contributory());
539
540    let plaintext_msg = decrypt(&enc_key, client_msg);
541
542    // Handle the message and decide how to reply.
543    let reply = reply_fn.reply(&plaintext_msg);
544
545    // It's not exactly constant time to use is_some() and
546    // unwrap_or_else() here, but that should be somewhat
547    // hidden by the rest of the computation.
548    okay &= ct::bool_to_choice(reply.is_some());
549    let reply = reply.unwrap_or_default();
550
551    // If we reach this point, we are actually replying, or pretending
552    // that we're going to reply.
553
554    let secret_input = {
555        let mut si = SecretBuf::new();
556        si.write(&xy)
557            .and_then(|_| si.write(&xb))
558            .and_then(|_| si.write(&keypair.pk.id))
559            .and_then(|_| si.write(&keypair.pk.pk))
560            .and_then(|_| si.write(&client_pk))
561            .and_then(|_| si.write(&y_pk))
562            .and_then(|_| si.write(PROTOID))
563            .and_then(|_| si.write(&Encap(verification)))
564            .map_err(into_internal!("can't derive ntor3 secret_input"))?;
565        si
566    };
567    let ntor_key_seed = h_key_seed(&secret_input);
568    let verify = h_verify(&secret_input);
569
570    let (enc_key, keystream) = {
571        use digest::{ExtendableOutput, XofReader};
572        let mut xof = DigestWriter(Shake256::default());
573        xof.write(&T_FINAL)
574            .and_then(|_| xof.write(&ntor_key_seed))
575            .map_err(into_internal!("can't generate ntor3 xof."))?;
576        let mut r = xof.take().finalize_xof();
577        let mut enc_key = Zeroizing::new([0_u8; ENC_KEY_LEN]);
578        r.read(&mut enc_key[..]);
579        (enc_key, r)
580    };
581    let encrypted_reply = encrypt(&enc_key, &reply);
582    let auth: DigestVal = {
583        use digest::Digest;
584        let mut auth = DigestWriter(Sha3_256::default());
585        auth.write(&T_AUTH)
586            .and_then(|_| auth.write(&verify))
587            .and_then(|_| auth.write(&keypair.pk.id))
588            .and_then(|_| auth.write(&keypair.pk.pk))
589            .and_then(|_| auth.write(&y_pk))
590            .and_then(|_| auth.write(&client_pk))
591            .and_then(|_| auth.write(&msg_mac))
592            .and_then(|_| auth.write(&Encap(&encrypted_reply)))
593            .and_then(|_| auth.write(PROTOID))
594            .and_then(|_| auth.write(&b"Server"[..]))
595            .map_err(into_internal!("can't derive ntor3 authentication"))?;
596        auth.take().finalize().into()
597    };
598
599    let reply = {
600        let mut reply = Vec::new();
601        reply
602            .write(&y_pk)
603            .and_then(|_| reply.write(&auth))
604            .and_then(|_| reply.write(&encrypted_reply))
605            .map_err(into_internal!("can't encode ntor3 reply."))?;
606        reply
607    };
608
609    if okay.into() {
610        Ok((reply, NtorV3XofReader(keystream)))
611    } else {
612        Err(RelayHandshakeError::BadClientHandshake)
613    }
614}
615
616/// Finalize the handshake on the client side.
617///
618/// Called after we've received a message from the relay: try to
619/// complete the handshake and verify its correctness.
620///
621/// On success, return the server's reply to our original encrypted message,
622/// and an `XofReader` to use in generating circuit keys.
623fn client_handshake_ntor_v3_part2(
624    state: &NtorV3HandshakeState,
625    relay_handshake: &[u8],
626    verification: &[u8],
627) -> Result<(Vec<u8>, NtorV3XofReader)> {
628    let mut reader = Reader::from_slice(relay_handshake);
629    let y_pk: curve25519::PublicKey = reader
630        .extract()
631        .map_err(|e| Error::from_bytes_err(e, "v3 ntor handshake"))?;
632    let auth: DigestVal = reader
633        .extract()
634        .map_err(|e| Error::from_bytes_err(e, "v3 ntor handshake"))?;
635    let encrypted_msg = reader.into_rest();
636
637    // TODO: Some of this code is duplicated from the server handshake code!  It
638    // would be better to factor it out.
639    let yx = state.my_sk.diffie_hellman(&y_pk);
640    let secret_input = {
641        let mut si = SecretBuf::new();
642        si.write(&yx)
643            .and_then(|_| si.write(&state.shared_secret))
644            .and_then(|_| si.write(&state.relay_public.id))
645            .and_then(|_| si.write(&state.relay_public.pk))
646            .and_then(|_| si.write(&state.my_public))
647            .and_then(|_| si.write(&y_pk))
648            .and_then(|_| si.write(PROTOID))
649            .and_then(|_| si.write(&Encap(verification)))
650            .map_err(into_internal!("error encoding ntor3 secret_input"))?;
651        si
652    };
653    let ntor_key_seed = h_key_seed(&secret_input);
654    let verify = h_verify(&secret_input);
655
656    let computed_auth: DigestVal = {
657        use digest::Digest;
658        let mut auth = DigestWriter(Sha3_256::default());
659        auth.write(&T_AUTH)
660            .and_then(|_| auth.write(&verify))
661            .and_then(|_| auth.write(&state.relay_public.id))
662            .and_then(|_| auth.write(&state.relay_public.pk))
663            .and_then(|_| auth.write(&y_pk))
664            .and_then(|_| auth.write(&state.my_public))
665            .and_then(|_| auth.write(&state.msg_mac))
666            .and_then(|_| auth.write(&Encap(encrypted_msg)))
667            .and_then(|_| auth.write(PROTOID))
668            .and_then(|_| auth.write(&b"Server"[..]))
669            .map_err(into_internal!("error encoding ntor3 authentication input"))?;
670        auth.take().finalize().into()
671    };
672
673    let okay = computed_auth.ct_eq(&auth)
674        & ct::bool_to_choice(yx.was_contributory())
675        & ct::bool_to_choice(state.shared_secret.was_contributory());
676
677    let (enc_key, keystream) = {
678        use digest::{ExtendableOutput, XofReader};
679        let mut xof = DigestWriter(Shake256::default());
680        xof.write(&T_FINAL)
681            .and_then(|_| xof.write(&ntor_key_seed))
682            .map_err(into_internal!("error encoding ntor3 xof input"))?;
683        let mut r = xof.take().finalize_xof();
684        let mut enc_key = Zeroizing::new([0_u8; ENC_KEY_LEN]);
685        r.read(&mut enc_key[..]);
686        (enc_key, r)
687    };
688    let server_reply = decrypt(&enc_key, encrypted_msg);
689
690    if okay.into() {
691        Ok((server_reply, NtorV3XofReader(keystream)))
692    } else {
693        Err(Error::BadCircHandshakeAuth)
694    }
695}
696
697#[cfg(test)]
698#[allow(non_snake_case)] // to enable variable names matching the spec.
699#[allow(clippy::many_single_char_names)] // ibid
700mod test {
701    // @@ begin test lint list maintained by maint/add_warning @@
702    #![allow(clippy::bool_assert_comparison)]
703    #![allow(clippy::clone_on_copy)]
704    #![allow(clippy::dbg_macro)]
705    #![allow(clippy::mixed_attributes_style)]
706    #![allow(clippy::print_stderr)]
707    #![allow(clippy::print_stdout)]
708    #![allow(clippy::single_char_pattern)]
709    #![allow(clippy::unwrap_used)]
710    #![allow(clippy::unchecked_duration_subtraction)]
711    #![allow(clippy::useless_vec)]
712    #![allow(clippy::needless_pass_by_value)]
713    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
714    use crate::crypto::handshake::{ClientHandshake, ServerHandshake};
715
716    use super::*;
717    use hex_literal::hex;
718    use tor_basic_utils::test_rng::testing_rng;
719    use tor_cell::relaycell::extend::{CcRequest, CcResponse, CircResponseExt};
720
721    #[test]
722    fn test_ntor3_roundtrip() {
723        let mut rng = rand::rng();
724        let relay_private = NtorV3SecretKey::generate_for_test(&mut testing_rng());
725
726        let verification = &b"shared secret"[..];
727        let client_message = &b"Hello. I am a client. Let's be friends!"[..];
728        let relay_message = &b"Greetings, client. I am a robot. Beep boop."[..];
729
730        let (c_state, c_handshake) =
731            client_handshake_ntor_v3(&mut rng, &relay_private.pk, client_message, verification)
732                .unwrap();
733
734        struct Rep(Vec<u8>, Vec<u8>);
735        impl MsgReply for Rep {
736            fn reply(&mut self, msg: &[u8]) -> Option<Vec<u8>> {
737                self.0 = msg.to_vec();
738                Some(self.1.clone())
739            }
740        }
741        let mut rep = Rep(Vec::new(), relay_message.to_vec());
742
743        let (s_handshake, mut s_keygen) = server_handshake_ntor_v3(
744            &mut rng,
745            &mut rep,
746            &c_handshake,
747            &[relay_private],
748            verification,
749        )
750        .unwrap();
751
752        let (s_msg, mut c_keygen) =
753            client_handshake_ntor_v3_part2(&c_state, &s_handshake, verification).unwrap();
754
755        assert_eq!(rep.0[..], client_message[..]);
756        assert_eq!(s_msg[..], relay_message[..]);
757        use digest::XofReader;
758        let mut s_keys = [0_u8; 100];
759        let mut c_keys = [0_u8; 1000];
760        s_keygen.read(&mut s_keys);
761        c_keygen.read(&mut c_keys);
762        assert_eq!(s_keys[..], c_keys[..100]);
763    }
764
765    // Same as previous test, but use the higher-level APIs instead.
766    #[test]
767    fn test_ntor3_roundtrip_highlevel() {
768        let mut rng = rand::rng();
769        let relay_private = NtorV3SecretKey::generate_for_test(&mut testing_rng());
770
771        let (c_state, c_handshake) =
772            NtorV3Client::client1(&mut rng, &relay_private.pk, &[]).unwrap();
773
774        let mut rep = |_: &[CircRequestExt]| Some(vec![]);
775
776        let (s_keygen, s_handshake) =
777            NtorV3Server::server(&mut rng, &mut rep, &[relay_private], &c_handshake).unwrap();
778
779        let (extensions, keygen) = NtorV3Client::client2(c_state, s_handshake).unwrap();
780
781        assert!(extensions.is_empty());
782        let c_keys = keygen.expand(1000).unwrap();
783        let s_keys = s_keygen.expand(100).unwrap();
784        assert_eq!(s_keys[..], c_keys[..100]);
785    }
786
787    // Same as previous test, but encode some congestion control extensions.
788    #[test]
789    fn test_ntor3_roundtrip_highlevel_cc() {
790        let mut rng = rand::rng();
791        let relay_private = NtorV3SecretKey::generate_for_test(&mut testing_rng());
792
793        let client_exts = vec![CircRequestExt::CcRequest(CcRequest::default())];
794        let reply_exts = vec![CircResponseExt::CcResponse(CcResponse::new(42))];
795
796        let (c_state, c_handshake) = NtorV3Client::client1(
797            &mut rng,
798            &relay_private.pk,
799            &[CircRequestExt::CcRequest(CcRequest::default())],
800        )
801        .unwrap();
802
803        let mut rep = |msg: &[CircRequestExt]| -> Option<Vec<CircResponseExt>> {
804            assert_eq!(msg, client_exts);
805            Some(reply_exts.clone())
806        };
807
808        let (s_keygen, s_handshake) =
809            NtorV3Server::server(&mut rng, &mut rep, &[relay_private], &c_handshake).unwrap();
810
811        let (extensions, keygen) = NtorV3Client::client2(c_state, s_handshake).unwrap();
812
813        assert_eq!(extensions, reply_exts);
814        let c_keys = keygen.expand(1000).unwrap();
815        let s_keys = s_keygen.expand(100).unwrap();
816        assert_eq!(s_keys[..], c_keys[..100]);
817    }
818
819    #[test]
820    fn test_ntor3_testvec() {
821        let b = hex!("4051daa5921cfa2a1c27b08451324919538e79e788a81b38cbed097a5dff454a");
822        let id = hex!("9fad2af287ef942632833d21f946c6260c33fae6172b60006e86e4a6911753a2");
823        let x = hex!("b825a3719147bcbe5fb1d0b0fcb9c09e51948048e2e3283d2ab7b45b5ef38b49");
824        let y = hex!("4865a5b7689dafd978f529291c7171bc159be076b92186405d13220b80e2a053");
825        let b: curve25519::StaticSecret = b.into();
826        let B: curve25519::PublicKey = (&b).into();
827        let id: Ed25519Identity = id.into();
828        let x: curve25519::StaticSecret = x.into();
829        //let X = (&x).into();
830        let y: curve25519::StaticSecret = y.into();
831
832        let client_message = hex!("68656c6c6f20776f726c64");
833        let verification = hex!("78797a7a79");
834        let server_message = hex!("486f6c61204d756e646f");
835
836        let relay_public = NtorV3PublicKey { pk: B, id };
837        let relay_private = NtorV3SecretKey {
838            sk: b,
839            pk: relay_public.clone(),
840        };
841
842        let (state, client_handshake) =
843            client_handshake_ntor_v3_no_keygen(&relay_public, &client_message, &verification, x)
844                .unwrap();
845
846        assert_eq!(client_handshake[..], hex!("9fad2af287ef942632833d21f946c6260c33fae6172b60006e86e4a6911753a2f8307a2bc1870b00b828bb74dbb8fd88e632a6375ab3bcd1ae706aaa8b6cdd1d252fe9ae91264c91d4ecb8501f79d0387e34ad8ca0f7c995184f7d11d5da4f463bebd9151fd3b47c180abc9e044d53565f04d82bbb3bebed3d06cea65db8be9c72b68cd461942088502f67")[..]);
847
848        struct Replier(Vec<u8>, Vec<u8>, bool);
849        impl MsgReply for Replier {
850            fn reply(&mut self, msg: &[u8]) -> Option<Vec<u8>> {
851                assert_eq!(msg, &self.0);
852                self.2 = true;
853                Some(self.1.clone())
854            }
855        }
856        let mut rep = Replier(client_message.to_vec(), server_message.to_vec(), false);
857
858        let (server_handshake, mut server_keygen) = server_handshake_ntor_v3_no_keygen(
859            &mut rep,
860            &y,
861            &client_handshake,
862            &[relay_private],
863            &verification,
864        )
865        .unwrap();
866        assert!(rep.2);
867
868        assert_eq!(server_handshake[..], hex!("4bf4814326fdab45ad5184f5518bd7fae25dc59374062698201a50a22954246d2fc5f8773ca824542bc6cf6f57c7c29bbf4e5476461ab130c5b18ab0a91276651202c3e1e87c0d32054c")[..]);
869
870        let (server_msg_received, mut client_keygen) =
871            client_handshake_ntor_v3_part2(&state, &server_handshake, &verification).unwrap();
872        assert_eq!(&server_msg_received, &server_message);
873
874        let (c_keys, s_keys) = {
875            use digest::XofReader;
876            let mut c = [0_u8; 256];
877            let mut s = [0_u8; 256];
878            client_keygen.read(&mut c);
879            server_keygen.read(&mut s);
880            (c, s)
881        };
882        assert_eq!(c_keys, s_keys);
883        assert_eq!(c_keys[..], hex!("9c19b631fd94ed86a817e01f6c80b0743a43f5faebd39cfaa8b00fa8bcc65c3bfeaa403d91acbd68a821bf6ee8504602b094a254392a07737d5662768c7a9fb1b2814bb34780eaee6e867c773e28c212ead563e98a1cd5d5b4576f5ee61c59bde025ff2851bb19b721421694f263818e3531e43a9e4e3e2c661e2ad547d8984caa28ebecd3e4525452299be26b9185a20a90ce1eac20a91f2832d731b54502b09749b5a2a2949292f8cfcbeffb790c7790ed935a9d251e7e336148ea83b063a5618fcff674a44581585fd22077ca0e52c59a24347a38d1a1ceebddbf238541f226b8f88d0fb9c07a1bcd2ea764bbbb5dacdaf5312a14c0b9e4f06309b0333b4a")[..]);
884    }
885}