rustls/manual/howto.rs
1/*! # Customising private key usage
2
3By default rustls supports PKCS#8-format[^1] RSA or ECDSA keys, plus PKCS#1-format RSA keys.
4
5However, if your private key resides in a HSM, or in another process, or perhaps
6another machine, rustls has some extension points to support this:
7
8The main trait you must implement is [`SigningKey`][signing_key]. The primary method here
9is [`choose_scheme()`][choose_scheme] where you are given a set of [`SignatureScheme`s][sig_scheme] the client says
10it supports: you must choose one (or return `None` -- this aborts the handshake). Having
11done that, you return an implementation of the [`Signer`][signer] trait.
12The [`sign()`][sign_method] performs the signature and returns it.
13
14(Unfortunately this is currently designed for keys with low latency access, like in a
15PKCS#11 provider, Microsoft CryptoAPI, etc. so is blocking rather than asynchronous.
16It's a TODO to make these and other extension points async.)
17
18Once you have these two pieces, configuring a server to use them involves, briefly:
19
20- packaging your [`SigningKey`][signing_key] with the matching certificate chain into a [`Credentials`][credentials]
21- making a [`ServerNameResolver`][cert_using_sni] and feeding in your [`Credentials`][credentials] for all SNI hostnames you want to use it for,
22- setting that as your `ServerConfig`'s [`cert_resolver`][cert_resolver]
23
24For a complete example of implementing a custom [`SigningKey`][signing_key] and
25[`Signer`][signer] see the [`signer` module in the `rustls-cng` crate][rustls-cng-signer].
26
27[signing_key]: crate::crypto::SigningKey
28[choose_scheme]: crate::crypto::SigningKey::choose_scheme
29[sig_scheme]: crate::crypto::SignatureScheme
30[signer]: crate::crypto::Signer
31[sign_method]: crate::crypto::Signer::sign
32[credentials]: crate::crypto::Credentials
33[cert_using_sni]: crate::server::ServerNameResolver
34[cert_resolver]: crate::ServerConfig::cert_resolver
35[rustls-cng-signer]: https://github.com/rustls/rustls-cng/blob/dev/src/signer.rs
36
37[^1]: For PKCS#8 it does not support password encryption -- there's not a meaningful threat
38 model addressed by this, and the encryption supported is typically extremely poor.
39
40# Unexpected EOF
41
42TLS has a `close_notify` mechanism to prevent truncation attacks[^2].
43According to the TLS RFCs, each party is required to send a `close_notify` message before
44closing the write side of the connection. However, some implementations don't send it.
45So long as the application layer protocol (for instance HTTP/2) has message length framing
46and can reject truncated messages, this is not a security problem.
47
48When an EOF is received from the network using `TlsInputBuffer::read()`, rustls sets an
49`has_seen_eof()` flag on that input buffer. If the `MessageHandler::state()` does not have
50`peer_has_closed()` yielding `true` and the read side of the connection has seen an EOF, an
51`UnexpectedEof` error should be raised unless the application layer protocol knows for sure
52that no message is in flight. This could be the case if the connection has been idle or
53if application messages are framed with their length.
54
55[^2]: <https://datatracker.ietf.org/doc/html/rfc9846#section-6.1>
56
57# Debugging
58
59If you encounter a bug with Rustls it can be helpful to collect up as much diagnostic
60information as possible.
61
62## Collecting logs
63
64If your bug reproduces with one of the [Rustls examples] you can use the
65[`RUST_LOG`] environment variable to increase the log verbosity. If you're using
66your own application, you may need to configure it with a tracing backend
67such as those available from [`tracing-subscriber`].
68
69Consider reproducing your bug with `RUST_LOG=rustls=trace` and sharing the result
70in a [GitHub gist].
71
72[Rustls examples]: https://github.com/rustls/rustls/tree/main/examples
73[`RUST_LOG`]: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html
74[`tracing-subscriber`]: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/
75[GitHub gist]: https://docs.github.com/en/get-started/writing-on-github/editing-and-sharing-content-with-gists/creating-gists
76
77## Taking a packet capture
78
79When logs aren't enough taking a packet capture ("pcap") is another helpful tool.
80The details of how to accomplish this vary by operating system/context.
81
82### tcpdump
83
84As one example, on Linux using [`tcpdump`] is often easiest.
85
86If you know the IP address of the remote server your bug demonstrates with you
87could take a short packet capture with this command (after replacing
88`XX.XX.XX.XX` with the correct IP address):
89
90```bash
91sudo tcpdump -i any tcp and dst host XX.XX.XX.XX -C5 -w rustls.pcap
92```
93
94The `-i any` captures on any network interface. The `tcp and dst host XX.XX.XX.XX`
95portion target the capture to TCP traffic to the specified IP address. The `-C5`
96argument limits the capture to at most 5MB. Lastly the `-w` argument writes the
97capture to `rustls.pcap`.
98
99Another approach is to use `tcp and port XXXX` instead of `tcp and dst host XX.XX.XX.XX`
100to capture all traffic to a specific port instead of a specific host server.
101
102[`tcpdump`]: https://web.archive.org/web/www.redhat.com/en/blog/introduction-using-tcpdump-linux-command-line
103
104### SSLKEYLOGFILE
105
106If the bug you are reporting happens after data is encrypted you may also wish to
107share the secret keys required to decrypt the post-handshake traffic.
108
109If you're using one of the [Rustls examples] you can set the `SSLKEYLOGFILE` environment
110variable to a path where secrets will be written. E.g. `SSLKEYLOGFILE=rustls.pcap.keys`.
111
112If you're using your own application you may need to customize the Rustls `ClientConfig`
113or `ServerConfig`'s `key_log` setting like the example applications do.
114
115With the file from `SSLKEYLOGFILE` it is possible to use [Wireshark] or another tool to
116decrypt the post-handshake messages, following [these instructions][curl-sslkeylogfile].
117
118Remember this allows plaintext decryption and should only be done in testing contexts
119where no sensitive data (API keys, etc) are being shared.
120
121[Wireshark]: https://www.wireshark.org/download.html
122[curl-sslkeylogfile]: https://everything.curl.dev/usingcurl/tls/sslkeylogfile.html
123*/