Skip to content

Commit 41f7d2e

Browse files
kota-yatadjc
authored andcommitted
docs: separate example code from document
separate certificate's examples out of md file into rs files format
1 parent f8165c3 commit 41f7d2e

File tree

10 files changed

+258
-149
lines changed

10 files changed

+258
-149
lines changed

Cargo.lock

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

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[workspace]
2-
members = ["quinn", "quinn-proto", "quinn-udp", "bench", "perf", "fuzz"]
2+
members = ["quinn", "quinn-proto", "quinn-udp", "bench", "perf", "fuzz", "docs/book"]
33
default-members = ["quinn", "quinn-proto", "quinn-udp", "bench", "perf"]
44
resolver = "2"
55

docs/book/Cargo.toml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
[package]
2+
name = "book"
3+
version = "0.1.0"
4+
rust-version.workspace = true
5+
edition.workspace = true
6+
license.workspace = true
7+
repository.workspace = true
8+
keywords.workspace = true
9+
categories.workspace = true
10+
11+
[dependencies]
12+
anyhow.workspace = true
13+
quinn = { version = "0.11.7", path = "../../quinn" }
14+
rcgen.workspace = true
15+
rustls.workspace = true
16+
rustls-pemfile.workspace = true
17+
18+
[[bin]]
19+
name = "certificate-insecure"
20+
path = "src/quinn/certificate-insecure.rs"
21+
22+
[[bin]]
23+
name = "certificate-certsr"
24+
path = "src/quinn/certificate-certs.rs"
25+
26+
[[bin]]
27+
name = "data-transfer"
28+
path = "src/quinn/data-transfer.rs"
29+
30+
[[bin]]
31+
name = "set-up-connection"
32+
path = "src/quinn/set-up-connection.rs"
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
use std::error::Error;
2+
3+
use rustls::{client, pki_types::pem::PemObject};
4+
5+
fn read_certs_from_file() -> Result<
6+
(
7+
Vec<rustls::pki_types::CertificateDer<'static>>,
8+
rustls::pki_types::PrivateKeyDer<'static>,
9+
),
10+
Box<dyn Error>,
11+
> {
12+
let certs = rustls::pki_types::CertificateDer::pem_file_iter("./fullchain.pem")
13+
.unwrap()
14+
.map(|cert| cert.unwrap())
15+
.collect();
16+
let key = rustls::pki_types::PrivateKeyDer::from_pem_file("./privkey.pem").unwrap();
17+
Ok((certs, key))
18+
}
19+
20+
fn generate_self_signed_cert() -> Result<
21+
(
22+
rustls::pki_types::CertificateDer<'static>,
23+
rustls::pki_types::PrivatePkcs8KeyDer<'static>,
24+
),
25+
Box<dyn Error>,
26+
> {
27+
let cert = rcgen::generate_simple_self_signed(vec!["localhost".to_string()])?;
28+
let cert_der = rustls::pki_types::CertificateDer::from(cert.cert);
29+
let key = rustls::pki_types::PrivatePkcs8KeyDer::from(cert.key_pair.serialize_der());
30+
Ok((cert_der, key))
31+
}
32+
33+
fn main() {
34+
let (self_signed_certs, self_signed_key) = generate_self_signed_cert().unwrap();
35+
let (certs, key) = read_certs_from_file().unwrap();
36+
let server_config = quinn::ServerConfig::with_single_cert(certs, key);
37+
let client_config = quinn::ClientConfig::with_platform_verifier();
38+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
use std::sync::Arc;
2+
3+
use quinn::{
4+
ClientConfig,
5+
crypto::rustls::{NoInitialCipherSuite, QuicClientConfig},
6+
};
7+
8+
// Implementation of `ServerCertVerifier` that verifies everything as trustworthy.
9+
#[derive(Debug)]
10+
struct SkipServerVerification(Arc<rustls::crypto::CryptoProvider>);
11+
12+
impl SkipServerVerification {
13+
fn new() -> Arc<Self> {
14+
Arc::new(Self(Arc::new(rustls::crypto::ring::default_provider())))
15+
}
16+
}
17+
18+
impl rustls::client::danger::ServerCertVerifier for SkipServerVerification {
19+
fn verify_server_cert(
20+
&self,
21+
_end_entity: &rustls::pki_types::CertificateDer<'_>,
22+
_intermediates: &[rustls::pki_types::CertificateDer<'_>],
23+
_server_name: &rustls::pki_types::ServerName<'_>,
24+
_ocsp: &[u8],
25+
_now: rustls::pki_types::UnixTime,
26+
) -> Result<rustls::client::danger::ServerCertVerified, rustls::Error> {
27+
Ok(rustls::client::danger::ServerCertVerified::assertion())
28+
}
29+
fn verify_tls12_signature(
30+
&self,
31+
message: &[u8],
32+
cert: &rustls::pki_types::CertificateDer<'_>,
33+
dss: &rustls::DigitallySignedStruct,
34+
) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
35+
rustls::crypto::verify_tls12_signature(
36+
message,
37+
cert,
38+
dss,
39+
&self.0.signature_verification_algorithms,
40+
)
41+
}
42+
43+
fn verify_tls13_signature(
44+
&self,
45+
message: &[u8],
46+
cert: &rustls::pki_types::CertificateDer<'_>,
47+
dss: &rustls::DigitallySignedStruct,
48+
) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
49+
rustls::crypto::verify_tls13_signature(
50+
message,
51+
cert,
52+
dss,
53+
&self.0.signature_verification_algorithms,
54+
)
55+
}
56+
57+
fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
58+
self.0.signature_verification_algorithms.supported_schemes()
59+
}
60+
}
61+
62+
fn configure_client() -> Result<ClientConfig, NoInitialCipherSuite> {
63+
let crypto = rustls::ClientConfig::builder()
64+
.dangerous()
65+
.with_custom_certificate_verifier(SkipServerVerification::new())
66+
.with_no_client_auth();
67+
68+
Ok(ClientConfig::new(Arc::new(QuicClientConfig::try_from(
69+
crypto,
70+
)?)))
71+
}
72+
73+
fn main() {
74+
let client_config = configure_client().unwrap();
75+
}

docs/book/src/quinn/certificate.md

Lines changed: 6 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -19,41 +19,13 @@ rustls = { version = "*", features = ["dangerous_configuration", "quic"] }
1919
Then, allow the client to skip the certificate validation by implementing [ServerCertVerifier][ServerCertVerifier] and letting it assert verification for any server.
2020

2121
```rust
22-
// Implementation of `ServerCertVerifier` that verifies everything as trustworthy.
23-
struct SkipServerVerification;
24-
25-
impl SkipServerVerification {
26-
fn new() -> Arc<Self> {
27-
Arc::new(Self)
28-
}
29-
}
30-
31-
impl rustls::client::ServerCertVerifier for SkipServerVerification {
32-
fn verify_server_cert(
33-
&self,
34-
_end_entity: &rustls::Certificate,
35-
_intermediates: &[rustls::Certificate],
36-
_server_name: &rustls::ServerName,
37-
_scts: &mut dyn Iterator<Item = &[u8]>,
38-
_ocsp_response: &[u8],
39-
_now: std::time::SystemTime,
40-
) -> Result<rustls::client::ServerCertVerified, rustls::Error> {
41-
Ok(rustls::client::ServerCertVerified::assertion())
42-
}
43-
}
22+
{{#include certificate-insecure.rs:5:57}}
4423
```
4524

4625
After that, modify the [ClientConfig][ClientConfig] to use this [ServerCertVerifier][ServerCertVerifier] implementation.
4726

4827
```rust
49-
fn configure_client() -> ClientConfig {
50-
let crypto = rustls::ClientConfig::builder()
51-
.with_safe_defaults()
52-
.with_custom_certificate_verifier(SkipServerVerification::new())
53-
.with_no_client_auth();
54-
55-
ClientConfig::new(Arc::new(crypto))
56-
}
28+
{{#include certificate-insecure.rs:59:66}}
5729
```
5830

5931
Finally, if you plug this [ClientConfig][ClientConfig] into the [Endpoint::set_default_client_config()][set_default_client_config] your client endpoint should verify all connections as trustworthy.
@@ -73,12 +45,7 @@ This example uses [rcgen][4] to generate a certificate.
7345
Let's look at an example:
7446

7547
```rust
76-
fn generate_self_signed_cert() -> Result<(rustls::Certificate, rustls::PrivateKey), Box<dyn Error>>
77-
{
78-
let cert = rcgen::generate_simple_self_signed(vec!["localhost".to_string()])?;
79-
let key = rustls::PrivateKey(cert.serialize_private_key_der());
80-
Ok((rustls::Certificate(cert.serialize_der()?), key))
81-
}
48+
{{#include certificate-certs.rs:14:19}}
8249
```
8350

8451
*Note that [generate_simple_self_signed][generate_simple_self_signed] returns a [Certificate][2] that can be serialized to both `.der` and `.pem` formats.*
@@ -101,27 +68,7 @@ certbot asks for the required data and writes the certificates to `fullchain.pem
10168
These files can then be referenced in code.
10269

10370
```rust
104-
use std::{error::Error, fs::File, io::BufReader};
105-
106-
pub fn read_certs_from_file(
107-
) -> Result<(Vec<rustls::Certificate>, rustls::PrivateKey), Box<dyn Error>> {
108-
let mut cert_chain_reader = BufReader::new(File::open("./fullchain.pem")?);
109-
let certs = rustls_pemfile::certs(&mut cert_chain_reader)?
110-
.into_iter()
111-
.map(rustls::Certificate)
112-
.collect();
113-
114-
let mut key_reader = BufReader::new(File::open("./privkey.pem")?);
115-
// if the file starts with "BEGIN RSA PRIVATE KEY"
116-
// let mut keys = rustls_pemfile::rsa_private_keys(&mut key_reader)?;
117-
// if the file starts with "BEGIN PRIVATE KEY"
118-
let mut keys = rustls_pemfile::pkcs8_private_keys(&mut key_reader)?;
119-
120-
assert_eq!(keys.len(), 1);
121-
let key = rustls::PrivateKey(keys.remove(0));
122-
123-
Ok((certs, key))
124-
}
71+
{{#include certificate-certs.rs:5:12}}
12572
```
12673

12774
### Configuring Certificates
@@ -132,15 +79,15 @@ After configuring plug the configuration into the `Endpoint`.
13279
**Configure Server**
13380

13481
```rust
135-
let server_config = ServerConfig::with_single_cert(certs, key)?;
82+
{{#include certificate-certs.rs:24}}
13683
```
13784

13885
This is the only thing you need to do for your server to be secured.
13986

14087
**Configure Client**
14188

14289
```rust
143-
let client_config = ClientConfig::with_native_roots();
90+
{{#include certificate-certs.rs:25}}
14491
```
14592

14693
This is the only thing you need to do for your client to trust a server certificate signed by a conventional certificate authority.

docs/book/src/quinn/data-transfer.md

Lines changed: 6 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -34,34 +34,13 @@ For example, from the connection initiator to the peer and the other way around.
3434
*open bidirectional stream*
3535

3636
```rust
37-
async fn open_bidirectional_stream(connection: Connection) -> anyhow::Result<()> {
38-
let (mut send, recv) = connection
39-
.open_bi()
40-
.await?;
41-
42-
send.write_all(b"test").await?;
43-
send.finish().await?;
44-
45-
let received = recv.read_to_end(10).await?;
46-
47-
Ok(())
48-
}
37+
{{#include data-transfer.rs:7:13}}
4938
```
5039

5140
*iterate incoming bidirectional stream(s)*
5241

5342
```rust
54-
async fn receive_bidirectional_stream(connection: Connection) -> anyhow::Result<()> {
55-
while let Ok((mut send, recv)) = connection.accept_bi().await {
56-
// Because it is a bidirectional stream, we can both send and receive.
57-
println!("request: {:?}", recv.read_to_end(50).await?);
58-
59-
send.write_all(b"response").await?;
60-
send.finish().await?;
61-
}
62-
63-
Ok(())
64-
}
43+
{{#include data-transfer.rs:15:23}}
6544
```
6645

6746
## Unidirectional Streams
@@ -72,29 +51,13 @@ It is possible to get reliability without ordering (so no head-of-line blocking)
7251
*open unidirectional stream*
7352

7453
```rust
75-
async fn open_unidirectional_stream(connection: Connection)-> anyhow::Result<()> {
76-
let mut send = connection
77-
.open_uni()
78-
.await?;
79-
80-
send.write_all(b"test").await?;
81-
send.finish().await?;
82-
83-
Ok(())
84-
}
54+
{{#include data-transfer.rs:25:30}}
8555
```
8656

8757
*iterating incoming unidirectional stream(s)*
8858

8959
```rust
90-
async fn receive_unidirectional_stream(connection: Connection) -> anyhow::Result<()> {
91-
while let Ok(recv) = connection.accept_uni().await {
92-
// Because it is a unidirectional stream, we can only receive not send back.
93-
println!("{:?}", recv.read_to_end(50).await?);
94-
}
95-
96-
Ok(())
97-
}
60+
{{#include data-transfer.rs:32:38}}
9861
```
9962

10063
## Unreliable Messaging
@@ -105,26 +68,13 @@ This could be useful if data arrival isn't essential or when high throughput is
10568
*send datagram*
10669

10770
```rust
108-
async fn send_unreliable(connection: Connection)-> anyhow::Result<()> {
109-
connection
110-
.send_datagram(b"test".into())
111-
.await?;
112-
113-
Ok(())
114-
}
71+
{{#include data-transfer.rs:40:43}}
11572
```
11673

11774
*iterating datagram stream(s)*
11875

11976
```rust
120-
async fn receive_datagram(connection: Connection) -> anyhow::Result<()> {
121-
while let Ok(received_bytes) = connection.read_datagram().await {
122-
// Because it is a unidirectional stream, we can only receive not send back.
123-
println!("request: {:?}", received);
124-
}
125-
126-
Ok(())
127-
}
77+
{{#include data-transfer.rs:45:51}}
12878
```
12979

13080
[Endpoint]: https://docs.rs/quinn/latest/quinn/struct.Endpoint.html

0 commit comments

Comments
 (0)