Skip to content

Commit 5fd0b58

Browse files
committed
Add unstable support for ML-DSA algorithms
1 parent e1ab63c commit 5fd0b58

File tree

11 files changed

+176
-13
lines changed

11 files changed

+176
-13
lines changed

.github/workflows/ci.yml

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,15 @@ jobs:
2727
with:
2828
components: clippy, rustfmt
2929
- run: cargo fmt -- --check
30-
- run: cargo clippy --all-features --all-targets
30+
# `fips` and `aws_lc_rs_unstable` cannot be used together, so avoid `--all-features`
31+
- run: cargo clippy --features ring,pem,x509-parser --all-targets
3132
# rustls-cert-gen require either aws_lc_rs or ring feature
3233
- run: cargo clippy -p rcgen --no-default-features --all-targets
3334
- run: cargo clippy --no-default-features --features ring --all-targets
35+
- run: cargo clippy --no-default-features --features aws_lc_rs,pem,x509-parser --all-targets
36+
- run: cargo clippy --no-default-features --features aws_lc_rs_unstable,pem,x509-parser --all-targets
3437
- run: cargo clippy --no-default-features --features aws_lc_rs --all-targets
35-
- run: cargo clippy --no-default-features --features aws_lc_rs,pem --all-targets
38+
- run: cargo clippy --no-default-features --features fips,pem,x509-parser --all-targets
3639

3740
rustdoc:
3841
name: Documentation
@@ -49,8 +52,16 @@ jobs:
4952
uses: dtolnay/rust-toolchain@master
5053
with:
5154
toolchain: ${{ matrix.toolchain }}
52-
- name: cargo doc (all features)
53-
run: cargo doc --all-features --document-private-items
55+
- name: cargo doc (ring)
56+
run: cargo doc --features ring,pem,x509-parser --document-private-items
57+
env:
58+
RUSTDOCFLAGS: ${{ matrix.toolchain == 'nightly' && '-Dwarnings --cfg=docsrs' || '-Dwarnings' }}
59+
- name: cargo doc (aws_lc_rs_unstable)
60+
run: cargo doc --features aws_lc_rs_unstable,pem,x509-parser --document-private-items
61+
env:
62+
RUSTDOCFLAGS: ${{ matrix.toolchain == 'nightly' && '-Dwarnings --cfg=docsrs' || '-Dwarnings' }}
63+
- name: cargo doc (fips)
64+
run: cargo doc --no-default-features --features fips --document-private-items
5465
env:
5566
RUSTDOCFLAGS: ${{ matrix.toolchain == 'nightly' && '-Dwarnings --cfg=docsrs' || '-Dwarnings' }}
5667

@@ -70,7 +81,10 @@ jobs:
7081
- run: cargo install --locked cargo-check-external-types
7182
- name: run cargo-check-external-types for rcgen/
7283
working-directory: rcgen/
73-
run: cargo check-external-types --all-features
84+
run: cargo check-external-types --features ring,pem,x509-parser
85+
- name: run cargo-check-external-types for rcgen/
86+
working-directory: rcgen/
87+
run: cargo check-external-types --features aws_lc_rs_unstable,pem,x509-parser
7488

7589
semver:
7690
name: Check semver compatibility
@@ -94,7 +108,9 @@ jobs:
94108
- uses: dtolnay/rust-toolchain@master
95109
with:
96110
toolchain: 1.71.0
97-
- run: cargo check --locked --lib --all-features
111+
- run: cargo check --locked --lib --features ring,pem,x509-parser
112+
- run: cargo check --locked --lib --features aws_lc_rs_unstable
113+
- run: cargo check --locked --lib --features fips
98114

99115
build-windows:
100116
runs-on: windows-latest
@@ -214,7 +230,7 @@ jobs:
214230
with:
215231
components: llvm-tools
216232
- name: Measure coverage
217-
run: cargo llvm-cov --all-features --lcov --output-path ./lcov.info
233+
run: cargo llvm-cov --features ring,pem,x509-parser --lcov --output-path ./lcov.info
218234
- name: Report to codecov.io
219235
uses: codecov/codecov-action@v5
220236
with:

Cargo.lock

Lines changed: 5 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ keywords = ["mkcert", "ca", "certificate"]
1414
[workspace.dependencies]
1515
anyhow = "1.0.75"
1616
assert_fs = "1.0.13"
17-
aws-lc-rs = { version = "1.6.0", default-features = false }
17+
aws-lc-rs = { version = "1.13.3", default-features = false }
1818
botan = { version = "0.11", features = ["vendored"] }
1919
bpaf = { version = "0.9.5", features = ["derive"] }
2020
openssl = "0.10"

rcgen/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ keywords.workspace = true
1313
[features]
1414
default = ["crypto", "pem", "ring"]
1515
aws_lc_rs = ["crypto", "dep:aws-lc-rs", "aws-lc-rs/aws-lc-sys"]
16+
aws_lc_rs_unstable = ["aws_lc_rs", "aws-lc-rs/unstable"]
1617
fips = ["crypto", "dep:aws-lc-rs", "aws-lc-rs/fips"]
1718
crypto = []
1819
ring = ["crypto", "dep:ring"]

rcgen/src/key_pair.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ use crate::sign_algo::{algo::*, SignAlgo};
2727
#[cfg(feature = "pem")]
2828
use crate::ENCODE_CONFIG;
2929
use crate::{sign_algo::SignatureAlgorithm, Error};
30+
#[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))]
31+
use aws_lc_rs::unstable::signature::PqdsaKeyPair;
3032

3133
/// A key pair variant
3234
#[allow(clippy::large_enum_variant)]
@@ -36,6 +38,9 @@ pub(crate) enum KeyPairKind {
3638
Ec(EcdsaKeyPair),
3739
/// A Ed25519 key pair
3840
Ed(Ed25519KeyPair),
41+
/// A Pqdsa key pair
42+
#[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))]
43+
Pq(PqdsaKeyPair),
3944
/// A RSA key pair
4045
Rsa(RsaKeyPair, &'static dyn RsaEncoding),
4146
}
@@ -46,6 +51,8 @@ impl fmt::Debug for KeyPairKind {
4651
match self {
4752
Self::Ec(key_pair) => write!(f, "{key_pair:?}"),
4853
Self::Ed(key_pair) => write!(f, "{key_pair:?}"),
54+
#[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))]
55+
Self::Pq(key_pair) => write!(f, "{key_pair:?}"),
4956
Self::Rsa(key_pair, _) => write!(f, "{key_pair:?}"),
5057
}
5158
}
@@ -111,6 +118,17 @@ impl KeyPair {
111118
serialized_der: key_pair_serialized,
112119
})
113120
},
121+
#[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))]
122+
SignAlgo::PqDsa(sign_alg) => {
123+
let key_pair = PqdsaKeyPair::generate(sign_alg)._err()?;
124+
let key_pair_serialized = key_pair.to_pkcs8()._err()?.as_ref().to_vec();
125+
126+
Ok(KeyPair {
127+
kind: KeyPairKind::Pq(key_pair),
128+
alg,
129+
serialized_der: key_pair_serialized,
130+
})
131+
},
114132
#[cfg(feature = "aws_lc_rs")]
115133
SignAlgo::Rsa(sign_alg) => Self::generate_rsa_inner(alg, sign_alg, KeySize::Rsa2048),
116134
// Ring doesn't have RSA key generation yet:
@@ -433,6 +451,12 @@ impl SigningKey for KeyPair {
433451
signature.as_ref().to_owned()
434452
},
435453
KeyPairKind::Ed(kp) => kp.sign(msg).as_ref().to_owned(),
454+
#[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))]
455+
KeyPairKind::Pq(kp) => {
456+
let mut signature = vec![0; kp.algorithm().signature_len()];
457+
kp.sign(msg, &mut signature)._err()?;
458+
signature
459+
},
436460
KeyPairKind::Rsa(kp, padding_alg) => {
437461
let system_random = SystemRandom::new();
438462
let mut signature = vec![0; rsa_key_pair_public_modulus_len(kp)];
@@ -450,6 +474,8 @@ impl PublicKeyData for KeyPair {
450474
match &self.kind {
451475
KeyPairKind::Ec(kp) => kp.public_key().as_ref(),
452476
KeyPairKind::Ed(kp) => kp.public_key().as_ref(),
477+
#[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))]
478+
KeyPairKind::Pq(kp) => kp.public_key().as_ref(),
453479
KeyPairKind::Rsa(kp, _) => kp.public_key().as_ref(),
454480
}
455481
}

rcgen/src/oid.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ pub(crate) const EC_SECP_384_R1: &[u64] = &[1, 3, 132, 0, 34];
2525
#[cfg(feature = "aws_lc_rs")]
2626
pub(crate) const EC_SECP_521_R1: &[u64] = &[1, 3, 132, 0, 35];
2727

28+
#[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))]
29+
pub(crate) const ML_DSA_44: &[u64] = &[2, 16, 840, 1, 101, 3, 4, 3, 17];
30+
#[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))]
31+
pub(crate) const ML_DSA_65: &[u64] = &[2, 16, 840, 1, 101, 3, 4, 3, 18];
32+
#[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))]
33+
pub(crate) const ML_DSA_87: &[u64] = &[2, 16, 840, 1, 101, 3, 4, 3, 19];
34+
2835
/// rsaEncryption in [RFC 4055](https://www.rfc-editor.org/rfc/rfc4055#section-6)
2936
pub(crate) const RSA_ENCRYPTION: &[u64] = &[1, 2, 840, 113549, 1, 1, 1];
3037

rcgen/src/sign_algo.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,18 @@ use yasna::Tag;
88
#[cfg(feature = "crypto")]
99
use crate::ring_like::signature::{self, EcdsaSigningAlgorithm, EdDSAParameters, RsaEncoding};
1010
use crate::Error;
11+
#[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))]
12+
use aws_lc_rs::unstable::signature::{
13+
PqdsaSigningAlgorithm, ML_DSA_44_SIGNING, ML_DSA_65_SIGNING, ML_DSA_87_SIGNING,
14+
};
1115

1216
#[cfg(feature = "crypto")]
1317
#[derive(Clone, Copy, Debug)]
1418
pub(crate) enum SignAlgo {
1519
EcDsa(&'static EcdsaSigningAlgorithm),
1620
EdDsa(&'static EdDSAParameters),
21+
#[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))]
22+
PqDsa(&'static PqdsaSigningAlgorithm),
1723
Rsa(&'static dyn RsaEncoding),
1824
}
1925

@@ -209,6 +215,36 @@ pub(crate) mod algo {
209215
oid_components: &[1, 3, 101, 112],
210216
params: SignatureAlgorithmParams::None,
211217
};
218+
219+
/// ML-DSA-44 signing as per <https://www.ietf.org/archive/id/draft-ietf-lamps-dilithium-certificates-12.html#name-identifiers>.
220+
#[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))]
221+
pub static PKCS_ML_DSA_44: SignatureAlgorithm = SignatureAlgorithm {
222+
oids_sign_alg: &[ML_DSA_44],
223+
#[cfg(all(feature = "crypto", feature = "aws_lc_rs_unstable"))]
224+
sign_alg: SignAlgo::PqDsa(&ML_DSA_44_SIGNING),
225+
oid_components: ML_DSA_44,
226+
params: SignatureAlgorithmParams::None,
227+
};
228+
229+
/// ML-DSA-44 signing as per <https://www.ietf.org/archive/id/draft-ietf-lamps-dilithium-certificates-12.html#name-identifiers>.
230+
#[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))]
231+
pub static PKCS_ML_DSA_65: SignatureAlgorithm = SignatureAlgorithm {
232+
oids_sign_alg: &[ML_DSA_65],
233+
#[cfg(all(feature = "crypto", feature = "aws_lc_rs_unstable"))]
234+
sign_alg: SignAlgo::PqDsa(&ML_DSA_65_SIGNING),
235+
oid_components: ML_DSA_65,
236+
params: SignatureAlgorithmParams::None,
237+
};
238+
239+
/// ML-DSA-44 signing as per <https://www.ietf.org/archive/id/draft-ietf-lamps-dilithium-certificates-12.html#name-identifiers>.
240+
#[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))]
241+
pub static PKCS_ML_DSA_87: SignatureAlgorithm = SignatureAlgorithm {
242+
oids_sign_alg: &[ML_DSA_87],
243+
#[cfg(all(feature = "crypto", feature = "aws_lc_rs_unstable"))]
244+
sign_alg: SignAlgo::PqDsa(&ML_DSA_87_SIGNING),
245+
oid_components: ML_DSA_87,
246+
params: SignatureAlgorithmParams::None,
247+
};
212248
}
213249
// Signature algorithm IDs as per https://tools.ietf.org/html/rfc4055
214250
impl SignatureAlgorithm {

rustls-cert-gen/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ keywords.workspace = true
1313
[features]
1414
default = ["ring"]
1515
aws_lc_rs = ["dep:aws-lc-rs", "rcgen/aws_lc_rs", "aws-lc-rs/aws-lc-sys"]
16+
aws_lc_rs_unstable = ["rcgen/aws_lc_rs_unstable"]
1617
fips = ["dep:aws-lc-rs", "rcgen/aws_lc_rs", "aws-lc-rs/fips"]
1718
ring = ["dep:ring", "rcgen/ring"]
1819

rustls-cert-gen/src/cert.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,12 @@ pub enum KeyPairAlgorithm {
194194
EcdsaP384,
195195
#[cfg(feature = "aws_lc_rs")]
196196
EcdsaP521,
197+
#[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))]
198+
MlDsa44,
199+
#[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))]
200+
MlDsa65,
201+
#[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))]
202+
MlDsa87,
197203
}
198204

199205
impl From<KeyPairAlgorithm> for &'static SignatureAlgorithm {
@@ -205,6 +211,12 @@ impl From<KeyPairAlgorithm> for &'static SignatureAlgorithm {
205211
KeyPairAlgorithm::EcdsaP384 => &rcgen::PKCS_ECDSA_P384_SHA384,
206212
#[cfg(feature = "aws_lc_rs")]
207213
KeyPairAlgorithm::EcdsaP521 => &rcgen::PKCS_ECDSA_P521_SHA512,
214+
#[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))]
215+
KeyPairAlgorithm::MlDsa44 => &rcgen::PKCS_ML_DSA_44,
216+
#[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))]
217+
KeyPairAlgorithm::MlDsa65 => &rcgen::PKCS_ML_DSA_65,
218+
#[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))]
219+
KeyPairAlgorithm::MlDsa87 => &rcgen::PKCS_ML_DSA_87,
208220
}
209221
}
210222
}
@@ -218,6 +230,12 @@ impl fmt::Display for KeyPairAlgorithm {
218230
KeyPairAlgorithm::EcdsaP384 => write!(f, "ecdsa-p384"),
219231
#[cfg(feature = "aws_lc_rs")]
220232
KeyPairAlgorithm::EcdsaP521 => write!(f, "ecdsa-p521"),
233+
#[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))]
234+
KeyPairAlgorithm::MlDsa44 => write!(f, "ml-dsa-44"),
235+
#[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))]
236+
KeyPairAlgorithm::MlDsa65 => write!(f, "ml-dsa-65"),
237+
#[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))]
238+
KeyPairAlgorithm::MlDsa87 => write!(f, "ml-dsa-87"),
221239
}
222240
}
223241
}
@@ -233,6 +251,12 @@ impl FromStr for KeyPairAlgorithm {
233251
"ecdsa-p384" => Ok(Self::EcdsaP384),
234252
#[cfg(feature = "aws_lc_rs")]
235253
"ecdsa-p521" => Ok(Self::EcdsaP521),
254+
#[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))]
255+
"ml-dsa-44" => Ok(Self::MlDsa44),
256+
#[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))]
257+
"ml-dsa-65" => Ok(Self::MlDsa65),
258+
#[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))]
259+
"ml-dsa-87" => Ok(Self::MlDsa87),
236260
_ => Err(anyhow::anyhow!("unknown key algorithm: {s}")),
237261
}
238262
}

verify-tests/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ publish = false
77
[features]
88
default = []
99
aws_lc_rs = ["rcgen/aws_lc_rs"]
10+
aws_lc_rs_unstable = ["dep:aws-lc-rs", "rcgen/aws_lc_rs_unstable", "rustls-webpki/aws-lc-rs-unstable"]
1011
fips = ["rcgen/fips"]
1112
pem = ["dep:pem", "rcgen/pem"]
1213
ring = ["rcgen/ring"]
@@ -17,13 +18,13 @@ aws-lc-rs = { workspace = true, optional = true }
1718
pem = { workspace = true, optional = true }
1819
rcgen = { path = "../rcgen", features = ["pem", "x509-parser"] }
1920
ring = { workspace = true }
21+
rustls-webpki = { version = "0.103", features = ["ring", "std"] }
2022
time = { workspace = true }
2123
x509-parser = { workspace = true, features = ["verify"], optional = true }
2224
yasna = { workspace = true }
2325

2426
[dev-dependencies]
2527
pki-types = { workspace = true }
26-
rustls-webpki = { version = "0.103", features = ["ring", "std"] }
2728
botan = { version = "0.11", features = ["vendored"] }
2829
ring = { workspace = true }
2930

0 commit comments

Comments
 (0)