aws_kms_tls_auth/lib.rs
1#![allow(dead_code)]
2// allow dead code for piece-wise commits
3
4// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
5// SPDX-License-Identifier: Apache-2.0
6
7//! The KMS TLS PSK Provider provides a way to get a mutually authenticated TLS
8//! connection using IAM credentials, KMS, and the external PSK feature of TLS 1.3.
9//!
10//! The client must have IAM credentials that allow `generate-datakey` API calls
11//! for some KMS Key.
12//!
13//! The server must have IAM credentials that allow `decrypt` calls.
14//!
15//! ## Generate Data Key
16//! The client first calls generate data key. The plaintext datakey is used as the
17//! PSK secret, and is the input for [`s2n_tls::psk::Builder::set_secret`]. The
18//! ciphertext datakey is set as the PSK identity (sort of, see PSK Identity section).
19//!
20//! ## Decrypt
21//! The client then connects to the server, sending the PSK as part of its client
22//! hello. The server then retrieves the PSK identity (ciphertext datakey) from the
23//! client hello and calls the KMS decrypt API to retrieve the plaintext datakey.
24//!
25//! At this point it can construct the same PSK that the client used, so the handshake
26//! is able to continue and complete successfully.
27//!
28//! ## Caching
29//! The server component [`PskReceiver`] will cache successfully decrypted ciphertexts.
30//! This means that the first handshake from a new client will result in a network
31//! call to KMS, but future handshakes from that client will be able to retrieve
32//! the plaintext datakey from memory.
33//!
34//! Note that this cache is bounded to a size of [`MAXIMUM_KEY_CACHE_SIZE`].
35//!
36//! ## Rotation
37//! The client component [`PskProvider`] will automatically rotate the PSK. This
38//! is controlled by the [`KEY_ROTATION_PERIOD`] which is currently 24 hours.
39//!
40//! ## PSK Identity
41//! The ciphertext datakey is not directly used as the PSK identity. Because PSK
42//! identities can be observed on the wire, the ciphertext is first encrypted using
43//! the obfuscation key. This prevents any possible data leakage of ciphertext details.
44//!
45//! ## Deployment Concerns
46//! The obfuscation key that the [`PskProvider`] is configured with must also
47//! be supplied to the [`PskReceiver`]. Otherwise handshakes will fail.
48//!
49//! The KMS Key ARN that the [`PskProvider`] is configured with must be supplied
50//! to the [`PskReceiver`]. Otherwise handshakes will fail.
51//!
52//! Note that the [`PskReceiver`] supports lists for both of these items, so
53//! zero-downtime migrations are possible. _Example_: if the client fleet wanted
54//! to switch from Key A to Key B it would go through the following stages
55//! 1. client -> [A], server -> [A]
56//! 2. client -> [A], server -> [A, B]
57//! 3. client -> [A, B], server -> [A, B]
58//! 4. client -> [B], server -> [A, B]
59//! 5. client -> [B], server -> [B]
60//!
61//! ## Versioning
62//!
63//! [`PskVersion`] changes are backwards compatible, but not necessarily forwards
64//! compatible.
65//!
66//! > Note that crate versions and formats below are an example only. There are no
67//! > PskVersion changes currently planned. When a new PskVersion is made available
68//! > it will be communicated by marking the old PskVersion as `#[deprecated]`.
69//!
70//! Example:
71//! - `PskVersion::V1`: available in `0.0.1`
72//! - `PskVersion::V2`: available in `0.0.2`
73//!
74//! A [`PskReceiver`] will support all available `PskVersion`s, and does not have
75//! an explicitly configured version. The `PskReceiver` from `0.0.2` will be able
76//! to handshake with V1 and V2 configured clients. The `PskReceiver` from `0.0.1`
77//! will only be able to handshake V1 configured clients.
78//!
79//! A [`PskProvider`] has an explicitly configured `PskVersion`. The `PskProvider`
80//! from `0.0.2` can be configured to send `PskVersion::V1` xor `PskVersion::V2`.
81//! The `PskProvider` from `0.0.1` can only be configured with `PskVersion::V1`.
82//!
83//! Consider a fleet of clients and server that is currently using `PskVersion::V1`
84//! with crate version `0.0.1`. Upgrading to `PskVersion::V2` would require the
85//! following steps:
86//!
87//! 1. Deploy `0.0.2` across all clients and server. This will allow all `PskReceiver`s
88//! to understand both `PskVersion::V1` and `PskVersion::V2`.
89//! 2. Enable `PskVersion::V2` on the `PskProvider` through the `psk_version`
90//! argument in [`PskProvider::initialize`]. Because all of the servers understand
91//! both V1 and V2 formats this can be deployed without any downtime.
92//!
93//! Note that these steps MUST NOT overlap. A `0.0.1` `PskReceiver` will fail to
94//! handshake with a `PskProvider` configured to send `PskVersion::V2`.
95
96mod codec;
97mod identity;
98mod prefixed_list;
99mod provider;
100mod psk_parser;
101mod receiver;
102#[cfg(test)]
103pub(crate) mod test_utils;
104
105use s2n_tls::error::Error as S2NError;
106use std::time::Duration;
107
108pub type KeyArn = String;
109pub use identity::{ObfuscationKey, PskVersion};
110pub use provider::PskProvider;
111pub use receiver::PskReceiver;
112
113// We have "pub" use statement so these can be fuzz tested
114pub use codec::DecodeValue;
115pub use psk_parser::PresharedKeyClientHello;
116
117const MAXIMUM_KEY_CACHE_SIZE: usize = 100_000;
118const PSK_SIZE: usize = 32;
119const AES_256_GCM_SIV_KEY_LEN: usize = 32;
120const AES_256_GCM_SIV_NONCE_LEN: usize = 12;
121/// The key is automatically rotated every period. Currently 24 hours.
122const KEY_ROTATION_PERIOD: Duration = Duration::from_secs(3_600 * 24);
123/// The maximum allowed age of a PSK identity.
124///
125/// PSK identities include their creation time. The server will reject the PSK
126/// identity and fail the handshake if the PSK identity is older than this value.
127const PSK_IDENTITY_VALIDITY: Duration = Duration::from_secs(60);
128
129fn psk_from_material(identity: &[u8], secret: &[u8]) -> Result<s2n_tls::psk::Psk, S2NError> {
130 let mut psk = s2n_tls::psk::Psk::builder()?;
131 psk.set_hmac(s2n_tls::enums::PskHmac::SHA384)?;
132 psk.set_identity(identity)?;
133 psk.set_secret(secret)?;
134 psk.build()
135}
136
137#[cfg(test)]
138mod tests {
139 use crate::{AES_256_GCM_SIV_KEY_LEN, AES_256_GCM_SIV_NONCE_LEN};
140 use aws_lc_rs::aead::AES_256_GCM_SIV;
141
142 /// `key_len()` and `nonce_len()` aren't const functions, so we define
143 /// our own constants to let us use those values in things like array sizes.
144 #[test]
145 fn constant_check() {
146 assert_eq!(AES_256_GCM_SIV_KEY_LEN, AES_256_GCM_SIV.key_len());
147 assert_eq!(AES_256_GCM_SIV_NONCE_LEN, AES_256_GCM_SIV.nonce_len());
148 }
149}