Skip to content

Commit c32b266

Browse files
authored
Add post-quantum support (#29)
Add post-quantum support. Bring in code from https://github.com/tofay/rustls-liboqs 2024 edition
1 parent 04abf67 commit c32b266

File tree

20 files changed

+786
-260
lines changed

20 files changed

+786
-260
lines changed

.github/workflows/ci.yml

Lines changed: 23 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -15,38 +15,29 @@ jobs:
1515
name: Test
1616
runs-on: ubuntu-latest
1717
steps:
18-
- name: Check out repository
19-
uses: actions/checkout@v4
20-
- name: Install toolchain
21-
uses: dtolnay/rust-toolchain@v1
18+
- uses: actions/checkout@v4
19+
- uses: dtolnay/rust-toolchain@v1
2220
with:
2321
toolchain: stable
24-
- name: Cache build artifacts
25-
uses: Swatinem/rust-cache@v2
22+
- uses: Swatinem/rust-cache@v2
2623
- name: cargo test
27-
run: cargo test
24+
run: cargo test --features vendored
2825
# https://github.com/rust-lang/cargo/issues/6669
2926
- name: cargo test --doc
30-
run: cargo test --doc
27+
run: cargo test --doc --features vendored
3128
lint:
3229
name: Lint
3330
runs-on: ubuntu-latest
3431
steps:
35-
- name: Check out repository
36-
uses: actions/checkout@v4
37-
- name: Install toolchain
38-
uses: dtolnay/rust-toolchain@v1
32+
- uses: actions/checkout@v4
33+
- uses: dtolnay/rust-toolchain@v1
3934
with:
4035
toolchain: stable
4136
components: rustfmt, clippy
42-
- name: Cache build artifacts
43-
uses: Swatinem/rust-cache@v2
44-
- name: cargo fmt (check)
45-
run: cargo fmt -- --check -l
46-
- name: cargo clippy (warnings)
47-
run: cargo clippy --all-targets -- -D warnings
48-
- name: cargo clippy --no-default-features (warnings)
49-
run: cargo clippy --no-default-features --all-targets -- -D warnings
37+
- uses: Swatinem/rust-cache@v2
38+
- run: cargo fmt -- --check -l
39+
- run: cargo clippy --features vendored --all-targets -- -D warnings
40+
- run: cargo clippy --features vendored --no-default-features --all-targets -- -D warnings
5041

5142
test-fips-1-1-1:
5243
name: Test using FIPS openssl 1.1.1
@@ -56,14 +47,11 @@ jobs:
5647
steps:
5748
- name: Install dependencies
5849
run: dnf install -y gcc openssl-devel
59-
- name: Check out repository
60-
uses: actions/checkout@v4
61-
- name: Install toolchain
62-
uses: dtolnay/rust-toolchain@v1
50+
- uses: actions/checkout@v4
51+
- uses: dtolnay/rust-toolchain@v1
6352
with:
6453
toolchain: stable
65-
- name: Cache build artifacts
66-
uses: Swatinem/rust-cache@v2
54+
- uses: Swatinem/rust-cache@v2
6755
# Use single thread on FIPS to avoid running out of entropy
6856
- name: Run cargo test --features fips
6957
run: cargo test --tests --features fips -- --test-threads=1
@@ -76,36 +64,27 @@ jobs:
7664
steps:
7765
- name: Install dependencies
7866
run: dnf install -y gcc openssl-devel
79-
- name: Check out repository
80-
uses: actions/checkout@v4
81-
- name: Install toolchain
82-
uses: dtolnay/rust-toolchain@v1
67+
- uses: actions/checkout@v4
68+
- uses: dtolnay/rust-toolchain@v1
8369
with:
8470
toolchain: stable
85-
- name: Cache build artifacts
86-
uses: Swatinem/rust-cache@v2
87-
- name: Run cargo test --features fips
88-
run: cargo test --tests --features fips -- --test-threads=1
71+
- uses: Swatinem/rust-cache@v2
72+
- run: cargo test --tests --features fips -- --test-threads=1
8973

9074
coverage:
9175
name: Coverage
9276
runs-on: ubuntu-latest
9377
steps:
94-
- name: Check out repository
95-
uses: actions/checkout@v4
96-
- name: Install toolchain
97-
uses: dtolnay/rust-toolchain@v1
78+
- uses: actions/checkout@v4
79+
- uses: dtolnay/rust-toolchain@v1
9880
with:
9981
toolchain: stable
10082
components: llvm-tools
101-
- name: Cache build artifacts
102-
uses: Swatinem/rust-cache@v2
103-
- name: Install cargo-llvm-cov
104-
uses: taiki-e/install-action@cargo-llvm-cov
83+
- uses: Swatinem/rust-cache@v2
84+
- uses: taiki-e/install-action@cargo-llvm-cov
10585
- name: Generate coverage
10686
run: cargo llvm-cov --lcov --output-path lcov.info
107-
- name: Report to codecov.io
108-
uses: codecov/codecov-action@v5
87+
- uses: codecov/codecov-action@v5
10988
with:
11089
files: lcov.info
11190
token: ${{ secrets.CODECOV_TOKEN }}

Cargo.toml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
[package]
22
name = "rustls-openssl"
33
authors = ["Tom Fay <tom@teamfay.co.uk>"]
4-
version = "0.2.1"
5-
edition = "2021"
4+
version = "0.3.0"
5+
edition = "2024"
66
license = "MIT"
77
description = "Rustls crypto provider for OpenSSL"
88
homepage = "https://github.com/tofay/rustls-openssl"
@@ -18,9 +18,11 @@ rustls = { version = "0.23.20", default-features = false }
1818
zeroize = "1.8.1"
1919

2020
[features]
21-
default = ["tls12"]
21+
default = ["tls12", "prefer-post-quantum"]
2222
fips = []
2323
tls12 = ["rustls/tls12"]
24+
prefer-post-quantum = []
25+
vendored = ["openssl/vendored"]
2426

2527
[dev-dependencies]
2628
hex = "0.4.3"

build.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ fn main() {
88
println!("cargo:rustc-check-cfg=cfg(chacha)");
99
println!("cargo:rustc-check-cfg=cfg(fips_module)");
1010
println!("cargo:rustc-check-cfg=cfg(ossl320)");
11+
println!("cargo:rustc-check-cfg=cfg(ossl350)");
1112
// Determine whether to work around https://github.com/openssl/openssl/issues/23448
1213
// according to the OpenSSL version
1314
println!("cargo:rustc-check-cfg=cfg(bugged_add_hkdf_info)");
@@ -25,6 +26,10 @@ fn main() {
2526
if version >= 0x3_02_00_00_0 {
2627
println!("cargo:rustc-cfg=ossl320");
2728
}
29+
30+
if version >= 0x3_05_00_00_0 {
31+
println!("cargo:rustc-cfg=ossl350");
32+
}
2833
}
2934

3035
// Enable the `chacha` cfg if the `OPENSSL_NO_CHACHA` OpenSSL config is not set.

src/aead.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use openssl::cipher::{Cipher, CipherRef};
22
use openssl::cipher_ctx::CipherCtx;
3-
use rustls::crypto::cipher::NONCE_LEN;
43
use rustls::Error;
4+
use rustls::crypto::cipher::NONCE_LEN;
55

66
#[derive(Debug, Clone, Copy)]
77
pub(crate) enum Algorithm {
@@ -88,7 +88,7 @@ impl Algorithm {
8888

8989
#[cfg(test)]
9090
mod test {
91-
use wycheproof::{aead::TestFlag, TestResult};
91+
use wycheproof::{TestResult, aead::TestFlag};
9292

9393
fn test_aead(alg: super::Algorithm) {
9494
let test_name = match alg {

src/hkdf.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ impl Drop for HkdfExpander {
134134
#[cfg(test)]
135135
mod test {
136136
use rustls::crypto::tls13::Hkdf;
137-
use wycheproof::{hkdf::TestName, TestResult};
137+
use wycheproof::{TestResult, hkdf::TestName};
138138

139139
fn test_hkdf(hkdf: &dyn Hkdf, test_name: TestName) {
140140
let test_set = wycheproof::hkdf::TestSet::load(test_name).unwrap();

src/kx.rs renamed to src/kx_group/ec.rs

Lines changed: 4 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,10 @@ use openssl::derive::Deriver;
33
use openssl::ec::{EcGroup, EcKey, EcPoint, PointConversionForm};
44
use openssl::error::ErrorStack;
55
use openssl::nid::Nid;
6-
#[cfg(not(feature = "fips"))]
7-
use openssl::pkey::Id;
86
use openssl::pkey::{PKey, Private, Public};
97
use rustls::crypto::{ActiveKeyExchange, SharedSecret, SupportedKxGroup};
108
use rustls::{Error, NamedGroup};
119

12-
/// [Supported KeyExchange groups](SupportedKxGroup).
13-
/// * [SECP384R1]
14-
/// * [SECP256R1]
15-
/// * [X25519]
16-
///
17-
/// If the `fips` feature is enabled, only [SECP384R1] and [SECP256R1] are available.
18-
pub const ALL_KX_GROUPS: &[&dyn SupportedKxGroup] = &[
19-
SECP256R1,
20-
SECP384R1,
21-
#[cfg(not(feature = "fips"))]
22-
X25519,
23-
];
24-
2510
/// `KXGroup`'s that use `openssl::ec` module with Nid's for key exchange.
2611
#[derive(Debug)]
2712
struct EcKxGroup {
@@ -36,21 +21,6 @@ struct EcKeyExchange {
3621
pub_key: Vec<u8>,
3722
}
3823

39-
#[cfg(not(feature = "fips"))]
40-
/// `KXGroup`` for X25519
41-
#[derive(Debug)]
42-
struct X25519KxGroup {}
43-
44-
#[cfg(not(feature = "fips"))]
45-
#[derive(Debug)]
46-
struct X25519KeyExchange {
47-
private_key: PKey<Private>,
48-
public_key: Vec<u8>,
49-
}
50-
51-
#[cfg(not(feature = "fips"))]
52-
/// X25519 key exchange group as registered with [IANA](https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8).
53-
pub const X25519: &dyn SupportedKxGroup = &X25519KxGroup {};
5424
/// secp256r1 key exchange group as registered with [IANA](https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8)
5525
pub const SECP256R1: &dyn SupportedKxGroup = &EcKxGroup {
5626
name: NamedGroup::secp256r1,
@@ -132,67 +102,22 @@ impl ActiveKeyExchange for EcKeyExchange {
132102
}
133103
}
134104

135-
#[cfg(not(feature = "fips"))]
136-
impl SupportedKxGroup for X25519KxGroup {
137-
fn start(&self) -> Result<Box<dyn ActiveKeyExchange>, Error> {
138-
PKey::generate_x25519()
139-
.and_then(|private_key| {
140-
let public_key = private_key.raw_public_key()?;
141-
Ok(Box::new(X25519KeyExchange {
142-
private_key,
143-
public_key,
144-
}) as Box<dyn ActiveKeyExchange>)
145-
})
146-
.map_err(|e| Error::General(format!("OpenSSL error: {e}")))
147-
}
148-
149-
fn name(&self) -> NamedGroup {
150-
NamedGroup::X25519
151-
}
152-
}
153-
154-
#[cfg(not(feature = "fips"))]
155-
impl ActiveKeyExchange for X25519KeyExchange {
156-
fn complete(self: Box<Self>, peer_pub_key: &[u8]) -> Result<SharedSecret, Error> {
157-
PKey::public_key_from_raw_bytes(peer_pub_key, Id::X25519)
158-
.and_then(|peer_pub_key| {
159-
let mut deriver = Deriver::new(&self.private_key)?;
160-
deriver.set_peer(&peer_pub_key)?;
161-
let secret = deriver.derive_to_vec()?;
162-
Ok(SharedSecret::from(secret.as_slice()))
163-
})
164-
.map_err(|e| Error::General(format!("OpenSSL error: {e}")))
165-
}
166-
167-
fn pub_key(&self) -> &[u8] {
168-
&self.public_key
169-
}
170-
171-
fn group(&self) -> NamedGroup {
172-
NamedGroup::X25519
173-
}
174-
}
175-
176105
#[cfg(test)]
177106
mod test {
178107
use openssl::{
179108
bn::BigNum,
180109
ec::{EcGroup, EcKey, EcPoint},
181110
nid::Nid,
182-
pkey::{Id, PKey},
183111
};
184-
use rustls::{crypto::ActiveKeyExchange, NamedGroup};
185-
use wycheproof::{ecdh::TestName, TestResult};
112+
use rustls::{NamedGroup, crypto::ActiveKeyExchange};
113+
use wycheproof::{TestResult, ecdh::TestName};
186114

187-
use crate::kx::EcKeyExchange;
188-
189-
#[cfg(not(feature = "fips"))]
190-
use super::X25519KeyExchange;
115+
use super::EcKeyExchange;
191116

192117
#[rstest::rstest]
193118
#[case::secp256r1(TestName::EcdhSecp256r1, NamedGroup::secp256r1, Nid::X9_62_PRIME256V1)]
194119
#[case::secp384r1(TestName::EcdhSecp384r1, NamedGroup::secp384r1, Nid::SECP384R1)]
195-
fn ec(#[case] test_name: TestName, #[case] rustls_group: NamedGroup, #[case] nid: Nid) {
120+
fn test_ec_kx(#[case] test_name: TestName, #[case] rustls_group: NamedGroup, #[case] nid: Nid) {
196121
let test_set = wycheproof::ecdh::TestSet::load(test_name).unwrap();
197122
let ctx = openssl::bn::BigNumContext::new().unwrap();
198123

@@ -231,45 +156,4 @@ mod test {
231156
}
232157
}
233158
}
234-
235-
#[cfg(not(feature = "fips"))]
236-
#[test]
237-
fn x25519() {
238-
let test_set = wycheproof::xdh::TestSet::load(wycheproof::xdh::TestName::X25519).unwrap();
239-
for test_group in &test_set.test_groups {
240-
for test in &test_group.tests {
241-
let kx = X25519KeyExchange {
242-
private_key: PKey::private_key_from_raw_bytes(&test.private_key, Id::X25519)
243-
.unwrap(),
244-
public_key: Vec::new(),
245-
};
246-
247-
let res = Box::new(kx).complete(&test.public_key);
248-
249-
// OpenSSL does not support producing a zero shared secret
250-
let zero_shared_secret = test
251-
.flags
252-
.contains(&wycheproof::xdh::TestFlag::ZeroSharedSecret);
253-
254-
match (&test.result, zero_shared_secret) {
255-
(TestResult::Acceptable, false) | (TestResult::Valid, _) => match res {
256-
Ok(sharedsecret) => {
257-
assert_eq!(
258-
sharedsecret.secret_bytes(),
259-
&test.shared_secret[..],
260-
"Derived incorrect secret: {:?}",
261-
test
262-
);
263-
}
264-
Err(e) => {
265-
panic!("Test failed: {:?}. Error {:?}", test, e);
266-
}
267-
},
268-
_ => {
269-
assert!(res.is_err(), "Expected error: {:?}", test);
270-
}
271-
}
272-
}
273-
}
274-
}
275159
}

0 commit comments

Comments
 (0)