| 1 | /*! # Customising private key usage |
| 2 | |
| 3 | By default rustls supports PKCS#8-format[^1] RSA or ECDSA keys, plus PKCS#1-format RSA keys. |
| 4 | |
| 5 | However, if your private key resides in a HSM, or in another process, or perhaps |
| 6 | another machine, rustls has some extension points to support this: |
| 7 | |
| 8 | The main trait you must implement is [`sign::SigningKey`][signing_key]. The primary method here |
| 9 | is [`choose_scheme()`][choose_scheme] where you are given a set of [`SignatureScheme`s][sig_scheme] the client says |
| 10 | it supports: you must choose one (or return `None` -- this aborts the handshake). Having |
| 11 | done that, you return an implementation of the [`sign::Signer`][signer] trait. |
| 12 | The [`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 |
| 15 | PKCS#11 provider, Microsoft CryptoAPI, etc. so is blocking rather than asynchronous. |
| 16 | It's a TODO to make these and other extension points async.) |
| 17 | |
| 18 | Once you have these two pieces, configuring a server to use them involves, briefly: |
| 19 | |
| 20 | - packaging your [`sign::SigningKey`][signing_key] with the matching certificate chain into a [`sign::CertifiedKey`][certified_key] |
| 21 | - making a [`ResolvesServerCertUsingSni`][cert_using_sni] and feeding in your [`sign::CertifiedKey`][certified_key] for all SNI hostnames you want to use it for, |
| 22 | - setting that as your `ServerConfig`'s [`cert_resolver`][cert_resolver] |
| 23 | |
| 24 | For a complete example of implementing a custom [`sign::SigningKey`][signing_key] and |
| 25 | [`sign::Signer`][signer] see the [`signer` module in the `rustls-cng` crate][rustls-cng-signer]. |
| 26 | |
| 27 | [signing_key]: crate::crypto::signer::SigningKey |
| 28 | [choose_scheme]: crate::crypto::signer::SigningKey::choose_scheme |
| 29 | [sig_scheme]: crate::SignatureScheme |
| 30 | [signer]: crate::crypto::signer::Signer |
| 31 | [sign_method]: crate::crypto::signer::Signer::sign |
| 32 | [certified_key]: crate::crypto::signer::CertifiedKey |
| 33 | [cert_using_sni]: crate::server::ResolvesServerCertUsingSni |
| 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 | |
| 42 | TLS has a `close_notify` mechanism to prevent truncation attacks[^2]. |
| 43 | According to the TLS RFCs, each party is required to send a `close_notify` message before |
| 44 | closing the write side of the connection. However, some implementations don't send it. |
| 45 | So long as the application layer protocol (for instance HTTP/2) has message length framing |
| 46 | and can reject truncated messages, this is not a security problem. |
| 47 | |
| 48 | Rustls treats an EOF without `close_notify` as an error of type `std::io::Error` with |
| 49 | `ErrorKind::UnexpectedEof`. In some situations it's appropriate for the application to handle |
| 50 | this error the same way it would handle a normal EOF (a read returning `Ok(0)`). In particular |
| 51 | if `UnexpectedEof` occurs on an idle connection it is appropriate to treat it the same way as a |
| 52 | clean shutdown. And if an application always uses messages with length framing (in other words, |
| 53 | messages are never delimited by the close of the TCP connection), it can unconditionally |
| 54 | ignore `UnexpectedEof` errors from rustls. |
| 55 | |
| 56 | [^2]: <https://datatracker.ietf.org/doc/html/rfc8446#section-6.1> |
| 57 | */ |
| 58 | |