Skip to content

Commit 8532513

Browse files
authored
feat(integration): add utilities for capability assertions (#5475)
1 parent 5111deb commit 8532513

File tree

6 files changed

+292
-177
lines changed

6 files changed

+292
-177
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
use std::{future::Future, panic::AssertUnwindSafe};
5+
6+
/// The libcrypto that s2n-tls is linked against.
7+
#[derive(Debug, PartialEq, Eq)]
8+
enum Libcrypto {
9+
Awslc,
10+
AwslcFips,
11+
OpenSsl102,
12+
OpenSsl111,
13+
OpenSsl30,
14+
}
15+
16+
impl Libcrypto {
17+
/// Retrieve the libcrypto from the `S2N_LIBCRYPTO` env variable if available,
18+
/// otherwise return "awslc".
19+
///
20+
/// S2N_LIBCRYPTO is set in CI as well as the Nix devshell.
21+
fn from_env() -> Self {
22+
let libcrypto = match std::env::var("S2N_LIBCRYPTO") {
23+
Ok(libcrypto) => libcrypto,
24+
Err(_) => {
25+
println!("S2N_LIBCRYPTO not set, assuming awslc");
26+
"awslc".to_string()
27+
}
28+
};
29+
30+
match libcrypto.as_str() {
31+
"awslc" => Libcrypto::Awslc,
32+
"awslc-fips" => Libcrypto::AwslcFips,
33+
"openssl-1.0.2" => Libcrypto::OpenSsl102,
34+
"openssl-1.1.1" => Libcrypto::OpenSsl111,
35+
"openssl-3.0" => Libcrypto::OpenSsl30,
36+
_ => panic!("unexpected libcrypto: {libcrypto}"),
37+
}
38+
}
39+
}
40+
41+
/// A `Capability` represents a functionality of s2n-tls that may or may not be
42+
/// available depending on the linked libcrypto.
43+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
44+
pub enum Capability {
45+
/// Support for TLS 1.3
46+
Tls13,
47+
/// Support for ML-DSA and ML-KEM
48+
PQAlgorithms,
49+
}
50+
51+
impl Capability {
52+
/// Returns whether a capability is supported.
53+
///
54+
/// Internally, this just maps from the libcrypto to its supported capabilities.
55+
fn supported(&self) -> bool {
56+
let libcrypto = Libcrypto::from_env();
57+
match self {
58+
// OpenSSL 1.0.2 doesn't support RSA-PSS, so TLS 1.3 isn't enabled
59+
Capability::Tls13 => libcrypto != Libcrypto::OpenSsl102,
60+
// PQ is only supported for AWS-LC
61+
Capability::PQAlgorithms => {
62+
libcrypto == Libcrypto::Awslc || libcrypto == Libcrypto::AwslcFips
63+
}
64+
}
65+
}
66+
}
67+
68+
/// Declare the required capabilities for a test to run.
69+
///
70+
/// If all the required capabilities are present then the test must pass. Otherwise
71+
/// we expect the test to panic/fail.
72+
pub fn required_capability(required_capabilities: &[Capability], test: fn()) {
73+
let result = std::panic::catch_unwind(test);
74+
if required_capabilities.iter().all(|c| c.supported()) {
75+
result.unwrap();
76+
} else {
77+
println!("expecting test failure");
78+
let panic = result.unwrap_err();
79+
println!("panic was {panic:?}");
80+
}
81+
}
82+
83+
pub fn required_capability_async(
84+
required_capabilities: &[Capability],
85+
test: impl Future<Output = Result<(), Box<dyn std::error::Error>>>,
86+
) {
87+
let rt = tokio::runtime::Builder::new_current_thread()
88+
.enable_all()
89+
.build()
90+
.unwrap();
91+
92+
let result = std::panic::catch_unwind(AssertUnwindSafe(|| rt.block_on(test)));
93+
94+
if required_capabilities.iter().all(Capability::supported) {
95+
// 1 -> no panic
96+
// 2 -> returned "ok"
97+
result.unwrap().unwrap();
98+
} else {
99+
println!("expecting test failure");
100+
match result {
101+
Ok(Ok(())) => panic!("test did not fail"),
102+
Ok(Err(e)) => println!("err was {e:?}"),
103+
Err(e) => println!("panic was {e:?}"),
104+
}
105+
}
106+
}

0 commit comments

Comments
 (0)