Skip to content

Support ECDSA_P521_SHA512 when using aws_lc_rs feature #241

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

Merged
merged 1 commit into from
Mar 20, 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
10 changes: 4 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ jobs:
matrix:
features:
- --all-features
- --no-default-features
# rustls-cert-gen require either aws_lc_rs or ring feature
- -p rcgen --no-default-features
- --no-default-features --features ring
- --no-default-features --features aws_lc_rs
- --no-default-features --features aws_lc_rs,pem
Expand Down Expand Up @@ -138,10 +139,9 @@ jobs:
run: cargo test --verbose --features x509-parser
- name: Run the tests with aws_lc_rs backend enabled
run: cargo test --verbose --no-default-features --features aws_lc_rs,pem
- name: Run the tests with FIPS aws_lc_rs module
run: cargo test --verbose --no-default-features --features fips,pem
# rustls-cert-gen require either aws_lc_rs or ring feature
- name: Run the tests with no features enabled
run: cargo test --verbose --no-default-features
run: cargo test -p rcgen --verbose --no-default-features

build:
strategy:
Expand Down Expand Up @@ -181,8 +181,6 @@ jobs:
run: cargo test --verbose --features x509-parser
- name: Run the tests with aws_lc_rs backend enabled
run: cargo test --verbose --no-default-features --features aws_lc_rs,pem
- name: Run the tests with FIPS aws_lc_rs module
run: cargo test --verbose --no-default-features --features fips,pem

# Build rustls-cert-gen as a standalone package, see this PR for why it's needed:
# https://github.com/rustls/rcgen/pull/206#pullrequestreview-1816197358
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ members = ["rcgen", "rustls-cert-gen"]
resolver = "2"

[workspace.dependencies]
aws-lc-rs = "1.6.0"
pem = "3.0.2"
pki-types = { package = "rustls-pki-types", version = "1.3.0" }
rand = "0.8"
Expand Down
2 changes: 1 addition & 1 deletion rcgen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ name = "simple"
required-features = ["crypto"]

[dependencies]
aws-lc-rs = { version = "1.6.0", optional = true }
aws-lc-rs = { workspace = true, optional = true }
yasna = { version = "0.5.2", features = ["time", "std"] }
ring = { workspace = true, optional = true }
pem = { workspace = true, optional = true }
Expand Down
26 changes: 25 additions & 1 deletion rcgen/src/key_pair.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,18 @@ impl KeyPair {
let rsakp = RsaKeyPair::from_pkcs8(&serialized_der)._err()?;
KeyPairKind::Rsa(rsakp, &signature::RSA_PSS_SHA256)
} else {
#[cfg(all(feature = "aws_lc_rs", not(feature = "ring")))]
if alg == &PKCS_ECDSA_P521_SHA512 {
KeyPairKind::Ec(ecdsa_from_pkcs8(
&signature::ECDSA_P521_SHA512_ASN1_SIGNING,
&serialized_der,
rng,
)?)
} else {
panic!("Unknown SignatureAlgorithm specified!");
}

#[cfg(feature = "ring")]
panic!("Unknown SignatureAlgorithm specified!");
};

Expand Down Expand Up @@ -290,7 +302,19 @@ impl KeyPair {
&PKCS_RSA_SHA256,
)
} else {
return Err(Error::CouldNotParseKeyPair);
#[cfg(all(feature = "aws_lc_rs", not(feature = "ring")))]
if let Ok(eckp) =
ecdsa_from_pkcs8(&signature::ECDSA_P521_SHA512_ASN1_SIGNING, pkcs8, &rng)
{
(KeyPairKind::Ec(eckp), &PKCS_ECDSA_P521_SHA512)
} else {
return Err(Error::CouldNotParseKeyPair);
}

#[cfg(feature = "ring")]
{
return Err(Error::CouldNotParseKeyPair);
}
};
Ok((kind, alg))
}
Expand Down
4 changes: 4 additions & 0 deletions rcgen/src/oid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ pub(crate) const EC_PUBLIC_KEY: &[u64] = &[1, 2, 840, 10045, 2, 1];
pub(crate) const EC_SECP_256_R1: &[u64] = &[1, 2, 840, 10045, 3, 1, 7];
/// secp384r1 in [RFC 5480](https://datatracker.ietf.org/doc/html/rfc5480#appendix-A)
pub(crate) const EC_SECP_384_R1: &[u64] = &[1, 3, 132, 0, 34];
/// secp521r1 in [RFC 5480](https://datatracker.ietf.org/doc/html/rfc5480#appendix-A)
/// Currently this is only supported with the `aws_lc_rs` feature
#[cfg(all(feature = "aws_lc_rs", not(feature = "ring")))]
pub(crate) const EC_SECP_521_R1: &[u64] = &[1, 3, 132, 0, 35];

/// rsaEncryption in [RFC 4055](https://www.rfc-editor.org/rfc/rfc4055#section-6)
pub(crate) const RSA_ENCRYPTION: &[u64] = &[1, 2, 840, 113549, 1, 1, 1];
Expand Down
20 changes: 18 additions & 2 deletions rcgen/src/sign_algo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ impl fmt::Debug for SignatureAlgorithm {
} else if self == &PKCS_ED25519 {
write!(f, "PKCS_ED25519")
} else {
#[cfg(all(feature = "aws_lc_rs", not(feature = "ring")))]
if self == &PKCS_ECDSA_P521_SHA512 {
return write!(f, "PKCS_ECDSA_P521_SHA512");
}

write!(f, "Unknown")
}
}
Expand Down Expand Up @@ -86,6 +91,8 @@ impl SignatureAlgorithm {
//&PKCS_RSA_PSS_SHA256,
&PKCS_ECDSA_P256_SHA256,
&PKCS_ECDSA_P384_SHA384,
#[cfg(all(feature = "aws_lc_rs", not(feature = "ring")))]
&PKCS_ECDSA_P521_SHA512,
&PKCS_ED25519,
];
ALGORITHMS.iter()
Expand Down Expand Up @@ -178,8 +185,17 @@ pub(crate) mod algo {
oid_components: &[1, 2, 840, 10045, 4, 3, 3],
params: SignatureAlgorithmParams::None,
};

// TODO PKCS_ECDSA_P521_SHA512 https://github.com/briansmith/ring/issues/824
/// ECDSA signing using the P-521 curves and SHA-512 hashing as per [RFC 5758](https://tools.ietf.org/html/rfc5758#section-3.2)
/// Currently this is only supported with the `aws_lc_rs` feature
#[cfg(all(feature = "aws_lc_rs", not(feature = "ring")))]
pub static PKCS_ECDSA_P521_SHA512: SignatureAlgorithm = SignatureAlgorithm {
oids_sign_alg: &[&EC_PUBLIC_KEY, &EC_SECP_521_R1],
#[cfg(feature = "crypto")]
sign_alg: SignAlgo::EcDsa(&signature::ECDSA_P521_SHA512_ASN1_SIGNING),
// ecdsa-with-SHA512 in RFC 5758
oid_components: &[1, 2, 840, 10045, 4, 3, 4],
params: SignatureAlgorithmParams::None,
};

/// ED25519 curve signing as per [RFC 8410](https://tools.ietf.org/html/rfc8410)
pub static PKCS_ED25519: SignatureAlgorithm = SignatureAlgorithm {
Expand Down
11 changes: 11 additions & 0 deletions rcgen/tests/botan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,17 @@ fn test_botan_384() {
check_cert(cert.der(), &cert);
}

#[test]
#[cfg(all(feature = "aws_lc_rs", not(feature = "ring")))]
fn test_botan_521() {
let (params, _) = default_params();
let key_pair = KeyPair::generate_for(&rcgen::PKCS_ECDSA_P521_SHA512).unwrap();
let cert = params.self_signed(&key_pair).unwrap();

// Now verify the certificate.
check_cert(cert.der(), &cert);
}

#[test]
fn test_botan_25519() {
let (params, _) = default_params();
Expand Down
2 changes: 2 additions & 0 deletions rcgen/tests/generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ mod test_key_params_mismatch {
&rcgen::PKCS_RSA_SHA256,
&rcgen::PKCS_ECDSA_P256_SHA256,
&rcgen::PKCS_ECDSA_P384_SHA384,
#[cfg(all(feature = "aws_lc_rs", not(feature = "ring")))]
&rcgen::PKCS_ECDSA_P521_SHA512,
&rcgen::PKCS_ED25519,
];
for (i, kalg_1) in available_key_params.iter().enumerate() {
Expand Down
12 changes: 12 additions & 0 deletions rcgen/tests/openssl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,18 @@ fn test_openssl_384() {
verify_csr(&cert, &key_pair);
}

#[test]
#[cfg(all(feature = "aws_lc_rs", not(feature = "ring")))]
fn test_openssl_521() {
let (params, _) = util::default_params();
let key_pair = KeyPair::generate_for(&rcgen::PKCS_ECDSA_P521_SHA512).unwrap();
let cert = params.self_signed(&key_pair).unwrap();

// Now verify the certificate.
verify_cert(&cert, &key_pair);
verify_csr(&cert, &key_pair);
}

#[test]
fn test_openssl_25519() {
let (params, _) = util::default_params();
Expand Down
11 changes: 9 additions & 2 deletions rustls-cert-gen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,21 @@ license.workspace = true
edition.workspace = true
keywords.workspace = true

[features]
default = ["ring"]
aws_lc_rs = ["dep:aws-lc-rs", "rcgen/aws_lc_rs"]
ring = ["dep:ring", "rcgen/ring"]
fips = ["aws_lc_rs", "aws-lc-rs?/fips"]

[dependencies]
rcgen = { path = "../rcgen", default-features = false, features = ["pem", "ring"] }
rcgen = { path = "../rcgen", default-features = false, features = ["pem"] }
bpaf = { version = "0.9.5", features = ["derive"] }
pem = { workspace = true }
pki-types = { workspace = true }
ring = { workspace = true }
ring = { workspace = true, optional = true }
rand = { workspace = true }
anyhow = "1.0.75"
aws-lc-rs = { workspace = true, optional = true }

[dev-dependencies]
assert_fs = "1.0.13"
Expand Down
67 changes: 59 additions & 8 deletions rustls-cert-gen/src/cert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ use rcgen::{
DnValue::PrintableString, ExtendedKeyUsagePurpose, IsCa, KeyPair, KeyUsagePurpose, SanType,
};

#[cfg(all(feature = "aws_lc_rs", not(feature = "ring")))]
use aws_lc_rs as ring_like;
#[cfg(feature = "ring")]
use ring as ring_like;

#[derive(Debug, Clone)]
/// PEM serialized Certificate and PEM serialized corresponding private key
pub struct PemCertifiedKey {
Expand Down Expand Up @@ -213,6 +218,8 @@ pub enum KeyPairAlgorithm {
#[default]
EcdsaP256,
EcdsaP384,
#[cfg(all(feature = "aws_lc_rs", not(feature = "ring")))]
EcdsaP521,
}

impl fmt::Display for KeyPairAlgorithm {
Expand All @@ -222,6 +229,8 @@ impl fmt::Display for KeyPairAlgorithm {
KeyPairAlgorithm::Ed25519 => write!(f, "ed25519"),
KeyPairAlgorithm::EcdsaP256 => write!(f, "ecdsa-p256"),
KeyPairAlgorithm::EcdsaP384 => write!(f, "ecdsa-p384"),
#[cfg(all(feature = "aws_lc_rs", not(feature = "ring")))]
KeyPairAlgorithm::EcdsaP521 => write!(f, "ecdsa-p521"),
}
}
}
Expand All @@ -232,38 +241,51 @@ impl KeyPairAlgorithm {
match self {
KeyPairAlgorithm::Rsa => rcgen::KeyPair::generate_for(&rcgen::PKCS_RSA_SHA256),
KeyPairAlgorithm::Ed25519 => {
use ring::signature::Ed25519KeyPair;
use ring_like::signature::Ed25519KeyPair;

let rng = ring::rand::SystemRandom::new();
let rng = ring_like::rand::SystemRandom::new();
let alg = &rcgen::PKCS_ED25519;
let pkcs8_bytes =
Ed25519KeyPair::generate_pkcs8(&rng).or(Err(rcgen::Error::RingUnspecified))?;

rcgen::KeyPair::from_pkcs8_der_and_sign_algo(&pkcs8_bytes.as_ref().into(), alg)
},
KeyPairAlgorithm::EcdsaP256 => {
use ring::signature::EcdsaKeyPair;
use ring::signature::ECDSA_P256_SHA256_ASN1_SIGNING;
use ring_like::signature::EcdsaKeyPair;
use ring_like::signature::ECDSA_P256_SHA256_ASN1_SIGNING;

let rng = ring::rand::SystemRandom::new();
let rng = ring_like::rand::SystemRandom::new();
let alg = &rcgen::PKCS_ECDSA_P256_SHA256;
let pkcs8_bytes =
EcdsaKeyPair::generate_pkcs8(&ECDSA_P256_SHA256_ASN1_SIGNING, &rng)
.or(Err(rcgen::Error::RingUnspecified))?;
rcgen::KeyPair::from_pkcs8_der_and_sign_algo(&pkcs8_bytes.as_ref().into(), alg)
},
KeyPairAlgorithm::EcdsaP384 => {
use ring::signature::EcdsaKeyPair;
use ring::signature::ECDSA_P384_SHA384_ASN1_SIGNING;
use ring_like::signature::EcdsaKeyPair;
use ring_like::signature::ECDSA_P384_SHA384_ASN1_SIGNING;

let rng = ring::rand::SystemRandom::new();
let rng = ring_like::rand::SystemRandom::new();
let alg = &rcgen::PKCS_ECDSA_P384_SHA384;
let pkcs8_bytes =
EcdsaKeyPair::generate_pkcs8(&ECDSA_P384_SHA384_ASN1_SIGNING, &rng)
.or(Err(rcgen::Error::RingUnspecified))?;

rcgen::KeyPair::from_pkcs8_der_and_sign_algo(&pkcs8_bytes.as_ref().into(), alg)
},
#[cfg(all(feature = "aws_lc_rs", not(feature = "ring")))]
KeyPairAlgorithm::EcdsaP521 => {
use ring_like::signature::EcdsaKeyPair;
use ring_like::signature::ECDSA_P521_SHA512_ASN1_SIGNING;

let rng = ring_like::rand::SystemRandom::new();
let alg = &rcgen::PKCS_ECDSA_P521_SHA512;
let pkcs8_bytes =
EcdsaKeyPair::generate_pkcs8(&ECDSA_P521_SHA512_ASN1_SIGNING, &rng)
.or(Err(rcgen::Error::RingUnspecified))?;

rcgen::KeyPair::from_pkcs8_der_and_sign_algo(&pkcs8_bytes.as_ref().into(), alg)
},
}
}
}
Expand Down Expand Up @@ -345,6 +367,26 @@ mod tests {
Ok(())
}

#[test]
#[cfg(all(feature = "aws_lc_rs", not(feature = "ring")))]
fn serialize_end_entity_ecdsa_p521_sha512_sig() -> anyhow::Result<()> {
let ca = CertificateBuilder::new().certificate_authority().build()?;
let end_entity = CertificateBuilder::new()
.signature_algorithm(KeyPairAlgorithm::EcdsaP521)?
.end_entity()
.build(&ca)?
.serialize_pem();

let der = pem::parse(end_entity.cert_pem)?;
let (_, cert) = X509Certificate::from_der(der.contents())?;

let issuer_der = pem::parse(ca.serialize_pem().cert_pem)?;
let (_, issuer) = X509Certificate::from_der(issuer_der.contents())?;

check_signature(&cert, &issuer);
Ok(())
}

#[test]
fn serialize_end_entity_ed25519_sig() -> anyhow::Result<()> {
let ca = CertificateBuilder::new().certificate_authority().build()?;
Expand Down Expand Up @@ -445,6 +487,15 @@ mod tests {
format!("{:?}", keypair.algorithm()),
"PKCS_ECDSA_P384_SHA384"
);

#[cfg(all(feature = "aws_lc_rs", not(feature = "ring")))]
{
let keypair = KeyPairAlgorithm::EcdsaP521.to_key_pair()?;
assert_eq!(
format!("{:?}", keypair.algorithm()),
"PKCS_ECDSA_P521_SHA512"
);
}
Ok(())
}
}