Skip to content

Commit 8eba7c4

Browse files
committed
feat(p2p/webrtc): authenticate connection after it has been established
1 parent e19fa40 commit 8eba7c4

25 files changed

+494
-55
lines changed

node/common/src/service/p2p.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use node::{
66
p2p::{
77
connection::outgoing::P2pConnectionOutgoingInitOpts,
88
identity::{EncryptableType, PublicKey},
9+
webrtc::ConnectionAuth,
910
PeerId,
1011
},
1112
};
@@ -55,6 +56,28 @@ impl webrtc::P2pServiceWebrtc for NodeService {
5556
) -> Result<T, ()> {
5657
self.p2p.sec_key.decrypt(other_pk, encrypted)
5758
}
59+
60+
fn auth_encrypt_and_send(
61+
&mut self,
62+
peer_id: PeerId,
63+
other_pub_key: &PublicKey,
64+
auth: ConnectionAuth,
65+
) {
66+
let encrypted = auth.encrypt(&self.p2p.sec_key, other_pub_key, &mut self.rng);
67+
if let Some(peer) = self.peers().get(&peer_id) {
68+
let _ = peer
69+
.cmd_sender
70+
.send(webrtc::PeerCmd::ConnectionAuthorizationSend(encrypted));
71+
}
72+
}
73+
74+
fn auth_decrypt(
75+
&mut self,
76+
other_pub_key: &PublicKey,
77+
auth: node::p2p::webrtc::ConnectionAuthEncrypted,
78+
) -> Option<ConnectionAuth> {
79+
auth.decrypt(&self.p2p.sec_key, other_pub_key)
80+
}
5881
}
5982

6083
impl webrtc_with_libp2p::P2pServiceWebrtcWithLibp2p for NodeService {

node/src/action_kind.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,8 @@ pub enum ActionKind {
318318
P2pConnectionIncomingLibp2pReceived,
319319
P2pConnectionIncomingSuccess,
320320
P2pConnectionIncomingTimeout,
321-
P2pConnectionIncomingEffectfulAnswerSend,
321+
P2pConnectionIncomingEffectfulConnectionAuthorizationDecryptAndCheck,
322+
P2pConnectionIncomingEffectfulConnectionAuthorizationEncryptAndSend,
322323
P2pConnectionIncomingEffectfulInit,
323324
P2pConnectionOutgoingAnswerRecvError,
324325
P2pConnectionOutgoingAnswerRecvPending,
@@ -338,6 +339,8 @@ pub enum ActionKind {
338339
P2pConnectionOutgoingSuccess,
339340
P2pConnectionOutgoingTimeout,
340341
P2pConnectionOutgoingEffectfulAnswerSet,
342+
P2pConnectionOutgoingEffectfulConnectionAuthorizationDecryptAndCheck,
343+
P2pConnectionOutgoingEffectfulConnectionAuthorizationEncryptAndSend,
341344
P2pConnectionOutgoingEffectfulInit,
342345
P2pConnectionOutgoingEffectfulOfferSend,
343346
P2pConnectionOutgoingEffectfulRandomInit,
@@ -657,7 +660,7 @@ pub enum ActionKind {
657660
}
658661

659662
impl ActionKind {
660-
pub const COUNT: u16 = 545;
663+
pub const COUNT: u16 = 548;
661664
}
662665

663666
impl std::fmt::Display for ActionKind {
@@ -1871,6 +1874,12 @@ impl ActionKindGet for P2pConnectionOutgoingEffectfulAction {
18711874
Self::Init { .. } => ActionKind::P2pConnectionOutgoingEffectfulInit,
18721875
Self::OfferSend { .. } => ActionKind::P2pConnectionOutgoingEffectfulOfferSend,
18731876
Self::AnswerSet { .. } => ActionKind::P2pConnectionOutgoingEffectfulAnswerSet,
1877+
Self::ConnectionAuthorizationEncryptAndSend { .. } => {
1878+
ActionKind::P2pConnectionOutgoingEffectfulConnectionAuthorizationEncryptAndSend
1879+
}
1880+
Self::ConnectionAuthorizationDecryptAndCheck { .. } => {
1881+
ActionKind::P2pConnectionOutgoingEffectfulConnectionAuthorizationDecryptAndCheck
1882+
}
18741883
}
18751884
}
18761885
}
@@ -1879,7 +1888,12 @@ impl ActionKindGet for P2pConnectionIncomingEffectfulAction {
18791888
fn kind(&self) -> ActionKind {
18801889
match self {
18811890
Self::Init { .. } => ActionKind::P2pConnectionIncomingEffectfulInit,
1882-
Self::AnswerSend { .. } => ActionKind::P2pConnectionIncomingEffectfulAnswerSend,
1891+
Self::ConnectionAuthorizationEncryptAndSend { .. } => {
1892+
ActionKind::P2pConnectionIncomingEffectfulConnectionAuthorizationEncryptAndSend
1893+
}
1894+
Self::ConnectionAuthorizationDecryptAndCheck { .. } => {
1895+
ActionKind::P2pConnectionIncomingEffectfulConnectionAuthorizationDecryptAndCheck
1896+
}
18831897
}
18841898
}
18851899
}

node/src/event_source/event_source_effects.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -184,12 +184,16 @@ pub fn event_source_effects<S: Service>(store: &mut Store<S>, action: EventSourc
184184
error,
185185
});
186186
}
187-
Ok(_) => {
188-
let _ = store
189-
.dispatch(P2pConnectionOutgoingAction::FinalizeSuccess { peer_id })
190-
|| store.dispatch(P2pConnectionIncomingAction::FinalizeSuccess {
187+
Ok(auth) => {
188+
let _ = store.dispatch(P2pConnectionOutgoingAction::FinalizeSuccess {
189+
peer_id,
190+
remote_auth: Some(auth.clone()),
191+
}) || store.dispatch(
192+
P2pConnectionIncomingAction::FinalizeSuccess {
191193
peer_id,
192-
});
194+
remote_auth: auth.clone(),
195+
},
196+
);
193197
}
194198
},
195199
P2pConnectionEvent::Closed(peer_id) => {

node/testing/src/node/rust/event.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use node::{
2-
p2p::{P2pConnectionEvent, P2pEvent, PeerId},
2+
p2p::{webrtc::ConnectionAuthEncrypted, P2pConnectionEvent, P2pEvent, PeerId},
33
rpc::{RpcId, RpcRequest},
44
};
55
use serde::{Deserialize, Serialize};
@@ -10,7 +10,7 @@ pub use node::event_source::Event;
1010
pub enum NonDeterministicEvent {
1111
/// Non-deterministic because libp2p kademlia initiates connections
1212
/// without state machine knowing about it.
13-
P2pConnectionFinalized(PeerId, Result<(), String>),
13+
P2pConnectionFinalized(PeerId, Result<ConnectionAuthEncrypted, String>),
1414
P2pConnectionClosed(PeerId),
1515

1616
RpcReadonly(RpcId, Box<RpcRequest>),

node/testing/src/service/mod.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,24 @@ impl P2pServiceWebrtc for NodeTestingService {
375375
) -> Result<T, ()> {
376376
self.real.decrypt(other_pub_key, encrypted)
377377
}
378+
379+
fn auth_encrypt_and_send(
380+
&mut self,
381+
peer_id: PeerId,
382+
other_pub_key: &node::p2p::identity::PublicKey,
383+
auth: webrtc::ConnectionAuth,
384+
) {
385+
self.real
386+
.auth_encrypt_and_send(peer_id, other_pub_key, auth)
387+
}
388+
389+
fn auth_decrypt(
390+
&mut self,
391+
other_pub_key: &node::p2p::identity::PublicKey,
392+
auth: webrtc::ConnectionAuthEncrypted,
393+
) -> Option<webrtc::ConnectionAuth> {
394+
self.real.auth_decrypt(other_pub_key, auth)
395+
}
378396
}
379397

380398
impl P2pServiceWebrtcWithLibp2p for NodeTestingService {

p2p/src/connection/incoming/p2p_connection_incoming_actions.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ pub enum P2pConnectionIncomingAction {
4949
/// Incoming connection finalized.
5050
FinalizeSuccess {
5151
peer_id: PeerId,
52+
remote_auth: webrtc::ConnectionAuthEncrypted,
5253
},
5354
/// Timeout establishing incoming connection.
5455
Timeout {
@@ -86,7 +87,7 @@ impl P2pConnectionIncomingAction {
8687
| Self::AnswerSendSuccess { peer_id }
8788
| Self::FinalizePending { peer_id }
8889
| Self::FinalizeError { peer_id, .. }
89-
| Self::FinalizeSuccess { peer_id }
90+
| Self::FinalizeSuccess { peer_id, .. }
9091
| Self::Timeout { peer_id }
9192
| Self::Error { peer_id, .. }
9293
| Self::Success { peer_id }
@@ -172,7 +173,7 @@ impl redux::EnablingCondition<P2pState> for P2pConnectionIncomingAction {
172173
)
173174
})
174175
}
175-
P2pConnectionIncomingAction::FinalizeSuccess { peer_id } => {
176+
P2pConnectionIncomingAction::FinalizeSuccess { peer_id, .. } => {
176177
state.peers.get(peer_id).map_or(false, |peer| {
177178
matches!(
178179
&peer.status,
@@ -198,6 +199,9 @@ impl redux::EnablingCondition<P2pState> for P2pConnectionIncomingAction {
198199
P2pConnectionIncomingError::FinalizeError(_) => {
199200
matches!(s, P2pConnectionIncomingState::FinalizePending { .. })
200201
}
202+
P2pConnectionIncomingError::ConnectionAuthError => {
203+
matches!(s, P2pConnectionIncomingState::FinalizeSuccess { .. })
204+
}
201205
P2pConnectionIncomingError::Timeout => true,
202206
},
203207
_ => false,

p2p/src/connection/incoming/p2p_connection_incoming_reducer.rs

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -174,10 +174,7 @@ impl P2pConnectionIncomingState {
174174

175175
match signaling {
176176
IncomingSignalingMethod::Http => {
177-
dispatcher.push(P2pConnectionIncomingEffectfulAction::AnswerSend {
178-
peer_id,
179-
answer: answer.clone(),
180-
});
177+
// Will respond to the rpc below.
181178
}
182179
IncomingSignalingMethod::P2p { relay_peer_id } => {
183180
dispatcher.push(P2pChannelsSignalingExchangeAction::AnswerSend {
@@ -243,19 +240,25 @@ impl P2pConnectionIncomingState {
243240
..
244241
} = state
245242
{
243+
let auth = offer.conn_auth(answer);
244+
let other_pub_key = offer.identity_pub_key.clone();
245+
246246
*state = Self::FinalizePending {
247247
time: meta.time(),
248248
signaling: *signaling,
249249
offer: offer.clone(),
250250
answer: answer.clone(),
251251
rpc_id: rpc_id.take(),
252252
};
253+
254+
state_context.into_dispatcher().push(P2pConnectionIncomingEffectfulAction::ConnectionAuthorizationEncryptAndSend { peer_id, other_pub_key, auth });
253255
} else {
254256
bug_condition!(
255257
"Invalid state for `P2pConnectionIncomingAction::FinalizePending`: {:?}",
256258
state
257259
);
258260
}
261+
259262
Ok(())
260263
}
261264
P2pConnectionIncomingAction::FinalizeError { error, .. } => {
@@ -266,35 +269,48 @@ impl P2pConnectionIncomingState {
266269
});
267270
Ok(())
268271
}
269-
P2pConnectionIncomingAction::FinalizeSuccess { .. } => {
272+
P2pConnectionIncomingAction::FinalizeSuccess { remote_auth, .. } => {
270273
let state = p2p_state
271274
.incoming_peer_connection_mut(&peer_id)
272-
.ok_or_else(|| format!("Invalid state for: {:?}", action))?;
273-
if let Self::FinalizePending {
275+
.ok_or_else(|| {
276+
"Invalid state for: P2pConnectionIncomingAction::FinalizeSuccess".to_owned()
277+
})?;
278+
let (expected_auth, other_pub_key) = if let Self::FinalizePending {
274279
signaling,
275280
offer,
276281
answer,
277282
rpc_id,
278283
..
279284
} = state
280285
{
286+
let expected_auth = offer.conn_auth(answer);
287+
let other_pub_key = offer.identity_pub_key.clone();
281288
*state = Self::FinalizeSuccess {
282289
time: meta.time(),
283290
signaling: *signaling,
284291
offer: offer.clone(),
285292
answer: answer.clone(),
286293
rpc_id: rpc_id.take(),
287294
};
295+
(expected_auth, other_pub_key)
288296
} else {
289297
bug_condition!(
290298
"Invalid state for `P2pConnectionIncomingAction::FinalizeSuccess`: {:?}",
291299
state
292300
);
293301
return Ok(());
294-
}
302+
};
295303

296304
let dispatcher = state_context.into_dispatcher();
297-
dispatcher.push(P2pConnectionIncomingAction::Success { peer_id });
305+
306+
dispatcher.push(
307+
P2pConnectionIncomingEffectfulAction::ConnectionAuthorizationDecryptAndCheck {
308+
peer_id,
309+
other_pub_key,
310+
expected_auth,
311+
auth: remote_auth,
312+
},
313+
);
298314
Ok(())
299315
}
300316
P2pConnectionIncomingAction::Timeout { .. } => {

p2p/src/connection/incoming/p2p_connection_incoming_state.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ pub enum P2pConnectionIncomingError {
127127
SdpCreateError(String),
128128
#[error("finalization error: {0}")]
129129
FinalizeError(String),
130+
#[error("connection authentication failed")]
131+
ConnectionAuthError,
130132
#[error("timeout error")]
131133
Timeout,
132134
}

p2p/src/connection/incoming_effectful/p2p_connection_incoming_effectful_actions.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use crate::{
22
connection::{incoming::P2pConnectionIncomingInitOpts, P2pConnectionEffectfulAction},
3-
webrtc, P2pState, PeerId,
3+
identity::PublicKey,
4+
webrtc::{ConnectionAuth, ConnectionAuthEncrypted},
5+
P2pState, PeerId,
46
};
57
use openmina_core::ActionEvent;
68
use serde::{Deserialize, Serialize};
@@ -10,9 +12,16 @@ use serde::{Deserialize, Serialize};
1012
pub enum P2pConnectionIncomingEffectfulAction {
1113
/// Incoming connection is initialized.
1214
Init { opts: P2pConnectionIncomingInitOpts },
13-
AnswerSend {
15+
ConnectionAuthorizationEncryptAndSend {
1416
peer_id: PeerId,
15-
answer: Box<webrtc::Answer>,
17+
other_pub_key: PublicKey,
18+
auth: ConnectionAuth,
19+
},
20+
ConnectionAuthorizationDecryptAndCheck {
21+
peer_id: PeerId,
22+
other_pub_key: PublicKey,
23+
expected_auth: ConnectionAuth,
24+
auth: ConnectionAuthEncrypted,
1625
},
1726
}
1827

p2p/src/connection/incoming_effectful/p2p_connection_incoming_effectful_effects.rs

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
use redux::ActionMeta;
22

33
use super::P2pConnectionIncomingEffectfulAction;
4-
use crate::connection::{incoming::P2pConnectionIncomingAction, P2pConnectionService};
4+
use crate::connection::{
5+
incoming::{P2pConnectionIncomingAction, P2pConnectionIncomingError},
6+
P2pConnectionService,
7+
};
58

69
impl P2pConnectionIncomingEffectfulAction {
710
pub fn effects<Store, S>(self, _meta: &ActionMeta, store: &mut Store)
@@ -15,8 +18,33 @@ impl P2pConnectionIncomingEffectfulAction {
1518
store.service().incoming_init(peer_id, *opts.offer);
1619
store.dispatch(P2pConnectionIncomingAction::AnswerSdpCreatePending { peer_id });
1720
}
18-
P2pConnectionIncomingEffectfulAction::AnswerSend { peer_id, answer } => {
19-
store.service().set_answer(peer_id, *answer);
21+
P2pConnectionIncomingEffectfulAction::ConnectionAuthorizationEncryptAndSend {
22+
peer_id,
23+
other_pub_key,
24+
auth,
25+
} => {
26+
store
27+
.service()
28+
.auth_encrypt_and_send(peer_id, &other_pub_key, auth);
29+
}
30+
P2pConnectionIncomingEffectfulAction::ConnectionAuthorizationDecryptAndCheck {
31+
peer_id,
32+
other_pub_key,
33+
expected_auth,
34+
auth,
35+
} => {
36+
if store
37+
.service()
38+
.auth_decrypt(&other_pub_key, auth)
39+
.map_or(false, |remote_auth| remote_auth == expected_auth)
40+
{
41+
store.dispatch(P2pConnectionIncomingAction::Success { peer_id });
42+
} else {
43+
store.dispatch(P2pConnectionIncomingAction::Error {
44+
peer_id,
45+
error: P2pConnectionIncomingError::ConnectionAuthError,
46+
});
47+
}
2048
}
2149
}
2250
}

0 commit comments

Comments
 (0)