Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(s2n-quic): provider-crypto-fips feature flag #2194

Merged
merged 4 commits into from
May 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading