mirror of
https://github.com/rosenpass/rosenpass.git
synced 2026-02-28 06:23:08 -08:00
dev(rosenpass): add support for the shake256 hash function in the rosenpass crate
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use rosenpass::protocol::{CryptoServer, HandleMsgResult, MsgBuf, PeerPtr, SPk, SSk, SymKey};
|
use rosenpass::protocol::{CryptoServer, HandleMsgResult, MsgBuf, PeerPtr, ProtocolVersion, SPk, SSk, SymKey};
|
||||||
use std::ops::DerefMut;
|
use std::ops::DerefMut;
|
||||||
|
|
||||||
use rosenpass_cipher_traits::Kem;
|
use rosenpass_cipher_traits::Kem;
|
||||||
@@ -45,21 +45,30 @@ fn keygen() -> Result<(SSk, SPk)> {
|
|||||||
Ok((sk, pk))
|
Ok((sk, pk))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_server_pair() -> Result<(CryptoServer, CryptoServer)> {
|
fn make_server_pair(protocol_version: ProtocolVersion) -> Result<(CryptoServer, CryptoServer)> {
|
||||||
let psk = SymKey::random();
|
let psk = SymKey::random();
|
||||||
let ((ska, pka), (skb, pkb)) = (keygen()?, keygen()?);
|
let ((ska, pka), (skb, pkb)) = (keygen()?, keygen()?);
|
||||||
let (mut a, mut b) = (
|
let (mut a, mut b) = (
|
||||||
CryptoServer::new(ska, pka.clone()),
|
CryptoServer::new(ska, pka.clone()),
|
||||||
CryptoServer::new(skb, pkb.clone()),
|
CryptoServer::new(skb, pkb.clone()),
|
||||||
);
|
);
|
||||||
a.add_peer(Some(psk.clone()), pkb)?;
|
// TODO: Adapt this to both protocol versions
|
||||||
b.add_peer(Some(psk), pka)?;
|
a.add_peer(Some(psk.clone()), pkb, protocol_version.clone())?;
|
||||||
|
b.add_peer(Some(psk), pka, protocol_version)?;
|
||||||
Ok((a, b))
|
Ok((a, b))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn criterion_benchmark(c: &mut Criterion) {
|
fn criterion_benchmark_v02(c: &mut Criterion) {
|
||||||
|
criterion_benchmark(c, ProtocolVersion::V02)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn criterion_benchmark_v03(c: &mut Criterion) {
|
||||||
|
criterion_benchmark(c, ProtocolVersion::V03)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn criterion_benchmark(c: &mut Criterion, protocol_version: ProtocolVersion) {
|
||||||
secret_policy_try_use_memfd_secrets();
|
secret_policy_try_use_memfd_secrets();
|
||||||
let (mut a, mut b) = make_server_pair().unwrap();
|
let (mut a, mut b) = make_server_pair(protocol_version).unwrap();
|
||||||
c.bench_function("cca_secret_alloc", |bench| {
|
c.bench_function("cca_secret_alloc", |bench| {
|
||||||
bench.iter(|| {
|
bench.iter(|| {
|
||||||
SSk::zero();
|
SSk::zero();
|
||||||
@@ -82,5 +91,6 @@ fn criterion_benchmark(c: &mut Criterion) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
criterion_group!(benches, criterion_benchmark);
|
criterion_group!(benches_v02, criterion_benchmark_v02);
|
||||||
criterion_main!(benches);
|
criterion_group!(benches_v03, criterion_benchmark_v03);
|
||||||
|
criterion_main!(benches_v02, benches_v03);
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use rosenpass_util::attempt;
|
use rosenpass_util::attempt;
|
||||||
use rosenpass_util::b64::B64Display;
|
use rosenpass_util::b64::B64Display;
|
||||||
|
use crate::config::ProtocolVersion;
|
||||||
|
|
||||||
/// The maximum size of a base64 encoded symmetric key (estimate)
|
/// The maximum size of a base64 encoded symmetric key (estimate)
|
||||||
pub const MAX_B64_KEY_SIZE: usize = 32 * 5 / 3;
|
pub const MAX_B64_KEY_SIZE: usize = 32 * 5 / 3;
|
||||||
@@ -1042,11 +1043,12 @@ impl AppServer {
|
|||||||
outfile: Option<PathBuf>,
|
outfile: Option<PathBuf>,
|
||||||
broker_peer: Option<BrokerPeer>,
|
broker_peer: Option<BrokerPeer>,
|
||||||
hostname: Option<String>,
|
hostname: Option<String>,
|
||||||
|
protocol_version: ProtocolVersion
|
||||||
) -> anyhow::Result<AppPeerPtr> {
|
) -> anyhow::Result<AppPeerPtr> {
|
||||||
let PeerPtr(pn) = match &mut self.crypto_site {
|
let PeerPtr(pn) = match &mut self.crypto_site {
|
||||||
ConstructionSite::Void => bail!("Crypto server construction site is void"),
|
ConstructionSite::Void => bail!("Crypto server construction site is void"),
|
||||||
ConstructionSite::Builder(builder) => builder.add_peer(psk, pk),
|
ConstructionSite::Builder(builder) => builder.add_peer(psk, pk, protocol_version),
|
||||||
ConstructionSite::Product(srv) => srv.add_peer(psk, pk)?,
|
ConstructionSite::Product(srv) => srv.add_peer(psk, pk, protocol_version.into())?,
|
||||||
};
|
};
|
||||||
assert!(pn == self.peers.len());
|
assert!(pn == self.peers.len());
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ use anyhow::{Context, Result};
|
|||||||
use heck::ToShoutySnakeCase;
|
use heck::ToShoutySnakeCase;
|
||||||
|
|
||||||
use rosenpass_ciphers::{hash_domain::HashDomain, KEY_LEN};
|
use rosenpass_ciphers::{hash_domain::HashDomain, KEY_LEN};
|
||||||
|
use rosenpass_ciphers::subtle::either_hash::EitherShakeOrBlake;
|
||||||
|
use rosenpass_ciphers::subtle::incorrect_hmac_blake2b::Blake2bCore;
|
||||||
|
use rosenpass_ciphers::subtle::keyed_shake256::SHAKE256Core;
|
||||||
|
|
||||||
/// Recursively calculate a concrete hash value for an API message type
|
/// Recursively calculate a concrete hash value for an API message type
|
||||||
fn calculate_hash_value(hd: HashDomain, values: &[&str]) -> Result<[u8; KEY_LEN]> {
|
fn calculate_hash_value(hd: HashDomain, values: &[&str]) -> Result<[u8; KEY_LEN]> {
|
||||||
@@ -12,8 +15,8 @@ fn calculate_hash_value(hd: HashDomain, values: &[&str]) -> Result<[u8; KEY_LEN]
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Print a hash literal for pasting into the Rosenpass source code
|
/// Print a hash literal for pasting into the Rosenpass source code
|
||||||
fn print_literal(path: &[&str]) -> Result<()> {
|
fn print_literal(path: &[&str], shake_or_blake: EitherShakeOrBlake) -> Result<()> {
|
||||||
let val = calculate_hash_value(HashDomain::zero(), path)?;
|
let val = calculate_hash_value(HashDomain::zero(shake_or_blake), path)?;
|
||||||
let (last, prefix) = path.split_last().context("developer error!")?;
|
let (last, prefix) = path.split_last().context("developer error!")?;
|
||||||
let var_name = last.to_shouty_snake_case();
|
let var_name = last.to_shouty_snake_case();
|
||||||
|
|
||||||
@@ -51,47 +54,53 @@ impl Tree {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen_code_inner(&self, prefix: &[&str]) -> Result<()> {
|
fn gen_code_inner(&self, prefix: &[&str], shake_or_blake: EitherShakeOrBlake) -> Result<()> {
|
||||||
let mut path = prefix.to_owned();
|
let mut path = prefix.to_owned();
|
||||||
path.push(self.name());
|
path.push(self.name());
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Self::Branch(_, ref children) => {
|
Self::Branch(_, ref children) => {
|
||||||
for c in children.iter() {
|
for c in children.iter() {
|
||||||
c.gen_code_inner(&path)?
|
c.gen_code_inner(&path, shake_or_blake.clone())?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::Leaf(_) => print_literal(&path)?,
|
Self::Leaf(_) => print_literal(&path, shake_or_blake)?,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen_code(&self) -> Result<()> {
|
fn gen_code(&self, shake_or_blake: EitherShakeOrBlake) -> Result<()> {
|
||||||
self.gen_code_inner(&[])
|
self.gen_code_inner(&[], shake_or_blake)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper for generating hash-based message IDs for the IPC API
|
/// Helper for generating hash-based message IDs for the IPC API
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
let tree = Tree::Branch(
|
|
||||||
"Rosenpass IPC API".to_owned(),
|
fn print_IPC_API_info(shake_or_blake: EitherShakeOrBlake, name: String) -> Result<()> {
|
||||||
vec![Tree::Branch(
|
let tree = Tree::Branch(
|
||||||
"Rosenpass Protocol Server".to_owned(),
|
format!("Rosenpass IPC API {}", name).to_owned(),
|
||||||
vec![
|
vec![Tree::Branch(
|
||||||
Tree::Leaf("Ping Request".to_owned()),
|
"Rosenpass Protocol Server".to_owned(),
|
||||||
Tree::Leaf("Ping Response".to_owned()),
|
vec![
|
||||||
Tree::Leaf("Supply Keypair Request".to_owned()),
|
Tree::Leaf("Ping Request".to_owned()),
|
||||||
Tree::Leaf("Supply Keypair Response".to_owned()),
|
Tree::Leaf("Ping Response".to_owned()),
|
||||||
Tree::Leaf("Add Listen Socket Request".to_owned()),
|
Tree::Leaf("Supply Keypair Request".to_owned()),
|
||||||
Tree::Leaf("Add Listen Socket Response".to_owned()),
|
Tree::Leaf("Supply Keypair Response".to_owned()),
|
||||||
Tree::Leaf("Add Psk Broker Request".to_owned()),
|
Tree::Leaf("Add Listen Socket Request".to_owned()),
|
||||||
Tree::Leaf("Add Psk Broker Response".to_owned()),
|
Tree::Leaf("Add Listen Socket Response".to_owned()),
|
||||||
],
|
Tree::Leaf("Add Psk Broker Request".to_owned()),
|
||||||
)],
|
Tree::Leaf("Add Psk Broker Response".to_owned()),
|
||||||
);
|
],
|
||||||
|
)],
|
||||||
|
);
|
||||||
|
|
||||||
println!("type RawMsgType = u128;");
|
println!("type RawMsgType = u128;");
|
||||||
println!();
|
println!();
|
||||||
tree.gen_code()
|
tree.gen_code(shake_or_blake)
|
||||||
|
}
|
||||||
|
|
||||||
|
print_IPC_API_info(EitherShakeOrBlake::Left(SHAKE256Core), " (SHAKE256)".to_owned())?;
|
||||||
|
print_IPC_API_info(EitherShakeOrBlake::Right(Blake2bCore), " (Blake2b)".to_owned())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -490,6 +490,7 @@ impl CliArgs {
|
|||||||
cfg_peer.key_out,
|
cfg_peer.key_out,
|
||||||
broker_peer,
|
broker_peer,
|
||||||
cfg_peer.endpoint.clone(),
|
cfg_peer.endpoint.clone(),
|
||||||
|
cfg_peer.protocol_version.into(),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -109,6 +109,14 @@ pub enum Verbosity {
|
|||||||
Verbose,
|
Verbose,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// TODO: Documentation
|
||||||
|
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Copy, Clone, Default)]
|
||||||
|
pub enum ProtocolVersion {
|
||||||
|
#[default]
|
||||||
|
V02,
|
||||||
|
V03,
|
||||||
|
}
|
||||||
|
|
||||||
/// Configuration data for a single Rosenpass peer
|
/// Configuration data for a single Rosenpass peer
|
||||||
#[derive(Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct RosenpassPeer {
|
pub struct RosenpassPeer {
|
||||||
@@ -138,6 +146,10 @@ pub struct RosenpassPeer {
|
|||||||
/// Information for supplying exchanged keys directly to WireGuard
|
/// Information for supplying exchanged keys directly to WireGuard
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub wg: Option<WireGuard>,
|
pub wg: Option<WireGuard>,
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
/// The protocol version to use for the exchange
|
||||||
|
pub protocol_version: ProtocolVersion,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Information for supplying exchanged keys directly to WireGuard
|
/// Information for supplying exchanged keys directly to WireGuard
|
||||||
|
|||||||
@@ -13,6 +13,8 @@
|
|||||||
//! use rosenpass::{hash_domain, hash_domain_ns};
|
//! use rosenpass::{hash_domain, hash_domain_ns};
|
||||||
//! use rosenpass::hash_domains::protocol;
|
//! use rosenpass::hash_domains::protocol;
|
||||||
//!
|
//!
|
||||||
|
//! use rosenpass_ciphers::subtle::either_hash::EitherShakeOrBlake;
|
||||||
|
//!
|
||||||
//! // Declaring a custom hash domain
|
//! // Declaring a custom hash domain
|
||||||
//! hash_domain_ns!(protocol, custom_domain, "my custom hash domain label");
|
//! hash_domain_ns!(protocol, custom_domain, "my custom hash domain label");
|
||||||
//!
|
//!
|
||||||
@@ -26,15 +28,18 @@
|
|||||||
//! hash_domain!(domain_separators, sep1, "1");
|
//! hash_domain!(domain_separators, sep1, "1");
|
||||||
//! hash_domain!(domain_separators, sep2, "2");
|
//! hash_domain!(domain_separators, sep2, "2");
|
||||||
//!
|
//!
|
||||||
|
//! // We use the SHAKE256 hash function for this example
|
||||||
|
//! let hash_choice = EitherShakeOrBlake::Left(rosenpass_ciphers::subtle::keyed_shake256::SHAKE256Core);
|
||||||
|
//!
|
||||||
//! // Generating values under hasher1 with both domain separators
|
//! // Generating values under hasher1 with both domain separators
|
||||||
//! let h1 = hasher1()?.mix(b"some data")?.dup();
|
//! let h1 = hasher1(hash_choice.clone())?.mix(b"some data")?.dup();
|
||||||
//! let h1v1 = h1.mix(&sep1()?)?.mix(b"More data")?.into_value();
|
//! let h1v1 = h1.mix(&sep1(hash_choice.clone())?)?.mix(b"More data")?.into_value();
|
||||||
//! let h1v2 = h1.mix(&sep2()?)?.mix(b"More data")?.into_value();
|
//! let h1v2 = h1.mix(&sep2(hash_choice.clone())?)?.mix(b"More data")?.into_value();
|
||||||
//!
|
//!
|
||||||
//! // Generating values under hasher2 with both domain separators
|
//! // Generating values under hasher2 with both domain separators
|
||||||
//! let h2 = hasher2()?.mix(b"some data")?.dup();
|
//! let h2 = hasher2(hash_choice.clone())?.mix(b"some data")?.dup();
|
||||||
//! let h2v1 = h2.mix(&sep1()?)?.mix(b"More data")?.into_value();
|
//! let h2v1 = h2.mix(&sep1(hash_choice.clone())?)?.mix(b"More data")?.into_value();
|
||||||
//! let h2v2 = h2.mix(&sep2()?)?.mix(b"More data")?.into_value();
|
//! let h2v2 = h2.mix(&sep2(hash_choice.clone())?)?.mix(b"More data")?.into_value();
|
||||||
//!
|
//!
|
||||||
//! // All of the domain separators are now different, random strings
|
//! // All of the domain separators are now different, random strings
|
||||||
//! let values = [h1v1, h1v2, h2v1, h2v2];
|
//! let values = [h1v1, h1v2, h2v1, h2v2];
|
||||||
@@ -49,6 +54,9 @@
|
|||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use rosenpass_ciphers::hash_domain::HashDomain;
|
use rosenpass_ciphers::hash_domain::HashDomain;
|
||||||
|
use rosenpass_ciphers::subtle::either_hash::EitherShakeOrBlake;
|
||||||
|
use rosenpass_ciphers::subtle::incorrect_hmac_blake2b::Blake2bCore;
|
||||||
|
use rosenpass_ciphers::subtle::keyed_shake256::SHAKE256Core;
|
||||||
|
|
||||||
/// Declare a hash function
|
/// Declare a hash function
|
||||||
///
|
///
|
||||||
@@ -62,8 +70,8 @@ use rosenpass_ciphers::hash_domain::HashDomain;
|
|||||||
macro_rules! hash_domain_ns {
|
macro_rules! hash_domain_ns {
|
||||||
($(#[$($attrss:tt)*])* $base:ident, $name:ident, $($lbl:expr),+ ) => {
|
($(#[$($attrss:tt)*])* $base:ident, $name:ident, $($lbl:expr),+ ) => {
|
||||||
$(#[$($attrss)*])*
|
$(#[$($attrss)*])*
|
||||||
pub fn $name() -> ::anyhow::Result<::rosenpass_ciphers::hash_domain::HashDomain> {
|
pub fn $name(hash_choice: EitherShakeOrBlake) -> ::anyhow::Result<::rosenpass_ciphers::hash_domain::HashDomain> {
|
||||||
let t = $base()?;
|
let t = $base(hash_choice)?;
|
||||||
$( let t = t.mix($lbl.as_bytes())?; )*
|
$( let t = t.mix($lbl.as_bytes())?; )*
|
||||||
Ok(t)
|
Ok(t)
|
||||||
}
|
}
|
||||||
@@ -81,8 +89,8 @@ macro_rules! hash_domain_ns {
|
|||||||
macro_rules! hash_domain {
|
macro_rules! hash_domain {
|
||||||
($(#[$($attrss:tt)*])* $base:ident, $name:ident, $($lbl:expr),+ ) => {
|
($(#[$($attrss:tt)*])* $base:ident, $name:ident, $($lbl:expr),+ ) => {
|
||||||
$(#[$($attrss)*])*
|
$(#[$($attrss)*])*
|
||||||
pub fn $name() -> ::anyhow::Result<[u8; ::rosenpass_ciphers::KEY_LEN]> {
|
pub fn $name(hash_choice: EitherShakeOrBlake) -> ::anyhow::Result<[u8; ::rosenpass_ciphers::KEY_LEN]> {
|
||||||
let t = $base()?;
|
let t = $base(hash_choice)?;
|
||||||
$( let t = t.mix($lbl.as_bytes())?; )*
|
$( let t = t.mix($lbl.as_bytes())?; )*
|
||||||
Ok(t.into_value())
|
Ok(t.into_value())
|
||||||
}
|
}
|
||||||
@@ -95,14 +103,21 @@ macro_rules! hash_domain {
|
|||||||
/// used in various places in the rosenpass protocol.
|
/// used in various places in the rosenpass protocol.
|
||||||
///
|
///
|
||||||
/// This is generally used to create further hash-domains for specific purposes. See
|
/// This is generally used to create further hash-domains for specific purposes. See
|
||||||
|
///
|
||||||
|
/// TODO: Update documentation
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// See the source file for details about how this is used concretely.
|
/// See the source file for details about how this is used concretely.
|
||||||
///
|
///
|
||||||
/// See the [module](self) documentation on how to use the hash domains in general
|
/// See the [module](self) documentation on how to use the hash domains in general
|
||||||
pub fn protocol() -> Result<HashDomain> {
|
pub fn protocol(hash_choice: EitherShakeOrBlake) -> Result<HashDomain> {
|
||||||
HashDomain::zero().mix("Rosenpass v1 mceliece460896 Kyber512 ChaChaPoly1305 BLAKE2s".as_bytes())
|
// TODO: Update this string that is mixed in?
|
||||||
|
match hash_choice {
|
||||||
|
EitherShakeOrBlake::Left(SHAKE256Core) => HashDomain::zero(hash_choice).mix("Rosenpass v1 mceliece460896 Kyber512 ChaChaPoly1305 SHAKE256".as_bytes()),
|
||||||
|
EitherShakeOrBlake::Right(Blake2bCore) => HashDomain::zero(hash_choice).mix("Rosenpass v1 mceliece460896 Kyber512 ChaChaPoly1305 Blake2b".as_bytes()),
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hash_domain_ns!(
|
hash_domain_ns!(
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use rosenpass_util::{
|
|||||||
result::ensure_or,
|
result::ensure_or,
|
||||||
};
|
};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
use crate::config::ProtocolVersion;
|
||||||
use super::{CryptoServer, PeerPtr, SPk, SSk, SymKey};
|
use super::{CryptoServer, PeerPtr, SPk, SSk, SymKey};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -146,17 +146,18 @@ pub struct MissingKeypair;
|
|||||||
/// ```rust
|
/// ```rust
|
||||||
/// use rosenpass_util::build::Build;
|
/// use rosenpass_util::build::Build;
|
||||||
/// use rosenpass::protocol::{BuildCryptoServer, Keypair, PeerParams, SPk, SymKey};
|
/// use rosenpass::protocol::{BuildCryptoServer, Keypair, PeerParams, SPk, SymKey};
|
||||||
|
/// use rosenpass::config::ProtocolVersion;
|
||||||
///
|
///
|
||||||
/// // We have to define the security policy before using Secrets.
|
/// // We have to define the security policy before using Secrets.
|
||||||
/// use rosenpass_secret_memory::secret_policy_use_only_malloc_secrets;
|
/// use rosenpass_secret_memory::secret_policy_use_only_malloc_secrets;
|
||||||
/// secret_policy_use_only_malloc_secrets();
|
/// secret_policy_use_only_malloc_secrets();
|
||||||
///
|
///
|
||||||
/// let keypair = Keypair::random();
|
/// let keypair = Keypair::random();
|
||||||
/// let peer1 = PeerParams { psk: Some(SymKey::random()), pk: SPk::random() };
|
/// let peer1 = PeerParams { psk: Some(SymKey::random()), pk: SPk::random(), protocol_version: ProtocolVersion::V02 };
|
||||||
/// let peer2 = PeerParams { psk: None, pk: SPk::random() };
|
/// let peer2 = PeerParams { psk: None, pk: SPk::random(), protocol_version: ProtocolVersion::V02 };
|
||||||
///
|
///
|
||||||
/// let mut builder = BuildCryptoServer::new(Some(keypair.clone()), vec![peer1]);
|
/// let mut builder = BuildCryptoServer::new(Some(keypair.clone()), vec![peer1]);
|
||||||
/// builder.add_peer(peer2.psk.clone(), peer2.pk);
|
/// builder.add_peer(peer2.psk.clone(), peer2.pk, ProtocolVersion::V02);
|
||||||
///
|
///
|
||||||
/// let server = builder.build().expect("build failed");
|
/// let server = builder.build().expect("build failed");
|
||||||
/// assert_eq!(server.peers.len(), 2);
|
/// assert_eq!(server.peers.len(), 2);
|
||||||
@@ -186,8 +187,8 @@ impl Build<CryptoServer> for BuildCryptoServer {
|
|||||||
|
|
||||||
let mut srv = CryptoServer::new(sk, pk);
|
let mut srv = CryptoServer::new(sk, pk);
|
||||||
|
|
||||||
for (idx, PeerParams { psk, pk }) in self.peers.into_iter().enumerate() {
|
for (idx, PeerParams { psk, pk , protocol_version}) in self.peers.into_iter().enumerate() {
|
||||||
let PeerPtr(idx2) = srv.add_peer(psk, pk)?;
|
let PeerPtr(idx2) = srv.add_peer(psk, pk, protocol_version.into())?;
|
||||||
assert!(idx == idx2, "Peer id changed during CryptoServer construction from {idx} to {idx2}. This is a developer error.")
|
assert!(idx == idx2, "Peer id changed during CryptoServer construction from {idx} to {idx2}. This is a developer error.")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,6 +209,8 @@ pub struct PeerParams {
|
|||||||
pub psk: Option<SymKey>,
|
pub psk: Option<SymKey>,
|
||||||
/// Public key identifying the peer.
|
/// Public key identifying the peer.
|
||||||
pub pk: SPk,
|
pub pk: SPk,
|
||||||
|
/// The used protocol version.
|
||||||
|
pub protocol_version: ProtocolVersion,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BuildCryptoServer {
|
impl BuildCryptoServer {
|
||||||
@@ -305,6 +308,7 @@ impl BuildCryptoServer {
|
|||||||
/// Adding peers to an existing builder:
|
/// Adding peers to an existing builder:
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
|
/// use rosenpass::config::ProtocolVersion;
|
||||||
/// // We have to define the security policy before using Secrets.
|
/// // We have to define the security policy before using Secrets.
|
||||||
/// use rosenpass_secret_memory::secret_policy_use_only_malloc_secrets;
|
/// use rosenpass_secret_memory::secret_policy_use_only_malloc_secrets;
|
||||||
/// secret_policy_use_only_malloc_secrets();
|
/// secret_policy_use_only_malloc_secrets();
|
||||||
@@ -323,7 +327,7 @@ impl BuildCryptoServer {
|
|||||||
/// // Now we've found a peer that should be added to the configuration
|
/// // Now we've found a peer that should be added to the configuration
|
||||||
/// let pre_shared_key = SymKey::random();
|
/// let pre_shared_key = SymKey::random();
|
||||||
/// let public_key = SPk::random();
|
/// let public_key = SPk::random();
|
||||||
/// builder.with_added_peer(Some(pre_shared_key.clone()), public_key.clone());
|
/// builder.with_added_peer(Some(pre_shared_key.clone()), public_key.clone(), ProtocolVersion::V02);
|
||||||
///
|
///
|
||||||
/// // New server instances will then start with the peer being registered already
|
/// // New server instances will then start with the peer being registered already
|
||||||
/// let server = builder.build().expect("build failed");
|
/// let server = builder.build().expect("build failed");
|
||||||
@@ -333,16 +337,16 @@ impl BuildCryptoServer {
|
|||||||
/// assert_eq!(peer.spkt, public_key);
|
/// assert_eq!(peer.spkt, public_key);
|
||||||
/// assert_eq!(peer_psk.secret(), pre_shared_key.secret());
|
/// assert_eq!(peer_psk.secret(), pre_shared_key.secret());
|
||||||
/// ```
|
/// ```
|
||||||
pub fn with_added_peer(&mut self, psk: Option<SymKey>, pk: SPk) -> &mut Self {
|
pub fn with_added_peer(&mut self, psk: Option<SymKey>, pk: SPk, protocol_version: ProtocolVersion) -> &mut Self {
|
||||||
// TODO: Check here already whether peer was already added
|
// TODO: Check here already whether peer was already added
|
||||||
self.peers.push(PeerParams { psk, pk });
|
self.peers.push(PeerParams { psk, pk, protocol_version });
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a new entry to the list of registered peers, with or without a pre-shared key.
|
/// Add a new entry to the list of registered peers, with or without a pre-shared key.
|
||||||
pub fn add_peer(&mut self, psk: Option<SymKey>, pk: SPk) -> PeerPtr {
|
pub fn add_peer(&mut self, psk: Option<SymKey>, pk: SPk, protocol_version: ProtocolVersion) -> PeerPtr {
|
||||||
let id = PeerPtr(self.peers.len());
|
let id = PeerPtr(self.peers.len());
|
||||||
self.with_added_peer(psk, pk);
|
self.with_added_peer(psk, pk, protocol_version);
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,6 +360,8 @@ impl BuildCryptoServer {
|
|||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// // We have to define the security policy before using Secrets.
|
/// // We have to define the security policy before using Secrets.
|
||||||
|
/// use rosenpass::config::ProtocolVersion;
|
||||||
|
/// use rosenpass::hash_domains::protocol;
|
||||||
/// use rosenpass_secret_memory::secret_policy_use_only_malloc_secrets;
|
/// use rosenpass_secret_memory::secret_policy_use_only_malloc_secrets;
|
||||||
/// secret_policy_use_only_malloc_secrets();
|
/// secret_policy_use_only_malloc_secrets();
|
||||||
///
|
///
|
||||||
@@ -365,7 +371,7 @@ impl BuildCryptoServer {
|
|||||||
/// let keypair = Keypair::random();
|
/// let keypair = Keypair::random();
|
||||||
/// let peer_pk = SPk::random();
|
/// let peer_pk = SPk::random();
|
||||||
/// let mut builder = BuildCryptoServer::new(Some(keypair.clone()), vec![]);
|
/// let mut builder = BuildCryptoServer::new(Some(keypair.clone()), vec![]);
|
||||||
/// builder.add_peer(None, peer_pk);
|
/// builder.add_peer(None, peer_pk, ProtocolVersion::V02);
|
||||||
///
|
///
|
||||||
/// // Extract configuration parameters from the decomissioned builder
|
/// // Extract configuration parameters from the decomissioned builder
|
||||||
/// let (keypair_option, peers) = builder.take_parts();
|
/// let (keypair_option, peers) = builder.take_parts();
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
//! # fn main() -> anyhow::Result<()> {
|
//! # fn main() -> anyhow::Result<()> {
|
||||||
//! // Set security policy for storing secrets
|
//! // Set security policy for storing secrets
|
||||||
//!
|
//!
|
||||||
|
//! use rosenpass::protocol::ProtocolVersion;
|
||||||
//! secret_policy_try_use_memfd_secrets();
|
//! secret_policy_try_use_memfd_secrets();
|
||||||
//!
|
//!
|
||||||
//! // initialize secret and public key for peer a ...
|
//! // initialize secret and public key for peer a ...
|
||||||
@@ -49,8 +50,8 @@
|
|||||||
//! let mut b = CryptoServer::new(peer_b_sk, peer_b_pk.clone());
|
//! let mut b = CryptoServer::new(peer_b_sk, peer_b_pk.clone());
|
||||||
//!
|
//!
|
||||||
//! // introduce peers to each other
|
//! // introduce peers to each other
|
||||||
//! a.add_peer(Some(psk.clone()), peer_b_pk)?;
|
//! a.add_peer(Some(psk.clone()), peer_b_pk, ProtocolVersion::V03)?;
|
||||||
//! b.add_peer(Some(psk), peer_a_pk)?;
|
//! b.add_peer(Some(psk), peer_a_pk, ProtocolVersion::V03)?;
|
||||||
//!
|
//!
|
||||||
//! // declare buffers for message exchange
|
//! // declare buffers for message exchange
|
||||||
//! let (mut a_buf, mut b_buf) = (MsgBuf::zero(), MsgBuf::zero());
|
//! let (mut a_buf, mut b_buf) = (MsgBuf::zero(), MsgBuf::zero());
|
||||||
|
|||||||
@@ -33,7 +33,9 @@ use rosenpass_util::functional::ApplyExt;
|
|||||||
use rosenpass_util::mem::DiscardResultExt;
|
use rosenpass_util::mem::DiscardResultExt;
|
||||||
use rosenpass_util::{cat, mem::cpy_min, time::Timebase};
|
use rosenpass_util::{cat, mem::cpy_min, time::Timebase};
|
||||||
use zerocopy::{AsBytes, FromBytes, Ref};
|
use zerocopy::{AsBytes, FromBytes, Ref};
|
||||||
|
use rosenpass_ciphers::subtle::either_hash::{EitherShakeOrBlake};
|
||||||
|
use rosenpass_ciphers::subtle::incorrect_hmac_blake2b::Blake2bCore;
|
||||||
|
use rosenpass_ciphers::subtle::keyed_shake256::SHAKE256Core;
|
||||||
use crate::{hash_domains, msgs::*, RosenpassError};
|
use crate::{hash_domains, msgs::*, RosenpassError};
|
||||||
|
|
||||||
// CONSTANTS & SETTINGS //////////////////////////
|
// CONSTANTS & SETTINGS //////////////////////////
|
||||||
@@ -364,6 +366,30 @@ pub enum IndexKey {
|
|||||||
KnownInitConfResponse(KnownResponseHash),
|
KnownInitConfResponse(KnownResponseHash),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum ProtocolVersion {
|
||||||
|
V02,
|
||||||
|
V03
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProtocolVersion {
|
||||||
|
pub fn shake_or_blake(&self) -> EitherShakeOrBlake {
|
||||||
|
match self {
|
||||||
|
ProtocolVersion::V02 => EitherShakeOrBlake::Right(Blake2bCore),
|
||||||
|
ProtocolVersion::V03 => EitherShakeOrBlake::Left(SHAKE256Core),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<crate::config::ProtocolVersion> for ProtocolVersion {
|
||||||
|
fn from(v: crate::config::ProtocolVersion) -> Self {
|
||||||
|
match v {
|
||||||
|
crate::config::ProtocolVersion::V02 => ProtocolVersion::V02,
|
||||||
|
crate::config::ProtocolVersion::V03 => ProtocolVersion::V03,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A peer that the server can execute a key exchange with.
|
/// A peer that the server can execute a key exchange with.
|
||||||
///
|
///
|
||||||
/// Peers generally live in [CryptoServer::peers]. [PeerNo] captures an array
|
/// Peers generally live in [CryptoServer::peers]. [PeerNo] captures an array
|
||||||
@@ -375,7 +401,7 @@ pub enum IndexKey {
|
|||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use std::ops::DerefMut;
|
/// use std::ops::DerefMut;
|
||||||
/// use rosenpass::protocol::{SSk, SPk, SymKey, Peer};
|
/// use rosenpass::protocol::{SSk, SPk, SymKey, Peer, ProtocolVersion};
|
||||||
/// use rosenpass_ciphers::kem::StaticKem;
|
/// use rosenpass_ciphers::kem::StaticKem;
|
||||||
/// use rosenpass_cipher_traits::Kem;
|
/// use rosenpass_cipher_traits::Kem;
|
||||||
///
|
///
|
||||||
@@ -390,13 +416,13 @@ pub enum IndexKey {
|
|||||||
/// let psk = SymKey::random();
|
/// let psk = SymKey::random();
|
||||||
///
|
///
|
||||||
/// // Creation with a PSK
|
/// // Creation with a PSK
|
||||||
/// let peer_psk = Peer::new(psk, spkt.clone());
|
/// let peer_psk = Peer::new(psk, spkt.clone(), ProtocolVersion::V03);
|
||||||
///
|
///
|
||||||
/// // Creation without a PSK
|
/// // Creation without a PSK
|
||||||
/// let peer_nopsk = Peer::new(SymKey::zero(), spkt);
|
/// let peer_nopsk = Peer::new(SymKey::zero(), spkt, ProtocolVersion::V03);
|
||||||
///
|
///
|
||||||
/// // Create a second peer
|
/// // Create a second peer
|
||||||
/// let peer_psk_2 = Peer::new(SymKey::zero(), spkt2);
|
/// let peer_psk_2 = Peer::new(SymKey::zero(), spkt2, ProtocolVersion::V03);
|
||||||
///
|
///
|
||||||
/// // Peer ID does not depend on PSK, but it does depend on the public key
|
/// // Peer ID does not depend on PSK, but it does depend on the public key
|
||||||
/// assert_eq!(peer_psk.pidt()?, peer_nopsk.pidt()?);
|
/// assert_eq!(peer_psk.pidt()?, peer_nopsk.pidt()?);
|
||||||
@@ -452,6 +478,9 @@ pub struct Peer {
|
|||||||
/// This allows us to perform retransmission for the purpose of dealing with packet loss
|
/// This allows us to perform retransmission for the purpose of dealing with packet loss
|
||||||
/// on the network without having to account for it in the cryptographic code itself.
|
/// on the network without having to account for it in the cryptographic code itself.
|
||||||
pub known_init_conf_response: Option<KnownInitConfResponse>,
|
pub known_init_conf_response: Option<KnownInitConfResponse>,
|
||||||
|
|
||||||
|
/// TODO: Documentation
|
||||||
|
pub protocol_version: ProtocolVersion,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Peer {
|
impl Peer {
|
||||||
@@ -460,14 +489,14 @@ impl Peer {
|
|||||||
/// This is dirty but allows us to perform easy incremental construction of [Self].
|
/// This is dirty but allows us to perform easy incremental construction of [Self].
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use rosenpass::protocol::{Peer, SymKey, SPk};
|
/// use rosenpass::protocol::{Peer, SymKey, SPk, ProtocolVersion};
|
||||||
/// rosenpass_secret_memory::secret_policy_try_use_memfd_secrets();
|
/// rosenpass_secret_memory::secret_policy_try_use_memfd_secrets();
|
||||||
/// let p = Peer::zero();
|
/// let p = Peer::zero(ProtocolVersion::V03);
|
||||||
/// assert_eq!(p.psk.secret(), SymKey::zero().secret());
|
/// assert_eq!(p.psk.secret(), SymKey::zero().secret());
|
||||||
/// assert_eq!(p.spkt, SPk::zero());
|
/// assert_eq!(p.spkt, SPk::zero());
|
||||||
/// // etc.
|
/// // etc.
|
||||||
/// ```
|
/// ```
|
||||||
pub fn zero() -> Self {
|
pub fn zero(protocol_version: ProtocolVersion) -> Self {
|
||||||
Self {
|
Self {
|
||||||
psk: SymKey::zero(),
|
psk: SymKey::zero(),
|
||||||
spkt: SPk::zero(),
|
spkt: SPk::zero(),
|
||||||
@@ -476,6 +505,7 @@ impl Peer {
|
|||||||
initiation_requested: false,
|
initiation_requested: false,
|
||||||
handshake: None,
|
handshake: None,
|
||||||
known_init_conf_response: None,
|
known_init_conf_response: None,
|
||||||
|
protocol_version: protocol_version,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -625,7 +655,7 @@ fn known_response_format() {
|
|||||||
response: Envelope::new_zeroed(),
|
response: Envelope::new_zeroed(),
|
||||||
};
|
};
|
||||||
let s = format!("{v:?}");
|
let s = format!("{v:?}");
|
||||||
assert!(s.contains("response")); // Smoke test only, its a formatter
|
assert!(s.contains("response")); // Smoke test only, it's a formatter
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Known [EmptyData] response to an [InitConf] message
|
/// Known [EmptyData] response to an [InitConf] message
|
||||||
@@ -804,11 +834,11 @@ pub trait Mortal {
|
|||||||
/// ```
|
/// ```
|
||||||
/// use std::ops::DerefMut;
|
/// use std::ops::DerefMut;
|
||||||
/// use rosenpass_ciphers::kem::StaticKem;
|
/// use rosenpass_ciphers::kem::StaticKem;
|
||||||
/// use rosenpass::protocol::{SSk, SPk, testutils::ServerForTesting};
|
/// use rosenpass::protocol::{SSk, SPk, testutils::ServerForTesting, ProtocolVersion};
|
||||||
///
|
///
|
||||||
/// rosenpass_secret_memory::secret_policy_try_use_memfd_secrets();
|
/// rosenpass_secret_memory::secret_policy_try_use_memfd_secrets();
|
||||||
///
|
///
|
||||||
/// let (peer, (_, spkt), mut srv) = ServerForTesting::new()?.tuple();
|
/// let (peer, (_, spkt), mut srv) = ServerForTesting::new(ProtocolVersion::V03)?.tuple();
|
||||||
///
|
///
|
||||||
/// // Immutable access
|
/// // Immutable access
|
||||||
/// assert_eq!(peer.get(&srv).spkt, spkt);
|
/// assert_eq!(peer.get(&srv).spkt, spkt);
|
||||||
@@ -1344,7 +1374,7 @@ impl CryptoServer {
|
|||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use std::ops::DerefMut;
|
/// use std::ops::DerefMut;
|
||||||
/// use rosenpass::protocol::{SSk, SPk, CryptoServer};
|
/// use rosenpass::protocol::{SSk, SPk, CryptoServer, ProtocolVersion};
|
||||||
/// use rosenpass_ciphers::kem::StaticKem;
|
/// use rosenpass_ciphers::kem::StaticKem;
|
||||||
/// use rosenpass_cipher_traits::Kem;
|
/// use rosenpass_cipher_traits::Kem;
|
||||||
///
|
///
|
||||||
@@ -1388,9 +1418,9 @@ impl CryptoServer {
|
|||||||
|
|
||||||
/// Calculate the peer ID of this CryptoServer
|
/// Calculate the peer ID of this CryptoServer
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
pub fn pidm(&self) -> Result<PeerId> {
|
pub fn pidm(&self, shake_or_blake: EitherShakeOrBlake) -> Result<PeerId> {
|
||||||
Ok(Public::new(
|
Ok(Public::new(
|
||||||
hash_domains::peerid()?
|
hash_domains::peerid(shake_or_blake)?
|
||||||
.mix(self.spkm.deref())?
|
.mix(self.spkm.deref())?
|
||||||
.into_value()))
|
.into_value()))
|
||||||
}
|
}
|
||||||
@@ -1404,10 +1434,12 @@ impl CryptoServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Add a peer with an optional pre shared key (`psk`) and its public key (`pk`)
|
/// Add a peer with an optional pre shared key (`psk`) and its public key (`pk`)
|
||||||
|
///
|
||||||
|
/// TODO: Adapt documentation
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use std::ops::DerefMut;
|
/// use std::ops::DerefMut;
|
||||||
/// use rosenpass::protocol::{SSk, SPk, SymKey, CryptoServer};
|
/// use rosenpass::protocol::{SSk, SPk, SymKey, CryptoServer, ProtocolVersion};
|
||||||
/// use rosenpass_ciphers::kem::StaticKem;
|
/// use rosenpass_ciphers::kem::StaticKem;
|
||||||
/// use rosenpass_cipher_traits::Kem;
|
/// use rosenpass_cipher_traits::Kem;
|
||||||
///
|
///
|
||||||
@@ -1422,13 +1454,13 @@ impl CryptoServer {
|
|||||||
///
|
///
|
||||||
/// let psk = SymKey::random();
|
/// let psk = SymKey::random();
|
||||||
///
|
///
|
||||||
/// let peer = srv.add_peer(Some(psk), spkt.clone())?;
|
/// let peer = srv.add_peer(Some(psk), spkt.clone(), ProtocolVersion::V03)?;
|
||||||
///
|
///
|
||||||
/// assert_eq!(peer.get(&srv).spkt, spkt);
|
/// assert_eq!(peer.get(&srv).spkt, spkt);
|
||||||
///
|
///
|
||||||
/// Ok::<(), anyhow::Error>(())
|
/// Ok::<(), anyhow::Error>(())
|
||||||
/// ```
|
/// ```
|
||||||
pub fn add_peer(&mut self, psk: Option<SymKey>, pk: SPk) -> Result<PeerPtr> {
|
pub fn add_peer(&mut self, psk: Option<SymKey>, pk: SPk, protocol_version: ProtocolVersion) -> Result<PeerPtr> {
|
||||||
let peer = Peer {
|
let peer = Peer {
|
||||||
psk: psk.unwrap_or_else(SymKey::zero),
|
psk: psk.unwrap_or_else(SymKey::zero),
|
||||||
spkt: pk,
|
spkt: pk,
|
||||||
@@ -1437,6 +1469,7 @@ impl CryptoServer {
|
|||||||
handshake: None,
|
handshake: None,
|
||||||
known_init_conf_response: None,
|
known_init_conf_response: None,
|
||||||
initiation_requested: false,
|
initiation_requested: false,
|
||||||
|
protocol_version: protocol_version,
|
||||||
};
|
};
|
||||||
let peerid = peer.pidt()?;
|
let peerid = peer.pidt()?;
|
||||||
let peerno = self.peers.len();
|
let peerno = self.peers.len();
|
||||||
@@ -1549,7 +1582,7 @@ impl CryptoServer {
|
|||||||
/// Retrieve the active biscuit key, cycling biscuit keys if necessary.
|
/// Retrieve the active biscuit key, cycling biscuit keys if necessary.
|
||||||
///
|
///
|
||||||
/// Two biscuit keys are maintained inside [Self::biscuit_keys]; they are
|
/// Two biscuit keys are maintained inside [Self::biscuit_keys]; they are
|
||||||
/// considered fresh ([Lifecycle::Young]) for one [BISCUIT_EPOCH] after creation
|
/// considered fresh ([Lifecycle::Young]) for one [BISCUIT_EPOCH] after creation,
|
||||||
/// and they are considered stale ([Lifecycle::Retired]) for another [BISCUIT_EPOCH].
|
/// and they are considered stale ([Lifecycle::Retired]) for another [BISCUIT_EPOCH].
|
||||||
///
|
///
|
||||||
/// While young, they are used for encryption of biscuits and while retired they are
|
/// While young, they are used for encryption of biscuits and while retired they are
|
||||||
@@ -1624,7 +1657,7 @@ impl Peer {
|
|||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// See example in [Self].
|
/// See example in [Self].
|
||||||
pub fn new(psk: SymKey, pk: SPk) -> Peer {
|
pub fn new(psk: SymKey, pk: SPk, protocol_version: ProtocolVersion) -> Peer {
|
||||||
Peer {
|
Peer {
|
||||||
psk,
|
psk,
|
||||||
spkt: pk,
|
spkt: pk,
|
||||||
@@ -1633,11 +1666,12 @@ impl Peer {
|
|||||||
handshake: None,
|
handshake: None,
|
||||||
known_init_conf_response: None,
|
known_init_conf_response: None,
|
||||||
initiation_requested: false,
|
initiation_requested: false,
|
||||||
|
protocol_version: protocol_version,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute the peer ID of the peer,
|
/// Compute the peer ID of the peer,
|
||||||
/// as specified in the the [whitepaper](https://rosenpass.eu/whitepaper.pdf).
|
/// as specified in the [whitepaper](https://rosenpass.eu/whitepaper.pdf).
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
@@ -1645,7 +1679,7 @@ impl Peer {
|
|||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
pub fn pidt(&self) -> Result<PeerId> {
|
pub fn pidt(&self) -> Result<PeerId> {
|
||||||
Ok(Public::new(
|
Ok(Public::new(
|
||||||
hash_domains::peerid()?
|
hash_domains::peerid(self.protocol_version.shake_or_blake())?
|
||||||
.mix(self.spkt.deref())?
|
.mix(self.spkt.deref())?
|
||||||
.into_value()))
|
.into_value()))
|
||||||
}
|
}
|
||||||
@@ -1658,20 +1692,22 @@ impl Session {
|
|||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use rosenpass::protocol::{Session, HandshakeRole};
|
/// use rosenpass::protocol::{Session, HandshakeRole};
|
||||||
|
/// use rosenpass_ciphers::subtle::either_hash::EitherShakeOrBlake;
|
||||||
|
/// use rosenpass_ciphers::subtle::keyed_shake256::SHAKE256Core;
|
||||||
///
|
///
|
||||||
/// rosenpass_secret_memory::secret_policy_try_use_memfd_secrets();
|
/// rosenpass_secret_memory::secret_policy_try_use_memfd_secrets();
|
||||||
///
|
///
|
||||||
/// let s = Session::zero();
|
/// let s = Session::zero(EitherShakeOrBlake::Left(SHAKE256Core));
|
||||||
/// assert_eq!(s.created_at, 0.0);
|
/// assert_eq!(s.created_at, 0.0);
|
||||||
/// assert_eq!(s.handshake_role, HandshakeRole::Initiator);
|
/// assert_eq!(s.handshake_role, HandshakeRole::Initiator);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn zero() -> Self {
|
pub fn zero(shake_or_blake: EitherShakeOrBlake) -> Self {
|
||||||
Self {
|
Self {
|
||||||
created_at: 0.0,
|
created_at: 0.0,
|
||||||
sidm: SessionId::zero(),
|
sidm: SessionId::zero(),
|
||||||
sidt: SessionId::zero(),
|
sidt: SessionId::zero(),
|
||||||
handshake_role: HandshakeRole::Initiator,
|
handshake_role: HandshakeRole::Initiator,
|
||||||
ck: SecretHashDomain::zero().dup(),
|
ck: SecretHashDomain::zero(shake_or_blake).dup(),
|
||||||
txkm: SymKey::zero(),
|
txkm: SymKey::zero(),
|
||||||
txkt: SymKey::zero(),
|
txkt: SymKey::zero(),
|
||||||
txnm: 0,
|
txnm: 0,
|
||||||
@@ -1886,7 +1922,7 @@ impl Mortal for KnownInitConfResponsePtr {
|
|||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use rosenpass::protocol::{Timing, Mortal, MortalExt, Lifecycle, CryptoServer};
|
/// use rosenpass::protocol::{Timing, Mortal, MortalExt, Lifecycle, CryptoServer, ProtocolVersion};
|
||||||
/// use rosenpass::protocol::testutils::{ServerForTesting, time_travel_forward};
|
/// use rosenpass::protocol::testutils::{ServerForTesting, time_travel_forward};
|
||||||
///
|
///
|
||||||
/// rosenpass_secret_memory::secret_policy_try_use_memfd_secrets();
|
/// rosenpass_secret_memory::secret_policy_try_use_memfd_secrets();
|
||||||
@@ -1896,7 +1932,7 @@ impl Mortal for KnownInitConfResponsePtr {
|
|||||||
/// const D : Timing = 24.0 * H;
|
/// const D : Timing = 24.0 * H;
|
||||||
/// const Y : Timing = 356.0 * D;
|
/// const Y : Timing = 356.0 * D;
|
||||||
///
|
///
|
||||||
/// let mut ts = ServerForTesting::new()?;
|
/// let mut ts = ServerForTesting::new(ProtocolVersion::V03)?;
|
||||||
///
|
///
|
||||||
/// fn eq_up_to_minute(a: Timing, b: Timing) -> bool {
|
/// fn eq_up_to_minute(a: Timing, b: Timing) -> bool {
|
||||||
/// (a - b) < M
|
/// (a - b) < M
|
||||||
@@ -2136,7 +2172,7 @@ impl CryptoServer {
|
|||||||
let cookie_secret = cookie_secret.get(self).value.secret();
|
let cookie_secret = cookie_secret.get(self).value.secret();
|
||||||
let mut cookie_value = [0u8; 16];
|
let mut cookie_value = [0u8; 16];
|
||||||
cookie_value.copy_from_slice(
|
cookie_value.copy_from_slice(
|
||||||
&hash_domains::cookie_value()?
|
&hash_domains::cookie_value(EitherShakeOrBlake::Left(SHAKE256Core))?
|
||||||
.mix(cookie_secret)?
|
.mix(cookie_secret)?
|
||||||
.mix(host_identification.encode())?
|
.mix(host_identification.encode())?
|
||||||
.into_value()[..16],
|
.into_value()[..16],
|
||||||
@@ -2152,7 +2188,7 @@ impl CryptoServer {
|
|||||||
let msg_in = Ref::<&[u8], Envelope<InitHello>>::new(rx_buf)
|
let msg_in = Ref::<&[u8], Envelope<InitHello>>::new(rx_buf)
|
||||||
.ok_or(RosenpassError::BufferSizeMismatch)?;
|
.ok_or(RosenpassError::BufferSizeMismatch)?;
|
||||||
expected.copy_from_slice(
|
expected.copy_from_slice(
|
||||||
&hash_domains::cookie()?
|
&hash_domains::cookie(EitherShakeOrBlake::Left(SHAKE256Core))?
|
||||||
.mix(&cookie_value)?
|
.mix(&cookie_value)?
|
||||||
.mix(&msg_in.as_bytes()[span_of!(Envelope<InitHello>, msg_type..cookie)])?
|
.mix(&msg_in.as_bytes()[span_of!(Envelope<InitHello>, msg_type..cookie)])?
|
||||||
.into_value()[..16],
|
.into_value()[..16],
|
||||||
@@ -2189,7 +2225,7 @@ impl CryptoServer {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let cookie_value = active_cookie_value.unwrap();
|
let cookie_value = active_cookie_value.unwrap();
|
||||||
let cookie_key = hash_domains::cookie_key()?
|
let cookie_key = hash_domains::cookie_key(EitherShakeOrBlake::Left(SHAKE256Core))?
|
||||||
.mix(self.spkm.deref())?
|
.mix(self.spkm.deref())?
|
||||||
.into_value();
|
.into_value();
|
||||||
|
|
||||||
@@ -2269,24 +2305,43 @@ impl CryptoServer {
|
|||||||
|
|
||||||
log::debug!("Rx {:?}, processing", msg_type);
|
log::debug!("Rx {:?}, processing", msg_type);
|
||||||
|
|
||||||
|
let mut msg_out = truncating_cast_into::<Envelope<RespHello>>(tx_buf)?;
|
||||||
|
|
||||||
let peer = match msg_type {
|
let peer = match msg_type {
|
||||||
Ok(MsgType::InitHello) => {
|
Ok(MsgType::InitHello) => {
|
||||||
let msg_in: Ref<&[u8], Envelope<InitHello>> =
|
let msg_in: Ref<&[u8], Envelope<InitHello>> =
|
||||||
Ref::new(rx_buf).ok_or(RosenpassError::BufferSizeMismatch)?;
|
Ref::new(rx_buf).ok_or(RosenpassError::BufferSizeMismatch)?;
|
||||||
ensure!(msg_in.check_seal(self)?, seal_broken);
|
|
||||||
|
|
||||||
let mut msg_out = truncating_cast_into::<Envelope<RespHello>>(tx_buf)?;
|
// At this point, we do not know the hash functon used by the peer, thus we try both,
|
||||||
let peer = self.handle_init_hello(&msg_in.payload, &mut msg_out.payload)?;
|
// with a preference for SHAKE256.
|
||||||
|
let peer_shake256 = self.handle_init_hello(&msg_in.payload, &mut msg_out.payload, EitherShakeOrBlake::Left(SHAKE256Core));
|
||||||
|
let (peer, peer_hash_choice) = match peer_shake256 {
|
||||||
|
Ok(peer ) => (peer, EitherShakeOrBlake::Left(SHAKE256Core)),
|
||||||
|
Err(_) => {
|
||||||
|
let peer_blake2b = self.handle_init_hello(&msg_in.payload, &mut msg_out.payload, EitherShakeOrBlake::Right(Blake2bCore));
|
||||||
|
match peer_blake2b {
|
||||||
|
Ok(peer) => (peer, EitherShakeOrBlake::Right(Blake2bCore)),
|
||||||
|
Err(_) => bail!("No valid hash function found for InitHello")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Now, we make sure that the hash function used by the peer is the same as the one
|
||||||
|
// that is specified in the local configuration.
|
||||||
|
self.verify_hash_choice_match(peer, peer_hash_choice.clone())?;
|
||||||
|
|
||||||
|
ensure!(msg_in.check_seal(self, peer_hash_choice)?, seal_broken);
|
||||||
|
|
||||||
len = self.seal_and_commit_msg(peer, MsgType::RespHello, &mut msg_out)?;
|
len = self.seal_and_commit_msg(peer, MsgType::RespHello, &mut msg_out)?;
|
||||||
peer
|
peer
|
||||||
}
|
}
|
||||||
Ok(MsgType::RespHello) => {
|
Ok(MsgType::RespHello) => {
|
||||||
let msg_in: Ref<&[u8], Envelope<RespHello>> =
|
let msg_in: Ref<&[u8], Envelope<RespHello>> =
|
||||||
Ref::new(rx_buf).ok_or(RosenpassError::BufferSizeMismatch)?;
|
Ref::new(rx_buf).ok_or(RosenpassError::BufferSizeMismatch)?;
|
||||||
ensure!(msg_in.check_seal(self)?, seal_broken);
|
|
||||||
|
|
||||||
let mut msg_out = truncating_cast_into::<Envelope<InitConf>>(tx_buf)?;
|
let mut msg_out = truncating_cast_into::<Envelope<InitConf>>(tx_buf)?;
|
||||||
let peer = self.handle_resp_hello(&msg_in.payload, &mut msg_out.payload)?;
|
let peer = self.handle_resp_hello(&msg_in.payload, &mut msg_out.payload)?;
|
||||||
|
ensure!(msg_in.check_seal(self, peer.get(self).protocol_version.shake_or_blake())?, seal_broken);
|
||||||
|
|
||||||
len = self.seal_and_commit_msg(peer, MsgType::InitConf, &mut msg_out)?;
|
len = self.seal_and_commit_msg(peer, MsgType::InitConf, &mut msg_out)?;
|
||||||
peer.hs()
|
peer.hs()
|
||||||
.store_msg_for_retransmission(self, &msg_out.as_bytes()[..len])?;
|
.store_msg_for_retransmission(self, &msg_out.as_bytes()[..len])?;
|
||||||
@@ -2296,7 +2351,7 @@ impl CryptoServer {
|
|||||||
Ok(MsgType::InitConf) => {
|
Ok(MsgType::InitConf) => {
|
||||||
let msg_in: Ref<&[u8], Envelope<InitConf>> =
|
let msg_in: Ref<&[u8], Envelope<InitConf>> =
|
||||||
Ref::new(rx_buf).ok_or(RosenpassError::BufferSizeMismatch)?;
|
Ref::new(rx_buf).ok_or(RosenpassError::BufferSizeMismatch)?;
|
||||||
ensure!(msg_in.check_seal(self)?, seal_broken);
|
|
||||||
|
|
||||||
let mut msg_out = truncating_cast_into::<Envelope<EmptyData>>(tx_buf)?;
|
let mut msg_out = truncating_cast_into::<Envelope<EmptyData>>(tx_buf)?;
|
||||||
|
|
||||||
@@ -2305,6 +2360,7 @@ impl CryptoServer {
|
|||||||
// Cached response; copy out of cache
|
// Cached response; copy out of cache
|
||||||
Some(cached) => {
|
Some(cached) => {
|
||||||
let peer = cached.peer();
|
let peer = cached.peer();
|
||||||
|
ensure!(msg_in.check_seal(self, peer.get(self).protocol_version.shake_or_blake())?, seal_broken);
|
||||||
let cached = cached
|
let cached = cached
|
||||||
.get(self)
|
.get(self)
|
||||||
.map(|v| v.response.borrow())
|
.map(|v| v.response.borrow())
|
||||||
@@ -2316,8 +2372,24 @@ impl CryptoServer {
|
|||||||
|
|
||||||
// No cached response, actually call cryptographic handler
|
// No cached response, actually call cryptographic handler
|
||||||
None => {
|
None => {
|
||||||
let peer = self.handle_init_conf(&msg_in.payload, &mut msg_out.payload)?;
|
// At this point, we do not know the hash functon used by the peer, thus we try both,
|
||||||
|
// with a preference for SHAKE256.
|
||||||
|
let peer_shake256 = self.handle_init_conf(&msg_in.payload, &mut msg_out.payload, EitherShakeOrBlake::Left(SHAKE256Core));
|
||||||
|
let (peer, peer_hash_choice) = match peer_shake256 {
|
||||||
|
Ok(peer) => (peer, EitherShakeOrBlake::Left(SHAKE256Core)),
|
||||||
|
Err(_) => {
|
||||||
|
let peer_blake2b = self.handle_init_conf(&msg_in.payload, &mut msg_out.payload, EitherShakeOrBlake::Right(Blake2bCore));
|
||||||
|
match peer_blake2b {
|
||||||
|
Ok(peer) => (peer, EitherShakeOrBlake::Right(Blake2bCore)),
|
||||||
|
Err(_) => bail!("No valid hash function found for InitHello")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Now, we make sure that the hash function used by the peer is the same as the one
|
||||||
|
// that is specified in the local configuration.
|
||||||
|
self.verify_hash_choice_match(peer, peer_hash_choice.clone())?;
|
||||||
|
ensure!(msg_in.check_seal(self, peer_hash_choice)?, seal_broken);
|
||||||
|
|
||||||
KnownInitConfResponsePtr::insert_for_request_msg(
|
KnownInitConfResponsePtr::insert_for_request_msg(
|
||||||
self,
|
self,
|
||||||
peer,
|
peer,
|
||||||
@@ -2336,9 +2408,8 @@ impl CryptoServer {
|
|||||||
Ok(MsgType::EmptyData) => {
|
Ok(MsgType::EmptyData) => {
|
||||||
let msg_in: Ref<&[u8], Envelope<EmptyData>> =
|
let msg_in: Ref<&[u8], Envelope<EmptyData>> =
|
||||||
Ref::new(rx_buf).ok_or(RosenpassError::BufferSizeMismatch)?;
|
Ref::new(rx_buf).ok_or(RosenpassError::BufferSizeMismatch)?;
|
||||||
ensure!(msg_in.check_seal(self)?, seal_broken);
|
|
||||||
|
|
||||||
self.handle_resp_conf(&msg_in.payload)?
|
self.handle_resp_conf(&msg_in, seal_broken.to_string())?
|
||||||
}
|
}
|
||||||
Ok(MsgType::CookieReply) => {
|
Ok(MsgType::CookieReply) => {
|
||||||
let msg_in: Ref<&[u8], CookieReply> =
|
let msg_in: Ref<&[u8], CookieReply> =
|
||||||
@@ -2357,6 +2428,20 @@ impl CryptoServer {
|
|||||||
resp: if len == 0 { None } else { Some(len) },
|
resp: if len == 0 { None } else { Some(len) },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// TODO documentation
|
||||||
|
fn verify_hash_choice_match(&self, peer: PeerPtr, peer_hash_choice: EitherShakeOrBlake) -> Result<()> {
|
||||||
|
match peer.get(self).protocol_version.shake_or_blake() {
|
||||||
|
EitherShakeOrBlake::Left(SHAKE256Core) => match peer_hash_choice {
|
||||||
|
EitherShakeOrBlake::Left(SHAKE256Core) => Ok(()),
|
||||||
|
EitherShakeOrBlake::Right(Blake2bCore) => bail!("Hash function mismatch"),
|
||||||
|
},
|
||||||
|
EitherShakeOrBlake::Right(Blake2bCore) => match peer_hash_choice {
|
||||||
|
EitherShakeOrBlake::Left(SHAKE256Core) => bail!("Hash function mismatch"),
|
||||||
|
EitherShakeOrBlake::Right(Blake2bCore) => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// This is used to finalize a message in a transmission buffer
|
/// This is used to finalize a message in a transmission buffer
|
||||||
/// while ensuring that the [Envelope::mac] and [Envelope::cookie]
|
/// while ensuring that the [Envelope::mac] and [Envelope::cookie]
|
||||||
@@ -3096,7 +3181,7 @@ where
|
|||||||
{
|
{
|
||||||
/// Internal business logic: Calculate the message authentication code (`mac`) and also append cookie value
|
/// Internal business logic: Calculate the message authentication code (`mac`) and also append cookie value
|
||||||
pub fn seal(&mut self, peer: PeerPtr, srv: &CryptoServer) -> Result<()> {
|
pub fn seal(&mut self, peer: PeerPtr, srv: &CryptoServer) -> Result<()> {
|
||||||
let mac = hash_domains::mac()?
|
let mac = hash_domains::mac(peer.get(srv).protocol_version.shake_or_blake())?
|
||||||
.mix(peer.get(srv).spkt.deref())?
|
.mix(peer.get(srv).spkt.deref())?
|
||||||
.mix(&self.as_bytes()[span_of!(Self, msg_type..mac)])?;
|
.mix(&self.as_bytes()[span_of!(Self, msg_type..mac)])?;
|
||||||
self.mac.copy_from_slice(mac.into_value()[..16].as_ref());
|
self.mac.copy_from_slice(mac.into_value()[..16].as_ref());
|
||||||
@@ -3109,7 +3194,7 @@ where
|
|||||||
/// This is called inside [Self::seal] and does not need to be called again separately.
|
/// This is called inside [Self::seal] and does not need to be called again separately.
|
||||||
pub fn seal_cookie(&mut self, peer: PeerPtr, srv: &CryptoServer) -> Result<()> {
|
pub fn seal_cookie(&mut self, peer: PeerPtr, srv: &CryptoServer) -> Result<()> {
|
||||||
if let Some(cookie_key) = &peer.cv().get(srv) {
|
if let Some(cookie_key) = &peer.cv().get(srv) {
|
||||||
let cookie = hash_domains::cookie()?
|
let cookie = hash_domains::cookie(peer.get(srv).protocol_version.shake_or_blake())?
|
||||||
.mix(cookie_key.value.secret())?
|
.mix(cookie_key.value.secret())?
|
||||||
.mix(&self.as_bytes()[span_of!(Self, msg_type..cookie)])?;
|
.mix(&self.as_bytes()[span_of!(Self, msg_type..cookie)])?;
|
||||||
self.cookie
|
self.cookie
|
||||||
@@ -3124,8 +3209,8 @@ where
|
|||||||
M: AsBytes + FromBytes,
|
M: AsBytes + FromBytes,
|
||||||
{
|
{
|
||||||
/// Internal business logic: Check the message authentication code produced by [Self::seal]
|
/// Internal business logic: Check the message authentication code produced by [Self::seal]
|
||||||
pub fn check_seal(&self, srv: &CryptoServer) -> Result<bool> {
|
pub fn check_seal(&self, srv: &CryptoServer, shake_or_blake: EitherShakeOrBlake) -> Result<bool> {
|
||||||
let expected = hash_domains::mac()?
|
let expected = hash_domains::mac(shake_or_blake)?
|
||||||
.mix(srv.spkm.deref())?
|
.mix(srv.spkm.deref())?
|
||||||
.mix(&self.as_bytes()[span_of!(Self, msg_type..mac)])?;
|
.mix(&self.as_bytes()[span_of!(Self, msg_type..mac)])?;
|
||||||
Ok(constant_time::memcmp(
|
Ok(constant_time::memcmp(
|
||||||
@@ -3137,11 +3222,11 @@ where
|
|||||||
|
|
||||||
impl InitiatorHandshake {
|
impl InitiatorHandshake {
|
||||||
/// Zero initialization of an InitiatorHandshake, with up to date timestamp
|
/// Zero initialization of an InitiatorHandshake, with up to date timestamp
|
||||||
pub fn zero_with_timestamp(srv: &CryptoServer) -> Self {
|
pub fn zero_with_timestamp(srv: &CryptoServer, shake_or_blake: EitherShakeOrBlake) -> Self {
|
||||||
InitiatorHandshake {
|
InitiatorHandshake {
|
||||||
created_at: srv.timebase.now(),
|
created_at: srv.timebase.now(),
|
||||||
next: HandshakeStateMachine::RespHello,
|
next: HandshakeStateMachine::RespHello,
|
||||||
core: HandshakeState::zero(),
|
core: HandshakeState::zero(shake_or_blake),
|
||||||
eski: ESk::zero(),
|
eski: ESk::zero(),
|
||||||
epki: EPk::zero(),
|
epki: EPk::zero(),
|
||||||
tx_at: 0.0,
|
tx_at: 0.0,
|
||||||
@@ -3156,37 +3241,37 @@ impl InitiatorHandshake {
|
|||||||
|
|
||||||
impl HandshakeState {
|
impl HandshakeState {
|
||||||
/// Zero initialization of an HandshakeState
|
/// Zero initialization of an HandshakeState
|
||||||
pub fn zero() -> Self {
|
pub fn zero(shake_or_blake: EitherShakeOrBlake) -> Self {
|
||||||
Self {
|
Self {
|
||||||
sidi: SessionId::zero(),
|
sidi: SessionId::zero(),
|
||||||
sidr: SessionId::zero(),
|
sidr: SessionId::zero(),
|
||||||
ck: SecretHashDomain::zero().dup(),
|
ck: SecretHashDomain::zero(shake_or_blake).dup(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Securely erase the chaining key
|
/// Securely erase the chaining key
|
||||||
pub fn erase(&mut self) {
|
pub fn erase(&mut self) {
|
||||||
self.ck = SecretHashDomain::zero().dup();
|
self.ck = SecretHashDomain::zero(self.ck.shake_or_blake().clone()).dup();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize the handshake state with the responder public key and the protocol domain
|
/// Initialize the handshake state with the responder public key and the protocol domain
|
||||||
/// separator
|
/// separator
|
||||||
pub fn init(&mut self, spkr: &[u8]) -> Result<&mut Self> {
|
pub fn init(&mut self, spkr: &[u8]) -> Result<&mut Self> {
|
||||||
self.ck = hash_domains::ckinit()?.turn_secret().mix(spkr)?.dup();
|
self.ck = hash_domains::ckinit(self.ck.shake_or_blake().clone())?.turn_secret().mix(spkr)?.dup();
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mix some data into the chaining key. This is used for mixing cryptographic keys and public
|
/// Mix some data into the chaining key. This is used for mixing cryptographic keys and public
|
||||||
/// data alike into the chaining key
|
/// data alike into the chaining key
|
||||||
pub fn mix(&mut self, a: &[u8]) -> Result<&mut Self> {
|
pub fn mix(&mut self, a: &[u8]) -> Result<&mut Self> {
|
||||||
self.ck = self.ck.mix(&hash_domains::mix()?)?.mix(a)?.dup();
|
self.ck = self.ck.mix(&hash_domains::mix(self.ck.shake_or_blake().clone())?)?.mix(a)?.dup();
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Encrypt some data with a value derived from the current chaining key and mix that data
|
/// Encrypt some data with a value derived from the current chaining key and mix that data
|
||||||
/// into the protocol state.
|
/// into the protocol state.
|
||||||
pub fn encrypt_and_mix(&mut self, ct: &mut [u8], pt: &[u8]) -> Result<&mut Self> {
|
pub fn encrypt_and_mix(&mut self, ct: &mut [u8], pt: &[u8]) -> Result<&mut Self> {
|
||||||
let k = self.ck.mix(&hash_domains::hs_enc()?)?.into_secret();
|
let k = self.ck.mix(&hash_domains::hs_enc(self.ck.shake_or_blake().clone())?)?.into_secret();
|
||||||
aead::encrypt(ct, k.secret(), &[0u8; aead::NONCE_LEN], &[], pt)?;
|
aead::encrypt(ct, k.secret(), &[0u8; aead::NONCE_LEN], &[], pt)?;
|
||||||
self.mix(ct)
|
self.mix(ct)
|
||||||
}
|
}
|
||||||
@@ -3196,7 +3281,7 @@ impl HandshakeState {
|
|||||||
/// Makes sure that the same values are mixed into the chaining that where mixed in on the
|
/// Makes sure that the same values are mixed into the chaining that where mixed in on the
|
||||||
/// sender side.
|
/// sender side.
|
||||||
pub fn decrypt_and_mix(&mut self, pt: &mut [u8], ct: &[u8]) -> Result<&mut Self> {
|
pub fn decrypt_and_mix(&mut self, pt: &mut [u8], ct: &[u8]) -> Result<&mut Self> {
|
||||||
let k = self.ck.mix(&hash_domains::hs_enc()?)?.into_secret();
|
let k = self.ck.mix(&hash_domains::hs_enc(self.ck.shake_or_blake().clone())?)?.into_secret();
|
||||||
aead::decrypt(pt, k.secret(), &[0u8; aead::NONCE_LEN], &[], ct)?;
|
aead::decrypt(pt, k.secret(), &[0u8; aead::NONCE_LEN], &[], ct)?;
|
||||||
self.mix(ct)
|
self.mix(ct)
|
||||||
}
|
}
|
||||||
@@ -3259,7 +3344,7 @@ impl HandshakeState {
|
|||||||
.copy_from_slice(self.ck.clone().danger_into_secret().secret());
|
.copy_from_slice(self.ck.clone().danger_into_secret().secret());
|
||||||
|
|
||||||
// calculate ad contents
|
// calculate ad contents
|
||||||
let ad = hash_domains::biscuit_ad()?
|
let ad = hash_domains::biscuit_ad(peer.get(srv).protocol_version.shake_or_blake())?
|
||||||
.mix(srv.spkm.deref())?
|
.mix(srv.spkm.deref())?
|
||||||
.mix(self.sidi.as_slice())?
|
.mix(self.sidi.as_slice())?
|
||||||
.mix(self.sidr.as_slice())?
|
.mix(self.sidr.as_slice())?
|
||||||
@@ -3288,12 +3373,13 @@ impl HandshakeState {
|
|||||||
biscuit_ct: &[u8],
|
biscuit_ct: &[u8],
|
||||||
sidi: SessionId,
|
sidi: SessionId,
|
||||||
sidr: SessionId,
|
sidr: SessionId,
|
||||||
|
shake_or_blake: EitherShakeOrBlake
|
||||||
) -> Result<(PeerPtr, BiscuitId, HandshakeState)> {
|
) -> Result<(PeerPtr, BiscuitId, HandshakeState)> {
|
||||||
// The first bit of the biscuit indicates which biscuit key was used
|
// The first bit of the biscuit indicates which biscuit key was used
|
||||||
let bk = BiscuitKeyPtr(((biscuit_ct[0] & 0b1000_0000) >> 7) as usize);
|
let bk = BiscuitKeyPtr(((biscuit_ct[0] & 0b1000_0000) >> 7) as usize);
|
||||||
|
|
||||||
// Calculate additional data fields
|
// Calculate additional data fields
|
||||||
let ad = hash_domains::biscuit_ad()?
|
let ad = hash_domains::biscuit_ad(shake_or_blake)?
|
||||||
.mix(srv.spkm.deref())?
|
.mix(srv.spkm.deref())?
|
||||||
.mix(sidi.as_slice())?
|
.mix(sidi.as_slice())?
|
||||||
.mix(sidr.as_slice())?
|
.mix(sidr.as_slice())?
|
||||||
@@ -3312,18 +3398,17 @@ impl HandshakeState {
|
|||||||
|
|
||||||
// Reconstruct the biscuit fields
|
// Reconstruct the biscuit fields
|
||||||
let no = BiscuitId::from_slice(&biscuit.biscuit_no);
|
let no = BiscuitId::from_slice(&biscuit.biscuit_no);
|
||||||
let ck = SecretHashDomain::danger_from_secret(Secret::from_slice(&biscuit.ck)).dup();
|
|
||||||
let pid = PeerId::from_slice(&biscuit.pidi);
|
let pid = PeerId::from_slice(&biscuit.pidi);
|
||||||
|
|
||||||
// Reconstruct the handshake state
|
|
||||||
let mut hs = Self { sidi, sidr, ck };
|
|
||||||
hs.mix(biscuit_ct)?;
|
|
||||||
|
|
||||||
// Look up the associated peer
|
// Look up the associated peer
|
||||||
let peer = srv
|
let peer = srv
|
||||||
.find_peer(pid) // TODO: FindPeer should return a Result<()>
|
.find_peer(pid) // TODO: FindPeer should return a Result<()>
|
||||||
.with_context(|| format!("Could not decode biscuit for peer {pid:?}: No such peer."))?;
|
.with_context(|| format!("Could not decode biscuit for peer {pid:?}: No such peer."))?;
|
||||||
|
|
||||||
|
let ck = SecretHashDomain::danger_from_secret(Secret::from_slice(&biscuit.ck), peer.get(srv).protocol_version.shake_or_blake()).dup();
|
||||||
|
// Reconstruct the handshake state
|
||||||
|
let mut hs = Self { sidi, sidr, ck };
|
||||||
|
hs.mix(biscuit_ct)?;
|
||||||
|
|
||||||
Ok((peer, no, hs))
|
Ok((peer, no, hs))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3332,10 +3417,10 @@ impl HandshakeState {
|
|||||||
/// This called by either party.
|
/// This called by either party.
|
||||||
///
|
///
|
||||||
/// `role` indicates whether the local peer was an initiator or responder in the handshake.
|
/// `role` indicates whether the local peer was an initiator or responder in the handshake.
|
||||||
pub fn enter_live(self, srv: &CryptoServer, role: HandshakeRole) -> Result<Session> {
|
pub fn enter_live(self, srv: &CryptoServer, role: HandshakeRole, either_shake_or_blake: EitherShakeOrBlake) -> Result<Session> {
|
||||||
let HandshakeState { ck, sidi, sidr } = self;
|
let HandshakeState { ck, sidi, sidr } = self;
|
||||||
let tki = ck.mix(&hash_domains::ini_enc()?)?.into_secret();
|
let tki = ck.mix(&hash_domains::ini_enc(either_shake_or_blake.clone())?)?.into_secret();
|
||||||
let tkr = ck.mix(&hash_domains::res_enc()?)?.into_secret();
|
let tkr = ck.mix(&hash_domains::res_enc(either_shake_or_blake)?)?.into_secret();
|
||||||
let created_at = srv.timebase.now();
|
let created_at = srv.timebase.now();
|
||||||
let (ntx, nrx) = (0, 0);
|
let (ntx, nrx) = (0, 0);
|
||||||
let (mysid, peersid, ktx, krx) = match role {
|
let (mysid, peersid, ktx, krx) = match role {
|
||||||
@@ -3373,7 +3458,7 @@ impl CryptoServer {
|
|||||||
.get(self)
|
.get(self)
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.with_context(|| format!("No current session for peer {:?}", peer))?;
|
.with_context(|| format!("No current session for peer {:?}", peer))?;
|
||||||
Ok(session.ck.mix(&hash_domains::osk()?)?.into_secret())
|
Ok(session.ck.mix(&hash_domains::osk(peer.get(self).protocol_version.shake_or_blake())?)?.into_secret())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3381,7 +3466,7 @@ impl CryptoServer {
|
|||||||
/// Core cryptographic protocol implementation: Kicks of the handshake
|
/// Core cryptographic protocol implementation: Kicks of the handshake
|
||||||
/// on the initiator side, producing the InitHello message.
|
/// on the initiator side, producing the InitHello message.
|
||||||
pub fn handle_initiation(&mut self, peer: PeerPtr, ih: &mut InitHello) -> Result<PeerPtr> {
|
pub fn handle_initiation(&mut self, peer: PeerPtr, ih: &mut InitHello) -> Result<PeerPtr> {
|
||||||
let mut hs = InitiatorHandshake::zero_with_timestamp(self);
|
let mut hs = InitiatorHandshake::zero_with_timestamp(self, peer.get(self).protocol_version.shake_or_blake());
|
||||||
|
|
||||||
// IHI1
|
// IHI1
|
||||||
hs.core.init(peer.get(self).spkt.deref())?;
|
hs.core.init(peer.get(self).spkt.deref())?;
|
||||||
@@ -3406,7 +3491,7 @@ impl CryptoServer {
|
|||||||
|
|
||||||
// IHI6
|
// IHI6
|
||||||
hs.core
|
hs.core
|
||||||
.encrypt_and_mix(ih.pidic.as_mut_slice(), self.pidm()?.as_ref())?;
|
.encrypt_and_mix(ih.pidic.as_mut_slice(), self.pidm(peer.get(self).protocol_version.shake_or_blake())?.as_ref())?;
|
||||||
|
|
||||||
// IHI7
|
// IHI7
|
||||||
hs.core
|
hs.core
|
||||||
@@ -3424,8 +3509,9 @@ impl CryptoServer {
|
|||||||
|
|
||||||
/// Core cryptographic protocol implementation: Parses an [InitHello] message and produces a
|
/// Core cryptographic protocol implementation: Parses an [InitHello] message and produces a
|
||||||
/// [RespHello] message on the responder side.
|
/// [RespHello] message on the responder side.
|
||||||
pub fn handle_init_hello(&mut self, ih: &InitHello, rh: &mut RespHello) -> Result<PeerPtr> {
|
/// TODO: Document Hash Functon usage
|
||||||
let mut core = HandshakeState::zero();
|
pub fn handle_init_hello(&mut self, ih: &InitHello, rh: &mut RespHello, shake_or_blake: EitherShakeOrBlake) -> Result<PeerPtr> {
|
||||||
|
let mut core = HandshakeState::zero(shake_or_blake);
|
||||||
|
|
||||||
core.sidi = SessionId::from_slice(&ih.sidi);
|
core.sidi = SessionId::from_slice(&ih.sidi);
|
||||||
|
|
||||||
@@ -3570,7 +3656,7 @@ impl CryptoServer {
|
|||||||
|
|
||||||
// ICI7
|
// ICI7
|
||||||
peer.session()
|
peer.session()
|
||||||
.insert(self, core.enter_live(self, HandshakeRole::Initiator)?)?;
|
.insert(self, core.enter_live(self, HandshakeRole::Initiator, peer.get(self).protocol_version.shake_or_blake())?)?;
|
||||||
hs_mut!().core.erase();
|
hs_mut!().core.erase();
|
||||||
hs_mut!().next = HandshakeStateMachine::RespConf;
|
hs_mut!().next = HandshakeStateMachine::RespConf;
|
||||||
|
|
||||||
@@ -3578,11 +3664,12 @@ impl CryptoServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Core cryptographic protocol implementation: Parses an [InitConf] message and produces an
|
/// Core cryptographic protocol implementation: Parses an [InitConf] message and produces an
|
||||||
/// [EmptyData] (responder confimation) message on the responder side.
|
/// [EmptyData] (responder confirmation) message on the responder side.
|
||||||
///
|
///
|
||||||
/// This concludes the handshake on the cryptographic level; the [EmptyData] message is just
|
/// This concludes the handshake on the cryptographic level; the [EmptyData] message is just
|
||||||
/// an acknowledgement message telling the initiator to stop performing retransmissions.
|
/// an acknowledgement message telling the initiator to stop performing retransmissions.
|
||||||
pub fn handle_init_conf(&mut self, ic: &InitConf, rc: &mut EmptyData) -> Result<PeerPtr> {
|
/// TODO: documentation
|
||||||
|
pub fn handle_init_conf(&mut self, ic: &InitConf, rc: &mut EmptyData, shake_or_blake: EitherShakeOrBlake) -> Result<PeerPtr> {
|
||||||
// (peer, bn) ← LoadBiscuit(InitConf.biscuit)
|
// (peer, bn) ← LoadBiscuit(InitConf.biscuit)
|
||||||
// ICR1
|
// ICR1
|
||||||
let (peer, biscuit_no, mut core) = HandshakeState::load_biscuit(
|
let (peer, biscuit_no, mut core) = HandshakeState::load_biscuit(
|
||||||
@@ -3590,6 +3677,7 @@ impl CryptoServer {
|
|||||||
&ic.biscuit,
|
&ic.biscuit,
|
||||||
SessionId::from_slice(&ic.sidi),
|
SessionId::from_slice(&ic.sidi),
|
||||||
SessionId::from_slice(&ic.sidr),
|
SessionId::from_slice(&ic.sidr),
|
||||||
|
shake_or_blake,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// ICR2
|
// ICR2
|
||||||
@@ -3615,7 +3703,7 @@ impl CryptoServer {
|
|||||||
|
|
||||||
// ICR7
|
// ICR7
|
||||||
peer.session()
|
peer.session()
|
||||||
.insert(self, core.enter_live(self, HandshakeRole::Responder)?)?;
|
.insert(self, core.enter_live(self, HandshakeRole::Responder, peer.get(self).protocol_version.shake_or_blake())?)?;
|
||||||
// TODO: This should be part of the protocol specification.
|
// TODO: This should be part of the protocol specification.
|
||||||
// Abort any ongoing handshake from initiator role
|
// Abort any ongoing handshake from initiator role
|
||||||
peer.hs().take(self);
|
peer.hs().take(self);
|
||||||
@@ -3663,11 +3751,13 @@ impl CryptoServer {
|
|||||||
/// message then terminates the handshake.
|
/// message then terminates the handshake.
|
||||||
///
|
///
|
||||||
/// The EmptyData message is just there to tell the initiator to abort retransmissions.
|
/// The EmptyData message is just there to tell the initiator to abort retransmissions.
|
||||||
pub fn handle_resp_conf(&mut self, rc: &EmptyData) -> Result<PeerPtr> {
|
pub fn handle_resp_conf(&mut self, msg_in: &Ref<&[u8], Envelope<EmptyData>>, seal_broken: String) -> Result<PeerPtr> {
|
||||||
|
let rc: &EmptyData = &msg_in.payload;
|
||||||
let sid = SessionId::from_slice(&rc.sid);
|
let sid = SessionId::from_slice(&rc.sid);
|
||||||
let hs = self
|
let hs = self
|
||||||
.lookup_handshake(sid)
|
.lookup_handshake(sid)
|
||||||
.with_context(|| format!("Got RespConf packet for non-existent session {sid:?}"))?;
|
.with_context(|| format!("Got RespConf packet for non-existent session {sid:?}"))?;
|
||||||
|
ensure!(msg_in.check_seal(self, hs.peer().get(self).protocol_version.shake_or_blake())?, seal_broken);
|
||||||
let ses = hs.peer().session();
|
let ses = hs.peer().session();
|
||||||
|
|
||||||
let exp = hs.get(self).as_ref().map(|h| h.next);
|
let exp = hs.get(self).as_ref().map(|h| h.next);
|
||||||
@@ -3685,7 +3775,7 @@ impl CryptoServer {
|
|||||||
let s = ses.get_mut(self).as_mut().with_context(|| {
|
let s = ses.get_mut(self).as_mut().with_context(|| {
|
||||||
format!("Cannot validate EmptyData message. Missing encryption session for {sid:?}")
|
format!("Cannot validate EmptyData message. Missing encryption session for {sid:?}")
|
||||||
})?;
|
})?;
|
||||||
// the unwrap can not fail, because the slice returned by ctr() is
|
// the unwrapping can not fail, because the slice returned by ctr() is
|
||||||
// guaranteed to have the correct size
|
// guaranteed to have the correct size
|
||||||
let n = u64::from_le_bytes(rc.ctr);
|
let n = u64::from_le_bytes(rc.ctr);
|
||||||
ensure!(n >= s.txnt, "Stale nonce");
|
ensure!(n >= s.txnt, "Stale nonce");
|
||||||
@@ -3750,7 +3840,7 @@ impl CryptoServer {
|
|||||||
}?;
|
}?;
|
||||||
|
|
||||||
let spkt = peer.get(self).spkt.deref();
|
let spkt = peer.get(self).spkt.deref();
|
||||||
let cookie_key = hash_domains::cookie_key()?.mix(spkt)?.into_value();
|
let cookie_key = hash_domains::cookie_key(EitherShakeOrBlake::Left(SHAKE256Core))?.mix(spkt)?.into_value();
|
||||||
let cookie_value = peer.cv().update_mut(self).unwrap();
|
let cookie_value = peer.cv().update_mut(self).unwrap();
|
||||||
|
|
||||||
xaead::decrypt(cookie_value, &cookie_key, &mac, &cr.inner.cookie_encrypted)?;
|
xaead::decrypt(cookie_value, &cookie_key, &mac, &cr.inner.cookie_encrypted)?;
|
||||||
@@ -3795,15 +3885,16 @@ pub mod testutils {
|
|||||||
pub srv: CryptoServer,
|
pub srv: CryptoServer,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// TODO: Document that the protocol verson s only used for creating the peer for testing
|
||||||
impl ServerForTesting {
|
impl ServerForTesting {
|
||||||
pub fn new() -> anyhow::Result<Self> {
|
pub fn new(protocol_version: ProtocolVersion) -> anyhow::Result<Self> {
|
||||||
let (mut sskm, mut spkm) = (SSk::zero(), SPk::zero());
|
let (mut sskm, mut spkm) = (SSk::zero(), SPk::zero());
|
||||||
StaticKem::keygen(sskm.secret_mut(), spkm.deref_mut())?;
|
StaticKem::keygen(sskm.secret_mut(), spkm.deref_mut())?;
|
||||||
let mut srv = CryptoServer::new(sskm, spkm);
|
let mut srv = CryptoServer::new(sskm, spkm);
|
||||||
|
|
||||||
let (mut sskt, mut spkt) = (SSk::zero(), SPk::zero());
|
let (mut sskt, mut spkt) = (SSk::zero(), SPk::zero());
|
||||||
StaticKem::keygen(sskt.secret_mut(), spkt.deref_mut())?;
|
StaticKem::keygen(sskt.secret_mut(), spkt.deref_mut())?;
|
||||||
let peer = srv.add_peer(None, spkt.clone())?;
|
let peer = srv.add_peer(None, spkt.clone(), protocol_version)?;
|
||||||
|
|
||||||
let peer_keys = (sskt, spkt);
|
let peer_keys = (sskt, spkt);
|
||||||
Ok(ServerForTesting {
|
Ok(ServerForTesting {
|
||||||
@@ -3868,6 +3959,17 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[serial]
|
#[serial]
|
||||||
|
fn handles_incorrect_size_messages_v02() {
|
||||||
|
handles_incorrect_size_messages(ProtocolVersion::V02)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial]
|
||||||
|
fn handles_incorrect_size_messages_v03() {
|
||||||
|
handles_incorrect_size_messages(ProtocolVersion::V03)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Ensure that the protocol implementation can deal with truncated
|
/// Ensure that the protocol implementation can deal with truncated
|
||||||
/// messages and with overlong messages.
|
/// messages and with overlong messages.
|
||||||
///
|
///
|
||||||
@@ -3882,7 +3984,7 @@ mod test {
|
|||||||
///
|
///
|
||||||
/// Through all this, the handshake should still successfully terminate;
|
/// Through all this, the handshake should still successfully terminate;
|
||||||
/// i.e. an exchanged key must be produced in both servers.
|
/// i.e. an exchanged key must be produced in both servers.
|
||||||
fn handles_incorrect_size_messages() {
|
fn handles_incorrect_size_messages(protocol_version: ProtocolVersion) {
|
||||||
setup_logging();
|
setup_logging();
|
||||||
rosenpass_secret_memory::secret_policy_try_use_memfd_secrets();
|
rosenpass_secret_memory::secret_policy_try_use_memfd_secrets();
|
||||||
stacker::grow(8 * 1024 * 1024, || {
|
stacker::grow(8 * 1024 * 1024, || {
|
||||||
@@ -3891,7 +3993,7 @@ mod test {
|
|||||||
|
|
||||||
const PEER0: PeerPtr = PeerPtr(0);
|
const PEER0: PeerPtr = PeerPtr(0);
|
||||||
|
|
||||||
let (mut me, mut they) = make_server_pair().unwrap();
|
let (mut me, mut they) = make_server_pair(protocol_version).unwrap();
|
||||||
let (mut msgbuf, mut resbuf) = (MsgBufPlus::zero(), MsgBufPlus::zero());
|
let (mut msgbuf, mut resbuf) = (MsgBufPlus::zero(), MsgBufPlus::zero());
|
||||||
|
|
||||||
// Process the entire handshake
|
// Process the entire handshake
|
||||||
@@ -3941,7 +4043,7 @@ mod test {
|
|||||||
Ok((sk, pk))
|
Ok((sk, pk))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_server_pair() -> Result<(CryptoServer, CryptoServer)> {
|
fn make_server_pair(protocol_version: ProtocolVersion) -> Result<(CryptoServer, CryptoServer)> {
|
||||||
// TODO: Copied from the benchmark; deduplicate
|
// TODO: Copied from the benchmark; deduplicate
|
||||||
let psk = SymKey::random();
|
let psk = SymKey::random();
|
||||||
let ((ska, pka), (skb, pkb)) = (keygen()?, keygen()?);
|
let ((ska, pka), (skb, pkb)) = (keygen()?, keygen()?);
|
||||||
@@ -3949,19 +4051,29 @@ mod test {
|
|||||||
CryptoServer::new(ska, pka.clone()),
|
CryptoServer::new(ska, pka.clone()),
|
||||||
CryptoServer::new(skb, pkb.clone()),
|
CryptoServer::new(skb, pkb.clone()),
|
||||||
);
|
);
|
||||||
a.add_peer(Some(psk.clone()), pkb)?;
|
a.add_peer(Some(psk.clone()), pkb, protocol_version.clone())?;
|
||||||
b.add_peer(Some(psk), pka)?;
|
b.add_peer(Some(psk), pka, protocol_version)?;
|
||||||
Ok((a, b))
|
Ok((a, b))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[serial]
|
#[serial]
|
||||||
fn test_regular_exchange() {
|
fn test_regular_exchange_v02() {
|
||||||
|
test_regular_exchange(ProtocolVersion::V02)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial]
|
||||||
|
fn test_regular_exchange_v03() {
|
||||||
|
test_regular_exchange(ProtocolVersion::V03)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_regular_exchange(protocol_version: ProtocolVersion) {
|
||||||
setup_logging();
|
setup_logging();
|
||||||
rosenpass_secret_memory::secret_policy_try_use_memfd_secrets();
|
rosenpass_secret_memory::secret_policy_try_use_memfd_secrets();
|
||||||
stacker::grow(8 * 1024 * 1024, || {
|
stacker::grow(8 * 1024 * 1024, || {
|
||||||
type MsgBufPlus = Public<MAX_MESSAGE_LEN>;
|
type MsgBufPlus = Public<MAX_MESSAGE_LEN>;
|
||||||
let (mut a, mut b) = make_server_pair().unwrap();
|
let (mut a, mut b) = make_server_pair(protocol_version).unwrap();
|
||||||
|
|
||||||
let mut a_to_b_buf = MsgBufPlus::zero();
|
let mut a_to_b_buf = MsgBufPlus::zero();
|
||||||
let mut b_to_a_buf = MsgBufPlus::zero();
|
let mut b_to_a_buf = MsgBufPlus::zero();
|
||||||
@@ -4017,12 +4129,22 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[serial]
|
#[serial]
|
||||||
fn test_regular_init_conf_retransmit() {
|
fn test_regular_init_conf_retransmit_v02() {
|
||||||
|
test_regular_init_conf_retransmit(ProtocolVersion::V02)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial]
|
||||||
|
fn test_regular_init_conf_retransmit_v03() {
|
||||||
|
test_regular_init_conf_retransmit(ProtocolVersion::V03)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_regular_init_conf_retransmit(protocol_version: ProtocolVersion) {
|
||||||
setup_logging();
|
setup_logging();
|
||||||
rosenpass_secret_memory::secret_policy_try_use_memfd_secrets();
|
rosenpass_secret_memory::secret_policy_try_use_memfd_secrets();
|
||||||
stacker::grow(8 * 1024 * 1024, || {
|
stacker::grow(8 * 1024 * 1024, || {
|
||||||
type MsgBufPlus = Public<MAX_MESSAGE_LEN>;
|
type MsgBufPlus = Public<MAX_MESSAGE_LEN>;
|
||||||
let (mut a, mut b) = make_server_pair().unwrap();
|
let (mut a, mut b) = make_server_pair(protocol_version).unwrap();
|
||||||
|
|
||||||
let mut a_to_b_buf = MsgBufPlus::zero();
|
let mut a_to_b_buf = MsgBufPlus::zero();
|
||||||
let mut b_to_a_buf = MsgBufPlus::zero();
|
let mut b_to_a_buf = MsgBufPlus::zero();
|
||||||
@@ -4092,12 +4214,22 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[serial]
|
#[serial]
|
||||||
fn cookie_reply_mechanism_responder_under_load() {
|
fn cookie_reply_mechanism_responder_under_load_v02() {
|
||||||
|
cookie_reply_mechanism_initiator_bails_on_message_under_load(ProtocolVersion::V02)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial]
|
||||||
|
fn cookie_reply_mechanism_responder_under_load_v03() {
|
||||||
|
cookie_reply_mechanism_initiator_bails_on_message_under_load(ProtocolVersion::V03)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cookie_reply_mechanism_responder_under_load(protocol_version: ProtocolVersion) {
|
||||||
setup_logging();
|
setup_logging();
|
||||||
rosenpass_secret_memory::secret_policy_try_use_memfd_secrets();
|
rosenpass_secret_memory::secret_policy_try_use_memfd_secrets();
|
||||||
stacker::grow(8 * 1024 * 1024, || {
|
stacker::grow(8 * 1024 * 1024, || {
|
||||||
type MsgBufPlus = Public<MAX_MESSAGE_LEN>;
|
type MsgBufPlus = Public<MAX_MESSAGE_LEN>;
|
||||||
let (mut a, mut b) = make_server_pair().unwrap();
|
let (mut a, mut b) = make_server_pair(protocol_version.clone()).unwrap();
|
||||||
|
|
||||||
let mut a_to_b_buf = MsgBufPlus::zero();
|
let mut a_to_b_buf = MsgBufPlus::zero();
|
||||||
let mut b_to_a_buf = MsgBufPlus::zero();
|
let mut b_to_a_buf = MsgBufPlus::zero();
|
||||||
@@ -4136,7 +4268,7 @@ mod test {
|
|||||||
|
|
||||||
assert_eq!(PeerPtr(0).cv().lifecycle(&a), Lifecycle::Young);
|
assert_eq!(PeerPtr(0).cv().lifecycle(&a), Lifecycle::Young);
|
||||||
|
|
||||||
let expected_cookie_value = hash_domains::cookie_value()
|
let expected_cookie_value = hash_domains::cookie_value(protocol_version.shake_or_blake())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.mix(
|
.mix(
|
||||||
b.active_or_retired_cookie_secrets()[0]
|
b.active_or_retired_cookie_secrets()[0]
|
||||||
@@ -4189,12 +4321,22 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[serial]
|
#[serial]
|
||||||
fn cookie_reply_mechanism_initiator_bails_on_message_under_load() {
|
fn cookie_reply_mechanism_initiator_bails_on_message_under_load_v02() {
|
||||||
|
cookie_reply_mechanism_initiator_bails_on_message_under_load(ProtocolVersion::V02)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial]
|
||||||
|
fn cookie_reply_mechanism_initiator_bails_on_message_under_load_v03() {
|
||||||
|
cookie_reply_mechanism_initiator_bails_on_message_under_load(ProtocolVersion::V03)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cookie_reply_mechanism_initiator_bails_on_message_under_load(protocol_version: ProtocolVersion) {
|
||||||
setup_logging();
|
setup_logging();
|
||||||
rosenpass_secret_memory::secret_policy_try_use_memfd_secrets();
|
rosenpass_secret_memory::secret_policy_try_use_memfd_secrets();
|
||||||
stacker::grow(8 * 1024 * 1024, || {
|
stacker::grow(8 * 1024 * 1024, || {
|
||||||
type MsgBufPlus = Public<MAX_MESSAGE_LEN>;
|
type MsgBufPlus = Public<MAX_MESSAGE_LEN>;
|
||||||
let (mut a, mut b) = make_server_pair().unwrap();
|
let (mut a, mut b) = make_server_pair(protocol_version).unwrap();
|
||||||
|
|
||||||
let mut a_to_b_buf = MsgBufPlus::zero();
|
let mut a_to_b_buf = MsgBufPlus::zero();
|
||||||
let mut b_to_a_buf = MsgBufPlus::zero();
|
let mut b_to_a_buf = MsgBufPlus::zero();
|
||||||
@@ -4249,10 +4391,19 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn init_conf_retransmission() -> anyhow::Result<()> {
|
fn init_conf_retransmission_v02() -> Result<()> {
|
||||||
|
init_conf_retransmission(ProtocolVersion::V02)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn init_conf_retransmission_v03() -> Result<()> {
|
||||||
|
init_conf_retransmission(ProtocolVersion::V03)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_conf_retransmission(protocol_version: ProtocolVersion) -> anyhow::Result<()> {
|
||||||
rosenpass_secret_memory::secret_policy_try_use_memfd_secrets();
|
rosenpass_secret_memory::secret_policy_try_use_memfd_secrets();
|
||||||
|
|
||||||
fn keypair() -> anyhow::Result<(SSk, SPk)> {
|
fn keypair() -> Result<(SSk, SPk)> {
|
||||||
let (mut sk, mut pk) = (SSk::zero(), SPk::zero());
|
let (mut sk, mut pk) = (SSk::zero(), SPk::zero());
|
||||||
StaticKem::keygen(sk.secret_mut(), pk.deref_mut())?;
|
StaticKem::keygen(sk.secret_mut(), pk.deref_mut())?;
|
||||||
Ok((sk, pk))
|
Ok((sk, pk))
|
||||||
@@ -4261,7 +4412,7 @@ mod test {
|
|||||||
fn proc_initiation(
|
fn proc_initiation(
|
||||||
srv: &mut CryptoServer,
|
srv: &mut CryptoServer,
|
||||||
peer: PeerPtr,
|
peer: PeerPtr,
|
||||||
) -> anyhow::Result<Envelope<InitHello>> {
|
) -> Result<Envelope<InitHello>> {
|
||||||
let mut buf = MsgBuf::zero();
|
let mut buf = MsgBuf::zero();
|
||||||
srv.initiate_handshake(peer, buf.as_mut_slice())?
|
srv.initiate_handshake(peer, buf.as_mut_slice())?
|
||||||
.discard_result();
|
.discard_result();
|
||||||
@@ -4331,12 +4482,8 @@ mod test {
|
|||||||
assert!(res.is_err());
|
assert!(res.is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_retransmission(
|
// we this as a closure in orer to use the protocol_version variable in it.
|
||||||
srv: &mut CryptoServer,
|
let check_retransmission = |srv: &mut CryptoServer, ic: &Envelope<InitConf>, ic_broken: &Envelope<InitConf>, rc: &Envelope<EmptyData>| -> Result<()> {
|
||||||
ic: &Envelope<InitConf>,
|
|
||||||
ic_broken: &Envelope<InitConf>,
|
|
||||||
rc: &Envelope<EmptyData>,
|
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
// Processing the same RespHello package again leads to retransmission (i.e. exactly the
|
// Processing the same RespHello package again leads to retransmission (i.e. exactly the
|
||||||
// same output)
|
// same output)
|
||||||
let rc_dup = proc_init_conf(srv, ic)?;
|
let rc_dup = proc_init_conf(srv, ic)?;
|
||||||
@@ -4345,14 +4492,14 @@ mod test {
|
|||||||
// Though if we directly call handle_resp_hello() we get an error since
|
// Though if we directly call handle_resp_hello() we get an error since
|
||||||
// retransmission is not being handled by the cryptographic code
|
// retransmission is not being handled by the cryptographic code
|
||||||
let mut discard_resp_conf = EmptyData::new_zeroed();
|
let mut discard_resp_conf = EmptyData::new_zeroed();
|
||||||
let res = srv.handle_init_conf(&ic.payload, &mut discard_resp_conf);
|
let res = srv.handle_init_conf(&ic.payload, &mut discard_resp_conf, protocol_version.clone().shake_or_blake());
|
||||||
assert!(res.is_err());
|
assert!(res.is_err());
|
||||||
|
|
||||||
// Obviously, a broken InitConf message should still be rejected
|
// Obviously, a broken InitConf message should still be rejected
|
||||||
check_faulty_proc_init_conf(srv, ic_broken);
|
check_faulty_proc_init_conf(srv, ic_broken);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
};
|
||||||
|
|
||||||
let (ska, pka) = keypair()?;
|
let (ska, pka) = keypair()?;
|
||||||
let (skb, pkb) = keypair()?;
|
let (skb, pkb) = keypair()?;
|
||||||
@@ -4362,8 +4509,8 @@ mod test {
|
|||||||
let mut b = CryptoServer::new(skb, pkb.clone());
|
let mut b = CryptoServer::new(skb, pkb.clone());
|
||||||
|
|
||||||
// introduce peers to each other
|
// introduce peers to each other
|
||||||
let b_peer = a.add_peer(None, pkb)?;
|
let b_peer = a.add_peer(None, pkb, protocol_version.clone())?;
|
||||||
let a_peer = b.add_peer(None, pka)?;
|
let a_peer = b.add_peer(None, pka, protocol_version.clone())?;
|
||||||
|
|
||||||
// Execute protocol up till the responder confirmation (EmptyData)
|
// Execute protocol up till the responder confirmation (EmptyData)
|
||||||
let ih1 = proc_initiation(&mut a, b_peer)?;
|
let ih1 = proc_initiation(&mut a, b_peer)?;
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ use rosenpass_util::{
|
|||||||
use std::os::fd::{AsFd, AsRawFd};
|
use std::os::fd::{AsFd, AsRawFd};
|
||||||
use tempfile::TempDir;
|
use tempfile::TempDir;
|
||||||
use zerocopy::AsBytes;
|
use zerocopy::AsBytes;
|
||||||
|
use rosenpass::config::ProtocolVersion;
|
||||||
use rosenpass::protocol::SymKey;
|
use rosenpass::protocol::SymKey;
|
||||||
|
|
||||||
struct KillChild(std::process::Child);
|
struct KillChild(std::process::Child);
|
||||||
@@ -48,7 +48,16 @@ impl Drop for KillChild {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn api_integration_api_setup() -> anyhow::Result<()> {
|
fn api_integration_api_setup_v02() -> anyhow::Result<()> {
|
||||||
|
api_integration_api_setup(ProtocolVersion::V02)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn api_integration_api_setup_v03() -> anyhow::Result<()> {
|
||||||
|
api_integration_api_setup(ProtocolVersion::V03)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn api_integration_api_setup(protocol_version: ProtocolVersion) -> anyhow::Result<()> {
|
||||||
rosenpass_secret_memory::policy::secret_policy_use_only_malloc_secrets();
|
rosenpass_secret_memory::policy::secret_policy_use_only_malloc_secrets();
|
||||||
|
|
||||||
let dir = TempDir::with_prefix("rosenpass-api-integration-test")?;
|
let dir = TempDir::with_prefix("rosenpass-api-integration-test")?;
|
||||||
@@ -96,6 +105,7 @@ fn api_integration_api_setup() -> anyhow::Result<()> {
|
|||||||
peer: format!("{}", peer_b_wg_peer_id.fmt_b64::<8129>()),
|
peer: format!("{}", peer_b_wg_peer_id.fmt_b64::<8129>()),
|
||||||
extra_params: vec![],
|
extra_params: vec![],
|
||||||
}),
|
}),
|
||||||
|
protocol_version: protocol_version.clone(),
|
||||||
}],
|
}],
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -116,6 +126,7 @@ fn api_integration_api_setup() -> anyhow::Result<()> {
|
|||||||
endpoint: Some(peer_a_endpoint.to_owned()),
|
endpoint: Some(peer_a_endpoint.to_owned()),
|
||||||
pre_shared_key: None,
|
pre_shared_key: None,
|
||||||
wg: None,
|
wg: None,
|
||||||
|
protocol_version: protocol_version.clone(),
|
||||||
}],
|
}],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ use tempfile::TempDir;
|
|||||||
use zerocopy::AsBytes;
|
use zerocopy::AsBytes;
|
||||||
|
|
||||||
use rosenpass::protocol::SymKey;
|
use rosenpass::protocol::SymKey;
|
||||||
|
use rosenpass::config::ProtocolVersion;
|
||||||
|
|
||||||
struct KillChild(std::process::Child);
|
struct KillChild(std::process::Child);
|
||||||
|
|
||||||
@@ -37,7 +38,16 @@ impl Drop for KillChild {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn api_integration_test() -> anyhow::Result<()> {
|
fn api_integration_test_v02() -> anyhow::Result<()> {
|
||||||
|
api_integration_test(ProtocolVersion::V02)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn api_integration_test_v03() -> anyhow::Result<()> {
|
||||||
|
api_integration_test(ProtocolVersion::V03)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn api_integration_test(protocol_version: ProtocolVersion) -> anyhow::Result<()> {
|
||||||
rosenpass_secret_memory::policy::secret_policy_use_only_malloc_secrets();
|
rosenpass_secret_memory::policy::secret_policy_use_only_malloc_secrets();
|
||||||
|
|
||||||
let dir = TempDir::with_prefix("rosenpass-api-integration-test")?;
|
let dir = TempDir::with_prefix("rosenpass-api-integration-test")?;
|
||||||
@@ -73,6 +83,7 @@ fn api_integration_test() -> anyhow::Result<()> {
|
|||||||
endpoint: None,
|
endpoint: None,
|
||||||
pre_shared_key: None,
|
pre_shared_key: None,
|
||||||
wg: None,
|
wg: None,
|
||||||
|
protocol_version: protocol_version.clone(),
|
||||||
}],
|
}],
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -93,6 +104,7 @@ fn api_integration_test() -> anyhow::Result<()> {
|
|||||||
endpoint: Some(peer_a_endpoint.to_owned()),
|
endpoint: Some(peer_a_endpoint.to_owned()),
|
||||||
pre_shared_key: None,
|
pre_shared_key: None,
|
||||||
wg: None,
|
wg: None,
|
||||||
|
protocol_version: protocol_version.clone(),
|
||||||
}],
|
}],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -13,13 +13,23 @@ use rosenpass::{
|
|||||||
app_server::{ipv4_any_binding, ipv6_any_binding, AppServer, AppServerTest, MAX_B64_KEY_SIZE},
|
app_server::{ipv4_any_binding, ipv6_any_binding, AppServer, AppServerTest, MAX_B64_KEY_SIZE},
|
||||||
protocol::{SPk, SSk, SymKey},
|
protocol::{SPk, SSk, SymKey},
|
||||||
};
|
};
|
||||||
|
use rosenpass::config::ProtocolVersion;
|
||||||
use rosenpass_cipher_traits::Kem;
|
use rosenpass_cipher_traits::Kem;
|
||||||
use rosenpass_ciphers::kem::StaticKem;
|
use rosenpass_ciphers::kem::StaticKem;
|
||||||
use rosenpass_secret_memory::Secret;
|
use rosenpass_secret_memory::Secret;
|
||||||
use rosenpass_util::{file::LoadValueB64, functional::run, mem::DiscardResultExt, result::OkExt};
|
use rosenpass_util::{file::LoadValueB64, functional::run, mem::DiscardResultExt, result::OkExt};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn key_exchange_with_app_server() -> anyhow::Result<()> {
|
fn key_exchange_with_app_server_v02() -> anyhow::Result<()> {
|
||||||
|
key_exchange_with_app_server(ProtocolVersion::V02)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn key_exchange_with_app_server_v03() -> anyhow::Result<()> {
|
||||||
|
key_exchange_with_app_server(ProtocolVersion::V03)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn key_exchange_with_app_server(protocol_version: ProtocolVersion) -> anyhow::Result<()> {
|
||||||
let tmpdir = tempfile::tempdir()?;
|
let tmpdir = tempfile::tempdir()?;
|
||||||
let outfile_a = tmpdir.path().join("osk_a");
|
let outfile_a = tmpdir.path().join("osk_a");
|
||||||
let outfile_b = tmpdir.path().join("osk_b");
|
let outfile_b = tmpdir.path().join("osk_b");
|
||||||
@@ -57,7 +67,7 @@ fn key_exchange_with_app_server() -> anyhow::Result<()> {
|
|||||||
let port = otr_port;
|
let port = otr_port;
|
||||||
let hostname = is_client.then(|| format!("[::1]:{port}"));
|
let hostname = is_client.then(|| format!("[::1]:{port}"));
|
||||||
srv.app_srv
|
srv.app_srv
|
||||||
.add_peer(psk, pk, outfile, broker_peer, hostname)?;
|
.add_peer(psk, pk, outfile, broker_peer, hostname, protocol_version.clone())?;
|
||||||
|
|
||||||
srv.app_srv.event_loop()
|
srv.app_srv.event_loop()
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -251,7 +251,7 @@ fn check_exchange_under_normal() {
|
|||||||
fs::remove_dir_all(&tmpdir).unwrap();
|
fs::remove_dir_all(&tmpdir).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
// check that we can trigger a DoS condition and we can exchange keys under DoS
|
// check that we can trigger a DoS condition, and we can exchange keys under DoS
|
||||||
// This test creates a responder (server) with the feature flag "integration_test_always_under_load" to always be under load condition for the test.
|
// This test creates a responder (server) with the feature flag "integration_test_always_under_load" to always be under load condition for the test.
|
||||||
#[test]
|
#[test]
|
||||||
#[serial]
|
#[serial]
|
||||||
|
|||||||
@@ -9,20 +9,26 @@ use rosenpass_cipher_traits::Kem;
|
|||||||
use rosenpass_ciphers::kem::StaticKem;
|
use rosenpass_ciphers::kem::StaticKem;
|
||||||
use rosenpass_util::result::OkExt;
|
use rosenpass_util::result::OkExt;
|
||||||
|
|
||||||
use rosenpass::protocol::{
|
use rosenpass::protocol::{testutils::time_travel_forward, CryptoServer, HostIdentification, MsgBuf, PeerPtr, PollResult, ProtocolVersion, SPk, SSk, SymKey, Timing, UNENDING};
|
||||||
testutils::time_travel_forward, CryptoServer, HostIdentification, MsgBuf, PeerPtr, PollResult,
|
|
||||||
SPk, SSk, SymKey, Timing, UNENDING,
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: Most of the utility functions in here should probably be moved to
|
// TODO: Most of the utility functions in here should probably be moved to
|
||||||
// rosenpass::protocol::testutils;
|
// rosenpass::protocol::testutils;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_successful_exchange_with_poll() -> anyhow::Result<()> {
|
fn test_successful_exchange_with_poll_v02() -> anyhow::Result<()> {
|
||||||
|
test_successful_exchange_with_poll(ProtocolVersion::V02)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_successful_exchange_with_poll_v03() -> anyhow::Result<()> {
|
||||||
|
test_successful_exchange_with_poll(ProtocolVersion::V03)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_successful_exchange_with_poll(protocol_version: ProtocolVersion) -> anyhow::Result<()> {
|
||||||
// Set security policy for storing secrets; choose the one that is faster for testing
|
// Set security policy for storing secrets; choose the one that is faster for testing
|
||||||
rosenpass_secret_memory::policy::secret_policy_use_only_malloc_secrets();
|
rosenpass_secret_memory::policy::secret_policy_use_only_malloc_secrets();
|
||||||
|
|
||||||
let mut sim = RosenpassSimulator::new()?;
|
let mut sim = RosenpassSimulator::new(protocol_version)?;
|
||||||
sim.poll_loop(150)?; // Poll 75 times
|
sim.poll_loop(150)?; // Poll 75 times
|
||||||
let transcript = sim.transcript;
|
let transcript = sim.transcript;
|
||||||
|
|
||||||
@@ -79,12 +85,21 @@ fn test_successful_exchange_with_poll() -> anyhow::Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_successful_exchange_under_packet_loss() -> anyhow::Result<()> {
|
fn test_successful_exchange_under_packet_loss_v02() -> anyhow::Result<()> {
|
||||||
|
test_successful_exchange_under_packet_loss(ProtocolVersion::V02)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_successful_exchange_under_packet_loss_v03() -> anyhow::Result<()> {
|
||||||
|
test_successful_exchange_under_packet_loss(ProtocolVersion::V03)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_successful_exchange_under_packet_loss(protocol_version: ProtocolVersion) -> anyhow::Result<()> {
|
||||||
// Set security policy for storing secrets; choose the one that is faster for testing
|
// Set security policy for storing secrets; choose the one that is faster for testing
|
||||||
rosenpass_secret_memory::policy::secret_policy_use_only_malloc_secrets();
|
rosenpass_secret_memory::policy::secret_policy_use_only_malloc_secrets();
|
||||||
|
|
||||||
// Create the simulator
|
// Create the simulator
|
||||||
let mut sim = RosenpassSimulator::new()?;
|
let mut sim = RosenpassSimulator::new(protocol_version)?;
|
||||||
|
|
||||||
// Make sure the servers are set to under load condition
|
// Make sure the servers are set to under load condition
|
||||||
sim.srv_a.under_load = true;
|
sim.srv_a.under_load = true;
|
||||||
@@ -272,7 +287,7 @@ struct SimulatorServer {
|
|||||||
|
|
||||||
impl RosenpassSimulator {
|
impl RosenpassSimulator {
|
||||||
/// Set up the simulator
|
/// Set up the simulator
|
||||||
fn new() -> anyhow::Result<Self> {
|
fn new(protocol_version: ProtocolVersion) -> anyhow::Result<Self> {
|
||||||
// Set up the first server
|
// Set up the first server
|
||||||
let (mut peer_a_sk, mut peer_a_pk) = (SSk::zero(), SPk::zero());
|
let (mut peer_a_sk, mut peer_a_pk) = (SSk::zero(), SPk::zero());
|
||||||
StaticKem::keygen(peer_a_sk.secret_mut(), peer_a_pk.deref_mut())?;
|
StaticKem::keygen(peer_a_sk.secret_mut(), peer_a_pk.deref_mut())?;
|
||||||
@@ -285,8 +300,8 @@ impl RosenpassSimulator {
|
|||||||
|
|
||||||
// Generate a PSK and introduce the Peers to each other.
|
// Generate a PSK and introduce the Peers to each other.
|
||||||
let psk = SymKey::random();
|
let psk = SymKey::random();
|
||||||
let peer_a = srv_a.add_peer(Some(psk.clone()), peer_b_pk)?;
|
let peer_a = srv_a.add_peer(Some(psk.clone()), peer_b_pk, protocol_version.clone())?;
|
||||||
let peer_b = srv_b.add_peer(Some(psk), peer_a_pk)?;
|
let peer_b = srv_b.add_peer(Some(psk), peer_a_pk, protocol_version.clone())?;
|
||||||
|
|
||||||
// Set up the individual server data structures
|
// Set up the individual server data structures
|
||||||
let srv_a = SimulatorServer::new(srv_a, peer_b);
|
let srv_a = SimulatorServer::new(srv_a, peer_b);
|
||||||
@@ -314,8 +329,8 @@ impl RosenpassSimulator {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Every call to poll produces one [TranscriptEvent] and
|
/// Every call to poll produces one [TranscriptEvent]
|
||||||
/// and implicitly adds it to [Self:::transcript]
|
/// and implicitly adds it to [Self::transcript]
|
||||||
fn poll(&mut self) -> anyhow::Result<&TranscriptEvent> {
|
fn poll(&mut self) -> anyhow::Result<&TranscriptEvent> {
|
||||||
let ev = TranscriptEvent::begin_poll()
|
let ev = TranscriptEvent::begin_poll()
|
||||||
.try_fold_with(|| self.poll_focus.poll(self))?
|
.try_fold_with(|| self.poll_focus.poll(self))?
|
||||||
|
|||||||
Reference in New Issue
Block a user