1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
//! Circuit extension handshake for Tor.
//!
//! Tor circuit handshakes all implement a one-way-authenticated key
//! exchange, where a client that knows a public "onion key" for a
//! relay sends a "client onionskin" to extend to a relay, and receives a
//! "relay onionskin" in response. When the handshake is successful,
//! both the client and relay share a set of session keys, and the
//! client knows that nobody _else_ shares those keys unless they
//! relay's private onion key.
//!
//! Currently, this module implements only the "ntor" handshake used
//! for circuits on today's Tor.
pub(crate) mod fast;
#[cfg(feature = "hs")]
pub(crate) mod hs_ntor;
pub(crate) mod ntor;
#[cfg(feature = "ntor_v3")]
pub(crate) mod ntor_v3;
use crate::{Result, SecretBytes};
//use zeroize::Zeroizing;
use rand_core::{CryptoRng, RngCore};
/// A ClientHandshake is used to generate a client onionskin and
/// handle a relay onionskin.
pub(crate) trait ClientHandshake {
/// The type for the onion key.
type KeyType;
/// The type for the state that the client holds while waiting for a reply.
type StateType;
/// A type that is returned and used to generate session keys.x
type KeyGen;
/// Generate a new client onionskin for a relay with a given onion key.
///
/// On success, return a state object that will be used to
/// complete the handshake, along with the message to send.
fn client1<R: RngCore + CryptoRng>(
rng: &mut R,
key: &Self::KeyType,
) -> Result<(Self::StateType, Vec<u8>)>;
/// Handle an onionskin from a relay, and produce a key generator.
///
/// The state object must match the one that was used to make the
/// client onionskin that the server is replying to.
fn client2<T: AsRef<[u8]>>(state: Self::StateType, msg: T) -> Result<Self::KeyGen>;
}
/// A ServerHandshake is used to handle a client onionskin and generate a
/// server onionskin.
pub(crate) trait ServerHandshake {
/// The type for the onion key. This is a private key type.
type KeyType;
/// The returned key generator type.
type KeyGen;
/// Perform the server handshake. Take as input a strong PRNG in `rng`,
/// a slice of all our private onion keys, and the client's message.
///
/// On success, return a key generator and a server handshake message
/// to send in reply.
fn server<R: RngCore + CryptoRng, T: AsRef<[u8]>>(
rng: &mut R,
key: &[Self::KeyType],
msg: T,
) -> RelayHandshakeResult<(Self::KeyGen, Vec<u8>)>;
}
/// A KeyGenerator is returned by a handshake, and used to generate
/// session keys for the protocol.
///
/// Typically, it wraps a KDF function, and some seed key material.
///
/// It can only be used once.
pub(crate) trait KeyGenerator {
/// Consume the key
fn expand(self, keylen: usize) -> Result<SecretBytes>;
}
/// Generates keys based on the KDF-TOR function.
///
/// This is deprecated and shouldn't be used for new keys.
pub(crate) struct TapKeyGenerator {
/// Seed for the TAP KDF.
seed: SecretBytes,
}
impl TapKeyGenerator {
/// Create a key generator based on a provided seed
pub(crate) fn new(seed: SecretBytes) -> Self {
TapKeyGenerator { seed }
}
}
impl KeyGenerator for TapKeyGenerator {
fn expand(self, keylen: usize) -> Result<SecretBytes> {
use crate::crypto::ll::kdf::{Kdf, LegacyKdf};
LegacyKdf::new(1).derive(&self.seed[..], keylen)
}
}
/// Generates keys based on SHAKE-256.
pub(crate) struct ShakeKeyGenerator {
/// Seed for the key generator
seed: SecretBytes,
}
impl ShakeKeyGenerator {
/// Create a key generator based on a provided seed
#[allow(dead_code)] // We'll construct these for v3 onion services
pub(crate) fn new(seed: SecretBytes) -> Self {
ShakeKeyGenerator { seed }
}
}
impl KeyGenerator for ShakeKeyGenerator {
fn expand(self, keylen: usize) -> Result<SecretBytes> {
use crate::crypto::ll::kdf::{Kdf, ShakeKdf};
ShakeKdf::new().derive(&self.seed[..], keylen)
}
}
/// An error produced by a Relay's attempt to handle a client's onion handshake.
#[derive(Clone, Debug, thiserror::Error)]
pub(crate) enum RelayHandshakeError {
/// An error in parsing or encoding a handshake message.
#[error("problem in handshake format.")]
Fmt(#[from] tor_bytes::Error),
/// The client asked for a key we didn't have.
#[error("unrecognized key or identity in handshake")]
MissingKey,
/// The client did something wrong with their handshake or cryptography.
#[error("bad handshake from client")]
BadHandshake,
/// An internal error.
#[error("internal error")]
Internal(#[from] tor_error::Bug),
}
/// Type alias for results from a relay's attempt to handle a client's onion
/// handshake.
pub(crate) type RelayHandshakeResult<T> = std::result::Result<T, RelayHandshakeError>;