Skip to content

Commit

Permalink
feat(s2n-quic): provider-crypto-fips feature flag (#2194)
Browse files Browse the repository at this point in the history
  • Loading branch information
toidiu authored May 9, 2024
1 parent c5ba081 commit 286adde
Show file tree
Hide file tree
Showing 30 changed files with 359 additions and 126 deletions.
19 changes: 19 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,25 @@ jobs:
run: |
${{ matrix.target != 'native' && 'cross' || 'cargo' }} test --workspace ${{ matrix.exclude }} ${{ matrix.target != 'native' && format('--target {0}', matrix.target) || '' }} ${{ matrix.args }}
fips:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true

- name: Install rust stable toolchain
id: stable-toolchain
run: |
rustup toolchain install stable
rustup override set stable
- uses: camshaft/rust-cache@v1

- name: Run test
run: |
cargo test --features provider-tls-fips
miri:
# miri needs quite a bit of memory so use a larger instance
runs-on:
Expand Down
26 changes: 13 additions & 13 deletions quic/s2n-quic-core/src/crypto/application/keyset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ impl<K: OneRttKey> KeySet<K> {

let key = &mut self.crypto[phase_to_use.into()];

let result = packet.decrypt(key.key());
let result = packet.decrypt(key.key_mut());

key.on_packet_decryption(&self.limits);

Expand Down Expand Up @@ -229,7 +229,7 @@ impl<K: OneRttKey> KeySet<K> {
where
F: FnOnce(
EncoderBuffer<'a>,
&K,
&mut K,
KeyPhase,
)
-> Result<(ProtectedPayload<'a>, EncoderBuffer<'a>), PacketEncodingError<'a>>,
Expand All @@ -249,7 +249,7 @@ impl<K: OneRttKey> KeySet<K> {
return Err(PacketEncodingError::AeadLimitReached(buffer));
}

let r = f(buffer, self.crypto[phase].key(), phase)?;
let r = f(buffer, self.crypto[phase].key_mut(), phase)?;

//= https://www.rfc-editor.org/rfc/rfc9001#section-6.6
//# Endpoints MUST count the number of encrypted packets for each set of
Expand Down Expand Up @@ -288,8 +288,8 @@ impl<K: OneRttKey> KeySet<K> {
self.packet_decryption_failures
}

pub fn cipher_suite(&self) -> crate::crypto::tls::CipherSuite {
self.crypto.0[0].key().cipher_suite()
pub fn cipher_suite(&mut self) -> crate::crypto::tls::CipherSuite {
self.crypto.0[0].key_mut().cipher_suite()
}
}

Expand Down Expand Up @@ -355,7 +355,7 @@ mod tests {
//# An endpoint SHOULD
//# retain old keys for some time after unprotecting a packet sent using
//# the new keys.
assert_eq!(keyset.crypto[KeyPhase::Zero].key().derivations, 0);
assert_eq!(keyset.crypto[KeyPhase::Zero].key_mut().derivations, 0);

clock.inc_by(Duration::from_millis(8));
keyset.on_timeout(clock.get_time());
Expand All @@ -364,7 +364,7 @@ mod tests {
//= type=test
//# After this period, old read keys and their corresponding secrets
//# SHOULD be discarded.
assert_eq!(keyset.crypto[KeyPhase::Zero].key().derivations, 2);
assert_eq!(keyset.crypto[KeyPhase::Zero].key_mut().derivations, 2);
}

#[test]
Expand All @@ -374,19 +374,19 @@ mod tests {
//# For this reason, endpoints MUST be able to retain two sets of packet
//# protection keys for receiving packets: the current and the next.

let keyset = KeySet::new(TestKey::default(), Default::default());
let mut keyset = KeySet::new(TestKey::default(), Default::default());

assert_eq!(keyset.crypto[KeyPhase::Zero].key().derivations, 0);
assert_eq!(keyset.crypto[KeyPhase::One].key().derivations, 1);
assert_eq!(keyset.crypto[KeyPhase::Zero].key_mut().derivations, 0);
assert_eq!(keyset.crypto[KeyPhase::One].key_mut().derivations, 1);
}

#[test]
fn test_phase_rotation() {
let mut keyset = KeySet::new(TestKey::default(), Default::default());

assert_eq!(keyset.active_key().key().derivations, 0);
assert_eq!(keyset.active_key_mut().key_mut().derivations, 0);
keyset.rotate_phase();
assert_eq!(keyset.active_key().key().derivations, 1);
assert_eq!(keyset.active_key_mut().key_mut().derivations, 1);
}

#[test]
Expand All @@ -396,7 +396,7 @@ mod tests {
keyset.rotate_phase();
keyset.derive_and_store_next_key();
keyset.rotate_phase();
assert_eq!(keyset.active_key().key().derivations, 2);
assert_eq!(keyset.active_key_mut().key_mut().derivations, 2);
}

//= https://www.rfc-editor.org/rfc/rfc9001#section-6.6
Expand Down
4 changes: 2 additions & 2 deletions quic/s2n-quic-core/src/crypto/application/limited.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ impl<K: OneRttKey> Key<K> {
}

#[inline]
pub fn key(&self) -> &K {
&self.key
pub fn key_mut(&mut self) -> &mut K {
&mut self.key
}
}
4 changes: 2 additions & 2 deletions quic/s2n-quic-core/src/crypto/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub trait Key: Send {

/// Encrypt a payload
fn encrypt(
&self,
&mut self,
packet_number: u64,
header: &[u8],
payload: &mut scatter::Buffer,
Expand Down Expand Up @@ -88,7 +88,7 @@ pub mod testing {

/// Encrypt a payload
fn encrypt(
&self,
&mut self,
_packet_number: u64,
_header: &[u8],
payload: &mut scatter::Buffer,
Expand Down
2 changes: 1 addition & 1 deletion quic/s2n-quic-core/src/crypto/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ pub fn unprotect<'a, K: HeaderKey>(
/// Encrypts a cleartext payload with a crypto key into a `EncryptedPayload`
#[inline]
pub fn encrypt<'a, K: Key>(
key: &K,
key: &mut K,
packet_number: PacketNumber,
packet_number_len: PacketNumberLen,
header_len: usize,
Expand Down
4 changes: 2 additions & 2 deletions quic/s2n-quic-core/src/crypto/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ fn fuzz_protect(
let packet_number_len = truncated_packet_number.len();

let (payload, _remaining) = crate::crypto::encrypt(
&FuzzCrypto,
&mut FuzzCrypto,
packet_number,
packet_number_len,
header_len,
Expand Down Expand Up @@ -117,7 +117,7 @@ impl Key for FuzzCrypto {
}

fn encrypt<'a>(
&self,
&mut self,
packet_number: u64,
_header: &[u8],
payload: &mut scatter::Buffer,
Expand Down
2 changes: 1 addition & 1 deletion quic/s2n-quic-core/src/crypto/tls/null.rs
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ mod key {

#[inline(always)]
fn encrypt(
&self,
&mut self,
_packet_number: u64,
_header: &[u8],
payload: &mut scatter::Buffer,
Expand Down
20 changes: 10 additions & 10 deletions quic/s2n-quic-core/src/crypto/tls/testing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,8 +281,8 @@ impl<S: tls::Session, C: tls::Session> Pair<S, C> {
}

/// Finished the test
pub fn finish(&self) {
self.client.context.finish(&self.server.context);
pub fn finish(&mut self) {
self.client.context.finish(&mut self.server.context);

assert_eq!(
self.client.context.transport_parameters.as_ref().unwrap(),
Expand Down Expand Up @@ -442,7 +442,7 @@ where
}

/// Finishes the test and asserts consistency
pub fn finish<O: CryptoSuite, OS: Debug, OP>(&self, other: &Context<O, OS, OP>)
pub fn finish<O: CryptoSuite, OS: Debug, OP>(&mut self, other: &mut Context<O, OS, OP>)
where
for<'a> OP: DecoderValue<'a>,
{
Expand All @@ -464,9 +464,9 @@ where
"0-rtt keys are not consistent between endpoints"
);

self.initial.finish(&other.initial);
self.handshake.finish(&other.handshake);
self.application.finish(&other.application);
self.initial.finish(&mut other.initial);
self.handshake.finish(&mut other.handshake);
self.application.finish(&mut other.application);
}

fn assert_done(&self) {
Expand Down Expand Up @@ -566,9 +566,9 @@ impl<K: Key, Hk: HeaderKey> Space<K, Hk> {
}
}

fn finish<O: Key, Ohk: HeaderKey>(&self, other: &Space<O, Ohk>) {
let (crypto_a, crypto_a_hk) = self.crypto.as_ref().expect("missing crypto");
let (crypto_b, crypto_b_hk) = other.crypto.as_ref().expect("missing crypto");
fn finish<O: Key, Ohk: HeaderKey>(&mut self, other: &mut Space<O, Ohk>) {
let (crypto_a, crypto_a_hk) = self.crypto.as_mut().expect("missing crypto");
let (crypto_b, crypto_b_hk) = other.crypto.as_mut().expect("missing crypto");

// ensure payloads can be encrypted and decrypted in both directions
seal_open(crypto_a, crypto_b);
Expand All @@ -582,7 +582,7 @@ impl<K: Key, Hk: HeaderKey> Space<K, Hk> {
}
}

fn seal_open<S: Key, O: Key>(sealer: &S, opener: &O) {
fn seal_open<S: Key, O: Key>(sealer: &mut S, opener: &O) {
let packet_number = 123;
let header = &[1, 2, 3, 4, 5, 6];

Expand Down
2 changes: 1 addition & 1 deletion quic/s2n-quic-core/src/packet/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ pub trait PacketEncoder<K: CryptoKey, H: HeaderKey, Payload: PacketPayloadEncode
// Encodes, encrypts, and header-protects a packet into a buffer
fn encode_packet<'a>(
mut self,
key: &K,
key: &mut K,
header_key: &H,
largest_acknowledged_packet_number: PacketNumber,
min_packet_len: Option<usize>,
Expand Down
8 changes: 4 additions & 4 deletions quic/s2n-quic-core/src/packet/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,14 +125,14 @@ fn encode_packet<'a>(packet: CleartextPacket, mut encoder: EncoderBuffer<'a>) ->
use CleartextPacket::*;
let result = match packet {
Handshake(packet) => packet.encode_packet(
&testing::Key::new(),
&mut testing::Key::new(),
&testing::HeaderKey::new(),
PacketNumberSpace::Handshake.new_packet_number(Default::default()),
None,
encoder,
),
Initial(packet) => packet.encode_packet(
&testing::Key::new(),
&mut testing::Key::new(),
&testing::HeaderKey::new(),
PacketNumberSpace::Initial.new_packet_number(Default::default()),
None,
Expand All @@ -143,14 +143,14 @@ fn encode_packet<'a>(packet: CleartextPacket, mut encoder: EncoderBuffer<'a>) ->
return encoder;
}
Short(packet) => packet.encode_packet(
&testing::Key::new(),
&mut testing::Key::new(),
&testing::HeaderKey::new(),
PacketNumberSpace::ApplicationData.new_packet_number(Default::default()),
None,
encoder,
),
ZeroRtt(packet) => packet.encode_packet(
&testing::Key::new(),
&mut testing::Key::new(),
&testing::HeaderKey::new(),
PacketNumberSpace::ApplicationData.new_packet_number(Default::default()),
None,
Expand Down
1 change: 1 addition & 0 deletions quic/s2n-quic-crypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ exclude = ["corpus.tar.gz"]
[features]
default = []
aws-lc-bindgen = ["aws-lc-rs/bindgen"]
fips = ["aws-lc-rs/fips"]
testing = []

[dependencies]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,11 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

use crate::ring_aead::{Aad, LessSafeKey, Nonce, MAX_TAG_LEN, NONCE_LEN};
pub use s2n_quic_core::crypto::{packet_protection::Error, scatter};
pub type Result<T = (), E = Error> = core::result::Result<T, E>;

pub trait Aead {
type Nonce;
type Tag;

fn encrypt(&self, nonce: &Self::Nonce, aad: &[u8], payload: &mut scatter::Buffer) -> Result;

fn decrypt(
&self,
nonce: &Self::Nonce,
aad: &[u8],
payload: &mut [u8],
tag: &Self::Tag,
) -> Result;
}
use crate::{
aead::{Aead, Result},
ring_aead::{Aad, LessSafeKey, Nonce, MAX_TAG_LEN, NONCE_LEN},
};
use s2n_quic_core::crypto::{packet_protection::Error, scatter};

impl Aead for LessSafeKey {
type Nonce = [u8; NONCE_LEN];
Expand All @@ -27,7 +14,7 @@ impl Aead for LessSafeKey {
#[inline]
#[cfg(target_os = "windows")]
fn encrypt(
&self,
&mut self,
nonce: &[u8; NONCE_LEN],
aad: &[u8],
payload: &mut scatter::Buffer,
Expand Down Expand Up @@ -55,7 +42,7 @@ impl Aead for LessSafeKey {
#[inline]
#[cfg(not(target_os = "windows"))]
fn encrypt(
&self,
&mut self,
nonce: &[u8; NONCE_LEN],
aad: &[u8],
payload: &mut scatter::Buffer,
Expand Down
Loading

0 comments on commit 286adde

Please sign in to comment.