diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e04729..6f2d362 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Fixed +- A race condition when requesting multiple certificates on the same non-existent account has been fixed. + + ## [0.6.0] - 2019-06-05 ### Added diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3a56356..62b840b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -26,6 +26,10 @@ The [openssl](https://crates.io/crates/openssl) crate does not expose the Asn1Ti - https://github.com/sfackler/rust-openssl/issues/687 - https://github.com/sfackler/rust-openssl/pull/673 +An other improvement that would be appreciable is to add Curve 25519 support. + +- https://github.com/sfackler/rust-openssl/issues/947 + ## Improving the code diff --git a/acme_common/Cargo.toml b/acme_common/Cargo.toml index eed0737..7eb21da 100644 --- a/acme_common/Cargo.toml +++ b/acme_common/Cargo.toml @@ -7,6 +7,7 @@ repository = "https://github.com/breard-r/libreauth" readme = "../README.md" license = "MIT OR Apache-2.0" include = ["src/**/*", "Cargo.toml", "Licence_*.txt"] +publish = false [lib] name = "acme_common" diff --git a/acme_common/src/crypto/openssl_keys.rs b/acme_common/src/crypto/openssl_keys.rs index 9e6ca39..368c4ce 100644 --- a/acme_common/src/crypto/openssl_keys.rs +++ b/acme_common/src/crypto/openssl_keys.rs @@ -8,6 +8,7 @@ use openssl::nid::Nid; use openssl::pkey::{Id, PKey, Private}; use openssl::rsa::Rsa; use serde_json::json; +use serde_json::value::Value; macro_rules! get_key_type { ($key: expr) => { @@ -76,39 +77,28 @@ impl KeyPair { } } - pub fn get_jwk_thumbprint(&self) -> Result { - // TODO: implement Curve25519 and RSA JWK thumbprint + pub fn jwk_public_key(&self) -> Result { + self.get_jwk_public_key(false) + } + + pub fn jwk_public_key_thumbprint(&self) -> Result { + self.get_jwk_public_key(true) + } + + fn get_jwk_public_key(&self, thumbprint: bool) -> Result { match self.key_type { KeyType::Curve25519 => Err("Curve25519 thumbprint are not implemented yet".into()), - KeyType::EcdsaP256 | KeyType::EcdsaP384 => self.get_nist_ec_jwk(), + KeyType::EcdsaP256 | KeyType::EcdsaP384 => self.get_nist_ec_jwk(thumbprint), KeyType::Rsa2048 | KeyType::Rsa4096 => { Err("RSA jwk thumbprint are not implemented yet".into()) } } } - fn get_nist_ec_jwk(&self) -> Result { - let (x, y) = self.get_nist_ec_coordinates()?; - let crv = match self.key_type { - KeyType::EcdsaP256 => "P-256", - KeyType::EcdsaP384 => "P-384", - _ => { - return Err("Not a NIST elliptic curve.".into()); - } - }; - let jwk = json!({ - "crv": crv, - "kty": "EC", - "x": x, - "y": y, - }); - Ok(jwk.to_string()) - } - - pub fn get_nist_ec_coordinates(&self) -> Result<(String, String), Error> { - let curve = match self.key_type { - KeyType::EcdsaP256 => Nid::X9_62_PRIME256V1, - KeyType::EcdsaP384 => Nid::SECP384R1, + fn get_nist_ec_jwk(&self, thumbprint: bool) -> Result { + let (crv, curve) = match self.key_type { + KeyType::EcdsaP256 => ("P-256", Nid::X9_62_PRIME256V1), + KeyType::EcdsaP384 => ("P-384", Nid::SECP384R1), _ => { return Err("Not a NIST elliptic curve.".into()); } @@ -124,7 +114,24 @@ impl KeyPair { .affine_coordinates_gfp(&group, &mut x, &mut y, &mut ctx)?; let x = b64_encode(&x.to_vec()); let y = b64_encode(&y.to_vec()); - Ok((x, y)) + let jwk = if thumbprint { + json!({ + "crv": crv, + "kty": "EC", + "x": x, + "y": y, + }) + } else { + json!({ + "alg": "ES256", + "crv": crv, + "kty": "EC", + "use": "sig", + "x": x, + "y": y, + }) + }; + Ok(jwk) } } diff --git a/acmed/Cargo.toml b/acmed/Cargo.toml index 584618e..a0db3fc 100644 --- a/acmed/Cargo.toml +++ b/acmed/Cargo.toml @@ -10,6 +10,7 @@ readme = "../README.md" license = "MIT OR Apache-2.0" include = ["src/**/*", "Cargo.toml", "LICENSE-*.txt"] build = "build.rs" +publish = false [dependencies] acme_common = { path = "../acme_common" } diff --git a/acmed/src/acme_proto/structs/authorization.rs b/acmed/src/acme_proto/structs/authorization.rs index 656129d..42b69b5 100644 --- a/acmed/src/acme_proto/structs/authorization.rs +++ b/acmed/src/acme_proto/structs/authorization.rs @@ -155,8 +155,8 @@ pub struct TokenChallenge { impl TokenChallenge { fn key_authorization(&self, key_pair: &KeyPair) -> Result { - let thumbprint = key_pair.get_jwk_thumbprint()?; - let thumbprint = sha256(thumbprint.as_bytes()); + let thumbprint = key_pair.jwk_public_key_thumbprint()?; + let thumbprint = sha256(thumbprint.to_string().as_bytes()); let thumbprint = b64_encode(&thumbprint); let auth = format!("{}.{}", self.token, thumbprint); Ok(auth) diff --git a/acmed/src/certificate.rs b/acmed/src/certificate.rs index 1e86921..6a67b13 100644 --- a/acmed/src/certificate.rs +++ b/acmed/src/certificate.rs @@ -1,6 +1,6 @@ use crate::acme_proto::Challenge; -use crate::config::{Account, Domain, HookType}; -use crate::hooks::{self, ChallengeHookData, Hook, HookEnvData, PostOperationHookData}; +use crate::config::{Account, Domain}; +use crate::hooks::{self, ChallengeHookData, Hook, HookEnvData, HookType, PostOperationHookData}; use crate::storage::{certificate_files_exists, get_certificate}; use acme_common::crypto::X509Certificate; use acme_common::error::Error; diff --git a/acmed/src/hooks.rs b/acmed/src/hooks.rs index e5ca0aa..ad7e5c3 100644 --- a/acmed/src/hooks.rs +++ b/acmed/src/hooks.rs @@ -1,5 +1,5 @@ use crate::certificate::Certificate; -use crate::config::HookType; +pub use crate::config::HookType; use acme_common::error::Error; use handlebars::Handlebars; use serde::Serialize; diff --git a/acmed/src/jws.rs b/acmed/src/jws.rs index 31617d4..3638cab 100644 --- a/acmed/src/jws.rs +++ b/acmed/src/jws.rs @@ -3,9 +3,9 @@ use acme_common::b64_encode; use acme_common::crypto::{sha256, KeyPair}; use acme_common::error::Error; use serde::Serialize; +use serde_json::value::Value; pub mod algorithms; -mod jwk; #[derive(Serialize)] struct JwsData { @@ -17,7 +17,7 @@ struct JwsData { #[derive(Serialize)] struct JwsProtectedHeaderJwk { alg: String, - jwk: jwk::Jwk, + jwk: Value, nonce: String, url: String, } @@ -55,7 +55,7 @@ pub fn encode_jwk( let sign_alg = SignatureAlgorithm::from_pkey(key_pair)?; let protected = JwsProtectedHeaderJwk { alg: sign_alg.to_string(), - jwk: sign_alg.get_jwk(key_pair)?, + jwk: key_pair.jwk_public_key()?, nonce: nonce.into(), url: url.into(), }; diff --git a/acmed/src/jws/algorithms.rs b/acmed/src/jws/algorithms.rs index aed4ffd..fa04648 100644 --- a/acmed/src/jws/algorithms.rs +++ b/acmed/src/jws/algorithms.rs @@ -1,4 +1,3 @@ -use super::jwk::{Es256Jwk, Jwk}; use acme_common::crypto::{gen_keypair, KeyPair, KeyType}; use acme_common::error::Error; use std::fmt; @@ -37,12 +36,6 @@ impl SignatureAlgorithm { } } - pub fn get_jwk(&self, key_pair: &KeyPair) -> Result { - let (x, y) = key_pair.get_nist_ec_coordinates()?; - let jwk = Jwk::Es256(Es256Jwk::new(&x, &y)); - Ok(jwk) - } - pub fn gen_key_pair(&self) -> Result { match self { SignatureAlgorithm::Es256 => gen_keypair(KeyType::EcdsaP256), diff --git a/acmed/src/jws/jwk.rs b/acmed/src/jws/jwk.rs deleted file mode 100644 index 7448bf3..0000000 --- a/acmed/src/jws/jwk.rs +++ /dev/null @@ -1,31 +0,0 @@ -use serde::Serialize; - -#[derive(Serialize)] -#[serde(untagged)] -pub enum Jwk { - Es256(Es256Jwk), -} - -#[derive(Serialize)] -pub struct Es256Jwk { - kty: String, - #[serde(rename = "use")] - jwk_use: String, - crv: String, - alg: String, - x: String, - y: String, -} - -impl Es256Jwk { - pub fn new(x: &str, y: &str) -> Self { - Es256Jwk { - kty: "EC".into(), - jwk_use: "sig".into(), - crv: "P-256".into(), - alg: "ES256".into(), - x: x.to_string(), - y: y.to_string(), - } - } -} diff --git a/acmed/src/storage.rs b/acmed/src/storage.rs index 2f17de8..6acad59 100644 --- a/acmed/src/storage.rs +++ b/acmed/src/storage.rs @@ -1,6 +1,5 @@ use crate::certificate::Certificate; -use crate::config::HookType; -use crate::hooks::{self, FileStorageHookData, HookEnvData}; +use crate::hooks::{self, FileStorageHookData, HookEnvData, HookType}; use acme_common::b64_encode; use acme_common::crypto::{KeyPair, X509Certificate}; use acme_common::error::Error; diff --git a/tacd/Cargo.toml b/tacd/Cargo.toml index c443c40..37276d7 100644 --- a/tacd/Cargo.toml +++ b/tacd/Cargo.toml @@ -9,6 +9,7 @@ repository = "https://github.com/breard-r/acmed" readme = "../README.md" license = "MIT OR Apache-2.0" include = ["src/**/*", "Cargo.toml", "LICENSE-*.txt"] +publish = false [dependencies] acme_common = { path = "../acme_common" }