Skip to content

Commit

Permalink
Add support for NIST P-521 curve and ES512 signatures
Browse files Browse the repository at this point in the history
  • Loading branch information
breard-r committed Sep 20, 2020
1 parent 53a6eff commit 8477d92
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 5 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions acme_common/src/crypto/jws_signature_algorithm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub enum JwsSignatureAlgorithm {
Rs256,
Es256,
Es384,
Es512,
#[cfg(ed25519)]
Ed25519,
#[cfg(ed448)]
Expand All @@ -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)]
Expand All @@ -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)]
Expand Down
9 changes: 8 additions & 1 deletion acme_common/src/crypto/key_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub enum KeyType {
Rsa4096,
EcdsaP256,
EcdsaP384,
EcdsaP521,
#[cfg(ed25519)]
Ed25519,
#[cfg(ed448)]
Expand All @@ -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)]
Expand All @@ -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)]
Expand All @@ -54,6 +58,7 @@ impl KeyType {
"rsa4096",
"ecdsa-p256",
"ecdsa-p384",
"ecdsa-p521",
#[cfg(ed25519)]
"ed25519",
#[cfg(ed448)]
Expand All @@ -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)]
Expand All @@ -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)]
Expand Down
35 changes: 32 additions & 3 deletions acme_common/src/crypto/openssl_keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
Expand All @@ -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,
Expand Down Expand Up @@ -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)]
Expand All @@ -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)
Expand All @@ -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)]
Expand Down Expand Up @@ -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());
}
Expand Down Expand Up @@ -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)]
Expand Down
6 changes: 6 additions & 0 deletions man/en/acmed.toml.5
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
Expand Down Expand Up @@ -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:
Expand Down

0 comments on commit 8477d92

Please sign in to comment.