Browse Source

Add support for NIST P-521 curve and ES512 signatures

pull/39/head
Rodolphe Breard 4 years ago
parent
commit
8477d927a1
  1. 1
      CHANGELOG.md
  2. 2
      README.md
  3. 3
      acme_common/src/crypto/jws_signature_algorithm.rs
  4. 9
      acme_common/src/crypto/key_type.rs
  5. 35
      acme_common/src/crypto/openssl_keys.rs
  6. 6
      man/en/acmed.toml.5

1
CHANGELOG.md

@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Some subject attributes can now be specified.
- Support for NIST P-521 certificates and account keys.
## [0.11.0] - 2020-09-19

2
README.md

@ -20,7 +20,7 @@ The Automatic Certificate Management Environment (ACME), is an internet standard
- http-01, dns-01 and [tls-alpn-01](https://tools.ietf.org/html/rfc8737) challenges
- IP identifier validation extension [RFC 8738](https://tools.ietf.org/html/rfc8738)
- RSA 2048, RSA 4096, ECDSA P-256 and ECDSA P-384 certificates
- RSA 2048, RSA 4096, ECDSA P-256, ECDSA P-384 and ECDSA P-521 certificates
- Internationalized domain names support
- Fully customizable challenge validation action
- Fully customizable archiving method (yes, you can use git or anything else)

3
acme_common/src/crypto/jws_signature_algorithm.rs

@ -10,6 +10,7 @@ pub enum JwsSignatureAlgorithm {
Rs256,
Es256,
Es384,
Es512,
#[cfg(ed25519)]
Ed25519,
#[cfg(ed448)]
@ -27,6 +28,7 @@ impl FromStr for JwsSignatureAlgorithm {
"rs256" => Ok(JwsSignatureAlgorithm::Rs256),
"es256" => Ok(JwsSignatureAlgorithm::Es256),
"es384" => Ok(JwsSignatureAlgorithm::Es384),
"es512" => Ok(JwsSignatureAlgorithm::Es512),
#[cfg(ed25519)]
"ed25519" => Ok(JwsSignatureAlgorithm::Ed25519),
#[cfg(ed448)]
@ -45,6 +47,7 @@ impl fmt::Display for JwsSignatureAlgorithm {
JwsSignatureAlgorithm::Rs256 => "RS256",
JwsSignatureAlgorithm::Es256 => "ES256",
JwsSignatureAlgorithm::Es384 => "ES384",
JwsSignatureAlgorithm::Es512 => "ES512",
#[cfg(ed25519)]
JwsSignatureAlgorithm::Ed25519 => "Ed25519",
#[cfg(ed448)]

9
acme_common/src/crypto/key_type.rs

@ -9,6 +9,7 @@ pub enum KeyType {
Rsa4096,
EcdsaP256,
EcdsaP384,
EcdsaP521,
#[cfg(ed25519)]
Ed25519,
#[cfg(ed448)]
@ -21,6 +22,7 @@ impl KeyType {
KeyType::Rsa2048 | KeyType::Rsa4096 => JwsSignatureAlgorithm::Rs256,
KeyType::EcdsaP256 => JwsSignatureAlgorithm::Es256,
KeyType::EcdsaP384 => JwsSignatureAlgorithm::Es384,
KeyType::EcdsaP521 => JwsSignatureAlgorithm::Es512,
#[cfg(ed25519)]
KeyType::Ed25519 => JwsSignatureAlgorithm::Ed25519,
#[cfg(ed448)]
@ -31,7 +33,9 @@ impl KeyType {
pub fn check_alg_compatibility(&self, alg: &JwsSignatureAlgorithm) -> Result<(), Error> {
let ok = match self {
KeyType::Rsa2048 | KeyType::Rsa4096 => *alg == JwsSignatureAlgorithm::Rs256,
KeyType::EcdsaP256 | KeyType::EcdsaP384 => *alg == self.get_default_signature_alg(),
KeyType::EcdsaP256 | KeyType::EcdsaP384 | KeyType::EcdsaP521 => {
*alg == self.get_default_signature_alg()
}
#[cfg(ed25519)]
KeyType::Ed25519 => *alg == self.get_default_signature_alg(),
#[cfg(ed448)]
@ -54,6 +58,7 @@ impl KeyType {
"rsa4096",
"ecdsa-p256",
"ecdsa-p384",
"ecdsa-p521",
#[cfg(ed25519)]
"ed25519",
#[cfg(ed448)]
@ -71,6 +76,7 @@ impl FromStr for KeyType {
"rsa4096" => Ok(KeyType::Rsa4096),
"ecdsa_p256" => Ok(KeyType::EcdsaP256),
"ecdsa_p384" => Ok(KeyType::EcdsaP384),
"ecdsa_p521" => Ok(KeyType::EcdsaP521),
#[cfg(ed25519)]
"ed25519" => Ok(KeyType::Ed25519),
#[cfg(ed448)]
@ -87,6 +93,7 @@ impl fmt::Display for KeyType {
KeyType::Rsa4096 => "rsa4096",
KeyType::EcdsaP256 => "ecdsa-p256",
KeyType::EcdsaP384 => "ecdsa-p384",
KeyType::EcdsaP521 => "ecdsa-p521",
#[cfg(ed25519)]
KeyType::Ed25519 => "ed25519",
#[cfg(ed448)]

35
acme_common/src/crypto/openssl_keys.rs

@ -25,6 +25,7 @@ macro_rules! get_key_type {
Id::EC => match $key.ec_key()?.group().curve_name() {
Some(Nid::X9_62_PRIME256V1) => KeyType::EcdsaP256,
Some(Nid::SECP384R1) => KeyType::EcdsaP384,
Some(Nid::SECP521R1) => KeyType::EcdsaP521,
Some(nid) => {
return Err(format!("{:?}: unsupported EC key", nid).into());
}
@ -43,6 +44,21 @@ macro_rules! get_key_type {
};
}
macro_rules! get_ecdsa_sig_part {
($part: expr, $size: ident) => {{
let mut p = $part.to_vec();
let length = p.len();
if length != $size {
let mut s: Vec<u8> = Vec::with_capacity($size);
s.resize_with($size - length, || 0);
s.append(&mut p);
s
} else {
p
}
}};
}
#[derive(Clone, Debug)]
pub struct KeyPair {
pub key_type: KeyType,
@ -95,6 +111,7 @@ impl KeyPair {
JwsSignatureAlgorithm::Rs256 => self.sign_rsa(&MessageDigest::sha256(), data),
JwsSignatureAlgorithm::Es256 => self.sign_ecdsa(&HashFunction::Sha256, data),
JwsSignatureAlgorithm::Es384 => self.sign_ecdsa(&HashFunction::Sha384, data),
JwsSignatureAlgorithm::Es512 => self.sign_ecdsa(&HashFunction::Sha512, data),
#[cfg(ed25519)]
JwsSignatureAlgorithm::Ed25519 => self.sign_eddsa(data),
#[cfg(ed448)]
@ -112,8 +129,16 @@ impl KeyPair {
fn sign_ecdsa(&self, hash_func: &HashFunction, data: &[u8]) -> Result<Vec<u8>, Error> {
let fingerprint = hash_func.hash(data);
let signature = EcdsaSig::sign(&fingerprint, self.inner_key.ec_key()?.as_ref())?;
let r = signature.r().to_vec();
let mut s = signature.s().to_vec();
let sig_size = match self.key_type {
KeyType::EcdsaP256 => 32,
KeyType::EcdsaP384 => 48,
KeyType::EcdsaP521 => 66,
_ => {
return Err("not an ecdsa key".into());
}
};
let r = get_ecdsa_sig_part!(signature.r(), sig_size);
let mut s = get_ecdsa_sig_part!(signature.s(), sig_size);
let mut signature = r;
signature.append(&mut s);
Ok(signature)
@ -137,7 +162,9 @@ impl KeyPair {
fn get_jwk_public_key(&self, thumbprint: bool) -> Result<Value, Error> {
match self.key_type {
KeyType::Rsa2048 | KeyType::Rsa4096 => self.get_rsa_jwk(thumbprint),
KeyType::EcdsaP256 | KeyType::EcdsaP384 => self.get_ecdsa_jwk(thumbprint),
KeyType::EcdsaP256 | KeyType::EcdsaP384 | KeyType::EcdsaP521 => {
self.get_ecdsa_jwk(thumbprint)
}
#[cfg(ed25519)]
KeyType::Ed25519 => self.get_eddsa_jwk(thumbprint),
#[cfg(ed448)]
@ -173,6 +200,7 @@ impl KeyPair {
let (crv, alg, curve) = match self.key_type {
KeyType::EcdsaP256 => ("P-256", "ES256", Nid::X9_62_PRIME256V1),
KeyType::EcdsaP384 => ("P-384", "ES384", Nid::SECP384R1),
KeyType::EcdsaP521 => ("P-521", "ES512", Nid::SECP521R1),
_ => {
return Err("not an ECDSA elliptic curve".into());
}
@ -275,6 +303,7 @@ pub fn gen_keypair(key_type: KeyType) -> Result<KeyPair, Error> {
KeyType::Rsa4096 => gen_rsa_pair(4096),
KeyType::EcdsaP256 => gen_ec_pair(Nid::X9_62_PRIME256V1),
KeyType::EcdsaP384 => gen_ec_pair(Nid::SECP384R1),
KeyType::EcdsaP521 => gen_ec_pair(Nid::SECP521R1),
#[cfg(ed25519)]
KeyType::Ed25519 => gen_ed25519_pair(),
#[cfg(ed448)]

6
man/en/acmed.toml.5

@ -183,6 +183,8 @@ ecdsa_p256
.Aq default
.It
ecdsa_p384
.It
ecdsa_p521
.El
.It Cm signature_algorithm Ar string
Name of the signature algorithm used to sign the messages sent to the endpoint as defined in
@ -195,6 +197,8 @@ RS256
ES256
.It
ES384
.It
ES512
.El
.It Ic env Ar table
Table of environment variables that will be accessible from hooks.
@ -301,6 +305,8 @@ rsa4096
ecdsa_p256
.It
ecdsa_p384
.It
ecdsa_p521
.El
.It Ic csr_digest Ar string
Name of the certificate's signing request digest algorithm. Possible values are:

Loading…
Cancel
Save