rustls/crypto/mod.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
use crate::sign::SigningKey;
use crate::suites;
use crate::{Error, NamedGroup};
use alloc::boxed::Box;
use alloc::sync::Arc;
use alloc::vec::Vec;
use core::fmt::Debug;
use pki_types::PrivateKeyDer;
use zeroize::Zeroize;
#[cfg(all(doc, feature = "tls12"))]
use crate::Tls12CipherSuite;
#[cfg(doc)]
use crate::{
client, crypto, server, sign, ClientConfig, ConfigBuilder, ServerConfig, SupportedCipherSuite,
Tls13CipherSuite,
};
pub use crate::webpki::{
verify_tls12_signature, verify_tls13_signature, WebPkiSupportedAlgorithms,
};
/// *ring* based CryptoProvider.
#[cfg(feature = "ring")]
pub mod ring;
/// aws-lc-rs-based CryptoProvider.
#[cfg(feature = "aws_lc_rs")]
pub mod aws_lc_rs;
/// TLS message encryption/decryption interfaces.
pub mod cipher;
/// Hashing interfaces.
pub mod hash;
/// HMAC interfaces.
pub mod hmac;
/// Cryptography specific to TLS1.2.
pub mod tls12;
/// Cryptography specific to TLS1.3.
pub mod tls13;
/// Hybrid public key encryption (RFC 9180).
#[doc(hidden)]
pub mod hpke;
// Message signing interfaces. Re-exported under rustls::sign. Kept crate-internal here to
// avoid having two import paths to the same types.
pub(crate) mod signer;
pub use crate::rand::GetRandomFailed;
pub use crate::suites::CipherSuiteCommon;
pub use crate::msgs::handshake::KeyExchangeAlgorithm;
/// Controls core cryptography used by rustls.
///
/// This crate comes with two built-in options, provided as
/// `CryptoProvider` structures:
///
/// - [`crypto::ring::default_provider`]: (behind the `ring` crate feature, which
/// is enabled by default). This provider uses the [*ring*](https://github.com/briansmith/ring)
/// crate.
/// - [`crypto::aws_lc_rs::default_provider`]: (behind the `aws_lc_rs` feature,
/// which is optional). This provider uses the [aws-lc-rs](https://github.com/aws/aws-lc-rs)
/// crate.
///
/// This structure provides defaults. Everything in it can be overridden at
/// runtime by replacing field values as needed.
///
/// # Using a specific `CryptoProvider`
///
/// Supply the provider when constructing your [`ClientConfig`] or [`ServerConfig`]:
///
/// - [`ClientConfig::builder_with_provider()`]
/// - [`ServerConfig::builder_with_provider()`]
///
/// When creating and configuring a webpki-backed client or server certificate verifier, a choice of
/// provider is also needed to start the configuration process:
///
/// - [`client::WebPkiServerVerifier::builder_with_provider()`]
/// - [`server::WebPkiClientVerifier::builder_with_provider()`]
///
/// # Making a custom `CryptoProvider`
///
/// Your goal will be to populate a [`crypto::CryptoProvider`] struct instance.
///
/// ## Which elements are required?
///
/// There is no requirement that the individual elements (`SupportedCipherSuite`, `SupportedKxGroup`,
/// `SigningKey`, etc.) come from the same crate. It is allowed and expected that uninteresting
/// elements would be delegated back to one of the default providers (statically) or a parent
/// provider (dynamically).
///
/// For example, if we want to make a provider that just overrides key loading in the config builder
/// API ([`ConfigBuilder::with_single_cert`] etc.), it might look like this:
///
/// ```
/// # #[cfg(feature = "ring")] {
/// # use std::sync::Arc;
/// # mod fictious_hsm_api { pub fn load_private_key(key_der: pki_types::PrivateKeyDer<'static>) -> ! { unreachable!(); } }
/// use rustls::crypto::ring;
///
/// pub fn provider() -> rustls::crypto::CryptoProvider {
/// rustls::crypto::CryptoProvider{
/// key_provider: &HsmKeyLoader,
/// ..ring::default_provider()
/// }
/// }
///
/// #[derive(Debug)]
/// struct HsmKeyLoader;
///
/// impl rustls::crypto::KeyProvider for HsmKeyLoader {
/// fn load_private_key(&self, key_der: pki_types::PrivateKeyDer<'static>) -> Result<Arc<dyn rustls::sign::SigningKey>, rustls::Error> {
/// fictious_hsm_api::load_private_key(key_der)
/// }
/// }
/// # }
/// ```
///
/// ## References to the individual elements
///
/// The elements are documented separately:
///
/// - **Random** - see [`crypto::SecureRandom::fill()`].
/// - **Cipher suites** - see [`SupportedCipherSuite`], [`Tls12CipherSuite`], and
/// [`Tls13CipherSuite`].
/// - **Key exchange groups** - see [`crypto::SupportedKxGroup`].
/// - **Signature verification algorithms** - see [`crypto::WebPkiSupportedAlgorithms`].
/// - **Authentication key loading** - see [`crypto::KeyProvider::load_private_key()`] and
/// [`sign::SigningKey`].
///
/// # Example code
///
/// See [provider-example/] for a full client and server example that uses
/// cryptography from the [rust-crypto] and [dalek-cryptography] projects.
///
/// ```shell
/// $ cargo run --example client | head -3
/// Current ciphersuite: TLS13_CHACHA20_POLY1305_SHA256
/// HTTP/1.1 200 OK
/// Content-Type: text/html; charset=utf-8
/// Content-Length: 19899
/// ```
///
/// [provider-example/]: https://github.com/rustls/rustls/tree/main/provider-example/
/// [rust-crypto]: https://github.com/rustcrypto
/// [dalek-cryptography]: https://github.com/dalek-cryptography
#[derive(Debug, Clone)]
pub struct CryptoProvider {
/// List of supported ciphersuites, in preference order -- the first element
/// is the highest priority.
///
/// The `SupportedCipherSuite` type carries both configuration and implementation.
pub cipher_suites: Vec<suites::SupportedCipherSuite>,
/// List of supported key exchange groups, in preference order -- the
/// first element is the highest priority.
///
/// The first element in this list is the _default key share algorithm_,
/// and in TLS1.3 a key share for it is sent in the client hello.
///
/// The `SupportedKxGroup` type carries both configuration and implementation.
pub kx_groups: Vec<&'static dyn SupportedKxGroup>,
/// List of signature verification algorithms for use with webpki.
///
/// These are used for both certificate chain verification and handshake signature verification.
///
/// This is called by [`ConfigBuilder::with_root_certificates()`],
/// [`server::WebPkiClientVerifier::builder_with_provider()`] and
/// [`client::WebPkiServerVerifier::builder_with_provider()`].
pub signature_verification_algorithms: WebPkiSupportedAlgorithms,
/// Source of cryptographically secure random numbers.
pub secure_random: &'static dyn SecureRandom,
/// Provider for loading private [SigningKey]s from [PrivateKeyDer].
pub key_provider: &'static dyn KeyProvider,
}
/// A source of cryptographically secure randomness.
pub trait SecureRandom: Send + Sync + Debug {
/// Fill the given buffer with random bytes.
///
/// The bytes must be sourced from a cryptographically secure random number
/// generator seeded with good quality, secret entropy.
///
/// This is used for all randomness required by rustls, but not necessarily
/// randomness required by the underlying cryptography library. For example:
/// [`SupportedKxGroup::start()`] requires random material to generate
/// an ephemeral key exchange key, but this is not included in the interface with
/// rustls: it is assumed that the cryptography library provides for this itself.
fn fill(&self, buf: &mut [u8]) -> Result<(), GetRandomFailed>;
}
/// A mechanism for loading private [SigningKey]s from [PrivateKeyDer].
pub trait KeyProvider: Send + Sync + Debug {
/// Decode and validate a private signing key from `key_der`.
///
/// This is used by [`ConfigBuilder::with_client_auth_cert()`], [`ConfigBuilder::with_single_cert()`],
/// and [`ConfigBuilder::with_single_cert_with_ocsp()`]. The key types and formats supported by this
/// function directly defines the key types and formats supported in those APIs.
///
/// Return an error if the key type encoding is not supported, or if the key fails validation.
fn load_private_key(
&self,
key_der: PrivateKeyDer<'static>,
) -> Result<Arc<dyn SigningKey>, Error>;
}
/// A supported key exchange group.
///
/// This type carries both configuration and implementation. Specifically,
/// it has a TLS-level name expressed using the [`NamedGroup`] enum, and
/// a function which produces a [`ActiveKeyExchange`].
///
/// Compare with [`NamedGroup`], which carries solely a protocol identifier.
pub trait SupportedKxGroup: Send + Sync + Debug {
/// Start a key exchange.
///
/// This will prepare an ephemeral secret key in the supported group, and a corresponding
/// public key. The key exchange can be completed by calling [ActiveKeyExchange#complete]
/// or discarded.
///
/// # Errors
///
/// This can fail if the random source fails during ephemeral key generation.
fn start(&self) -> Result<Box<dyn ActiveKeyExchange>, Error>;
/// Named group the SupportedKxGroup operates in.
///
/// If the `NamedGroup` enum does not have a name for the algorithm you are implementing,
/// you can use [`NamedGroup::Unknown`].
fn name(&self) -> NamedGroup;
}
/// An in-progress key exchange originating from a [`SupportedKxGroup`].
pub trait ActiveKeyExchange: Send + Sync {
/// Completes the key exchange, given the peer's public key.
///
/// This method must return an error if `peer_pub_key` is invalid: either
/// mis-encoded, or an invalid public key (such as, but not limited to, being
/// in a small order subgroup).
///
/// The shared secret is returned as a [`SharedSecret`] which can be constructed
/// from a `&[u8]`.
///
/// This consumes and so terminates the [`ActiveKeyExchange`].
fn complete(self: Box<Self>, peer_pub_key: &[u8]) -> Result<SharedSecret, Error>;
/// Return the public key being used.
///
/// The encoding required is defined in
/// [RFC8446 section 4.2.8.2](https://www.rfc-editor.org/rfc/rfc8446#section-4.2.8.2).
fn pub_key(&self) -> &[u8];
/// Return the group being used.
fn group(&self) -> NamedGroup;
}
/// The result from [`ActiveKeyExchange::complete`].
pub struct SharedSecret(Vec<u8>);
impl SharedSecret {
/// Returns the shared secret as a slice of bytes.
pub fn secret_bytes(&self) -> &[u8] {
&self.0
}
}
impl Drop for SharedSecret {
fn drop(&mut self) {
self.0.zeroize();
}
}
impl From<&[u8]> for SharedSecret {
fn from(source: &[u8]) -> Self {
Self(source.to_vec())
}
}