Browse Source

Refactor the hash function interface

pull/39/head
Rodolphe Breard 4 years ago
parent
commit
f640688a3b
  1. 38
      acme_common/src/crypto.rs
  2. 16
      acme_common/src/crypto/openssl_hash.rs
  3. 14
      acme_common/src/crypto/openssl_keys.rs
  4. 1
      acme_common/src/tests.rs
  5. 140
      acme_common/src/tests/hash.rs
  6. 8
      acmed/src/acme_proto/structs/authorization.rs

38
acme_common/src/crypto.rs

@ -1,3 +1,7 @@
use crate::error::Error;
use std::fmt;
use std::str::FromStr;
mod jws_signature_algorithm;
mod key_type;
mod openssl_certificate;
@ -8,8 +12,40 @@ pub const DEFAULT_ALGO: &str = "rsa2048";
pub const TLS_LIB_NAME: &str = env!("ACMED_TLS_LIB_NAME");
pub const TLS_LIB_VERSION: &str = env!("ACMED_TLS_LIB_VERSION");
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum BaseHashFunction {
Sha256,
Sha384,
Sha512,
}
impl FromStr for BaseHashFunction {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Error> {
let s = s.to_lowercase().replace("-", "").replace("_", "");
match s.as_str() {
"sha256" => Ok(BaseHashFunction::Sha256),
"sha384" => Ok(BaseHashFunction::Sha384),
"sha512" => Ok(BaseHashFunction::Sha512),
_ => Err(format!("{}: unknown hash function.", s).into()),
}
}
}
impl fmt::Display for BaseHashFunction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let s = match self {
BaseHashFunction::Sha256 => "sha256",
BaseHashFunction::Sha384 => "sha384",
BaseHashFunction::Sha512 => "sha512",
};
write!(f, "{}", s)
}
}
pub use jws_signature_algorithm::JwsSignatureAlgorithm;
pub use key_type::KeyType;
pub use openssl_certificate::{Csr, X509Certificate};
pub use openssl_hash::{sha256, sha384};
pub use openssl_hash::HashFunction;
pub use openssl_keys::{gen_keypair, KeyPair};

16
acme_common/src/crypto/openssl_hash.rs

@ -1,7 +1,13 @@
pub fn sha256(data: &[u8]) -> Vec<u8> {
openssl::sha::sha256(data).to_vec()
}
use openssl::sha::{sha256, sha384, sha512};
pub type HashFunction = super::BaseHashFunction;
pub fn sha384(data: &[u8]) -> Vec<u8> {
openssl::sha::sha384(data).to_vec()
impl HashFunction {
pub fn hash(&self, data: &[u8]) -> Vec<u8> {
match self {
HashFunction::Sha256 => sha256(data).to_vec(),
HashFunction::Sha384 => sha384(data).to_vec(),
HashFunction::Sha512 => sha512(data).to_vec(),
}
}
}

14
acme_common/src/crypto/openssl_keys.rs

@ -1,5 +1,5 @@
use crate::b64_encode;
use crate::crypto::{JwsSignatureAlgorithm, KeyType};
use crate::crypto::{HashFunction, JwsSignatureAlgorithm, KeyType};
use crate::error::Error;
use openssl::bn::{BigNum, BigNumContext};
use openssl::ec::{Asn1Flag, EcGroup, EcKey};
@ -72,8 +72,8 @@ impl KeyPair {
let _ = self.key_type.check_alg_compatibility(alg)?;
match alg {
JwsSignatureAlgorithm::Rs256 => self.sign_rsa(&MessageDigest::sha256(), data),
JwsSignatureAlgorithm::Es256 => self.sign_ecdsa(&crate::crypto::sha256, data),
JwsSignatureAlgorithm::Es384 => self.sign_ecdsa(&crate::crypto::sha384, data),
JwsSignatureAlgorithm::Es256 => self.sign_ecdsa(&HashFunction::Sha256, data),
JwsSignatureAlgorithm::Es384 => self.sign_ecdsa(&HashFunction::Sha384, data),
#[cfg(ed25519)]
JwsSignatureAlgorithm::Ed25519 => self.sign_eddsa(data),
#[cfg(ed448)]
@ -88,12 +88,8 @@ impl KeyPair {
Ok(signature)
}
fn sign_ecdsa(
&self,
hash_func: &dyn Fn(&[u8]) -> Vec<u8>,
data: &[u8],
) -> Result<Vec<u8>, Error> {
let fingerprint = hash_func(data);
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();

1
acme_common/src/tests.rs

@ -1,4 +1,5 @@
mod certificate;
mod crypto_keys;
mod hash;
mod idna;
mod jws_signature_algorithm;

140
acme_common/src/tests/hash.rs

@ -0,0 +1,140 @@
use crate::crypto::HashFunction;
#[test]
fn test_hash_from_str() {
let test_vectors = vec![
("sha256", HashFunction::Sha256),
("Sha256", HashFunction::Sha256),
("sha-256", HashFunction::Sha256),
("SHA_256", HashFunction::Sha256),
("sha384", HashFunction::Sha384),
("Sha-512", HashFunction::Sha512),
];
for (s, ref_h) in test_vectors {
let h: HashFunction = s.parse().unwrap();
assert_eq!(h, ref_h);
}
}
#[test]
fn test_hash_from_invalid_str() {
let test_vectors = vec!["sha42", "sha", "", "plop"];
for s in test_vectors {
let h = s.parse::<HashFunction>();
assert!(h.is_err());
}
}
#[test]
fn test_hash_sha256() {
let test_vectors = vec![
(
"Hello World!".as_bytes(),
vec![
127, 131, 177, 101, 127, 241, 252, 83, 185, 45, 193, 129, 72, 161, 214, 93, 252,
45, 75, 31, 163, 214, 119, 40, 74, 221, 210, 0, 18, 109, 144, 105,
],
),
(
&[],
vec![
227, 176, 196, 66, 152, 252, 28, 20, 154, 251, 244, 200, 153, 111, 185, 36, 39,
174, 65, 228, 100, 155, 147, 76, 164, 149, 153, 27, 120, 82, 184, 85,
],
),
(
&[
194, 43, 6, 43, 252, 50, 206, 26, 240, 105, 85, 119, 40, 153, 213, 123, 158, 59, 8,
45, 114,
],
vec![
65, 72, 199, 76, 128, 174, 196, 223, 91, 235, 87, 119, 200, 212, 133, 13, 219, 223,
60, 4, 73, 70, 65, 41, 226, 83, 221, 107, 112, 29, 205, 28,
],
),
];
for (data, expected) in test_vectors {
let h = HashFunction::Sha256;
let res = h.hash(data);
assert_eq!(res, expected);
}
}
#[test]
fn test_hash_sha384() {
let test_vectors = vec![
(
"Hello World!".as_bytes(),
vec![
191, 215, 108, 14, 187, 208, 6, 254, 229, 131, 65, 5, 71, 193, 136, 123, 2, 146,
190, 118, 213, 130, 217, 108, 36, 45, 42, 121, 39, 35, 227, 253, 111, 208, 97, 249,
213, 207, 209, 59, 143, 150, 19, 88, 230, 173, 186, 74,
],
),
(
&[],
vec![
56, 176, 96, 167, 81, 172, 150, 56, 76, 217, 50, 126, 177, 177, 227, 106, 33, 253,
183, 17, 20, 190, 7, 67, 76, 12, 199, 191, 99, 246, 225, 218, 39, 78, 222, 191,
231, 111, 101, 251, 213, 26, 210, 241, 72, 152, 185, 91,
],
),
(
&[
194, 43, 6, 43, 252, 50, 206, 26, 240, 105, 85, 119, 40, 153, 213, 123, 158, 59, 8,
45, 114,
],
vec![
170, 126, 84, 2, 141, 91, 106, 70, 80, 53, 98, 101, 184, 3, 34, 146, 130, 238, 146,
221, 113, 197, 154, 91, 4, 208, 229, 15, 8, 179, 51, 29, 224, 200, 187, 127, 9,
243, 29, 171, 189, 124, 60, 39, 3, 74, 171, 156,
],
),
];
for (data, expected) in test_vectors {
let h = HashFunction::Sha384;
let res = h.hash(data);
assert_eq!(res, expected);
}
}
#[test]
fn test_hash_sha512() {
let test_vectors = vec![
(
"Hello World!".as_bytes(),
vec![
134, 24, 68, 214, 112, 78, 133, 115, 254, 195, 77, 150, 126, 32, 188, 254, 243,
212, 36, 207, 72, 190, 4, 230, 220, 8, 242, 189, 88, 199, 41, 116, 51, 113, 1, 94,
173, 137, 28, 195, 207, 28, 157, 52, 180, 146, 100, 181, 16, 117, 27, 31, 249, 229,
55, 147, 123, 196, 107, 93, 111, 244, 236, 200,
],
),
(
&[],
vec![
207, 131, 225, 53, 126, 239, 184, 189, 241, 84, 40, 80, 214, 109, 128, 7, 214, 32,
228, 5, 11, 87, 21, 220, 131, 244, 169, 33, 211, 108, 233, 206, 71, 208, 209, 60,
93, 133, 242, 176, 255, 131, 24, 210, 135, 126, 236, 47, 99, 185, 49, 189, 71, 65,
122, 129, 165, 56, 50, 122, 249, 39, 218, 62,
],
),
(
&[
194, 43, 6, 43, 252, 50, 206, 26, 240, 105, 85, 119, 40, 153, 213, 123, 158, 59, 8,
45, 114,
],
vec![
58, 93, 210, 174, 119, 179, 246, 25, 14, 148, 182, 109, 28, 14, 16, 80, 45, 231,
104, 169, 130, 43, 39, 221, 12, 112, 85, 159, 123, 6, 227, 35, 61, 24, 158, 190,
162, 11, 247, 204, 98, 41, 242, 5, 52, 116, 149, 220, 124, 82, 159, 181, 74, 210,
85, 190, 59, 130, 209, 8, 181, 247, 192, 65,
],
),
];
for (data, expected) in test_vectors {
let h = HashFunction::Sha512;
let res = h.hash(data);
assert_eq!(res, expected);
}
}

8
acmed/src/acme_proto/structs/authorization.rs

@ -1,6 +1,6 @@
use crate::acme_proto::structs::{ApiError, HttpApiError, Identifier};
use acme_common::b64_encode;
use acme_common::crypto::{sha256, KeyPair};
use acme_common::crypto::{HashFunction, KeyPair};
use acme_common::error::Error;
use serde::Deserialize;
use std::fmt;
@ -97,14 +97,14 @@ impl Challenge {
Challenge::Http01(tc) => tc.key_authorization(key_pair),
Challenge::Dns01(tc) => {
let ka = tc.key_authorization(key_pair)?;
let a = sha256(ka.as_bytes());
let a = HashFunction::Sha256.hash(ka.as_bytes());
let a = b64_encode(&a);
Ok(a)
}
Challenge::TlsAlpn01(tc) => {
let acme_ext_name = format!("{}.{}", ACME_OID, ID_PE_ACME_ID);
let ka = tc.key_authorization(key_pair)?;
let proof = sha256(ka.as_bytes());
let proof = HashFunction::Sha256.hash(ka.as_bytes());
let proof_str = proof
.iter()
.map(|e| format!("{:02x}", e))
@ -156,7 +156,7 @@ pub struct TokenChallenge {
impl TokenChallenge {
fn key_authorization(&self, key_pair: &KeyPair) -> Result<String, Error> {
let thumbprint = key_pair.jwk_public_key_thumbprint()?;
let thumbprint = sha256(thumbprint.to_string().as_bytes());
let thumbprint = HashFunction::Sha256.hash(thumbprint.to_string().as_bytes());
let thumbprint = b64_encode(&thumbprint);
let auth = format!("{}.{}", self.token, thumbprint);
Ok(auth)

Loading…
Cancel
Save