Skip to content

Commit 787fa30

Browse files
committed
(feat/webrtc-sniffer): reconstruct ephemeral keys
1 parent 0e32b41 commit 787fa30

File tree

13 files changed

+112
-72
lines changed

13 files changed

+112
-72
lines changed

Cargo.lock

Lines changed: 24 additions & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cli/src/commands/node/mod.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,9 @@ pub struct Node {
171171
/// - OPENMINA_AWS_BUCKET_NAME
172172
#[arg(long, env)]
173173
pub archive_aws_storage: bool,
174+
175+
#[arg(long, env)]
176+
pub rng_seed: Option<String>,
174177
}
175178

176179
impl Node {
@@ -216,7 +219,27 @@ impl Node {
216219
node::config::DEVNET_CONFIG.clone(),
217220
),
218221
};
219-
let mut node_builder: NodeBuilder = NodeBuilder::new(None, daemon_conf, genesis_conf);
222+
223+
let custom_rng_seed = match self.rng_seed {
224+
None => None,
225+
Some(v) => match hex::decode(v)
226+
.map_err(anyhow::Error::from)
227+
.and_then(|bytes| {
228+
<[u8; 32]>::try_from(bytes.as_slice()).map_err(anyhow::Error::from)
229+
}) {
230+
Ok(v) => Some(v),
231+
Err(err) => {
232+
node::core::error!(
233+
node::core::log::system_time();
234+
summary = "bad rng seed",
235+
err = err.to_string(),
236+
);
237+
return Err(err);
238+
}
239+
},
240+
};
241+
let mut node_builder: NodeBuilder =
242+
NodeBuilder::new(custom_rng_seed, daemon_conf, genesis_conf);
220243

221244
// let genesis_config = match self.config {
222245
// Some(config_path) => GenesisConfig::DaemonJsonFile(config_path).into(),

node/common/src/service/builder.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ impl NodeServiceCommonBuilder {
112112
self.p2p = Some(<NodeService as P2pServiceWebrtcWithLibp2p>::init(
113113
secret_key.clone(),
114114
task_spawner,
115+
self.rng_seed,
115116
));
116117
self
117118
}

p2p/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ p2p-testing = { path = "testing" }
8080
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
8181
redux = { workspace = true, features = ["serializable_callbacks"] }
8282
tokio = { version = "1.26", features = ["rt"] }
83-
webrtc = { git = "https://github.com/openmina/webrtc.git", rev = "e8705db39af1b198b324a5db6ff57fb213ba75e9", optional = true }
83+
webrtc = { git = "https://github.com/openmina/webrtc.git", rev = "aeaa62682b97f6984627bedd6e6811fe17af18eb", optional = true }
8484
datachannel = { git = "https://github.com/openmina/datachannel-rs.git", rev = "1bfb064d0ff3e54a93ae0288409902aab8d102d3", optional = true, features = [
8585
"vendored",
8686
] }

p2p/src/service_impl/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,11 @@ pub mod webrtc {
5151

5252
fn peers(&mut self) -> &mut BTreeMap<PeerId, PeerState>;
5353

54-
fn init<S: TaskSpawner>(_secret_key: SecretKey, _spawner: S) -> P2pServiceCtx {
54+
fn init<S: TaskSpawner>(
55+
_secret_key: SecretKey,
56+
_spawner: S,
57+
_rng_seed: [u8; 32],
58+
) -> P2pServiceCtx {
5559
let (cmd_sender, _) = mpsc::unbounded_channel();
5660
P2pServiceCtx {
5761
cmd_sender,

p2p/src/service_impl/webrtc/mod.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ pub type OnConnectionStateChangeHdlrFn = Box<
141141
pub struct RTCConfig {
142142
pub ice_servers: RTCConfigIceServers,
143143
pub certificate: RTCCertificate,
144+
pub seed: [u8; 32],
144145
}
145146

146147
#[derive(Serialize)]
@@ -229,6 +230,7 @@ async fn peer_start(
229230
abort: Aborted,
230231
closed: mpsc::Sender<()>,
231232
certificate: RTCCertificate,
233+
rng_seed: [u8; 32],
232234
) {
233235
let PeerAddArgs {
234236
peer_id,
@@ -241,6 +243,7 @@ async fn peer_start(
241243
let config = RTCConfig {
242244
ice_servers: Default::default(),
243245
certificate,
246+
seed: rng_seed,
244247
};
245248
let fut = async {
246249
let mut pc = RTCConnection::create(&api, config).await?;
@@ -730,7 +733,11 @@ pub trait P2pServiceWebrtc: redux::Service {
730733

731734
fn peers(&mut self) -> &mut BTreeMap<PeerId, PeerState>;
732735

733-
fn init<S: TaskSpawner>(secret_key: SecretKey, spawner: S) -> P2pServiceCtx {
736+
fn init<S: TaskSpawner>(
737+
secret_key: SecretKey,
738+
spawner: S,
739+
rng_seed: [u8; 32],
740+
) -> P2pServiceCtx {
734741
const MAX_PEERS: usize = 500;
735742
let (cmd_sender, mut cmd_receiver) = mpsc::unbounded_channel();
736743

@@ -763,7 +770,7 @@ pub trait P2pServiceWebrtc: redux::Service {
763770
event_sender_clone(P2pConnectionEvent::Closed(peer_id).into());
764771
});
765772
tokio::select! {
766-
_ = peer_start(api, args, aborted.clone(), closed_tx.clone(), certificate) => {}
773+
_ = peer_start(api, args, aborted.clone(), closed_tx.clone(), certificate, rng_seed) => {}
767774
_ = aborted.wait() => {
768775
}
769776
}

p2p/src/service_impl/webrtc/webrtc_rs.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ impl From<RTCConfig> for RTCConfiguration {
200200
ice_servers: value.ice_servers.0.into_iter().map(Into::into).collect(),
201201
ice_transport_policy: RTCIceTransportPolicy::All,
202202
certificates: vec![value.certificate],
203+
seed: Some(value.seed.to_vec()),
203204
..Default::default()
204205
}
205206
}

p2p/src/service_impl/webrtc_with_libp2p.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,12 @@ pub trait P2pServiceWebrtcWithLibp2p: P2pServiceWebrtc {
2929

3030
fn connections(&self) -> BTreeSet<PeerId>;
3131

32-
fn init<S: TaskSpawner>(sec_key: SecretKey, spawner: S) -> P2pServiceCtx {
32+
fn init<S: TaskSpawner>(sec_key: SecretKey, spawner: S, rng_seed: [u8; 32]) -> P2pServiceCtx {
3333
P2pServiceCtx {
3434
sec_key: sec_key.clone(),
3535
#[cfg(feature = "p2p-libp2p")]
3636
mio: MioService::pending(sec_key.clone().try_into().expect("valid keypair")),
37-
webrtc: <Self as P2pServiceWebrtc>::init(sec_key, spawner),
37+
webrtc: <Self as P2pServiceWebrtc>::init(sec_key, spawner, rng_seed),
3838
}
3939
}
4040

tools/webrtc-sniffer/Cargo.toml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,12 @@ etherparse = { version = "0.17.0" }
1515
thiserror = { version = "2.0" }
1616
nom = { version = "8.0.0" }
1717

18-
p2p = { path = "../../p2p" }
18+
sha2 = { version = "0.10.8" }
19+
rand = { version = "0.8" }
20+
hkdf = { version = "0.12" }
21+
hmac = { version = "0.12" }
22+
p256 = { version = "0.13", features = ["default", "ecdh", "ecdsa"] }
23+
p384 = { version = "0.13" }
24+
aes = { version = "0.8" }
25+
cbc = { version = "0.1", features = ["block-padding", "alloc"] }
26+
aes-gcm = { version = "0.10" }

tools/webrtc-sniffer/src/bin/sniffer.rs

Lines changed: 7 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ use std::path::PathBuf;
33
use clap::Parser;
44
use pcap::{Capture, ConnectionStatus, Device, IfFlags};
55

6-
use p2p::identity::SecretKey;
7-
86
// cargo run --release --bin sniffer -- --interface auto --path target/test.pcap
97

108
#[derive(Parser)]
@@ -25,19 +23,9 @@ struct Cli {
2523
#[arg(long, help = "bpf filter, example: \"udp and not port 443\"")]
2624
filter: Option<String>,
2725

28-
/// Peer secret key
29-
#[arg(long, short = 's', env = "OPENMINA_P2P_SEC_KEY")]
30-
p2p_secret_key: Option<SecretKey>,
31-
32-
// warning, this overrides `OPENMINA_P2P_SEC_KEY`
33-
/// Compatibility with OCaml Mina node
34-
#[arg(long)]
35-
libp2p_keypair: Option<String>,
36-
37-
// warning, this overrides `OPENMINA_P2P_SEC_KEY`
38-
/// Compatibility with OCaml Mina node
39-
#[arg(env = "MINA_LIBP2P_PASS")]
40-
libp2p_password: Option<String>,
26+
/// rng seed
27+
#[arg(long, short)]
28+
rng_seed: String,
4129
}
4230

4331
fn init_logger_std() -> Box<dyn log::Log> {
@@ -56,28 +44,10 @@ fn main() {
5644
interface,
5745
path,
5846
filter,
59-
p2p_secret_key,
60-
libp2p_keypair,
61-
libp2p_password,
47+
rng_seed,
6248
} = Cli::parse();
6349

64-
let secret_key = if let Some(v) = p2p_secret_key {
65-
v
66-
} else {
67-
let (Some(libp2p_keypair), Some(libp2p_password)) = (libp2p_keypair, libp2p_password)
68-
else {
69-
log::error!("no secret key specified");
70-
return;
71-
};
72-
73-
match SecretKey::from_encrypted_file(libp2p_keypair, &libp2p_password) {
74-
Ok(v) => v,
75-
Err(err) => {
76-
log::error!("cannot read secret key {err}");
77-
return;
78-
}
79-
}
80-
};
50+
let rng_seed = <[u8; 32]>::try_from(hex::decode(rng_seed).unwrap().as_slice()).unwrap();
8151

8252
if let Some(name) = interface {
8353
sudo::escalate_if_needed().unwrap();
@@ -115,7 +85,7 @@ fn main() {
11585
.expect("Failed to apply filter");
11686
let savefile = capture.savefile(&path)?;
11787

118-
webrtc_sniffer::run(capture, Some(savefile), secret_key)
88+
webrtc_sniffer::run(capture, Some(savefile), rng_seed)
11989
});
12090
if let Err(err) = res {
12191
log::error!("{err}");
@@ -130,7 +100,7 @@ fn main() {
130100
capture
131101
.filter(&filter.unwrap_or_default(), true)
132102
.expect("Failed to apply filter");
133-
webrtc_sniffer::run(capture, None, secret_key)
103+
webrtc_sniffer::run(capture, None, rng_seed)
134104
});
135105
if let Err(err) = res {
136106
log::error!("{err}");

0 commit comments

Comments
 (0)