Skip to content

Commit

Permalink
Merge pull request #979 from NordSecurity/LLT-5457_add_zeroize_on_dro…
Browse files Browse the repository at this point in the history
…p_for_sensitive_key_types

Zeroize memory upon destruction of sensitive key structs
  • Loading branch information
Jauler authored Dec 4, 2024
2 parents 1e557f5 + 395984b commit 228d261
Show file tree
Hide file tree
Showing 29 changed files with 105 additions and 84 deletions.
1 change: 1 addition & 0 deletions .unreleased/LLT-5457
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
LLT-5457 - clear memory for sensitive key material on destructor
4 changes: 2 additions & 2 deletions clis/derpcli/src/conf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,10 @@ impl StressConfig {

impl Config {
pub fn get_key1(&self) -> crypto_box::SecretKey {
self.my_key.into()
self.my_key.clone().into()
}
pub fn get_key2(&self) -> crypto_box::SecretKey {
self.target_key.into()
self.target_key.clone().into()
}
pub fn get_pub_key1(&self) -> crypto_box::PublicKey {
BoxPublicKey::from(&self.get_key1())
Expand Down
8 changes: 4 additions & 4 deletions clis/derpcli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ async fn connect_client(
&client.derp_server,
*addrs.first().ok_or_else(|| anyhow!("Empty socket Addr"))?,
Config {
secret_key: client.private_key,
secret_key: client.private_key.clone(),
timeout: Duration::from_secs(10),
..Default::default()
},
Expand Down Expand Up @@ -343,7 +343,7 @@ async fn run_without_clients_config(config: conf::Config) -> Result<()> {
.first()
.ok_or_else(|| anyhow!("ERR!! Empty server addr"))?,
Config {
secret_key: config.my_key,
secret_key: config.my_key.clone(),
timeout: Duration::from_secs(5),
use_built_in_root_certificates: config.use_built_in_root_certificates,
..Default::default()
Expand Down Expand Up @@ -623,9 +623,9 @@ async fn run_with_clients_config(
.ok_or_else(|| anyhow!("Err! No derp found"))?
.clone();
let client1 = conf::ClientConfig {
private_key: key1,
private_key: key1.clone(),
derp_server: derps1,
peers: vec![key2],
peers: vec![key2.clone()],
};
let client2 = conf::ClientConfig {
private_key: key2,
Expand Down
8 changes: 4 additions & 4 deletions clis/interderpcli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,10 +203,10 @@ async fn test_pair(
let addr_2 = resolve_domain_name(&host_2).await?;

info!("Starting clients");
let mut client_1 = Box::pin(connect_client(addr_1, host_1.clone(), key_1))
let mut client_1 = Box::pin(connect_client(addr_1, host_1.clone(), key_1.clone()))
.await
.context("Failed to connect to first server")?;
let mut client_2 = Box::pin(connect_client(addr_2, host_2.clone(), key_2))
let mut client_2 = Box::pin(connect_client(addr_2, host_2.clone(), key_2.clone()))
.await
.context("Failed to connect to second server")?;

Expand All @@ -228,9 +228,9 @@ async fn config_file_scenario(config_file: PathBuf, verbose: bool) -> Result<()>
(Some(first), Some(second)) => {
match Box::pin(test_pair(
first.to_string(),
config.private_key_1,
config.private_key_1.clone(),
second.to_string(),
config.private_key_2,
config.private_key_2.clone(),
))
.await
{
Expand Down
2 changes: 1 addition & 1 deletion clis/tcli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -772,7 +772,7 @@ impl Cli {
) -> Result<(), Error> {
if !self.telio.is_running() {
let device_config = DeviceConfig {
private_key,
private_key: private_key.clone(),
name: Some(name),
adapter: adapter_type,
..Default::default()
Expand Down
2 changes: 1 addition & 1 deletion clis/tcli/src/derp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ impl DerpClient {
allowed_pk,
} => {
let mut config = telio_relay::Config {
secret_key,
secret_key: secret_key.clone(),
..Default::default()
};

Expand Down
2 changes: 1 addition & 1 deletion clis/teliod/src/core_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ pub async fn init_with_api(
Some(identity) => identity,
None => {
let private_key = SecretKey::gen();
let hw_identifier = generate_hw_identifier(private_key);
let hw_identifier = generate_hw_identifier(private_key.clone());

let machine_identifier =
match fetch_identifier_with_exp_backoff(auth_token, private_key.public()).await {
Expand Down
2 changes: 1 addition & 1 deletion clis/teliod/src/daemon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ fn telio_task(
if !auth_token.as_str().eq("") {
start_telio(
&mut telio,
node_identity.private_key,
node_identity.private_key.clone(),
&interface_config.name,
)?;
task_retrieve_meshmap(node_identity, auth_token, tx_channel.clone());
Expand Down
2 changes: 1 addition & 1 deletion crates/telio-crypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ aead = { version = "0.5.2", default-features = false }
serde_with = { features = ["macros"], default-features = false, version = "3.7.0" }
chacha20poly1305 = { default-features = false, version = "0.10.1" }
chacha20 = "0.9.1"
zeroize = { version = "1", default-features = false }
zeroize = { version = "1.8.1", features = ["derive"] }
curve25519-dalek = { default-features = false, version = "4.1.3" }

base64.workspace = true
Expand Down
15 changes: 13 additions & 2 deletions crates/telio-crypto/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,24 @@ use rand::prelude::*;
use serde::{Deserialize, Serialize};
use serde_with::{DeserializeFromStr, SerializeDisplay};
use telio_utils::Hidden;
use zeroize::ZeroizeOnDrop;

/// Secret, Public and Wireguard Preshared key size in bytes
pub const KEY_SIZE: usize = 32;

/// Secret key type
#[derive(
Default, Debug, PartialOrd, Ord, PartialEq, Eq, Hash, Copy, Clone, Serialize, Deserialize,
Default,
Debug,
PartialOrd,
Ord,
PartialEq,
Eq,
Hash,
Clone,
Serialize,
Deserialize,
ZeroizeOnDrop,
)]
pub struct SecretKey(Hidden<[u8; KEY_SIZE]>);

Expand Down Expand Up @@ -97,7 +108,7 @@ pub fn smaller_key_in_meshnet_canonical_order<'a>(
}

/// Preshared key type
#[derive(Default, Debug, PartialOrd, Ord, PartialEq, Eq, Hash, Copy, Clone)]
#[derive(Default, Debug, PartialOrd, Ord, PartialEq, Eq, Hash, Clone, ZeroizeOnDrop)]
pub struct PresharedKey(pub Hidden<[u8; KEY_SIZE]>);

/// Error returned when parsing fails for SecretKey or PublicKey.
Expand Down
6 changes: 3 additions & 3 deletions crates/telio-dns/src/dns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ impl LocalDnsResolver {

Ok(LocalDnsResolver {
socket: Arc::new(socket),
secret_key: dns_secret_key,
secret_key: dns_secret_key.clone(),
peer: Arc::new(Mutex::new(Tunn::new(
StaticSecret::from(dns_secret_key.into_bytes()),
telio_public_key,
Expand Down Expand Up @@ -149,7 +149,7 @@ impl DnsResolver for LocalDnsResolver {
}

fn public_key(&self) -> PublicKey {
let static_secret = &StaticSecret::from(self.secret_key.into_bytes());
let static_secret = &StaticSecret::from(self.secret_key.clone().into_bytes());
telio_log_debug!(
"Dns - public_key: {:?}",
PublicKeyDalek::from(static_secret)
Expand Down Expand Up @@ -191,7 +191,7 @@ impl DnsResolver for LocalDnsResolver {

async fn set_peer_public_key(&self, pubkey: PublicKey) {
let peer = match Tunn::new(
StaticSecret::from(self.secret_key.into_bytes()),
StaticSecret::from(self.secret_key.clone().into_bytes()),
PublicKeyDalek::from(pubkey.0),
None,
None,
Expand Down
4 changes: 2 additions & 2 deletions crates/telio-nurse/src/aggregator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,7 @@ mod tests {
.collect();
keys.sort_by_key(|(_sk, pk)| *pk);
let mut i = Interface::default();
i.private_key = Some(keys[1].0);
i.private_key = Some(keys[1].0.clone());
match rx_tx_bytes {
Some((rx, tx)) => {
i.peers = [(
Expand All @@ -577,7 +577,7 @@ mod tests {
}
};

let local_key = interface.private_key.unwrap().public();
let local_key = interface.private_key.clone().unwrap().public();

let mut wg_interface = MockWireGuard::new();
wg_interface
Expand Down
10 changes: 5 additions & 5 deletions crates/telio-nurse/src/heartbeat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1255,7 +1255,7 @@ mod tests {
let peer_sk_1 = SecretKey::gen();
let peer_sk_2 = SecretKey::gen();

setup_local_nodes(&mut analytics, true, [peer_sk_1, peer_sk_2]).await;
setup_local_nodes(&mut analytics, true, [peer_sk_1.clone(), peer_sk_2.clone()]).await;

analytics.handle_collection().await;
assert_eq!(RuntimeState::Collecting, analytics.state);
Expand All @@ -1280,7 +1280,7 @@ mod tests {
let peer_sk_1 = SecretKey::gen();
let peer_sk_2 = SecretKey::gen();

setup_local_nodes(&mut analytics, true, [peer_sk_1, peer_sk_2]).await;
setup_local_nodes(&mut analytics, true, [peer_sk_1.clone(), peer_sk_2.clone()]).await;

analytics.handle_collection().await;
assert_eq!(RuntimeState::Collecting, analytics.state);
Expand Down Expand Up @@ -1310,13 +1310,13 @@ mod tests {

let peer_sk = SecretKey::gen();

setup_local_nodes(&mut analytics, true, [peer_sk]).await;
setup_local_nodes(&mut analytics, true, [peer_sk.clone()]).await;

analytics.handle_collection().await;
assert_eq!(RuntimeState::Collecting, analytics.state);

let other_meshnet_id = Uuid::new_v4();
send_heartbeat_response(&mut analytics, peer_sk, other_meshnet_id).await;
send_heartbeat_response(&mut analytics, peer_sk.clone(), other_meshnet_id).await;

analytics.handle_aggregation().await;

Expand Down Expand Up @@ -1565,7 +1565,7 @@ mod tests {

let mut state: State = setup(Some(Duration::from_secs(3600)), Some(Arc::new(aggregator)));

setup_local_nodes(&mut state.analytics, true, [peer_sk]).await;
setup_local_nodes(&mut state.analytics, true, [peer_sk.clone()]).await;

state.analytics.handle_collection().await;
assert_eq!(RuntimeState::Collecting, state.analytics.state);
Expand Down
8 changes: 5 additions & 3 deletions crates/telio-pq/src/conn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@ impl ConnKeyRotation {
// It can only be closed on library shutdown, in that case we
// may not care since the task itself will be killed soon
#[allow(mpsc_blocking_send)]
let _ = chan.send(super::Event::Handshake(addr, wg_keys)).await;
let _ = chan
.send(super::Event::Handshake(addr, wg_keys.clone()))
.await;

telio_log_debug!("Rekey interval: {}s", rekey_interval.as_secs());
let mut interval = telio_utils::interval(rekey_interval);
Expand All @@ -77,13 +79,13 @@ impl ConnKeyRotation {
match tokio::time::timeout(request_retry, rekey).await {
Ok(Ok(key)) => {
telio_log_debug!("Successful PQ REKEY");
wg_keys.pq_shared = key;
wg_keys.pq_shared = key.clone();

// The channel is allways open during the library operation.
// It can only be closed on library shutdown, in that case we
// may not care since the task itself will be killed soon
#[allow(mpsc_blocking_send)]
let _ = chan.send(super::Event::Rekey(wg_keys)).await;
let _ = chan.send(super::Event::Rekey(wg_keys.clone())).await;
}
Ok(Err(err)) => {
telio_log_warn!("Failed to perform PQ rekey: {err}");
Expand Down
2 changes: 1 addition & 1 deletion crates/telio-pq/src/entity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub struct Entity {

impl crate::PostQuantum for Entity {
fn keys(&self) -> Option<crate::Keys> {
self.peer.as_ref().and_then(|p| p.keys)
self.peer.as_ref().and_then(|p| p.keys.clone())
}

fn is_rotating_keys(&self) -> bool {
Expand Down
4 changes: 2 additions & 2 deletions crates/telio-pq/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::net::SocketAddr;
pub use entity::Entity;

/// Post quantum keys retrived from hanshake
#[derive(Clone, Copy)]
#[derive(Clone)]
pub struct Keys {
/// Kyber shared secret
pub pq_shared: telio_crypto::PresharedKey,
Expand All @@ -22,7 +22,7 @@ pub trait PostQuantum {
fn is_rotating_keys(&self) -> bool;
}

#[derive(Copy, Clone)]
#[derive(Clone)]
pub enum Event {
Handshake(SocketAddr, Keys),
Rekey(Keys),
Expand Down
2 changes: 1 addition & 1 deletion crates/telio-pq/src/proto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ async fn handshake(
sock.connect(endpoint).await?;

let mut tunn = noise::Tunn::new(
secret.into_bytes().into(),
secret.clone().into_bytes().into(),
peers_pubkey.0.into(),
None,
None,
Expand Down
7 changes: 4 additions & 3 deletions crates/telio-relay/src/derp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -542,7 +542,8 @@ impl State {
msg.packet_type()
);
match msg.encode() {
Ok(buf) => match DerpRelay::encrypt_if_needed(config.secret_key, pk, rng, &buf) {
Ok(buf) => match DerpRelay::encrypt_if_needed(config.secret_key.clone(), pk, rng, &buf)
{
Ok(cipher_text) => {
let _ = permit.send((pk, cipher_text));
}
Expand Down Expand Up @@ -581,7 +582,7 @@ impl State {
config: &Config,
) {
if config.meshnet_peers.contains(&pk) {
match DerpRelay::decrypt_if_needed(config.secret_key, pk, &buf) {
match DerpRelay::decrypt_if_needed(config.secret_key.clone(), pk, &buf) {
Ok(plain_text) => match PacketRelayed::decode(&plain_text) {
Ok(msg) => {
telio_log_trace!(
Expand Down Expand Up @@ -995,7 +996,7 @@ mod tests {
} = McChan::default();

let config = Config {
secret_key: test_conf.private_key,
secret_key: test_conf.private_key.clone(),
servers: SortedServers::new(vec![Server {
hostname: "de1047.nordvpn.com".into(),
relay_port: 8765,
Expand Down
4 changes: 2 additions & 2 deletions crates/telio-relay/src/derp/proto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -502,10 +502,10 @@ mod tests {
let server_key1 = SecretKey::new([1_u8; KEY_SIZE]).public();
let secret_key2 = SecretKey::new([2_u8; KEY_SIZE]);
let server_key2 = SecretKey::new([3_u8; KEY_SIZE]).public();
write_client_key(&mut buf1, secret_key1, server_key1, None)
write_client_key(&mut buf1, secret_key1.clone(), server_key1.clone(), None)
.await
.unwrap();
write_client_key(&mut buf2, secret_key1, server_key1, None)
write_client_key(&mut buf2, secret_key1.clone(), server_key1.clone(), None)
.await
.unwrap();
write_client_key(&mut buf3, secret_key2, server_key2, None)
Expand Down
4 changes: 2 additions & 2 deletions crates/telio-starcast/src/starcast_peer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ impl State {

self.tunnel = Some(
Tunn::new(
StaticSecret::from(self.secret_key.into_bytes()),
StaticSecret::from(self.secret_key.clone().into_bytes()),
PublicKeyDalek::from(config.public_key.0),
None,
None,
Expand All @@ -184,7 +184,7 @@ impl State {
}

fn get_peer(&self) -> Result<Peer, Error> {
let static_secret = &StaticSecret::from(self.secret_key.into_bytes());
let static_secret = &StaticSecret::from(self.secret_key.clone().into_bytes());

Ok(Peer {
public_key: PublicKey(PublicKeyDalek::from(static_secret).to_bytes()),
Expand Down
Loading

0 comments on commit 228d261

Please sign in to comment.