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 ### Added
- Some subject attributes can now be specified. - Some subject attributes can now be specified.
- Support for NIST P-521 certificates and account keys.
## [0.11.0] - 2020-09-19 ## [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 - 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) - 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 - Internationalized domain names support
- Fully customizable challenge validation action - Fully customizable challenge validation action
- Fully customizable archiving method (yes, you can use git or anything else) - 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, Rs256,
Es256, Es256,
Es384, Es384,
Es512,
#[cfg(ed25519)] #[cfg(ed25519)]
Ed25519, Ed25519,
#[cfg(ed448)] #[cfg(ed448)]
@ -27,6 +28,7 @@ impl FromStr for JwsSignatureAlgorithm {
"rs256" => Ok(JwsSignatureAlgorithm::Rs256), "rs256" => Ok(JwsSignatureAlgorithm::Rs256),
"es256" => Ok(JwsSignatureAlgorithm::Es256), "es256" => Ok(JwsSignatureAlgorithm::Es256),
"es384" => Ok(JwsSignatureAlgorithm::Es384), "es384" => Ok(JwsSignatureAlgorithm::Es384),
"es512" => Ok(JwsSignatureAlgorithm::Es512),
#[cfg(ed25519)] #[cfg(ed25519)]
"ed25519" => Ok(JwsSignatureAlgorithm::Ed25519), "ed25519" => Ok(JwsSignatureAlgorithm::Ed25519),
#[cfg(ed448)] #[cfg(ed448)]
@ -45,6 +47,7 @@ impl fmt::Display for JwsSignatureAlgorithm {
JwsSignatureAlgorithm::Rs256 => "RS256", JwsSignatureAlgorithm::Rs256 => "RS256",
JwsSignatureAlgorithm::Es256 => "ES256", JwsSignatureAlgorithm::Es256 => "ES256",
JwsSignatureAlgorithm::Es384 => "ES384", JwsSignatureAlgorithm::Es384 => "ES384",
JwsSignatureAlgorithm::Es512 => "ES512",
#[cfg(ed25519)] #[cfg(ed25519)]
JwsSignatureAlgorithm::Ed25519 => "Ed25519", JwsSignatureAlgorithm::Ed25519 => "Ed25519",
#[cfg(ed448)] #[cfg(ed448)]

9
acme_common/src/crypto/key_type.rs

@ -9,6 +9,7 @@ pub enum KeyType {
Rsa4096, Rsa4096,
EcdsaP256, EcdsaP256,
EcdsaP384, EcdsaP384,
EcdsaP521,
#[cfg(ed25519)] #[cfg(ed25519)]
Ed25519, Ed25519,
#[cfg(ed448)] #[cfg(ed448)]
@ -21,6 +22,7 @@ impl KeyType {
KeyType::Rsa2048 | KeyType::Rsa4096 => JwsSignatureAlgorithm::Rs256, KeyType::Rsa2048 | KeyType::Rsa4096 => JwsSignatureAlgorithm::Rs256,
KeyType::EcdsaP256 => JwsSignatureAlgorithm::Es256, KeyType::EcdsaP256 => JwsSignatureAlgorithm::Es256,
KeyType::EcdsaP384 => JwsSignatureAlgorithm::Es384, KeyType::EcdsaP384 => JwsSignatureAlgorithm::Es384,
KeyType::EcdsaP521 => JwsSignatureAlgorithm::Es512,
#[cfg(ed25519)] #[cfg(ed25519)]
KeyType::Ed25519 => JwsSignatureAlgorithm::Ed25519, KeyType::Ed25519 => JwsSignatureAlgorithm::Ed25519,
#[cfg(ed448)] #[cfg(ed448)]
@ -31,7 +33,9 @@ impl KeyType {
pub fn check_alg_compatibility(&self, alg: &JwsSignatureAlgorithm) -> Result<(), Error> { pub fn check_alg_compatibility(&self, alg: &JwsSignatureAlgorithm) -> Result<(), Error> {
let ok = match self { let ok = match self {
KeyType::Rsa2048 | KeyType::Rsa4096 => *alg == JwsSignatureAlgorithm::Rs256, 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)] #[cfg(ed25519)]
KeyType::Ed25519 => *alg == self.get_default_signature_alg(), KeyType::Ed25519 => *alg == self.get_default_signature_alg(),
#[cfg(ed448)] #[cfg(ed448)]
@ -54,6 +58,7 @@ impl KeyType {
"rsa4096", "rsa4096",
"ecdsa-p256", "ecdsa-p256",
"ecdsa-p384", "ecdsa-p384",
"ecdsa-p521",
#[cfg(ed25519)] #[cfg(ed25519)]
"ed25519", "ed25519",
#[cfg(ed448)] #[cfg(ed448)]
@ -71,6 +76,7 @@ impl FromStr for KeyType {
"rsa4096" => Ok(KeyType::Rsa4096), "rsa4096" => Ok(KeyType::Rsa4096),
"ecdsa_p256" => Ok(KeyType::EcdsaP256), "ecdsa_p256" => Ok(KeyType::EcdsaP256),
"ecdsa_p384" => Ok(KeyType::EcdsaP384), "ecdsa_p384" => Ok(KeyType::EcdsaP384),
"ecdsa_p521" => Ok(KeyType::EcdsaP521),
#[cfg(ed25519)] #[cfg(ed25519)]
"ed25519" => Ok(KeyType::Ed25519), "ed25519" => Ok(KeyType::Ed25519),
#[cfg(ed448)] #[cfg(ed448)]
@ -87,6 +93,7 @@ impl fmt::Display for KeyType {
KeyType::Rsa4096 => "rsa4096", KeyType::Rsa4096 => "rsa4096",
KeyType::EcdsaP256 => "ecdsa-p256", KeyType::EcdsaP256 => "ecdsa-p256",
KeyType::EcdsaP384 => "ecdsa-p384", KeyType::EcdsaP384 => "ecdsa-p384",
KeyType::EcdsaP521 => "ecdsa-p521",
#[cfg(ed25519)] #[cfg(ed25519)]
KeyType::Ed25519 => "ed25519", KeyType::Ed25519 => "ed25519",
#[cfg(ed448)] #[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() { Id::EC => match $key.ec_key()?.group().curve_name() {
Some(Nid::X9_62_PRIME256V1) => KeyType::EcdsaP256, Some(Nid::X9_62_PRIME256V1) => KeyType::EcdsaP256,
Some(Nid::SECP384R1) => KeyType::EcdsaP384, Some(Nid::SECP384R1) => KeyType::EcdsaP384,
Some(Nid::SECP521R1) => KeyType::EcdsaP521,
Some(nid) => { Some(nid) => {
return Err(format!("{:?}: unsupported EC key", nid).into()); 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)] #[derive(Clone, Debug)]
pub struct KeyPair { pub struct KeyPair {
pub key_type: KeyType, pub key_type: KeyType,
@ -95,6 +111,7 @@ impl KeyPair {
JwsSignatureAlgorithm::Rs256 => self.sign_rsa(&MessageDigest::sha256(), data), JwsSignatureAlgorithm::Rs256 => self.sign_rsa(&MessageDigest::sha256(), data),
JwsSignatureAlgorithm::Es256 => self.sign_ecdsa(&HashFunction::Sha256, data), JwsSignatureAlgorithm::Es256 => self.sign_ecdsa(&HashFunction::Sha256, data),
JwsSignatureAlgorithm::Es384 => self.sign_ecdsa(&HashFunction::Sha384, data), JwsSignatureAlgorithm::Es384 => self.sign_ecdsa(&HashFunction::Sha384, data),
JwsSignatureAlgorithm::Es512 => self.sign_ecdsa(&HashFunction::Sha512, data),
#[cfg(ed25519)] #[cfg(ed25519)]
JwsSignatureAlgorithm::Ed25519 => self.sign_eddsa(data), JwsSignatureAlgorithm::Ed25519 => self.sign_eddsa(data),
#[cfg(ed448)] #[cfg(ed448)]
@ -112,8 +129,16 @@ impl KeyPair {
fn sign_ecdsa(&self, hash_func: &HashFunction, data: &[u8]) -> Result<Vec<u8>, Error> { fn sign_ecdsa(&self, hash_func: &HashFunction, data: &[u8]) -> Result<Vec<u8>, Error> {
let fingerprint = hash_func.hash(data); let fingerprint = hash_func.hash(data);
let signature = EcdsaSig::sign(&fingerprint, self.inner_key.ec_key()?.as_ref())?; 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; let mut signature = r;
signature.append(&mut s); signature.append(&mut s);
Ok(signature) Ok(signature)
@ -137,7 +162,9 @@ impl KeyPair {
fn get_jwk_public_key(&self, thumbprint: bool) -> Result<Value, Error> { fn get_jwk_public_key(&self, thumbprint: bool) -> Result<Value, Error> {
match self.key_type { match self.key_type {
KeyType::Rsa2048 | KeyType::Rsa4096 => self.get_rsa_jwk(thumbprint), 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)] #[cfg(ed25519)]
KeyType::Ed25519 => self.get_eddsa_jwk(thumbprint), KeyType::Ed25519 => self.get_eddsa_jwk(thumbprint),
#[cfg(ed448)] #[cfg(ed448)]
@ -173,6 +200,7 @@ impl KeyPair {
let (crv, alg, curve) = match self.key_type { let (crv, alg, curve) = match self.key_type {
KeyType::EcdsaP256 => ("P-256", "ES256", Nid::X9_62_PRIME256V1), KeyType::EcdsaP256 => ("P-256", "ES256", Nid::X9_62_PRIME256V1),
KeyType::EcdsaP384 => ("P-384", "ES384", Nid::SECP384R1), KeyType::EcdsaP384 => ("P-384", "ES384", Nid::SECP384R1),
KeyType::EcdsaP521 => ("P-521", "ES512", Nid::SECP521R1),
_ => { _ => {
return Err("not an ECDSA elliptic curve".into()); 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::Rsa4096 => gen_rsa_pair(4096),
KeyType::EcdsaP256 => gen_ec_pair(Nid::X9_62_PRIME256V1), KeyType::EcdsaP256 => gen_ec_pair(Nid::X9_62_PRIME256V1),
KeyType::EcdsaP384 => gen_ec_pair(Nid::SECP384R1), KeyType::EcdsaP384 => gen_ec_pair(Nid::SECP384R1),
KeyType::EcdsaP521 => gen_ec_pair(Nid::SECP521R1),
#[cfg(ed25519)] #[cfg(ed25519)]
KeyType::Ed25519 => gen_ed25519_pair(), KeyType::Ed25519 => gen_ed25519_pair(),
#[cfg(ed448)] #[cfg(ed448)]

6
man/en/acmed.toml.5

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

Loading…
Cancel
Save