Skip to content

Commit

Permalink
Use certhash fingerprint
Browse files Browse the repository at this point in the history
  • Loading branch information
mxinden committed Aug 19, 2023
1 parent 89b7aab commit 4badac4
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 5 deletions.
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions transports/webtransport/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ async-std = { version = "1.12.0", optional = true }
bytes = "1.4.0"
futures = "0.3.28"
futures-timer = "3.0.2"
hex = "0.4"
if-watch = "3.0.1"
# TODO: Remove
libp2p = { path = "../../libp2p", features = ["tokio", "macros", "ping"] }
Expand All @@ -24,6 +25,7 @@ parking_lot = "0.12.0"
quinn = { version = "0.10.1", default-features = false, features = ["tls-rustls", "futures-io", "runtime-tokio"] }
rand = "0.8.5"
rustls = { version = "0.21.2", default-features = false }
sha2 = "0.10.7"
thiserror = "1.0.44"
# TODO redo features
tokio = { version = "1.31.0", default-features = false, features = ["net", "rt", "time", "macros", "rt-multi-thread"] }
Expand All @@ -49,3 +51,4 @@ rustc-args = ["--cfg", "docsrs"]
async-std = { version = "1.12.0", features = ["attributes"] }
quickcheck = "1"
tokio = { version = "1.31.0", features = ["macros", "rt-multi-thread", "time"] }
hex-literal = "0.4"
2 changes: 1 addition & 1 deletion transports/webtransport/src/bin/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
let local_peer_id = PeerId::from(local_key.public());
println!("Local peer id: {local_peer_id:?}");

let transport = libp2p_webtransport::Transport::new().unwrap().boxed();
let transport = libp2p_webtransport::Transport::new(local_peer_id).unwrap().boxed();

let mut swarm =
SwarmBuilder::with_tokio_executor(transport, Behaviour::default(), local_peer_id).build();
Expand Down
97 changes: 97 additions & 0 deletions transports/webtransport/src/fingerprint.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Copyright 2022 Parity Technologies (UK) Ltd.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use sha2::Digest as _;
use std::fmt;

const SHA256: &str = "sha-256";
const MULTIHASH_SHA256_CODE: u64 = 0x12;

type Multihash = libp2p::core::multihash::Multihash<64>;

/// A certificate fingerprint that is assumed to be created using the SHA256 hash algorithm.
#[derive(Eq, PartialEq, Copy, Clone)]
pub struct Fingerprint([u8; 32]);

impl Fingerprint {
pub(crate) const FF: Fingerprint = Fingerprint([0xFF; 32]);

#[cfg(test)]
pub fn raw(bytes: [u8; 32]) -> Self {
Self(bytes)
}

/// Creates a fingerprint from a raw certificate.
pub fn from_certificate(bytes: &[u8]) -> Self {
Fingerprint(sha2::Sha256::digest(bytes).into())
}

/// Converts [`Multihash`](multihash::Multihash) to [`Fingerprint`].
pub fn try_from_multihash(hash: Multihash) -> Option<Self> {
if hash.code() != MULTIHASH_SHA256_CODE {
// Only support SHA256 for now.
return None;
}

let bytes = hash.digest().try_into().ok()?;

Some(Self(bytes))
}

/// Converts this fingerprint to [`Multihash`](multihash::Multihash).
pub fn to_multihash(self) -> Multihash {
Multihash::wrap(MULTIHASH_SHA256_CODE, &self.0).expect("fingerprint's len to be 32 bytes")
}

/// Formats this fingerprint as uppercase hex, separated by colons (`:`).
///
/// This is the format described in <https://www.rfc-editor.org/rfc/rfc4572#section-5>.
pub fn to_sdp_format(self) -> String {
self.0.map(|byte| format!("{byte:02X}")).join(":")
}

/// Returns the algorithm used (e.g. "sha-256").
/// See <https://datatracker.ietf.org/doc/html/rfc8122#section-5>
pub fn algorithm(&self) -> String {
SHA256.to_owned()
}
}

impl fmt::Debug for Fingerprint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&hex::encode(self.0))
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn sdp_format() {
let fp = Fingerprint::raw(hex_literal::hex!(
"7DE3D83F81A680592A471E6B6ABB0747ABD35385A8093FDFE112C1EEBB6CC6AC"
));

let sdp_format = fp.to_sdp_format();

assert_eq!(sdp_format, "7D:E3:D8:3F:81:A6:80:59:2A:47:1E:6B:6A:BB:07:47:AB:D3:53:85:A8:09:3F:DF:E1:12:C1:EE:BB:6C:C6:AC")
}
}
23 changes: 20 additions & 3 deletions transports/webtransport/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,38 @@ use futures::{future::BoxFuture, ready, FutureExt, SinkExt, StreamExt};
use h3::{error::ErrorLevel, ext::Protocol};
use libp2p_core::{muxing::StreamMuxerBox, transport::TransportEvent};
use libp2p_identity::PeerId;
use std::{sync::Arc, task::Poll};
use std::{net::SocketAddr, sync::Arc, task::Poll};

use rustls::{Certificate, PrivateKey};

mod fingerprint;

const P2P_ALPN: [u8; 6] = *b"libp2p";

pub struct Transport(
futures::channel::mpsc::Receiver<h3::server::Connection<h3_quinn::Connection, bytes::Bytes>>,
);

impl Transport {
pub fn new() -> Result<Self, Box<dyn std::error::Error>> {
pub fn new(peer_id: PeerId) -> Result<Self, Box<dyn std::error::Error>> {
let cert = Certificate(std::fs::read("server.cert")?);
let fingerprint = fingerprint::Fingerprint::from_certificate(cert.as_ref());
let key = PrivateKey(std::fs::read("server.key")?);

let socket_addr: SocketAddr = "[::1]:4433".parse().unwrap();

let addr = libp2p::core::Multiaddr::empty()
.with(socket_addr.ip().into())
.with(libp2p::core::multiaddr::Protocol::Udp(socket_addr.port()))
.with(libp2p::core::multiaddr::Protocol::QuicV1)
.with(libp2p::core::multiaddr::Protocol::WebTransport)
.with(libp2p::core::multiaddr::Protocol::Certhash(
fingerprint.to_multihash(),
))
.with(libp2p::core::multiaddr::Protocol::P2p(peer_id));

println!("Listening on: {addr:?}");

let mut tls_config = rustls::ServerConfig::builder()
.with_safe_default_cipher_suites()
.with_safe_default_kx_groups()
Expand All @@ -36,7 +53,7 @@ impl Transport {
tls_config.alpn_protocols = alpn;

let server_config = quinn::ServerConfig::with_crypto(Arc::new(tls_config));
let endpoint = quinn::Endpoint::server(server_config, "[::1]:4433".parse().unwrap())?;
let endpoint = quinn::Endpoint::server(server_config, socket_addr)?;

let (sender, receiver) = futures::channel::mpsc::channel(0);

Expand Down
2 changes: 1 addition & 1 deletion wasm-tests/webtransport-tests/echo-server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func addrReporter(ma multiaddr.Multiaddr) {
h.Add("Cross-Origin-Resource-Policy", "cross-origin")
h.Add("Content-Type", "text/plain; charset=utf-8")

fmt.Fprint(w, "/ip6/::1/udp/4433/quic-v1/webtransport/certhash/uEiBXLQJRE5AxMMO35cvj8mstOhnVem8zALKI6uP8URQCng/certhash/uEiCUNmVivYLh1oAejkCyYz2rbw4edcXAs1SNBhdYXAo80w/p2p/12D3KooWQLcKqKE33CbaNGQSQakEW6sAYnVxAMvnZDxTKmFFrmK9")
fmt.Fprint(w, "/ip6/::1/udp/4433/quic-v1/webtransport/certhash/uEiBAOgXcfExykedZKTU4zp3TRdt_qsaOepASE_sE92D1Cw/p2p/12D3KooWN4H4urugWTvubDGpEMH21VZsiZGWXUzLZ3SQUEjfmD1y")

})

Expand Down

0 comments on commit 4badac4

Please sign in to comment.