Skip to content

Commit e251570

Browse files
Not working because webrtc is stupid
1 parent 9a80510 commit e251570

File tree

5 files changed

+163
-43
lines changed

5 files changed

+163
-43
lines changed

transports/webrtc/Cargo.toml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ categories = ["network-programming", "asynchronous"]
1313
async-trait = "0.1"
1414
asynchronous-codec = "0.6"
1515
bytes = "1"
16+
ed25519-compact = "2.0.2"
1617
futures = "0.3"
1718
futures-timer = "3"
1819
hex = "0.4"
@@ -24,6 +25,9 @@ multihash = { version = "0.16", default-features = false, features = ["sha2"] }
2425
prost = "0.11"
2526
prost-codec = { version = "0.2.1", path = "../../misc/prost-codec" }
2627
rand = "0.8"
28+
rcgen = "0.9.3"
29+
ring = "0.16.20"
30+
rustls = "0.19" # Needs to match version in `webrtc`
2731
serde = { version = "1.0", features = ["derive"] }
2832
stun = "0.4"
2933
thiserror = "1"
@@ -43,5 +47,8 @@ anyhow = "1.0"
4347
env_logger = "0.9"
4448
hex-literal = "0.3"
4549
libp2p = { path = "../..", features = ["request-response", "webrtc"], default-features = false }
46-
rcgen = "0.9.3"
4750
unsigned-varint = { version = "0.7", features = ["asynchronous_codec"] }
51+
52+
[[test]]
53+
name = "smoke"
54+
required-features = ["tokio"]

transports/webrtc/src/certificate.rs

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
use rand::distributions::DistString;
2+
use rand::{CryptoRng, Rng, SeedableRng};
3+
use rcgen::{CertificateParams, RcgenError, PKCS_ED25519};
4+
use ring::signature::Ed25519KeyPair;
5+
use webrtc::dtls;
6+
use webrtc::dtls::crypto::{CryptoPrivateKey, CryptoPrivateKeyKind};
7+
use webrtc::peer_connection::certificate::RTCCertificate;
8+
9+
#[derive(PartialEq)]
10+
pub struct Certificate {
11+
seed: [u8; 32],
12+
alt_name: String,
13+
pub(crate) inner: RTCCertificate,
14+
}
15+
16+
impl Certificate {
17+
pub fn from_seed(seed: [u8; 32]) -> Result<Self, Error> {
18+
let mut rng = rand::rngs::StdRng::from_seed(seed);
19+
20+
Self::new(&mut rng)
21+
}
22+
23+
pub fn new<R>(rng: &mut R) -> Result<Self, Error>
24+
where
25+
R: CryptoRng + Rng,
26+
{
27+
let seed = rng.gen::<[u8; 32]>();
28+
let alt_name = rand::distributions::Alphanumeric.sample_string(rng, 16);
29+
30+
Self::from_seed_and_alt_name(seed, alt_name)
31+
}
32+
33+
fn from_seed_and_alt_name(seed: [u8; 32], alt_name: String) -> Result<Certificate, Error> {
34+
let der_keypair =
35+
ed25519_compact::KeyPair::from_seed(ed25519_compact::Seed::from(seed.clone()))
36+
.sk
37+
.to_der();
38+
39+
let mut params = CertificateParams::new(vec![alt_name.clone()]);
40+
params.alg = &PKCS_ED25519;
41+
params.key_pair = Some(
42+
rcgen::KeyPair::from_der_and_sign_algo(&der_keypair, &PKCS_ED25519)
43+
.map_err(Kind::Rcgen)?,
44+
);
45+
46+
let expiry = params.not_after;
47+
48+
let x509_cert = rcgen::Certificate::from_params(params).map_err(Kind::Rcgen)?;
49+
let certificate = x509_cert.serialize_der().map_err(Kind::Rcgen)?;
50+
51+
let private_key = CryptoPrivateKey {
52+
kind: CryptoPrivateKeyKind::Ed25519(
53+
Ed25519KeyPair::from_pkcs8_maybe_unchecked(&der_keypair).map_err(Kind::Ring)?,
54+
),
55+
serialized_der: der_keypair,
56+
};
57+
58+
let certificate = RTCCertificate::from_existing(
59+
dtls::crypto::Certificate {
60+
certificate: vec![rustls::Certificate(certificate)],
61+
private_key,
62+
},
63+
&x509_cert.serialize_pem().map_err(Kind::Rcgen)?,
64+
expiry.into(),
65+
);
66+
67+
Ok(Self {
68+
seed,
69+
alt_name,
70+
inner: certificate,
71+
})
72+
}
73+
74+
pub fn to_pem(&self) -> &str {
75+
self.inner.pem()
76+
}
77+
}
78+
79+
impl Clone for Certificate {
80+
fn clone(&self) -> Self {
81+
Certificate::from_seed_and_alt_name(self.seed, self.alt_name.clone())
82+
.expect("it worked the first time")
83+
}
84+
}
85+
86+
#[derive(thiserror::Error, Debug)]
87+
#[error("Failed to generate certificate")]
88+
pub struct Error(#[from] Kind);
89+
90+
#[derive(thiserror::Error, Debug)]
91+
enum Kind {
92+
#[error(transparent)]
93+
Rcgen(RcgenError),
94+
#[error(transparent)]
95+
Ring(ring::error::KeyRejected),
96+
}
97+
98+
#[cfg(test)]
99+
mod tests {
100+
use super::*;
101+
use rand::thread_rng;
102+
103+
#[test]
104+
fn certificate_generation_is_deterministic() {
105+
let certificate = Certificate::from_seed([0u8; 32]).unwrap();
106+
107+
let pem = certificate.to_pem();
108+
109+
let expected = "-----BEGIN CERTIFICATE-----\r\nMIIBGTCBzKADAgECAgkAmhN4/nhTqzYwBQYDK2VwMCExHzAdBgNVBAMMFnJjZ2Vu\r\nIHNlbGYgc2lnbmVkIGNlcnQwIBcNNzUwMTAxMDAwMDAwWhgPNDA5NjAxMDEwMDAw\r\nMDBaMCExHzAdBgNVBAMMFnJjZ2VuIHNlbGYgc2lnbmVkIGNlcnQwKjAFBgMrZXAD\r\nIQAZkVlx7FLxyVC7GOK7UhQusdNotn+7mJTPgLUmOYlaBKMfMB0wGwYDVR0RBBQw\r\nEoIQZlVrWHBQRnEwelNGUU9ySDAFBgMrZXADQQBk2U8R6h9c8d6veJS+CSxQu5HX\r\nz8/zwwDR/X6yFpVVUGvuOMS3a9J9t9IRZMwUn0fxqlC9rdS/NWzU2NWNVHAO\r\n-----END CERTIFICATE-----\r\n";
110+
assert_eq!(expected, pem)
111+
}
112+
113+
#[test]
114+
fn can_generate_random_certificate() {
115+
Certificate::new(&mut thread_rng()).unwrap();
116+
}
117+
118+
#[test]
119+
fn cloned_certificate_is_equivalent() {
120+
let certificate = Certificate::from_seed([0u8; 32]).unwrap();
121+
122+
let cloned_certificate = certificate.clone();
123+
124+
assert!(certificate == cloned_certificate)
125+
}
126+
}

transports/webrtc/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,9 @@ mod message_proto {
8888

8989
#[cfg(feature = "tokio")]
9090
pub mod tokio;
91+
92+
#[cfg(feature = "tokio")]
93+
mod certificate;
94+
95+
#[cfg(feature = "tokio")]
96+
pub use certificate::Certificate;

transports/webrtc/src/tokio/transport.rs

Lines changed: 20 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ use libp2p_core::{
2626
transport::{ListenerId, TransportError, TransportEvent},
2727
PeerId,
2828
};
29-
use webrtc::peer_connection::certificate::RTCCertificate;
3029
use webrtc::peer_connection::configuration::RTCConfiguration;
3130

31+
use crate::Certificate;
3232
use std::net::IpAddr;
3333
use std::{
3434
net::SocketAddr,
@@ -61,20 +61,16 @@ impl Transport {
6161
/// use libp2p_core::identity;
6262
/// use webrtc::peer_connection::certificate::RTCCertificate;
6363
/// use rand::distributions::DistString;
64+
/// use rand::thread_rng;
65+
/// use libp2p_webrtc::Certificate;
6466
/// use libp2p_webrtc::tokio::Transport;
6567
///
6668
/// let id_keys = identity::Keypair::generate_ed25519();
67-
/// let certificate = {
68-
/// let mut params = rcgen::CertificateParams::new(vec![
69-
/// rand::distributions::Alphanumeric.sample_string(&mut rand::thread_rng(), 16)
70-
/// ]);
71-
/// params.alg = &rcgen::PKCS_ECDSA_P256_SHA256;
72-
/// RTCCertificate::from_params(params).expect("default params to work")
73-
/// };
69+
/// let certificate = Certificate::new(&mut thread_rng()).unwrap();
7470
///
7571
/// let transport = Transport::new(id_keys, certificate);
7672
/// ```
77-
pub fn new(id_keys: identity::Keypair, certificate: RTCCertificate) -> Self {
73+
pub fn new(id_keys: identity::Keypair, certificate: Certificate) -> Self {
7874
Self {
7975
config: Config::new(id_keys, certificate),
8076
listeners: SelectAll::new(),
@@ -146,7 +142,7 @@ impl libp2p_core::Transport for Transport {
146142
Ok(async move {
147143
let (peer_id, connection) = upgrade::outbound(
148144
sock_addr,
149-
config.inner,
145+
config.rtc_configuration(),
150146
udp_mux,
151147
client_fingerprint,
152148
server_fingerprint,
@@ -310,7 +306,7 @@ impl Stream for ListenStream {
310306

311307
let upgrade = upgrade::inbound(
312308
new_addr.addr,
313-
self.config.inner.clone(),
309+
self.config.rtc_configuration(),
314310
self.udp_mux.udp_mux_handle(),
315311
self.config.fingerprint,
316312
new_addr.ufrag,
@@ -336,7 +332,7 @@ impl Stream for ListenStream {
336332
/// A config which holds peer's keys and a x509Cert used to authenticate WebRTC communications.
337333
#[derive(Clone)]
338334
struct Config {
339-
inner: RTCConfiguration,
335+
certificate: Certificate,
340336
fingerprint: Fingerprint,
341337
id_keys: identity::Keypair,
342338
}
@@ -348,23 +344,27 @@ impl Config {
348344
///
349345
/// This function will panic if there's no fingerprint with the SHA-256 algorithm (see
350346
/// [`RTCCertificate::get_fingerprints`]).
351-
fn new(id_keys: identity::Keypair, certificate: RTCCertificate) -> Self {
352-
let fingerprints = certificate.get_fingerprints().expect("to never fail");
347+
fn new(id_keys: identity::Keypair, certificate: Certificate) -> Self {
348+
let fingerprints = certificate.inner.get_fingerprints().expect("to never fail");
353349
let sha256_fingerprint = fingerprints
354350
.iter()
355351
.find(|f| f.algorithm == "sha-256")
356352
.expect("a SHA-256 fingerprint");
357353

358354
Self {
359355
id_keys,
360-
inner: RTCConfiguration {
361-
certificates: vec![certificate],
362-
..RTCConfiguration::default()
363-
},
356+
certificate,
364357
fingerprint: Fingerprint::try_from_rtc_dtls(sha256_fingerprint)
365358
.expect("we specified SHA-256"),
366359
}
367360
}
361+
362+
fn rtc_configuration(&self) -> RTCConfiguration {
363+
RTCConfiguration {
364+
certificates: vec![self.certificate.clone().inner],
365+
..RTCConfiguration::default()
366+
}
367+
}
368368
}
369369

370370
/// Turns an IP address and port into the corresponding WebRTC multiaddr.
@@ -447,7 +447,7 @@ mod tests {
447447
use super::*;
448448
use futures::future::poll_fn;
449449
use libp2p_core::{multiaddr::Protocol, Transport as _};
450-
use rand::distributions::DistString;
450+
use rand::thread_rng;
451451
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
452452

453453
#[test]
@@ -567,8 +567,7 @@ mod tests {
567567
#[tokio::test]
568568
async fn close_listener() {
569569
let id_keys = identity::Keypair::generate_ed25519();
570-
let certificate = generate_certificate();
571-
let mut transport = Transport::new(id_keys, certificate);
570+
let mut transport = Transport::new(id_keys, Certificate::new(&mut thread_rng()).unwrap());
572571

573572
assert!(poll_fn(|cx| Pin::new(&mut transport).as_mut().poll(cx))
574573
.now_or_never()
@@ -617,12 +616,4 @@ mod tests {
617616
assert!(transport.listeners.is_empty());
618617
}
619618
}
620-
621-
fn generate_certificate() -> RTCCertificate {
622-
let mut params = rcgen::CertificateParams::new(vec![
623-
rand::distributions::Alphanumeric.sample_string(&mut rand::thread_rng(), 16)
624-
]);
625-
params.alg = &rcgen::PKCS_ECDSA_P256_SHA256;
626-
RTCCertificate::from_params(params).expect("default params to work")
627-
}
628619
}

transports/webrtc/tests/smoke.rs

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
1919
// DEALINGS IN THE SOFTWARE.
2020

21-
use ::webrtc::peer_connection::certificate::RTCCertificate;
2221
use anyhow::Result;
2322
use async_trait::async_trait;
2423
use futures::{
@@ -33,9 +32,9 @@ use libp2p::request_response::{
3332
};
3433
use libp2p::swarm::{Swarm, SwarmBuilder, SwarmEvent};
3534
use libp2p::webrtc::tokio as webrtc;
36-
use rand::distributions::DistString;
37-
use rand::RngCore;
35+
use rand::{thread_rng, RngCore};
3836

37+
use libp2p_webrtc::Certificate;
3938
use std::{io, iter};
4039

4140
#[tokio::test]
@@ -472,8 +471,7 @@ impl RequestResponseCodec for PingCodec {
472471
fn create_swarm() -> Result<Swarm<RequestResponse<PingCodec>>> {
473472
let id_keys = identity::Keypair::generate_ed25519();
474473
let peer_id = id_keys.public().to_peer_id();
475-
let certificate = generate_certificate();
476-
let transport = webrtc::Transport::new(id_keys, certificate);
474+
let transport = webrtc::Transport::new(id_keys, Certificate::new(&mut thread_rng()).unwrap());
477475

478476
let protocols = iter::once((PingProtocol(), ProtocolSupport::Full));
479477
let cfg = RequestResponseConfig::default();
@@ -488,11 +486,3 @@ fn create_swarm() -> Result<Swarm<RequestResponse<PingCodec>>> {
488486
}))
489487
.build())
490488
}
491-
492-
fn generate_certificate() -> RTCCertificate {
493-
let mut params = rcgen::CertificateParams::new(vec![
494-
rand::distributions::Alphanumeric.sample_string(&mut rand::thread_rng(), 16)
495-
]);
496-
params.alg = &rcgen::PKCS_ECDSA_P256_SHA256;
497-
RTCCertificate::from_params(params).expect("default params to work")
498-
}

0 commit comments

Comments
 (0)