mirror of
https://github.com/rosenpass/rosenpass.git
synced 2025-12-17 04:44:37 +03:00
Start splitting protocol.rs into multiple files (#655)
Some checks failed
Nix / Build i686-linux.rosenpass (push) Has been cancelled
Nix / Run Nix checks on i686-linux (push) Has been cancelled
rosenpass-ciphers - primitives - benchmark / prim-benchmark (i686-linux) (push) Has been cancelled
rosenpass-ciphers - primitives - benchmark / prim-benchmark (x86_64-linux) (push) Has been cancelled
rosenpass - protocol - benchmark / proto-benchmark (i686-linux) (push) Has been cancelled
rosenpass - protocol - benchmark / proto-benchmark (x86_64-linux) (push) Has been cancelled
Build Docker Images / build-and-test-rp (amd64) (push) Has been cancelled
Build Docker Images / build-and-test-rp (arm64) (push) Has been cancelled
Nix on Mac / Build aarch64-darwin.rosenpass (push) Has been cancelled
Nix on Mac / Build aarch64-darwin.rp (push) Has been cancelled
Nix on Mac / Run Nix checks on aarch64-darwin (push) Has been cancelled
Nix / Build x86_64-linux.proverif-patched (push) Has been cancelled
Nix / Build x86_64-linux.rosenpass (push) Has been cancelled
Nix / Build aarch64-linux.rosenpass (push) Has been cancelled
Nix / Build aarch64-linux.rp (push) Has been cancelled
Nix / Build x86_64-linux.rosenpass-static (push) Has been cancelled
Nix / Build x86_64-linux.rp-static (push) Has been cancelled
Nix / Build x86_64-linux.whitepaper (push) Has been cancelled
Nix / Run Nix checks on x86_64-linux (push) Has been cancelled
Nix / Upload whitepaper x86_64-linux (push) Has been cancelled
QC Mac / cargo-test-mac (push) Has been cancelled
QC / prettier (push) Has been cancelled
QC / Shellcheck (push) Has been cancelled
QC / Rust code formatting (push) Has been cancelled
QC / cargo-bench (push) Has been cancelled
QC / mandoc (push) Has been cancelled
QC / cargo-audit (push) Has been cancelled
QC / cargo-clippy (push) Has been cancelled
QC / cargo-doc (push) Has been cancelled
QC / cargo-test (push) Has been cancelled
QC / cargo-test-nix-devshell-x86_64-linux (push) Has been cancelled
QC / cargo-fuzz (push) Has been cancelled
QC / codecov (push) Has been cancelled
Regressions / multi-peer (push) Has been cancelled
Regressions / boot-race (push) Has been cancelled
Supply-Chain / Deny dependencies with vulnerabilities or incompatible licenses (push) Has been cancelled
Supply-Chain / Supply Chain Report (push) Has been cancelled
Supply-Chain / Vet Dependencies (push) Has been cancelled
Nix / Build i686-linux.default (push) Has been cancelled
Nix / Build i686-linux.rosenpass-oci-image (push) Has been cancelled
Nix / Build x86_64-linux.default (push) Has been cancelled
Nix / Build x86_64-linux.proof-proverif (push) Has been cancelled
Build Docker Images / docker-image-rosenpass (arm64) (push) Has been cancelled
rosenpass-ciphers - primitives - benchmark / ciphers-primitives-bench-status (push) Has been cancelled
rosenpass - protocol - benchmark / ciphers-protocol-bench-status (push) Has been cancelled
Build Docker Images / docker-image-rp (amd64) (push) Has been cancelled
Build Docker Images / docker-image-rp (arm64) (push) Has been cancelled
Build Docker Images / docker-image-rosenpass (amd64) (push) Has been cancelled
Build Docker Images / merge-digests (rosenpass) (push) Has been cancelled
Build Docker Images / merge-digests (rp) (push) Has been cancelled
Nix on Mac / Build aarch64-darwin.default (push) Has been cancelled
Nix on Mac / Build aarch64-darwin.release-package (push) Has been cancelled
Nix on Mac / Build aarch64-darwin.rosenpass-oci-image (push) Has been cancelled
Nix / Build x86_64-linux.release-package (push) Has been cancelled
Nix / Build x86_64-linux.rosenpass-oci-image (push) Has been cancelled
Nix / Build aarch64-linux.rosenpass-oci-image (push) Has been cancelled
Nix / Build x86_64-linux.rosenpass-static-oci-image (push) Has been cancelled
Dependent Issues / check (push) Has been cancelled
Some checks failed
Nix / Build i686-linux.rosenpass (push) Has been cancelled
Nix / Run Nix checks on i686-linux (push) Has been cancelled
rosenpass-ciphers - primitives - benchmark / prim-benchmark (i686-linux) (push) Has been cancelled
rosenpass-ciphers - primitives - benchmark / prim-benchmark (x86_64-linux) (push) Has been cancelled
rosenpass - protocol - benchmark / proto-benchmark (i686-linux) (push) Has been cancelled
rosenpass - protocol - benchmark / proto-benchmark (x86_64-linux) (push) Has been cancelled
Build Docker Images / build-and-test-rp (amd64) (push) Has been cancelled
Build Docker Images / build-and-test-rp (arm64) (push) Has been cancelled
Nix on Mac / Build aarch64-darwin.rosenpass (push) Has been cancelled
Nix on Mac / Build aarch64-darwin.rp (push) Has been cancelled
Nix on Mac / Run Nix checks on aarch64-darwin (push) Has been cancelled
Nix / Build x86_64-linux.proverif-patched (push) Has been cancelled
Nix / Build x86_64-linux.rosenpass (push) Has been cancelled
Nix / Build aarch64-linux.rosenpass (push) Has been cancelled
Nix / Build aarch64-linux.rp (push) Has been cancelled
Nix / Build x86_64-linux.rosenpass-static (push) Has been cancelled
Nix / Build x86_64-linux.rp-static (push) Has been cancelled
Nix / Build x86_64-linux.whitepaper (push) Has been cancelled
Nix / Run Nix checks on x86_64-linux (push) Has been cancelled
Nix / Upload whitepaper x86_64-linux (push) Has been cancelled
QC Mac / cargo-test-mac (push) Has been cancelled
QC / prettier (push) Has been cancelled
QC / Shellcheck (push) Has been cancelled
QC / Rust code formatting (push) Has been cancelled
QC / cargo-bench (push) Has been cancelled
QC / mandoc (push) Has been cancelled
QC / cargo-audit (push) Has been cancelled
QC / cargo-clippy (push) Has been cancelled
QC / cargo-doc (push) Has been cancelled
QC / cargo-test (push) Has been cancelled
QC / cargo-test-nix-devshell-x86_64-linux (push) Has been cancelled
QC / cargo-fuzz (push) Has been cancelled
QC / codecov (push) Has been cancelled
Regressions / multi-peer (push) Has been cancelled
Regressions / boot-race (push) Has been cancelled
Supply-Chain / Deny dependencies with vulnerabilities or incompatible licenses (push) Has been cancelled
Supply-Chain / Supply Chain Report (push) Has been cancelled
Supply-Chain / Vet Dependencies (push) Has been cancelled
Nix / Build i686-linux.default (push) Has been cancelled
Nix / Build i686-linux.rosenpass-oci-image (push) Has been cancelled
Nix / Build x86_64-linux.default (push) Has been cancelled
Nix / Build x86_64-linux.proof-proverif (push) Has been cancelled
Build Docker Images / docker-image-rosenpass (arm64) (push) Has been cancelled
rosenpass-ciphers - primitives - benchmark / ciphers-primitives-bench-status (push) Has been cancelled
rosenpass - protocol - benchmark / ciphers-protocol-bench-status (push) Has been cancelled
Build Docker Images / docker-image-rp (amd64) (push) Has been cancelled
Build Docker Images / docker-image-rp (arm64) (push) Has been cancelled
Build Docker Images / docker-image-rosenpass (amd64) (push) Has been cancelled
Build Docker Images / merge-digests (rosenpass) (push) Has been cancelled
Build Docker Images / merge-digests (rp) (push) Has been cancelled
Nix on Mac / Build aarch64-darwin.default (push) Has been cancelled
Nix on Mac / Build aarch64-darwin.release-package (push) Has been cancelled
Nix on Mac / Build aarch64-darwin.rosenpass-oci-image (push) Has been cancelled
Nix / Build x86_64-linux.release-package (push) Has been cancelled
Nix / Build x86_64-linux.rosenpass-oci-image (push) Has been cancelled
Nix / Build aarch64-linux.rosenpass-oci-image (push) Has been cancelled
Nix / Build x86_64-linux.rosenpass-static-oci-image (push) Has been cancelled
Dependent Issues / check (push) Has been cancelled
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
use anyhow::Result;
|
||||
use rosenpass::protocol::{
|
||||
CryptoServer, HandleMsgResult, MsgBuf, PeerPtr, ProtocolVersion, SPk, SSk, SymKey,
|
||||
};
|
||||
use rosenpass::protocol::basic_types::{MsgBuf, SPk, SSk, SymKey};
|
||||
use rosenpass::protocol::{CryptoServer, HandleMsgResult, PeerPtr, ProtocolVersion};
|
||||
use std::ops::DerefMut;
|
||||
|
||||
use rosenpass_cipher_traits::primitives::Kem;
|
||||
|
||||
@@ -14,9 +14,8 @@ use rosenpass_ciphers::StaticKem;
|
||||
use rosenpass_secret_memory::secret_policy_try_use_memfd_secrets;
|
||||
use rosenpass_util::trace_bench::RpEventType;
|
||||
|
||||
use rosenpass::protocol::{
|
||||
CryptoServer, HandleMsgResult, MsgBuf, PeerPtr, ProtocolVersion, SPk, SSk, SymKey,
|
||||
};
|
||||
use rosenpass::protocol::basic_types::{MsgBuf, SPk, SSk, SymKey};
|
||||
use rosenpass::protocol::{CryptoServer, HandleMsgResult, PeerPtr, ProtocolVersion};
|
||||
|
||||
const ITERATIONS: usize = 100;
|
||||
|
||||
|
||||
@@ -158,10 +158,10 @@ where
|
||||
);
|
||||
|
||||
// Actually read the secrets
|
||||
let mut sk = crate::protocol::SSk::zero();
|
||||
let mut sk = crate::protocol::basic_types::SSk::zero();
|
||||
sk_io.read_exact_til_end(sk.secret_mut()).einvalid_req()?;
|
||||
|
||||
let mut pk = crate::protocol::SPk::zero();
|
||||
let mut pk = crate::protocol::basic_types::SPk::zero();
|
||||
pk_io.read_exact_til_end(pk.borrow_mut()).einvalid_req()?;
|
||||
|
||||
// Retrieve the construction site
|
||||
|
||||
@@ -47,7 +47,8 @@ use crate::protocol::BuildCryptoServer;
|
||||
use crate::protocol::HostIdentification;
|
||||
use crate::{
|
||||
config::Verbosity,
|
||||
protocol::{CryptoServer, MsgBuf, PeerPtr, SPk, SSk, SymKey, Timing},
|
||||
protocol::basic_types::{MsgBuf, SPk, SSk, SymKey},
|
||||
protocol::{timing::Timing, CryptoServer, PeerPtr},
|
||||
};
|
||||
use rosenpass_util::attempt;
|
||||
use rosenpass_util::b64::B64Display;
|
||||
@@ -1337,7 +1338,7 @@ impl AppServer {
|
||||
break A::SendRetransmission(AppPeerPtr(no))
|
||||
}
|
||||
Some(C::Sleep(timeout)) => timeout, // No event from crypto-server, do IO
|
||||
None => crate::protocol::UNENDING, // Crypto server is uninitialized, do IO
|
||||
None => crate::protocol::timing::UNENDING, // Crypto server is uninitialized, do IO
|
||||
};
|
||||
|
||||
// Perform IO (look for a message)
|
||||
|
||||
@@ -17,7 +17,7 @@ use std::path::PathBuf;
|
||||
|
||||
use crate::app_server::AppServerTest;
|
||||
use crate::app_server::{AppServer, BrokerPeer};
|
||||
use crate::protocol::{SPk, SSk, SymKey};
|
||||
use crate::protocol::basic_types::{SPk, SSk, SymKey};
|
||||
|
||||
use super::config;
|
||||
|
||||
@@ -607,8 +607,8 @@ impl CliArgs {
|
||||
|
||||
/// generate secret and public keys, store in files according to the paths passed as arguments
|
||||
pub fn generate_and_save_keypair(secret_key: PathBuf, public_key: PathBuf) -> anyhow::Result<()> {
|
||||
let mut ssk = crate::protocol::SSk::random();
|
||||
let mut spk = crate::protocol::SPk::random();
|
||||
let mut ssk = crate::protocol::basic_types::SSk::random();
|
||||
let mut spk = crate::protocol::basic_types::SPk::random();
|
||||
StaticKem.keygen(ssk.secret_mut(), spk.deref_mut())?;
|
||||
ssk.store_secret(secret_key)?;
|
||||
spk.store(public_key)
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
//! - TODO: support `~` in <https://github.com/rosenpass/rosenpass/issues/237>
|
||||
//! - TODO: provide tooling to create config file from shell <https://github.com/rosenpass/rosenpass/issues/247>
|
||||
|
||||
use crate::protocol::{SPk, SSk};
|
||||
use crate::protocol::basic_types::{SPk, SSk};
|
||||
use rosenpass_util::file::LoadValue;
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
|
||||
36
rosenpass/src/protocol/basic_types.rs
Normal file
36
rosenpass/src/protocol/basic_types.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
//! Key types and other fundamental types used in the Rosenpass protocol
|
||||
|
||||
use rosenpass_cipher_traits::primitives::{Aead, Kem};
|
||||
use rosenpass_ciphers::{EphemeralKem, StaticKem, XAead, KEY_LEN};
|
||||
use rosenpass_secret_memory::{Public, PublicBox, Secret};
|
||||
|
||||
use crate::msgs::{BISCUIT_ID_LEN, MAX_MESSAGE_LEN, SESSION_ID_LEN};
|
||||
|
||||
/// Static public key
|
||||
///
|
||||
/// Using [PublicBox] instead of [Public] because Classic McEliece keys are very large.
|
||||
pub type SPk = PublicBox<{ StaticKem::PK_LEN }>;
|
||||
/// Static secret key
|
||||
pub type SSk = Secret<{ StaticKem::SK_LEN }>;
|
||||
/// Ephemeral public key
|
||||
pub type EPk = Public<{ EphemeralKem::PK_LEN }>;
|
||||
pub type ESk = Secret<{ EphemeralKem::SK_LEN }>;
|
||||
|
||||
/// Symmetric key
|
||||
pub type SymKey = Secret<KEY_LEN>;
|
||||
|
||||
/// Peer ID (derived from the public key, see the hash derivations in the [whitepaper](https://rosenpass.eu/whitepaper.pdf))
|
||||
pub type PeerId = Public<KEY_LEN>;
|
||||
/// Session ID
|
||||
pub type SessionId = Public<SESSION_ID_LEN>;
|
||||
/// Biscuit ID
|
||||
pub type BiscuitId = Public<BISCUIT_ID_LEN>;
|
||||
|
||||
/// Nonce for use with random-nonce AEAD
|
||||
pub type XAEADNonce = Public<{ XAead::NONCE_LEN }>;
|
||||
|
||||
/// Buffer capably of holding any Rosenpass protocol message
|
||||
pub type MsgBuf = Public<MAX_MESSAGE_LEN>;
|
||||
|
||||
/// Server-local peer number; this is just the index in [super::CryptoServer::peers]
|
||||
pub type PeerNo = usize;
|
||||
@@ -1,4 +1,5 @@
|
||||
use super::{CryptoServer, PeerPtr, SPk, SSk, SymKey};
|
||||
use super::basic_types::{SPk, SSk, SymKey};
|
||||
use super::{CryptoServer, PeerPtr};
|
||||
use crate::config::ProtocolVersion;
|
||||
use rosenpass_util::{
|
||||
build::Build,
|
||||
@@ -47,7 +48,8 @@ impl Keypair {
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rosenpass::protocol::{Keypair, SSk, SPk};
|
||||
/// use rosenpass::protocol::basic_types::{SSk, SPk};
|
||||
/// use rosenpass::protocol::Keypair;
|
||||
///
|
||||
/// // We have to define the security policy before using Secrets.
|
||||
/// use rosenpass_secret_memory::secret_policy_use_only_malloc_secrets;
|
||||
@@ -66,12 +68,13 @@ impl Keypair {
|
||||
|
||||
/// Creates a new "empty" key pair. All bytes are initialized to zero.
|
||||
///
|
||||
/// See [SSk:zero()][crate::protocol::SSk::zero] and [SPk:zero()][crate::protocol::SPk::zero], respectively.
|
||||
/// See [SSk:zero()][SSk::zero] and [SPk:zero()][SPk::zero], respectively.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rosenpass::protocol::{Keypair, SSk, SPk};
|
||||
/// use rosenpass::protocol::basic_types::{SSk, SPk};
|
||||
/// use rosenpass::protocol::Keypair;
|
||||
///
|
||||
/// // We have to define the security policy before using Secrets.
|
||||
/// use rosenpass_secret_memory::secret_policy_use_only_malloc_secrets;
|
||||
@@ -90,7 +93,7 @@ impl Keypair {
|
||||
|
||||
/// Creates a new (securely-)random key pair. The mechanism is described in [rosenpass_secret_memory::Secret].
|
||||
///
|
||||
/// See [SSk:random()][crate::protocol::SSk::random] and [SPk:random()][crate::protocol::SPk::random], respectively.
|
||||
/// See [SSk:random()][SSk::random] and [SPk:random()][SPk::random], respectively.
|
||||
pub fn random() -> Self {
|
||||
Self::new(SSk::random(), SPk::random())
|
||||
}
|
||||
@@ -127,7 +130,7 @@ pub struct MissingKeypair;
|
||||
///
|
||||
/// There are multiple ways of creating a crypto server:
|
||||
///
|
||||
/// 1. Provide the key pair at initialization time (using [CryptoServer::new][crate::protocol::CryptoServer::new])
|
||||
/// 1. Provide the key pair at initialization time (using [CryptoServer::new][CryptoServer::new])
|
||||
/// 2. Provide the key pair at a later time (using [BuildCryptoServer::empty])
|
||||
///
|
||||
/// With BuildCryptoServer, you can gradually configure parameters as they become available.
|
||||
@@ -145,7 +148,8 @@ pub struct MissingKeypair;
|
||||
///
|
||||
/// ```rust
|
||||
/// use rosenpass_util::build::Build;
|
||||
/// use rosenpass::protocol::{BuildCryptoServer, Keypair, PeerParams, SPk, SymKey};
|
||||
/// use rosenpass::protocol::basic_types::{SPk, SymKey};
|
||||
/// use rosenpass::protocol::{BuildCryptoServer, Keypair, PeerParams};
|
||||
/// use rosenpass::config::ProtocolVersion;
|
||||
///
|
||||
/// // We have to define the security policy before using Secrets.
|
||||
@@ -205,13 +209,13 @@ impl Build<CryptoServer> for BuildCryptoServer {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
/// Cryptographic key(s) identifying the connected [peer][crate::protocol::Peer] ("client")
|
||||
/// Cryptographic key(s) identifying the connected [peer][super::Peer] ("client")
|
||||
/// for a given session that is being managed by the crypto server.
|
||||
///
|
||||
/// Each peer must be identified by a [public key (SPk)][crate::protocol::SPk].
|
||||
/// Optionally, a [symmetric key (SymKey)][crate::protocol::SymKey]
|
||||
/// Each peer must be identified by a [public key (SPk)][SPk].
|
||||
/// Optionally, a [symmetric key (SymKey)][SymKey]
|
||||
/// can be provided when setting up the connection.
|
||||
/// For more information on the intended usage and security considerations, see [Peer::psk][crate::protocol::Peer::psk] and [Peer::spkt][crate::protocol::Peer::spkt].
|
||||
/// For more information on the intended usage and security considerations, see [Peer::psk][super::Peer::psk] and [Peer::spkt][super::Peer::spkt].
|
||||
pub struct PeerParams {
|
||||
/// Pre-shared (symmetric) encryption keys that should be used with this peer.
|
||||
pub psk: Option<SymKey>,
|
||||
@@ -322,7 +326,8 @@ impl BuildCryptoServer {
|
||||
/// secret_policy_use_only_malloc_secrets();
|
||||
///
|
||||
/// use rosenpass_util::build::Build;
|
||||
/// use rosenpass::protocol::{BuildCryptoServer, Keypair, SymKey, SPk};
|
||||
/// use rosenpass::protocol::basic_types::{SymKey, SPk};
|
||||
/// use rosenpass::protocol::{BuildCryptoServer, Keypair};
|
||||
///
|
||||
/// // Deferred initialization: Create builder first, add some peers later
|
||||
/// let keypair_option = Some(Keypair::random());
|
||||
@@ -388,7 +393,8 @@ impl BuildCryptoServer {
|
||||
/// secret_policy_use_only_malloc_secrets();
|
||||
///
|
||||
/// use rosenpass_util::build::Build;
|
||||
/// use rosenpass::protocol::{BuildCryptoServer, Keypair, SymKey, SPk};
|
||||
/// use rosenpass::protocol::basic_types::{SymKey, SPk};
|
||||
/// use rosenpass::protocol::{BuildCryptoServer, Keypair};
|
||||
///
|
||||
/// let keypair = Keypair::random();
|
||||
/// let peer_pk = SPk::random();
|
||||
|
||||
64
rosenpass/src/protocol/constants.rs
Normal file
64
rosenpass/src/protocol/constants.rs
Normal file
@@ -0,0 +1,64 @@
|
||||
//! Constants and configuration values used in the rosenpass core protocol
|
||||
|
||||
use crate::msgs::MAC_SIZE;
|
||||
|
||||
use super::timing::Timing;
|
||||
|
||||
/// Time after which the responder attempts to rekey the session
|
||||
///
|
||||
/// From the wireguard paper: rekey every two minutes,
|
||||
/// discard the key if no rekey is achieved within three
|
||||
pub const REKEY_AFTER_TIME_RESPONDER: Timing = 120.0;
|
||||
/// Time after which the initiator attempts to rekey the session.
|
||||
///
|
||||
/// This happens ten seconds after [REKEY_AFTER_TIME_RESPONDER], so
|
||||
/// parties would usually switch roles after every handshake.
|
||||
///
|
||||
/// From the wireguard paper: rekey every two minutes,
|
||||
/// discard the key if no rekey is achieved within three
|
||||
pub const REKEY_AFTER_TIME_INITIATOR: Timing = 130.0;
|
||||
/// Time after which either party rejects the current key.
|
||||
///
|
||||
/// At this point a new key should have been negotiated.
|
||||
///
|
||||
/// Rejection happens 50-60 seconds after key renegotiation
|
||||
/// to allow for a graceful handover.
|
||||
/// From the wireguard paper: rekey every two minutes,
|
||||
/// discard the key if no rekey is achieved within three
|
||||
pub const REJECT_AFTER_TIME: Timing = 180.0;
|
||||
|
||||
/// The length of the `cookie_secret` in the [whitepaper](https://rosenpass.eu/whitepaper.pdf)
|
||||
pub const COOKIE_SECRET_LEN: usize = MAC_SIZE;
|
||||
/// The life time of the `cookie_secret` in the [whitepaper](https://rosenpass.eu/whitepaper.pdf)
|
||||
pub const COOKIE_SECRET_EPOCH: Timing = 120.0;
|
||||
|
||||
/// Length of a cookie value (see info about the cookie mechanism in the [whitepaper](https://rosenpass.eu/whitepaper.pdf))
|
||||
pub const COOKIE_VALUE_LEN: usize = MAC_SIZE;
|
||||
/// Time after which to delete a cookie, as the initiator, for a certain peer (see info about the cookie mechanism in the [whitepaper](https://rosenpass.eu/whitepaper.pdf))
|
||||
pub const PEER_COOKIE_VALUE_EPOCH: Timing = 120.0;
|
||||
|
||||
/// Seconds until the biscuit key is changed; we issue biscuits
|
||||
/// using one biscuit key for one epoch and store the biscuit for
|
||||
/// decryption for a second epoch
|
||||
///
|
||||
/// The biscuit mechanism is used to make sure the responder is stateless in our protocol.
|
||||
pub const BISCUIT_EPOCH: Timing = 300.0;
|
||||
|
||||
/// The initiator opportunistically retransmits their messages; it applies an increasing delay
|
||||
/// between each retreansmission. This is the factor by which the delay grows after each
|
||||
/// retransmission.
|
||||
pub const RETRANSMIT_DELAY_GROWTH: Timing = 2.0;
|
||||
/// The initiator opportunistically retransmits their messages; it applies an increasing delay
|
||||
/// between each retreansmission. This is the initial delay between retransmissions.
|
||||
pub const RETRANSMIT_DELAY_BEGIN: Timing = 0.5;
|
||||
/// The initiator opportunistically retransmits their messages; it applies an increasing delay
|
||||
/// between each retreansmission. This is the maximum delay between retransmissions.
|
||||
pub const RETRANSMIT_DELAY_END: Timing = 10.0;
|
||||
/// The initiator opportunistically retransmits their messages; it applies an increasing delay
|
||||
/// between each retreansmission. This is the jitter (randomness) applied to the retransmission
|
||||
/// delay.
|
||||
pub const RETRANSMIT_DELAY_JITTER: Timing = 0.5;
|
||||
|
||||
/// This is the maximum delay that can separate two events for us to consider the events to have
|
||||
/// happened at the same time.
|
||||
pub const EVENT_GRACE: Timing = 0.0025;
|
||||
98
rosenpass/src/protocol/cookies.rs
Normal file
98
rosenpass/src/protocol/cookies.rs
Normal file
@@ -0,0 +1,98 @@
|
||||
//! Cryptographic key management for cookies and biscuits used in the protocol
|
||||
//!
|
||||
//! Cookies in general are conceptually similar to browser cookies;
|
||||
//! i.e. mechanisms to store information in the party connected to via network.
|
||||
//!
|
||||
//! In our case specifically we refer to any mechanisms in the Rosenpass protocol
|
||||
//! where a peer stores some information in the other party that is cryptographically
|
||||
//! protected using a temporary, randomly generated key. This file contains the mechanisms
|
||||
//! used to store the secret keys.
|
||||
//!
|
||||
//! We have two cookie-mechanisms in particular:
|
||||
//!
|
||||
//! - Rosenpass "biscuits" — the mechanism used to make sure the Rosenpass protocol is stateless
|
||||
//! with respect to the responder
|
||||
//! - WireGuard's cookie mechanism to enable proof of IP ownership; Rosenpass has experimental
|
||||
//! support for this mechanism
|
||||
//!
|
||||
//! The CookieStore type is also used to store cookie secrets sent from the responder to the
|
||||
//! initiator. This is a bad design and we should separate out this functionality.
|
||||
//!
|
||||
//! TODO: CookieStore should not be used for cookie secrets sent from responder to initiator.
|
||||
//! TODO: Move cookie lifetime management functionality into here
|
||||
|
||||
use rosenpass_ciphers::KEY_LEN;
|
||||
use rosenpass_secret_memory::Secret;
|
||||
|
||||
use super::{constants::COOKIE_SECRET_LEN, timing::Timing};
|
||||
|
||||
/// Container for storing cookie secrets like [BiscuitKey] or [CookieSecret].
|
||||
///
|
||||
/// This is really just a secret key and a time stamp of creation. Concrete
|
||||
/// usages (such as for the biscuit key) impose a time limit about how long
|
||||
/// a key can be used and the time of creation is used to impose that time limit.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use rosenpass_util::time::Timebase;
|
||||
/// use rosenpass::protocol::{timing::BCE, basic_types::SymKey, cookies::CookieStore};
|
||||
///
|
||||
/// rosenpass_secret_memory::secret_policy_try_use_memfd_secrets();
|
||||
///
|
||||
/// let fixed_secret = SymKey::random();
|
||||
/// let timebase = Timebase::default();
|
||||
///
|
||||
/// let mut store = CookieStore::<32>::new();
|
||||
/// assert_ne!(store.value.secret(), SymKey::zero().secret());
|
||||
/// assert_eq!(store.created_at, BCE);
|
||||
///
|
||||
/// let time_before_call = timebase.now();
|
||||
/// store.update(&timebase, fixed_secret.secret());
|
||||
/// assert_eq!(store.value.secret(), fixed_secret.secret());
|
||||
/// assert!(store.created_at < timebase.now());
|
||||
/// assert!(store.created_at > time_before_call);
|
||||
///
|
||||
/// // Same as new()
|
||||
/// store.erase();
|
||||
/// assert_ne!(store.value.secret(), SymKey::zero().secret());
|
||||
/// assert_eq!(store.created_at, BCE);
|
||||
///
|
||||
/// let secret_before_call = store.value.clone();
|
||||
/// let time_before_call = timebase.now();
|
||||
/// store.randomize(&timebase);
|
||||
/// assert_ne!(store.value.secret(), secret_before_call.secret());
|
||||
/// assert!(store.created_at < timebase.now());
|
||||
/// assert!(store.created_at > time_before_call);
|
||||
/// ```
|
||||
#[derive(Debug)]
|
||||
pub struct CookieStore<const N: usize> {
|
||||
/// Time of creation of the secret key
|
||||
pub created_at: Timing,
|
||||
/// The secret key
|
||||
pub value: Secret<N>,
|
||||
}
|
||||
|
||||
/// Stores cookie secret, which is used to create a rotating the cookie value
|
||||
///
|
||||
/// Concrete value is in [super::CryptoServer::cookie_secrets].
|
||||
///
|
||||
/// The pointer type is [super::ServerCookieSecretPtr].
|
||||
pub type CookieSecret = CookieStore<COOKIE_SECRET_LEN>;
|
||||
|
||||
/// Storage for our biscuit keys.
|
||||
///
|
||||
/// The biscuit keys encrypt what we call "biscuits".
|
||||
/// These biscuits contain the responder state for a particular handshake. By moving
|
||||
/// state into these biscuits, we make sure the responder is stateless.
|
||||
///
|
||||
/// A Biscuit is like a fancy cookie. To avoid state disruption attacks,
|
||||
/// the responder doesn't store state. Instead the state is stored in a
|
||||
/// Biscuit, that is encrypted using the [BiscuitKey] which is only known to
|
||||
/// the Responder. Thus secrecy of the Responder state is not violated, still
|
||||
/// the responder can avoid storing this state.
|
||||
///
|
||||
/// Concrete value is in [super::CryptoServer::biscuit_keys].
|
||||
///
|
||||
/// The pointer type is [super::BiscuitKeyPtr].
|
||||
pub type BiscuitKey = CookieStore<KEY_LEN>;
|
||||
45
rosenpass/src/protocol/index.rs
Normal file
45
rosenpass/src/protocol/index.rs
Normal file
@@ -0,0 +1,45 @@
|
||||
//! Quick lookup of values in [super::CryptoServer]
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use super::basic_types::{PeerId, PeerNo, SessionId};
|
||||
use super::KnownResponseHash;
|
||||
|
||||
/// Maps various keys to peer (numbers).
|
||||
///
|
||||
/// See:
|
||||
/// - [super::CryptoServer::index]
|
||||
/// - [super::CryptoServer::peers]
|
||||
/// - [PeerNo]
|
||||
/// - [super::PeerPtr]
|
||||
/// - [super::Peer]
|
||||
pub type PeerIndex = HashMap<PeerIndexKey, PeerNo>;
|
||||
|
||||
/// We maintain various indices in [super::CryptoServer::index], mapping some key to a particular
|
||||
/// [PeerNo], i.e. to an index in [super::CryptoServer::peers]. These are the possible index key.
|
||||
#[derive(Hash, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||
pub enum PeerIndexKey {
|
||||
/// Lookup of a particular peer given the [PeerId], i.e. a value derived from the peers public
|
||||
/// key as created by [super::CryptoServer::pidm] or [super::Peer::pidt].
|
||||
///
|
||||
/// The peer id is used by the initiator to tell the responder about its identity in
|
||||
/// [crate::msgs::InitHello].
|
||||
///
|
||||
/// See also the pointer types [super::PeerPtr].
|
||||
Peer(PeerId),
|
||||
/// Lookup of a particular session id.
|
||||
///
|
||||
/// This is used to look up both established sessions (see
|
||||
/// [super::CryptoServer::lookup_session]) and ongoing handshakes (see [super::CryptoServer::lookup_handshake]).
|
||||
///
|
||||
/// Lookup of a peer to get an established session or a handshake is sufficient, because a peer
|
||||
/// contains a limited number of sessions and handshakes ([super::Peer::session] and [super::Peer::handshake] respectively).
|
||||
///
|
||||
/// See also the pointer types [super::IniHsPtr] and [super::SessionPtr].
|
||||
Sid(SessionId),
|
||||
/// Lookup of a cached response ([crate::msgs::Envelope]<[crate::msgs::EmptyData]>) to an [crate::msgs::InitConf] (i.e.
|
||||
/// [crate::msgs::Envelope]<[crate::msgs::InitConf]>) message.
|
||||
///
|
||||
/// See [super::KnownInitConfResponsePtr] on how this value is maintained.
|
||||
KnownInitConfResponse(KnownResponseHash),
|
||||
}
|
||||
@@ -27,9 +27,8 @@
|
||||
//! use rosenpass_secret_memory::policy::*;
|
||||
//! use rosenpass_cipher_traits::primitives::Kem;
|
||||
//! use rosenpass_ciphers::StaticKem;
|
||||
//! use rosenpass::{
|
||||
//! protocol::{SSk, SPk, MsgBuf, PeerPtr, CryptoServer, SymKey},
|
||||
//! };
|
||||
//! use rosenpass::protocol::basic_types::{SSk, SPk, MsgBuf, SymKey};
|
||||
//! use rosenpass::protocol::{PeerPtr, CryptoServer};
|
||||
//! # fn main() -> anyhow::Result<()> {
|
||||
//! // Set security policy for storing secrets
|
||||
//!
|
||||
@@ -76,8 +75,19 @@
|
||||
//! ```
|
||||
|
||||
mod build_crypto_server;
|
||||
pub use build_crypto_server::*;
|
||||
|
||||
pub mod basic_types;
|
||||
pub mod constants;
|
||||
pub mod cookies;
|
||||
pub mod index;
|
||||
pub mod testutils;
|
||||
pub mod timing;
|
||||
pub mod zerocopy;
|
||||
|
||||
#[allow(clippy::module_inception)]
|
||||
mod protocol;
|
||||
|
||||
pub use build_crypto_server::*;
|
||||
pub use protocol::*;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
682
rosenpass/src/protocol/test.rs
Normal file
682
rosenpass/src/protocol/test.rs
Normal file
@@ -0,0 +1,682 @@
|
||||
use std::{borrow::BorrowMut, fmt::Display, net::SocketAddrV4, ops::DerefMut};
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use serial_test::serial;
|
||||
use zerocopy::{AsBytes, FromBytes, FromZeroes};
|
||||
|
||||
use rosenpass_cipher_traits::primitives::Kem;
|
||||
use rosenpass_ciphers::StaticKem;
|
||||
use rosenpass_secret_memory::Public;
|
||||
use rosenpass_util::mem::DiscardResultExt;
|
||||
|
||||
use crate::msgs::{EmptyData, Envelope, InitConf, InitHello, MsgType, RespHello, MAX_MESSAGE_LEN};
|
||||
|
||||
use super::{
|
||||
basic_types::{MsgBuf, SPk, SSk, SymKey},
|
||||
constants::REKEY_AFTER_TIME_RESPONDER,
|
||||
zerocopy::{truncating_cast_into, truncating_cast_into_nomut},
|
||||
CryptoServer, HandleMsgResult, HostIdentification, KnownInitConfResponsePtr, PeerPtr,
|
||||
PollResult, ProtocolVersion,
|
||||
};
|
||||
|
||||
struct VecHostIdentifier(Vec<u8>);
|
||||
|
||||
impl HostIdentification for VecHostIdentifier {
|
||||
fn encode(&self) -> &[u8] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for VecHostIdentifier {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<u8>> for VecHostIdentifier {
|
||||
fn from(v: Vec<u8>) -> Self {
|
||||
VecHostIdentifier(v)
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_logging() {
|
||||
use std::io::Write;
|
||||
let mut log_builder = env_logger::Builder::from_default_env(); // sets log level filter from environment (or defaults)
|
||||
log_builder.filter_level(log::LevelFilter::Info);
|
||||
log_builder.format_timestamp_nanos();
|
||||
log_builder.format(|buf, record| {
|
||||
let ts_format = buf.timestamp_nanos().to_string();
|
||||
writeln!(buf, "{}: {}", &ts_format[14..], record.args())
|
||||
});
|
||||
|
||||
let _ = log_builder.try_init();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[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
|
||||
/// messages and with overlong messages.
|
||||
///
|
||||
/// This test performs a complete handshake between two randomly generated
|
||||
/// servers; instead of delivering the message correctly at first messages
|
||||
/// of length zero through about 1.2 times the correct message size are delivered.
|
||||
///
|
||||
/// Producing an error is expected on each of these messages.
|
||||
///
|
||||
/// Finally the correct message is delivered and the same process
|
||||
/// starts again in the other direction.
|
||||
///
|
||||
/// Through all this, the handshake should still successfully terminate;
|
||||
/// i.e. an exchanged key must be produced in both servers.
|
||||
fn handles_incorrect_size_messages(protocol_version: ProtocolVersion) {
|
||||
setup_logging();
|
||||
rosenpass_secret_memory::secret_policy_try_use_memfd_secrets();
|
||||
stacker::grow(8 * 1024 * 1024, || {
|
||||
const OVERSIZED_MESSAGE: usize = ((MAX_MESSAGE_LEN as f32) * 1.2) as usize;
|
||||
type MsgBufPlus = Public<OVERSIZED_MESSAGE>;
|
||||
|
||||
const PEER0: PeerPtr = PeerPtr(0);
|
||||
|
||||
let (mut me, mut they) = make_server_pair(protocol_version).unwrap();
|
||||
let (mut msgbuf, mut resbuf) = (MsgBufPlus::zero(), MsgBufPlus::zero());
|
||||
|
||||
// Process the entire handshake
|
||||
let mut msglen = Some(me.initiate_handshake(PEER0, &mut *resbuf).unwrap());
|
||||
while let Some(l) = msglen {
|
||||
std::mem::swap(&mut me, &mut they);
|
||||
std::mem::swap(&mut msgbuf, &mut resbuf);
|
||||
msglen = test_incorrect_sizes_for_msg(&mut me, &*msgbuf, l, &mut *resbuf);
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
me.osk(PEER0).unwrap().secret(),
|
||||
they.osk(PEER0).unwrap().secret()
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/// Used in handles_incorrect_size_messages() to first deliver many truncated
|
||||
/// and overlong messages, finally the correct message is delivered and the response
|
||||
/// returned.
|
||||
fn test_incorrect_sizes_for_msg(
|
||||
srv: &mut CryptoServer,
|
||||
msgbuf: &[u8],
|
||||
msglen: usize,
|
||||
resbuf: &mut [u8],
|
||||
) -> Option<usize> {
|
||||
resbuf.fill(0);
|
||||
|
||||
for l in 0..(((msglen as f32) * 1.2) as usize) {
|
||||
if l == msglen {
|
||||
continue;
|
||||
}
|
||||
|
||||
let res = srv.handle_msg(&msgbuf[..l], resbuf);
|
||||
assert!(res.is_err()); // handle_msg should raise an error
|
||||
assert!(!resbuf.iter().any(|x| *x != 0)); // resbuf should not have been changed
|
||||
}
|
||||
|
||||
// Apply the proper handle_msg operation
|
||||
srv.handle_msg(&msgbuf[..msglen], resbuf).unwrap().resp
|
||||
}
|
||||
|
||||
fn keygen() -> Result<(SSk, SPk)> {
|
||||
// TODO: Copied from the benchmark; deduplicate
|
||||
let (mut sk, mut pk) = (SSk::zero(), SPk::zero());
|
||||
StaticKem.keygen(sk.secret_mut(), pk.deref_mut())?;
|
||||
Ok((sk, pk))
|
||||
}
|
||||
|
||||
fn make_server_pair(protocol_version: ProtocolVersion) -> Result<(CryptoServer, CryptoServer)> {
|
||||
// TODO: Copied from the benchmark; deduplicate
|
||||
let psk = SymKey::random();
|
||||
let ((ska, pka), (skb, pkb)) = (keygen()?, keygen()?);
|
||||
let (mut a, mut b) = (
|
||||
CryptoServer::new(ska, pka.clone()),
|
||||
CryptoServer::new(skb, pkb.clone()),
|
||||
);
|
||||
a.add_peer(Some(psk.clone()), pkb, protocol_version.clone())?;
|
||||
b.add_peer(Some(psk), pka, protocol_version)?;
|
||||
Ok((a, b))
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
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();
|
||||
rosenpass_secret_memory::secret_policy_try_use_memfd_secrets();
|
||||
stacker::grow(8 * 1024 * 1024, || {
|
||||
type MsgBufPlus = Public<MAX_MESSAGE_LEN>;
|
||||
let (mut a, mut b) = make_server_pair(protocol_version).unwrap();
|
||||
|
||||
let mut a_to_b_buf = MsgBufPlus::zero();
|
||||
let mut b_to_a_buf = MsgBufPlus::zero();
|
||||
|
||||
let ip_a: SocketAddrV4 = "127.0.0.1:8080".parse().unwrap();
|
||||
let mut ip_addr_port_a = ip_a.ip().octets().to_vec();
|
||||
ip_addr_port_a.extend_from_slice(&ip_a.port().to_be_bytes());
|
||||
|
||||
let _ip_b: SocketAddrV4 = "127.0.0.1:8081".parse().unwrap();
|
||||
|
||||
let init_hello_len = a.initiate_handshake(PeerPtr(0), &mut *a_to_b_buf).unwrap();
|
||||
|
||||
let init_msg_type: MsgType = a_to_b_buf.value[0].try_into().unwrap();
|
||||
assert_eq!(init_msg_type, MsgType::InitHello);
|
||||
|
||||
//B handles InitHello, sends RespHello
|
||||
let HandleMsgResult { resp, .. } = b
|
||||
.handle_msg(&a_to_b_buf.as_slice()[..init_hello_len], &mut *b_to_a_buf)
|
||||
.unwrap();
|
||||
|
||||
let resp_hello_len = resp.unwrap();
|
||||
|
||||
let resp_msg_type: MsgType = b_to_a_buf.value[0].try_into().unwrap();
|
||||
assert_eq!(resp_msg_type, MsgType::RespHello);
|
||||
|
||||
let HandleMsgResult {
|
||||
resp,
|
||||
exchanged_with,
|
||||
} = a
|
||||
.handle_msg(&b_to_a_buf[..resp_hello_len], &mut *a_to_b_buf)
|
||||
.unwrap();
|
||||
|
||||
let init_conf_len = resp.unwrap();
|
||||
let init_conf_msg_type: MsgType = a_to_b_buf.value[0].try_into().unwrap();
|
||||
|
||||
assert_eq!(exchanged_with, Some(PeerPtr(0)));
|
||||
assert_eq!(init_conf_msg_type, MsgType::InitConf);
|
||||
|
||||
//B handles InitConf, sends EmptyData
|
||||
let HandleMsgResult {
|
||||
resp: _,
|
||||
exchanged_with,
|
||||
} = b
|
||||
.handle_msg(&a_to_b_buf.as_slice()[..init_conf_len], &mut *b_to_a_buf)
|
||||
.unwrap();
|
||||
|
||||
let empty_data_msg_type: MsgType = b_to_a_buf.value[0].try_into().unwrap();
|
||||
|
||||
assert_eq!(exchanged_with, Some(PeerPtr(0)));
|
||||
assert_eq!(empty_data_msg_type, MsgType::EmptyData);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
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();
|
||||
rosenpass_secret_memory::secret_policy_try_use_memfd_secrets();
|
||||
stacker::grow(8 * 1024 * 1024, || {
|
||||
type MsgBufPlus = Public<MAX_MESSAGE_LEN>;
|
||||
let (mut a, mut b) = make_server_pair(protocol_version).unwrap();
|
||||
|
||||
let mut a_to_b_buf = MsgBufPlus::zero();
|
||||
let mut b_to_a_buf = MsgBufPlus::zero();
|
||||
|
||||
let ip_a: SocketAddrV4 = "127.0.0.1:8080".parse().unwrap();
|
||||
let mut ip_addr_port_a = ip_a.ip().octets().to_vec();
|
||||
ip_addr_port_a.extend_from_slice(&ip_a.port().to_be_bytes());
|
||||
|
||||
let _ip_b: SocketAddrV4 = "127.0.0.1:8081".parse().unwrap();
|
||||
|
||||
let init_hello_len = a.initiate_handshake(PeerPtr(0), &mut *a_to_b_buf).unwrap();
|
||||
|
||||
let init_msg_type: MsgType = a_to_b_buf.value[0].try_into().unwrap();
|
||||
assert_eq!(init_msg_type, MsgType::InitHello);
|
||||
|
||||
//B handles InitHello, sends RespHello
|
||||
let HandleMsgResult { resp, .. } = b
|
||||
.handle_msg(&a_to_b_buf.as_slice()[..init_hello_len], &mut *b_to_a_buf)
|
||||
.unwrap();
|
||||
|
||||
let resp_hello_len = resp.unwrap();
|
||||
|
||||
let resp_msg_type: MsgType = b_to_a_buf.value[0].try_into().unwrap();
|
||||
assert_eq!(resp_msg_type, MsgType::RespHello);
|
||||
|
||||
//A handles RespHello, sends InitConf, exchanges keys
|
||||
let HandleMsgResult {
|
||||
resp,
|
||||
exchanged_with,
|
||||
} = a
|
||||
.handle_msg(&b_to_a_buf[..resp_hello_len], &mut *a_to_b_buf)
|
||||
.unwrap();
|
||||
|
||||
let init_conf_len = resp.unwrap();
|
||||
let init_conf_msg_type: MsgType = a_to_b_buf.value[0].try_into().unwrap();
|
||||
|
||||
assert_eq!(exchanged_with, Some(PeerPtr(0)));
|
||||
assert_eq!(init_conf_msg_type, MsgType::InitConf);
|
||||
|
||||
//B handles InitConf, sends EmptyData
|
||||
let HandleMsgResult {
|
||||
resp: _,
|
||||
exchanged_with,
|
||||
} = b
|
||||
.handle_msg(&a_to_b_buf.as_slice()[..init_conf_len], &mut *b_to_a_buf)
|
||||
.unwrap();
|
||||
|
||||
let empty_data_msg_type: MsgType = b_to_a_buf.value[0].try_into().unwrap();
|
||||
|
||||
assert_eq!(exchanged_with, Some(PeerPtr(0)));
|
||||
assert_eq!(empty_data_msg_type, MsgType::EmptyData);
|
||||
|
||||
//B handles InitConf again, sends EmptyData
|
||||
let HandleMsgResult {
|
||||
resp: _,
|
||||
exchanged_with,
|
||||
} = b
|
||||
.handle_msg(&a_to_b_buf.as_slice()[..init_conf_len], &mut *b_to_a_buf)
|
||||
.unwrap();
|
||||
|
||||
let empty_data_msg_type: MsgType = b_to_a_buf.value[0].try_into().unwrap();
|
||||
|
||||
assert!(exchanged_with.is_none());
|
||||
assert_eq!(empty_data_msg_type, MsgType::EmptyData);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
#[cfg(feature = "experiment_cookie_dos_mitigation")]
|
||||
fn cookie_reply_mechanism_responder_under_load_v02() {
|
||||
cookie_reply_mechanism_initiator_bails_on_message_under_load(ProtocolVersion::V02)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
#[cfg(feature = "experiment_cookie_dos_mitigation")]
|
||||
fn cookie_reply_mechanism_responder_under_load_v03() {
|
||||
cookie_reply_mechanism_initiator_bails_on_message_under_load(ProtocolVersion::V03)
|
||||
}
|
||||
|
||||
#[cfg(feature = "experiment_cookie_dos_mitigation")]
|
||||
fn cookie_reply_mechanism_responder_under_load(protocol_version: ProtocolVersion) {
|
||||
use std::{thread::sleep, time::Duration};
|
||||
|
||||
use super::{Lifecycle, MortalExt};
|
||||
|
||||
setup_logging();
|
||||
rosenpass_secret_memory::secret_policy_try_use_memfd_secrets();
|
||||
stacker::grow(8 * 1024 * 1024, || {
|
||||
type MsgBufPlus = Public<MAX_MESSAGE_LEN>;
|
||||
let (mut a, mut b) = make_server_pair(protocol_version.clone()).unwrap();
|
||||
|
||||
let mut a_to_b_buf = MsgBufPlus::zero();
|
||||
let mut b_to_a_buf = MsgBufPlus::zero();
|
||||
|
||||
let ip_a: SocketAddrV4 = "127.0.0.1:8080".parse().unwrap();
|
||||
let mut ip_addr_port_a = ip_a.ip().octets().to_vec();
|
||||
ip_addr_port_a.extend_from_slice(&ip_a.port().to_be_bytes());
|
||||
|
||||
let _ip_b: SocketAddrV4 = "127.0.0.1:8081".parse().unwrap();
|
||||
|
||||
let init_hello_len = a.initiate_handshake(PeerPtr(0), &mut *a_to_b_buf).unwrap();
|
||||
let socket_addr_a = std::net::SocketAddr::V4(ip_a);
|
||||
let mut ip_addr_port_a = match socket_addr_a.ip() {
|
||||
std::net::IpAddr::V4(ipv4) => ipv4.octets().to_vec(),
|
||||
std::net::IpAddr::V6(ipv6) => ipv6.octets().to_vec(),
|
||||
};
|
||||
|
||||
ip_addr_port_a.extend_from_slice(&socket_addr_a.port().to_be_bytes());
|
||||
|
||||
let ip_addr_port_a: VecHostIdentifier = ip_addr_port_a.into();
|
||||
|
||||
//B handles handshake under load, should send cookie reply message with invalid cookie
|
||||
let HandleMsgResult { resp, .. } = b
|
||||
.handle_msg_under_load(
|
||||
&a_to_b_buf.as_slice()[..init_hello_len],
|
||||
&mut *b_to_a_buf,
|
||||
&ip_addr_port_a,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let cookie_reply_len = resp.unwrap();
|
||||
|
||||
//A handles cookie reply message
|
||||
a.handle_msg(&b_to_a_buf[..cookie_reply_len], &mut *a_to_b_buf)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(PeerPtr(0).cv().lifecycle(&a), Lifecycle::Young);
|
||||
|
||||
let expected_cookie_value =
|
||||
crate::hash_domains::cookie_value(protocol_version.keyed_hash())
|
||||
.unwrap()
|
||||
.mix(
|
||||
b.active_or_retired_cookie_secrets()[0]
|
||||
.unwrap()
|
||||
.get(&b)
|
||||
.value
|
||||
.secret(),
|
||||
)
|
||||
.unwrap()
|
||||
.mix(ip_addr_port_a.encode())
|
||||
.unwrap()
|
||||
.into_value()[..16]
|
||||
.to_vec();
|
||||
|
||||
assert_eq!(
|
||||
PeerPtr(0).cv().get(&a).map(|x| &x.value.secret()[..]),
|
||||
Some(&expected_cookie_value[..])
|
||||
);
|
||||
|
||||
let retx_init_hello_len = loop {
|
||||
match a.poll().unwrap() {
|
||||
PollResult::SendRetransmission(peer) => {
|
||||
break a.retransmit_handshake(peer, &mut *a_to_b_buf).unwrap();
|
||||
}
|
||||
PollResult::Sleep(time) => {
|
||||
sleep(Duration::from_secs_f64(time));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
};
|
||||
|
||||
let retx_msg_type: MsgType = a_to_b_buf.value[0].try_into().unwrap();
|
||||
assert_eq!(retx_msg_type, MsgType::InitHello);
|
||||
|
||||
//B handles retransmitted message
|
||||
let HandleMsgResult { resp, .. } = b
|
||||
.handle_msg_under_load(
|
||||
&a_to_b_buf.as_slice()[..retx_init_hello_len],
|
||||
&mut *b_to_a_buf,
|
||||
&ip_addr_port_a,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let _resp_hello_len = resp.unwrap();
|
||||
|
||||
let resp_msg_type: MsgType = b_to_a_buf.value[0].try_into().unwrap();
|
||||
assert_eq!(resp_msg_type, MsgType::RespHello);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
#[cfg(feature = "experiment_cookie_dos_mitigation")]
|
||||
fn cookie_reply_mechanism_initiator_bails_on_message_under_load_v02() {
|
||||
cookie_reply_mechanism_initiator_bails_on_message_under_load(ProtocolVersion::V02)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
#[cfg(feature = "experiment_cookie_dos_mitigation")]
|
||||
fn cookie_reply_mechanism_initiator_bails_on_message_under_load_v03() {
|
||||
cookie_reply_mechanism_initiator_bails_on_message_under_load(ProtocolVersion::V03)
|
||||
}
|
||||
|
||||
#[cfg(feature = "experiment_cookie_dos_mitigation")]
|
||||
fn cookie_reply_mechanism_initiator_bails_on_message_under_load(protocol_version: ProtocolVersion) {
|
||||
setup_logging();
|
||||
rosenpass_secret_memory::secret_policy_try_use_memfd_secrets();
|
||||
stacker::grow(8 * 1024 * 1024, || {
|
||||
type MsgBufPlus = Public<MAX_MESSAGE_LEN>;
|
||||
let (mut a, mut b) = make_server_pair(protocol_version).unwrap();
|
||||
|
||||
let mut a_to_b_buf = MsgBufPlus::zero();
|
||||
let mut b_to_a_buf = MsgBufPlus::zero();
|
||||
|
||||
let ip_a: SocketAddrV4 = "127.0.0.1:8080".parse().unwrap();
|
||||
let mut ip_addr_port_a = ip_a.ip().octets().to_vec();
|
||||
ip_addr_port_a.extend_from_slice(&ip_a.port().to_be_bytes());
|
||||
let ip_b: SocketAddrV4 = "127.0.0.1:8081".parse().unwrap();
|
||||
|
||||
//A initiates handshake
|
||||
let init_hello_len = a.initiate_handshake(PeerPtr(0), &mut *a_to_b_buf).unwrap();
|
||||
|
||||
//B handles InitHello message, should respond with RespHello
|
||||
let HandleMsgResult { resp, .. } = b
|
||||
.handle_msg(&a_to_b_buf.as_slice()[..init_hello_len], &mut *b_to_a_buf)
|
||||
.unwrap();
|
||||
|
||||
let resp_hello_len = resp.unwrap();
|
||||
let resp_msg_type: MsgType = b_to_a_buf.value[0].try_into().unwrap();
|
||||
assert_eq!(resp_msg_type, MsgType::RespHello);
|
||||
|
||||
let socket_addr_b = std::net::SocketAddr::V4(ip_b);
|
||||
let mut ip_addr_port_b = [0u8; 18];
|
||||
let mut ip_addr_port_b_len = 0;
|
||||
match socket_addr_b.ip() {
|
||||
std::net::IpAddr::V4(ipv4) => {
|
||||
ip_addr_port_b[0..4].copy_from_slice(&ipv4.octets());
|
||||
ip_addr_port_b_len += 4;
|
||||
}
|
||||
std::net::IpAddr::V6(ipv6) => {
|
||||
ip_addr_port_b[0..16].copy_from_slice(&ipv6.octets());
|
||||
ip_addr_port_b_len += 16;
|
||||
}
|
||||
};
|
||||
|
||||
ip_addr_port_b[ip_addr_port_b_len..ip_addr_port_b_len + 2]
|
||||
.copy_from_slice(&socket_addr_b.port().to_be_bytes());
|
||||
ip_addr_port_b_len += 2;
|
||||
|
||||
let ip_addr_port_b: VecHostIdentifier =
|
||||
ip_addr_port_b[..ip_addr_port_b_len].to_vec().into();
|
||||
|
||||
//A handles RespHello message under load, should not send cookie reply
|
||||
assert!(a
|
||||
.handle_msg_under_load(
|
||||
&b_to_a_buf[..resp_hello_len],
|
||||
&mut *a_to_b_buf,
|
||||
&ip_addr_port_b
|
||||
)
|
||||
.is_err());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
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();
|
||||
|
||||
fn keypair() -> Result<(SSk, SPk)> {
|
||||
let (mut sk, mut pk) = (SSk::zero(), SPk::zero());
|
||||
StaticKem.keygen(sk.secret_mut(), pk.deref_mut())?;
|
||||
Ok((sk, pk))
|
||||
}
|
||||
|
||||
fn proc_initiation(srv: &mut CryptoServer, peer: PeerPtr) -> Result<Envelope<InitHello>> {
|
||||
let mut buf = MsgBuf::zero();
|
||||
srv.initiate_handshake(peer, buf.as_mut_slice())?
|
||||
.discard_result();
|
||||
let msg = truncating_cast_into::<Envelope<InitHello>>(buf.borrow_mut())?;
|
||||
Ok(msg.read())
|
||||
}
|
||||
|
||||
fn proc_msg<Rx: AsBytes + FromBytes, Tx: AsBytes + FromBytes>(
|
||||
srv: &mut CryptoServer,
|
||||
rx: &Envelope<Rx>,
|
||||
) -> anyhow::Result<Envelope<Tx>> {
|
||||
let mut buf = MsgBuf::zero();
|
||||
srv.handle_msg(rx.as_bytes(), buf.as_mut_slice())?
|
||||
.resp
|
||||
.context("Failed to produce RespHello message")?
|
||||
.discard_result();
|
||||
let msg = truncating_cast_into::<Envelope<Tx>>(buf.borrow_mut())?;
|
||||
Ok(msg.read())
|
||||
}
|
||||
|
||||
fn proc_init_hello(
|
||||
srv: &mut CryptoServer,
|
||||
ih: &Envelope<InitHello>,
|
||||
) -> anyhow::Result<Envelope<RespHello>> {
|
||||
proc_msg::<InitHello, RespHello>(srv, ih)
|
||||
}
|
||||
|
||||
fn proc_resp_hello(
|
||||
srv: &mut CryptoServer,
|
||||
rh: &Envelope<RespHello>,
|
||||
) -> anyhow::Result<Envelope<InitConf>> {
|
||||
proc_msg::<RespHello, InitConf>(srv, rh)
|
||||
}
|
||||
|
||||
fn proc_init_conf(
|
||||
srv: &mut CryptoServer,
|
||||
rh: &Envelope<InitConf>,
|
||||
) -> anyhow::Result<Envelope<EmptyData>> {
|
||||
proc_msg::<InitConf, EmptyData>(srv, rh)
|
||||
}
|
||||
|
||||
fn poll(srv: &mut CryptoServer) -> anyhow::Result<()> {
|
||||
// Discard all events; just apply the side effects
|
||||
while !matches!(srv.poll()?, PollResult::Sleep(_)) {}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// TODO: Implement Clone on our message types
|
||||
fn clone_msg<Msg: AsBytes + FromBytes>(msg: &Msg) -> anyhow::Result<Msg> {
|
||||
Ok(truncating_cast_into_nomut::<Msg>(msg.as_bytes())?.read())
|
||||
}
|
||||
|
||||
fn break_payload<Msg: AsBytes + FromBytes>(
|
||||
srv: &mut CryptoServer,
|
||||
peer: PeerPtr,
|
||||
msg: &Envelope<Msg>,
|
||||
) -> anyhow::Result<Envelope<Msg>> {
|
||||
let mut msg = clone_msg(msg)?;
|
||||
msg.as_bytes_mut()[memoffset::offset_of!(Envelope<Msg>, payload)] ^= 0x01;
|
||||
msg.seal(peer, srv)?; // Recalculate seal; we do not want to focus on "seal broken" errs
|
||||
Ok(msg)
|
||||
}
|
||||
|
||||
fn check_faulty_proc_init_conf(srv: &mut CryptoServer, ic_broken: &Envelope<InitConf>) {
|
||||
let mut buf = MsgBuf::zero();
|
||||
let res = srv.handle_msg(ic_broken.as_bytes(), buf.as_mut_slice());
|
||||
assert!(res.is_err());
|
||||
}
|
||||
|
||||
// we this as a closure in orer to use the protocol_version variable in it.
|
||||
let check_retransmission = |srv: &mut CryptoServer,
|
||||
ic: &Envelope<InitConf>,
|
||||
ic_broken: &Envelope<InitConf>,
|
||||
rc: &Envelope<EmptyData>|
|
||||
-> Result<()> {
|
||||
// Processing the same RespHello package again leads to retransmission (i.e. exactly the
|
||||
// same output)
|
||||
let rc_dup = proc_init_conf(srv, ic)?;
|
||||
assert_eq!(rc.as_bytes(), rc_dup.as_bytes());
|
||||
|
||||
// Though if we directly call handle_resp_hello() we get an error since
|
||||
// retransmission is not being handled by the cryptographic code
|
||||
let mut discard_resp_conf = EmptyData::new_zeroed();
|
||||
let res = srv.handle_init_conf(
|
||||
&ic.payload,
|
||||
&mut discard_resp_conf,
|
||||
protocol_version.clone().keyed_hash(),
|
||||
);
|
||||
assert!(res.is_err());
|
||||
|
||||
// Obviously, a broken InitConf message should still be rejected
|
||||
check_faulty_proc_init_conf(srv, ic_broken);
|
||||
|
||||
Ok(())
|
||||
};
|
||||
|
||||
let (ska, pka) = keypair()?;
|
||||
let (skb, pkb) = keypair()?;
|
||||
|
||||
// initialize server and a pre-shared key
|
||||
let mut a = CryptoServer::new(ska, pka.clone());
|
||||
let mut b = CryptoServer::new(skb, pkb.clone());
|
||||
|
||||
// introduce peers to each other
|
||||
let b_peer = a.add_peer(None, pkb, protocol_version.clone())?;
|
||||
let a_peer = b.add_peer(None, pka, protocol_version.clone())?;
|
||||
|
||||
// Execute protocol up till the responder confirmation (EmptyData)
|
||||
let ih1 = proc_initiation(&mut a, b_peer)?;
|
||||
let rh1 = proc_init_hello(&mut b, &ih1)?;
|
||||
let ic1 = proc_resp_hello(&mut a, &rh1)?;
|
||||
let rc1 = proc_init_conf(&mut b, &ic1)?;
|
||||
|
||||
// Modified version of ic1 and rc1, for tests that require it
|
||||
let ic1_broken = break_payload(&mut a, b_peer, &ic1)?;
|
||||
assert_ne!(ic1.as_bytes(), ic1_broken.as_bytes());
|
||||
|
||||
// Modified version of rc1, for tests that require it
|
||||
let rc1_broken = break_payload(&mut b, a_peer, &rc1)?;
|
||||
assert_ne!(rc1.as_bytes(), rc1_broken.as_bytes());
|
||||
|
||||
// Retransmission works as designed
|
||||
check_retransmission(&mut b, &ic1, &ic1_broken, &rc1)?;
|
||||
|
||||
// Even with a couple of poll operations in between (which clears the cache
|
||||
// after a time out of two minutes…we should never hit this time out in this
|
||||
// cache)
|
||||
for _ in 0..4 {
|
||||
poll(&mut b)?;
|
||||
check_retransmission(&mut b, &ic1, &ic1_broken, &rc1)?;
|
||||
}
|
||||
// We can even validate that the data is coming out of the cache by changing the cache
|
||||
// to use our broken messages. It does not matter that these messages are cryptographically
|
||||
// broken since we insert them manually into the cache
|
||||
// a_peer.known_init_conf_response()
|
||||
KnownInitConfResponsePtr::insert_for_request_msg(
|
||||
&mut b,
|
||||
a_peer,
|
||||
&ic1_broken,
|
||||
rc1_broken.clone(),
|
||||
);
|
||||
check_retransmission(&mut b, &ic1_broken, &ic1, &rc1_broken)?;
|
||||
|
||||
// Lets reset to the correct message though
|
||||
KnownInitConfResponsePtr::insert_for_request_msg(&mut b, a_peer, &ic1, rc1.clone());
|
||||
|
||||
// Again, nothing changes after calling poll
|
||||
poll(&mut b)?;
|
||||
check_retransmission(&mut b, &ic1, &ic1_broken, &rc1)?;
|
||||
|
||||
// Except if we jump forward into the future past the point where the responder
|
||||
// starts to initiate rekeying; in this case, the automatic time out is triggered and the cache is cleared
|
||||
super::testutils::time_travel_forward(&mut b, REKEY_AFTER_TIME_RESPONDER);
|
||||
|
||||
// As long as we do not call poll, everything is fine
|
||||
check_retransmission(&mut b, &ic1, &ic1_broken, &rc1)?;
|
||||
|
||||
// But after we do, the response is gone and can not be recreated
|
||||
// since the biscuit is stale
|
||||
poll(&mut b)?;
|
||||
check_faulty_proc_init_conf(&mut b, &ic1); // ic1 is now effectively broken
|
||||
assert!(b.peers[0].known_init_conf_response.is_none()); // The cache is gone
|
||||
|
||||
Ok(())
|
||||
}
|
||||
48
rosenpass/src/protocol/testutils.rs
Normal file
48
rosenpass/src/protocol/testutils.rs
Normal file
@@ -0,0 +1,48 @@
|
||||
//! Helpers used in tests
|
||||
|
||||
use std::ops::DerefMut;
|
||||
|
||||
use rosenpass_cipher_traits::primitives::Kem;
|
||||
use rosenpass_ciphers::StaticKem;
|
||||
|
||||
use super::{
|
||||
basic_types::{SPk, SSk},
|
||||
CryptoServer, PeerPtr, ProtocolVersion,
|
||||
};
|
||||
|
||||
/// Helper for tests and examples
|
||||
pub struct ServerForTesting {
|
||||
pub peer: PeerPtr,
|
||||
pub peer_keys: (SSk, SPk),
|
||||
pub srv: CryptoServer,
|
||||
}
|
||||
|
||||
/// TODO: Document that the protocol version is only used for creating the peer for testing
|
||||
impl ServerForTesting {
|
||||
pub fn new(protocol_version: ProtocolVersion) -> anyhow::Result<Self> {
|
||||
let (mut sskm, mut spkm) = (SSk::zero(), SPk::zero());
|
||||
StaticKem.keygen(sskm.secret_mut(), spkm.deref_mut())?;
|
||||
let mut srv = CryptoServer::new(sskm, spkm);
|
||||
|
||||
let (mut sskt, mut spkt) = (SSk::zero(), SPk::zero());
|
||||
StaticKem.keygen(sskt.secret_mut(), spkt.deref_mut())?;
|
||||
let peer = srv.add_peer(None, spkt.clone(), protocol_version)?;
|
||||
|
||||
let peer_keys = (sskt, spkt);
|
||||
Ok(ServerForTesting {
|
||||
peer,
|
||||
peer_keys,
|
||||
srv,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn tuple(self) -> (PeerPtr, (SSk, SPk), CryptoServer) {
|
||||
(self.peer, self.peer_keys, self.srv)
|
||||
}
|
||||
}
|
||||
|
||||
/// Time travel forward in time
|
||||
pub fn time_travel_forward(srv: &mut CryptoServer, secs: f64) {
|
||||
let dur = std::time::Duration::from_secs_f64(secs);
|
||||
srv.timebase.0 = srv.timebase.0.checked_sub(dur).unwrap();
|
||||
}
|
||||
46
rosenpass/src/protocol/timing.rs
Normal file
46
rosenpass/src/protocol/timing.rs
Normal file
@@ -0,0 +1,46 @@
|
||||
//! Time-keeping related utilities for the Rosenpass protocol
|
||||
|
||||
use super::constants::EVENT_GRACE;
|
||||
|
||||
/// A type for time, e.g. for backoff before re-tries
|
||||
pub type Timing = f64;
|
||||
|
||||
/// Magic time stamp to indicate some object is ancient; "Before Common Era"
|
||||
///
|
||||
/// This is for instance used as a magic time stamp indicating age when some
|
||||
/// cryptographic object certainly needs to be refreshed.
|
||||
///
|
||||
/// Using this instead of Timing::MIN or Timing::INFINITY to avoid floating
|
||||
/// point math weirdness.
|
||||
pub const BCE: Timing = -3600.0 * 24.0 * 356.0 * 10_000.0;
|
||||
|
||||
/// Magic time stamp to indicate that some process is not time-limited
|
||||
///
|
||||
/// Actually it's eight hours; This is intentional to avoid weirdness
|
||||
/// regarding unexpectedly large numbers in system APIs as this is < i16::MAX
|
||||
pub const UNENDING: Timing = 3600.0 * 8.0;
|
||||
|
||||
/// An even `ev` has happened relative to a point in time `now`
|
||||
/// if the `ev` does not lie in the future relative to now.
|
||||
///
|
||||
/// An event lies in the future relative to `now` if
|
||||
/// does not lie in the past or present.
|
||||
///
|
||||
/// An event `ev` lies in the past if `ev < now`. It lies in the
|
||||
/// present if the absolute difference between `ev` and `now` is
|
||||
/// smaller than [EVENT_GRACE].
|
||||
///
|
||||
/// Think of this as `ev <= now` for with [EVENT_GRACE] applied.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use rosenpass::protocol::{timing::has_happened, constants::EVENT_GRACE};
|
||||
/// assert!(has_happened(EVENT_GRACE * -1.0, 0.0));
|
||||
/// assert!(has_happened(0.0, 0.0));
|
||||
/// assert!(has_happened(EVENT_GRACE * 0.999, 0.0));
|
||||
/// assert!(!has_happened(EVENT_GRACE * 1.001, 0.0));
|
||||
/// ```
|
||||
pub fn has_happened(ev: Timing, now: Timing) -> bool {
|
||||
(ev - now) < EVENT_GRACE
|
||||
}
|
||||
21
rosenpass/src/protocol/zerocopy.rs
Normal file
21
rosenpass/src/protocol/zerocopy.rs
Normal file
@@ -0,0 +1,21 @@
|
||||
//! Helpers for working with the zerocopy crate
|
||||
|
||||
use std::mem::size_of;
|
||||
|
||||
use zerocopy::{FromBytes, Ref};
|
||||
|
||||
use crate::RosenpassError;
|
||||
|
||||
/// Used to parse a network message using [zerocopy]
|
||||
pub fn truncating_cast_into<T: FromBytes>(
|
||||
buf: &mut [u8],
|
||||
) -> Result<Ref<&mut [u8], T>, RosenpassError> {
|
||||
Ref::new(&mut buf[..size_of::<T>()]).ok_or(RosenpassError::BufferSizeMismatch)
|
||||
}
|
||||
|
||||
/// Used to parse a network message using [zerocopy], mutably
|
||||
pub fn truncating_cast_into_nomut<T: FromBytes>(
|
||||
buf: &[u8],
|
||||
) -> Result<Ref<&[u8], T>, RosenpassError> {
|
||||
Ref::new(&buf[..size_of::<T>()]).ok_or(RosenpassError::BufferSizeMismatch)
|
||||
}
|
||||
@@ -15,7 +15,7 @@ use rosenpass::api::{
|
||||
supply_keypair_response_status,
|
||||
};
|
||||
use rosenpass::config::ProtocolVersion;
|
||||
use rosenpass::protocol::SymKey;
|
||||
use rosenpass::protocol::basic_types::SymKey;
|
||||
use rosenpass_util::{
|
||||
b64::B64Display,
|
||||
file::LoadValueB64,
|
||||
|
||||
@@ -17,7 +17,7 @@ use tempfile::TempDir;
|
||||
use zerocopy::AsBytes;
|
||||
|
||||
use rosenpass::config::ProtocolVersion;
|
||||
use rosenpass::protocol::SymKey;
|
||||
use rosenpass::protocol::basic_types::SymKey;
|
||||
|
||||
struct KillChild(std::process::Child);
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ use std::{
|
||||
use rosenpass::config::ProtocolVersion;
|
||||
use rosenpass::{
|
||||
app_server::{AppServer, AppServerTest, MAX_B64_KEY_SIZE},
|
||||
protocol::{SPk, SSk, SymKey},
|
||||
protocol::basic_types::{SPk, SSk, SymKey},
|
||||
};
|
||||
use rosenpass_cipher_traits::primitives::Kem;
|
||||
use rosenpass_ciphers::StaticKem;
|
||||
|
||||
@@ -10,8 +10,10 @@ use rosenpass_ciphers::StaticKem;
|
||||
use rosenpass_util::result::OkExt;
|
||||
|
||||
use rosenpass::protocol::{
|
||||
testutils::time_travel_forward, CryptoServer, HostIdentification, MsgBuf, PeerPtr, PollResult,
|
||||
ProtocolVersion, SPk, SSk, SymKey, Timing, UNENDING,
|
||||
basic_types::{MsgBuf, SPk, SSk, SymKey},
|
||||
testutils::time_travel_forward,
|
||||
timing::{Timing, UNENDING},
|
||||
CryptoServer, HostIdentification, PeerPtr, PollResult, ProtocolVersion,
|
||||
};
|
||||
|
||||
// TODO: Most of the utility functions in here should probably be moved to
|
||||
|
||||
@@ -206,7 +206,7 @@ pub async fn exchange(options: ExchangeOptions) -> Result<()> {
|
||||
use rosenpass::{
|
||||
app_server::{AppServer, BrokerPeer},
|
||||
config::Verbosity,
|
||||
protocol::{SPk, SSk, SymKey},
|
||||
protocol::basic_types::{SPk, SSk, SymKey},
|
||||
};
|
||||
use rosenpass_secret_memory::Secret;
|
||||
use rosenpass_util::file::{LoadValue as _, LoadValueB64};
|
||||
|
||||
@@ -9,7 +9,7 @@ use anyhow::{anyhow, Result};
|
||||
use rosenpass_util::file::{LoadValueB64, StoreValue, StoreValueB64};
|
||||
use zeroize::Zeroize;
|
||||
|
||||
use rosenpass::protocol::{SPk, SSk};
|
||||
use rosenpass::protocol::basic_types::{SPk, SSk};
|
||||
use rosenpass_cipher_traits::primitives::Kem;
|
||||
use rosenpass_ciphers::StaticKem;
|
||||
use rosenpass_secret_memory::{file::StoreSecret as _, Public, Secret};
|
||||
@@ -118,7 +118,7 @@ pub fn pubkey(private_keys_dir: &Path, public_keys_dir: &Path) -> Result<()> {
|
||||
mod tests {
|
||||
use std::fs;
|
||||
|
||||
use rosenpass::protocol::{SPk, SSk};
|
||||
use rosenpass::protocol::basic_types::{SPk, SSk};
|
||||
use rosenpass_secret_memory::secret_policy_try_use_memfd_secrets;
|
||||
use rosenpass_secret_memory::Secret;
|
||||
use rosenpass_util::file::LoadValue;
|
||||
|
||||
Reference in New Issue
Block a user