Browse Source

Add support for RSA 2048 account keys

pull/39/head
Rodolphe Breard 4 years ago
parent
commit
eabcddb0af
  1. 40
      acme_common/src/crypto/openssl_keys.rs
  2. 48
      acme_common/src/lib.rs
  3. 2
      acme_common/src/tests.rs
  4. 266
      acme_common/src/tests/crypto_keys.rs
  5. 42
      acme_common/src/tests/idna.rs
  6. 4
      acmed/src/jws.rs
  7. 6
      acmed/src/jws/algorithms.rs

40
acme_common/src/crypto/openssl_keys.rs

@ -4,9 +4,11 @@ use crate::error::Error;
use openssl::bn::{BigNum, BigNumContext}; use openssl::bn::{BigNum, BigNumContext};
use openssl::ec::{Asn1Flag, EcGroup, EcKey}; use openssl::ec::{Asn1Flag, EcGroup, EcKey};
use openssl::ecdsa::EcdsaSig; use openssl::ecdsa::EcdsaSig;
use openssl::hash::MessageDigest;
use openssl::nid::Nid; use openssl::nid::Nid;
use openssl::pkey::{Id, PKey, Private}; use openssl::pkey::{Id, PKey, Private};
use openssl::rsa::Rsa; use openssl::rsa::Rsa;
use openssl::sign::Signer;
use serde_json::json; use serde_json::json;
use serde_json::value::Value; use serde_json::value::Value;
@ -14,8 +16,8 @@ macro_rules! get_key_type {
($key: expr) => { ($key: expr) => {
match $key.id() { match $key.id() {
Id::RSA => match $key.rsa()?.size() { Id::RSA => match $key.rsa()?.size() {
2048 => KeyType::Rsa2048,
4096 => KeyType::Rsa4096,
256 => KeyType::Rsa2048,
512 => KeyType::Rsa4096,
s => { s => {
return Err(format!("{}: unsupported RSA key size", s).into()); return Err(format!("{}: unsupported RSA key size", s).into());
} }
@ -74,8 +76,10 @@ impl KeyPair {
Ok(signature) Ok(signature)
} }
KeyType::Rsa2048 | KeyType::Rsa4096 => { KeyType::Rsa2048 | KeyType::Rsa4096 => {
// TODO: implement RSA signatures
Err("RSA signatures are not implemented yet".into())
let mut signer = Signer::new(MessageDigest::sha256(), &self.inner_key)?;
signer.update(data)?;
let signature = signer.sign_to_vec()?;
Ok(signature)
} }
} }
} }
@ -92,12 +96,34 @@ impl KeyPair {
match self.key_type { match self.key_type {
KeyType::Curve25519 => Err("Curve25519 thumbprint are not implemented yet".into()), KeyType::Curve25519 => Err("Curve25519 thumbprint are not implemented yet".into()),
KeyType::EcdsaP256 | KeyType::EcdsaP384 => self.get_nist_ec_jwk(thumbprint), KeyType::EcdsaP256 | KeyType::EcdsaP384 => self.get_nist_ec_jwk(thumbprint),
KeyType::Rsa2048 | KeyType::Rsa4096 => {
Err("RSA jwk thumbprint are not implemented yet".into())
}
KeyType::Rsa2048 | KeyType::Rsa4096 => self.get_rsa_jwk(thumbprint),
} }
} }
fn get_rsa_jwk(&self, thumbprint: bool) -> Result<Value, Error> {
let rsa = self.inner_key.rsa().unwrap();
let e = rsa.e();
let n = rsa.n();
let e = b64_encode(&e.to_vec());
let n = b64_encode(&n.to_vec());
let jwk = if thumbprint {
json!({
"kty": "RSA",
"e": e,
"n": n,
})
} else {
json!({
"alg": "RS256",
"kty": "RSA",
"use": "sig",
"e": e,
"n": n,
})
};
Ok(jwk)
}
fn get_nist_ec_jwk(&self, thumbprint: bool) -> Result<Value, Error> { fn get_nist_ec_jwk(&self, thumbprint: bool) -> Result<Value, Error> {
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),

48
acme_common/src/lib.rs

@ -6,6 +6,8 @@ use std::{fs, process};
pub mod crypto; pub mod crypto;
pub mod error; pub mod error;
pub mod logs; pub mod logs;
#[cfg(test)]
mod tests;
macro_rules! exit_match { macro_rules! exit_match {
($e: expr) => { ($e: expr) => {
@ -63,49 +65,3 @@ pub fn clean_pid_file(pid_file: Option<&str>) -> Result<(), error::Error> {
} }
Ok(()) Ok(())
} }
#[cfg(test)]
mod tests {
use super::to_idna;
#[test]
fn test_no_idna() {
let idna_res = to_idna("HeLo.example.com");
assert!(idna_res.is_ok());
assert_eq!(idna_res.unwrap(), "helo.example.com");
}
#[test]
fn test_simple_idna() {
let idna_res = to_idna("Hélo.Example.com");
assert!(idna_res.is_ok());
assert_eq!(idna_res.unwrap(), "xn--hlo-bma.example.com");
}
#[test]
fn test_multiple_idna() {
let idna_res = to_idna("ns1.hÉlo.aç-éièè.example.com");
assert!(idna_res.is_ok());
assert_eq!(
idna_res.unwrap(),
"ns1.xn--hlo-bma.xn--a-i-2lahae.example.com"
);
}
#[test]
fn test_already_idna() {
let idna_res = to_idna("xn--hlo-bma.example.com");
assert!(idna_res.is_ok());
assert_eq!(idna_res.unwrap(), "xn--hlo-bma.example.com");
}
#[test]
fn test_mixed_idna_parts() {
let idna_res = to_idna("ns1.xn--hlo-bma.aç-éièè.example.com");
assert!(idna_res.is_ok());
assert_eq!(
idna_res.unwrap(),
"ns1.xn--hlo-bma.xn--a-i-2lahae.example.com"
);
}
}

2
acme_common/src/tests.rs

@ -0,0 +1,2 @@
mod crypto_keys;
mod idna;

266
acme_common/src/tests/crypto_keys.rs

@ -0,0 +1,266 @@
use crate::crypto::KeyPair;
const KEY_ECDSA_P256_PEM: &str = r#"-----BEGIN PRIVATE KEY-----
MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCCQc9OXwvygYqOFT4fN
NpXynr1lu+1sSplFdYoWu7hE4g==
-----END PRIVATE KEY-----"#;
const KEY_ECDSA_P384_PEM: &str = r#"-----BEGIN PRIVATE KEY-----
ME4CAQAwEAYHKoZIzj0CAQYFK4EEACIENzA1AgEBBDCMsN9kHPueLABk+0PKi7WO
PO2/53dpt/yV5zOPrYPEoKs4t973nbt46IUN19lLF/s=
-----END PRIVATE KEY-----"#;
const KEY_RSA_2048_PEM: &str = r#"-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCzfwZGF8zKNAg2
9mdZ9ieE7V2clY3oeI+2V7eV5kUwOGqhhpDaDyDmju+l0dKFwF8xeDeeGmTSED10
e38ZsHqJF0cZqKDrB3hOeDAsn7Z6stHf/RZozQO5sAmZpN7g0P0lhXJnyAr+WL58
X41kWuufiPVbvURQv/tK3yN2K+rC6MdZ2lLsLemKiwAlbyGrPfUzuVc6dXrU8JvX
kkwuIpAyEEJ7OTXdBaT4VAHHtm2YDWIwW+34Otyp2FvbSJYsIwJjC00t7Phmah9b
MjiypCZB6OknZV7WAZ55jaF/rypARB/zzTieSyn4Qi/VjipWE7nO/GjubyzrJtQm
q+o7Pm71AgMBAAECggEAVAXEFA+UB5svtTrGym/Vs/3A8kl3sjitXTfWck7mWFow
YAgzyj+GsSZ7u+1qVL3mUavqrRHB3CtJ+TrOFmJsGbxRxgsPuLU4ddMBCgKBUxJd
+DHqyYgelE95TvjEdAygU24STc5whvtXv7Si5TVCUt2zrQv97KbRpQyq9ug77pxp
iQGiZ4spUH47TrYtw85HqU1Vb+hJamvcwLv1jv6sKOKv4A4nF3OsqJOqH1FAcFf7
f2Co2Zz83LV6WZ+yFAVG4C1OFMYJABHb3Sq+a5BOipkcCqQqK016NBcIsPvMGTuK
sHUBa2Reh9jLdOehfUa3p+Ir9ZALD+gs5jStRxFqCQKBgQD6Vcpsspsrl069fIJ2
gWd37saM0b0DTqf5Pb3JFKyD5yCyRQD0UtgrUSP8wPxhRtJN0Jku+X1IW3FjLPeg
S/VWEp2nmRTpvHGZ1KYD0gn3RQne8mbt43+f9AwlEfjhvrWDUQhb1TOdCwa/9/xY
HPRM0xV4UiYJG+GVLla4Rbs60wKBgQC3jtvZh/Nd8DwtuS8wXMHQxTLjiHdd6r5n
Lm1m6236NHs7NMA3NlcH9lOP+YfU3I0Ti4CnYI8YWyIrJAbck6maCzLlzUluSzeo
kJ+Ax0/H7DOM0ix7EMkUMCU8m5qi684qg1yngmWobd0Y3aCWjPgQa0oG04+uXb0A
w+GbrB+CFwKBgQDGfF1a4CauYnMZRO7AfYwHiPg+0VH3nFcNBQpEtDKxBwJittmx
3zns5pINJws1Kg03i6zZlRHj3DVEOHRC0dc9ntcH+xWc2kCMgxH6t4AVYdUYw8Qe
3KHltoAmqGBYxXhwHUDuZ1ZcL1DzxvF6/8IoY7mDREdKM6QiP7KcuxVf5wKBgHx/
NnnqDZRvNkHE0k64+vPAbG2Kx3s5lf6hrK4bjDIhmltjweMwxgKufaqvEgO7uyvA
eHgNs8BPP3OHMeg1dtj2M4VNoTpfZda8kJJlnKT6fVRL0MN/dQJuTTM4Tr+ls+V9
x0AN3ylHqqgM2biC0FVCj6jloRQgm+qC8OgG7C/tAoGAeMToPctEvifliZkiyA6P
INrBwWyg3d0Kk3Wlyne3HP9PwS5KrtbKqwkAXsFWNW0HMpG7lMkedvoYjmL71i/5
jIkjfccxlH1fRp/YOZ0wJ4ZWS6G/QgfqmvTeIpEcbokOmBGvHeuFLA8pyzfZa9rP
hEeZwTjgMoKYaVZ4q+23m/0=
-----END PRIVATE KEY-----"#;
const KEY_RSA_4096_PEM: &str = r#"-----BEGIN PRIVATE KEY-----
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
yr9E4nQyE5YlYlPUK6iIRBu9j1N2MhY=
-----END PRIVATE KEY-----"#;
#[test]
fn test_ecdsa_p256_jwk() {
let k = KeyPair::from_pem(KEY_ECDSA_P256_PEM.as_bytes()).unwrap();
let jwk = k.jwk_public_key().unwrap();
assert!(jwk.is_object());
let jwk = jwk.as_object().unwrap();
assert_eq!(jwk.len(), 6);
assert!(jwk.contains_key("kty"));
assert!(jwk.contains_key("crv"));
assert!(jwk.contains_key("x"));
assert!(jwk.contains_key("y"));
assert!(jwk.contains_key("use"));
assert!(jwk.contains_key("alg"));
assert_eq!(jwk.get("kty").unwrap(), "EC");
assert_eq!(jwk.get("crv").unwrap(), "P-256");
assert_eq!(
jwk.get("x").unwrap(),
"VpJrz2a8rASzmbHStuDxNCjQc8ZiDnrGvVeRayNskrQ"
);
assert_eq!(
jwk.get("y").unwrap(),
"GrVCHhF5hN68efEgdoYS7acUT88qhMKQbULVcBgPBUg"
);
assert_eq!(jwk.get("use").unwrap(), "sig");
assert_eq!(jwk.get("alg").unwrap(), "ES256");
}
#[test]
fn test_ecdsa_p256_jwk_thumbprint() {
let k = KeyPair::from_pem(KEY_ECDSA_P256_PEM.as_bytes()).unwrap();
let jwk = k.jwk_public_key_thumbprint().unwrap();
assert!(jwk.is_object());
let jwk = jwk.as_object().unwrap();
assert_eq!(jwk.len(), 4);
assert!(jwk.contains_key("kty"));
assert!(jwk.contains_key("crv"));
assert!(jwk.contains_key("x"));
assert!(jwk.contains_key("y"));
assert!(!jwk.contains_key("use"));
assert!(!jwk.contains_key("alg"));
assert_eq!(jwk.get("kty").unwrap(), "EC");
assert_eq!(jwk.get("crv").unwrap(), "P-256");
assert_eq!(
jwk.get("x").unwrap(),
"VpJrz2a8rASzmbHStuDxNCjQc8ZiDnrGvVeRayNskrQ"
);
assert_eq!(
jwk.get("y").unwrap(),
"GrVCHhF5hN68efEgdoYS7acUT88qhMKQbULVcBgPBUg"
);
}
#[test]
fn test_ecdsa_p384_jwk() {
let k = KeyPair::from_pem(KEY_ECDSA_P384_PEM.as_bytes()).unwrap();
let jwk = k.jwk_public_key().unwrap();
assert!(jwk.is_object());
let jwk = jwk.as_object().unwrap();
assert_eq!(jwk.len(), 6);
assert!(jwk.contains_key("kty"));
assert!(jwk.contains_key("crv"));
assert!(jwk.contains_key("x"));
assert!(jwk.contains_key("y"));
assert!(jwk.contains_key("use"));
assert!(jwk.contains_key("alg"));
assert_eq!(jwk.get("kty").unwrap(), "EC");
assert_eq!(jwk.get("crv").unwrap(), "P-384");
assert_eq!(
jwk.get("x").unwrap(),
"N7TmS8prIp0DAGvwg1saML4UK61oe2PPJTeGLJt0iW-PMNcetFPcMF4WCa0ez80a"
);
assert_eq!(
jwk.get("y").unwrap(),
"RE5dtMDKV9Y8hsKf3fqLzMx75WORJaGswqC68xkRNjo0HcTar4tCB9VF9eSFfTMU"
);
assert_eq!(jwk.get("use").unwrap(), "sig");
assert_eq!(jwk.get("alg").unwrap(), "ES384");
}
#[test]
fn test_ecdsa_p384_jwk_thumbprint() {
let k = KeyPair::from_pem(KEY_ECDSA_P384_PEM.as_bytes()).unwrap();
let jwk = k.jwk_public_key_thumbprint().unwrap();
assert!(jwk.is_object());
let jwk = jwk.as_object().unwrap();
assert_eq!(jwk.len(), 4);
assert!(jwk.contains_key("kty"));
assert!(jwk.contains_key("crv"));
assert!(jwk.contains_key("x"));
assert!(jwk.contains_key("y"));
assert!(!jwk.contains_key("use"));
assert!(!jwk.contains_key("alg"));
assert_eq!(jwk.get("kty").unwrap(), "EC");
assert_eq!(jwk.get("crv").unwrap(), "P-384");
assert_eq!(
jwk.get("x").unwrap(),
"N7TmS8prIp0DAGvwg1saML4UK61oe2PPJTeGLJt0iW-PMNcetFPcMF4WCa0ez80a"
);
assert_eq!(
jwk.get("y").unwrap(),
"RE5dtMDKV9Y8hsKf3fqLzMx75WORJaGswqC68xkRNjo0HcTar4tCB9VF9eSFfTMU"
);
}
#[test]
fn test_rsa_2048_jwk() {
let k = KeyPair::from_pem(KEY_RSA_2048_PEM.as_bytes()).unwrap();
let jwk = k.jwk_public_key().unwrap();
assert!(jwk.is_object());
let jwk = jwk.as_object().unwrap();
assert_eq!(jwk.len(), 5);
assert!(jwk.contains_key("kty"));
assert!(jwk.contains_key("e"));
assert!(jwk.contains_key("n"));
assert!(jwk.contains_key("use"));
assert!(jwk.contains_key("alg"));
assert_eq!(jwk.get("kty").unwrap(), "RSA");
assert_eq!(jwk.get("e").unwrap(), "AQAB");
assert_eq!(jwk.get("n").unwrap(), "s38GRhfMyjQINvZnWfYnhO1dnJWN6HiPtle3leZFMDhqoYaQ2g8g5o7vpdHShcBfMXg3nhpk0hA9dHt_GbB6iRdHGaig6wd4TngwLJ-2erLR3_0WaM0DubAJmaTe4ND9JYVyZ8gK_li-fF-NZFrrn4j1W71EUL_7St8jdivqwujHWdpS7C3piosAJW8hqz31M7lXOnV61PCb15JMLiKQMhBCezk13QWk-FQBx7ZtmA1iMFvt-Drcqdhb20iWLCMCYwtNLez4ZmofWzI4sqQmQejpJ2Ve1gGeeY2hf68qQEQf8804nksp-EIv1Y4qVhO5zvxo7m8s6ybUJqvqOz5u9Q");
assert_eq!(jwk.get("use").unwrap(), "sig");
assert_eq!(jwk.get("alg").unwrap(), "RS256");
}
#[test]
fn test_rsa_2048_jwk_thumbprint() {
let k = KeyPair::from_pem(KEY_RSA_2048_PEM.as_bytes()).unwrap();
let jwk = k.jwk_public_key_thumbprint().unwrap();
assert!(jwk.is_object());
let jwk = jwk.as_object().unwrap();
assert_eq!(jwk.len(), 3);
assert!(jwk.contains_key("kty"));
assert!(jwk.contains_key("e"));
assert!(jwk.contains_key("n"));
assert!(!jwk.contains_key("use"));
assert!(!jwk.contains_key("alg"));
assert_eq!(jwk.get("kty").unwrap(), "RSA");
assert_eq!(jwk.get("e").unwrap(), "AQAB");
assert_eq!(jwk.get("n").unwrap(), "s38GRhfMyjQINvZnWfYnhO1dnJWN6HiPtle3leZFMDhqoYaQ2g8g5o7vpdHShcBfMXg3nhpk0hA9dHt_GbB6iRdHGaig6wd4TngwLJ-2erLR3_0WaM0DubAJmaTe4ND9JYVyZ8gK_li-fF-NZFrrn4j1W71EUL_7St8jdivqwujHWdpS7C3piosAJW8hqz31M7lXOnV61PCb15JMLiKQMhBCezk13QWk-FQBx7ZtmA1iMFvt-Drcqdhb20iWLCMCYwtNLez4ZmofWzI4sqQmQejpJ2Ve1gGeeY2hf68qQEQf8804nksp-EIv1Y4qVhO5zvxo7m8s6ybUJqvqOz5u9Q");
}
#[test]
fn test_rsa_4096_jwk() {
let k = KeyPair::from_pem(KEY_RSA_4096_PEM.as_bytes()).unwrap();
let jwk = k.jwk_public_key().unwrap();
assert!(jwk.is_object());
let jwk = jwk.as_object().unwrap();
assert_eq!(jwk.len(), 5);
assert!(jwk.contains_key("kty"));
assert!(jwk.contains_key("e"));
assert!(jwk.contains_key("n"));
assert!(jwk.contains_key("use"));
assert!(jwk.contains_key("alg"));
assert_eq!(jwk.get("kty").unwrap(), "RSA");
assert_eq!(jwk.get("e").unwrap(), "AQAB");
assert_eq!(jwk.get("n").unwrap(), "jm0Jh8Zk-aRqUxME0yLeHhBtdDFq6IvVesr_ffFwGqtlI4tIa6MqYuuOE5qlqoBrxt1fpccqGF82j47JqeoWerkNdZxYh1uKGQa9G2vB4OBOFHxYujT-NNPPlwnVPrp1_pjxK0hiOGzZRliNhO65lMbEueQCaLbQ6wstr4aVsWKiw8O4MG8Cc2ZegkWlYg0ZHOAn-uJlAt17NJfX8x576XRwX2KCssPYeyiwBukRne3ahVVqrc35EmV9JH3CxDaG9MeBLo7FUV5P1GNOIs313cbAgdMYV6Ahr2LvsaLucFvhSwmHh42--meDui-0wdFILjrz7MsITZy4xXjl8_zqMZ2dBaO38wP5o9VCfCXaVlD3IYB9A4-Y9IQ6wEVeodzGloPQyddUZ70kZ7O3E1kYu0tBKhoAL1VcKiUvOj1ABGooqf8QIAWCiAWqDqkZJ5HiR61NC9lJ3MH-aqYXzeHUuOxdlfr3oWPQKlRyYoUW93xD4dXjHQyHsIS4gWYE9ZJ9aIomNHj93UPNfR8ScxQTQBJV9Ttgl_vOUdmlasTmo0OXbTLMexzWCVISvUuoBoTcTY4DXCFeYHz3EE3ijJ9fnDkX3SsvV43x8X58py9rEyAQnRxfeahpWEoxW6TA5qBxg1GMBQu6CY2MupqsmI0XHTXzy8xCt4Pqd_a5zP6Wh_E");
assert_eq!(jwk.get("use").unwrap(), "sig");
assert_eq!(jwk.get("alg").unwrap(), "RS256");
}
#[test]
fn test_rsa_4096_jwk_thumbprint() {
let k = KeyPair::from_pem(KEY_RSA_4096_PEM.as_bytes()).unwrap();
let jwk = k.jwk_public_key_thumbprint().unwrap();
assert!(jwk.is_object());
let jwk = jwk.as_object().unwrap();
assert_eq!(jwk.len(), 3);
assert!(jwk.contains_key("kty"));
assert!(jwk.contains_key("e"));
assert!(jwk.contains_key("n"));
assert!(!jwk.contains_key("use"));
assert!(!jwk.contains_key("alg"));
assert_eq!(jwk.get("kty").unwrap(), "RSA");
assert_eq!(jwk.get("e").unwrap(), "AQAB");
assert_eq!(jwk.get("n").unwrap(), "jm0Jh8Zk-aRqUxME0yLeHhBtdDFq6IvVesr_ffFwGqtlI4tIa6MqYuuOE5qlqoBrxt1fpccqGF82j47JqeoWerkNdZxYh1uKGQa9G2vB4OBOFHxYujT-NNPPlwnVPrp1_pjxK0hiOGzZRliNhO65lMbEueQCaLbQ6wstr4aVsWKiw8O4MG8Cc2ZegkWlYg0ZHOAn-uJlAt17NJfX8x576XRwX2KCssPYeyiwBukRne3ahVVqrc35EmV9JH3CxDaG9MeBLo7FUV5P1GNOIs313cbAgdMYV6Ahr2LvsaLucFvhSwmHh42--meDui-0wdFILjrz7MsITZy4xXjl8_zqMZ2dBaO38wP5o9VCfCXaVlD3IYB9A4-Y9IQ6wEVeodzGloPQyddUZ70kZ7O3E1kYu0tBKhoAL1VcKiUvOj1ABGooqf8QIAWCiAWqDqkZJ5HiR61NC9lJ3MH-aqYXzeHUuOxdlfr3oWPQKlRyYoUW93xD4dXjHQyHsIS4gWYE9ZJ9aIomNHj93UPNfR8ScxQTQBJV9Ttgl_vOUdmlasTmo0OXbTLMexzWCVISvUuoBoTcTY4DXCFeYHz3EE3ijJ9fnDkX3SsvV43x8X58py9rEyAQnRxfeahpWEoxW6TA5qBxg1GMBQu6CY2MupqsmI0XHTXzy8xCt4Pqd_a5zP6Wh_E");
}

42
acme_common/src/tests/idna.rs

@ -0,0 +1,42 @@
use crate::to_idna;
#[test]
fn test_no_idna() {
let idna_res = to_idna("HeLo.example.com");
assert!(idna_res.is_ok());
assert_eq!(idna_res.unwrap(), "helo.example.com");
}
#[test]
fn test_simple_idna() {
let idna_res = to_idna("Hélo.Example.com");
assert!(idna_res.is_ok());
assert_eq!(idna_res.unwrap(), "xn--hlo-bma.example.com");
}
#[test]
fn test_multiple_idna() {
let idna_res = to_idna("ns1.hÉlo.aç-éièè.example.com");
assert!(idna_res.is_ok());
assert_eq!(
idna_res.unwrap(),
"ns1.xn--hlo-bma.xn--a-i-2lahae.example.com"
);
}
#[test]
fn test_already_idna() {
let idna_res = to_idna("xn--hlo-bma.example.com");
assert!(idna_res.is_ok());
assert_eq!(idna_res.unwrap(), "xn--hlo-bma.example.com");
}
#[test]
fn test_mixed_idna_parts() {
let idna_res = to_idna("ns1.xn--hlo-bma.aç-éièè.example.com");
assert!(idna_res.is_ok());
assert_eq!(
idna_res.unwrap(),
"ns1.xn--hlo-bma.xn--a-i-2lahae.example.com"
);
}

4
acmed/src/jws.rs

@ -35,9 +35,9 @@ fn get_data(key_pair: &KeyPair, protected: &str, payload: &[u8]) -> Result<Strin
let payload = b64_encode(payload); let payload = b64_encode(payload);
let signing_input = format!("{}.{}", protected, payload); let signing_input = format!("{}.{}", protected, payload);
let hash_func = match key_pair.key_type { let hash_func = match key_pair.key_type {
KeyType::EcdsaP256 | KeyType::Rsa2048 | KeyType::Rsa4096 => sha256,
KeyType::EcdsaP256 => sha256,
KeyType::EcdsaP384 => sha384, KeyType::EcdsaP384 => sha384,
KeyType::Curve25519 => |d: &[u8]| d.to_vec(),
KeyType::Rsa2048 | KeyType::Rsa4096 | KeyType::Curve25519 => |d: &[u8]| d.to_vec(),
}; };
let fingerprint = hash_func(signing_input.as_bytes()); let fingerprint = hash_func(signing_input.as_bytes());
let signature = key_pair.sign(&fingerprint)?; let signature = key_pair.sign(&fingerprint)?;

6
acmed/src/jws/algorithms.rs

@ -5,6 +5,7 @@ use std::str::FromStr;
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub enum SignatureAlgorithm { pub enum SignatureAlgorithm {
Rs256,
Es256, Es256,
Es384, Es384,
} }
@ -12,6 +13,7 @@ pub enum SignatureAlgorithm {
impl fmt::Display for SignatureAlgorithm { impl fmt::Display for SignatureAlgorithm {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let s = match self { let s = match self {
SignatureAlgorithm::Rs256 => "RS256",
SignatureAlgorithm::Es256 => "ES256", SignatureAlgorithm::Es256 => "ES256",
SignatureAlgorithm::Es384 => "ES384", SignatureAlgorithm::Es384 => "ES384",
}; };
@ -24,6 +26,7 @@ impl FromStr for SignatureAlgorithm {
fn from_str(data: &str) -> Result<Self, Self::Err> { fn from_str(data: &str) -> Result<Self, Self::Err> {
match data.to_lowercase().as_str() { match data.to_lowercase().as_str() {
"rs256" => Ok(SignatureAlgorithm::Rs256),
"es256" => Ok(SignatureAlgorithm::Es256), "es256" => Ok(SignatureAlgorithm::Es256),
"es384" => Ok(SignatureAlgorithm::Es384), "es384" => Ok(SignatureAlgorithm::Es384),
_ => Err(format!("{}: unknown signature algorithm", data).into()), _ => Err(format!("{}: unknown signature algorithm", data).into()),
@ -34,6 +37,8 @@ impl FromStr for SignatureAlgorithm {
impl SignatureAlgorithm { impl SignatureAlgorithm {
pub fn from_pkey(key_pair: &KeyPair) -> Result<Self, Error> { pub fn from_pkey(key_pair: &KeyPair) -> Result<Self, Error> {
match key_pair.key_type { match key_pair.key_type {
KeyType::Rsa2048 => Ok(SignatureAlgorithm::Rs256),
KeyType::Rsa4096 => Ok(SignatureAlgorithm::Rs256),
KeyType::EcdsaP256 => Ok(SignatureAlgorithm::Es256), KeyType::EcdsaP256 => Ok(SignatureAlgorithm::Es256),
KeyType::EcdsaP384 => Ok(SignatureAlgorithm::Es384), KeyType::EcdsaP384 => Ok(SignatureAlgorithm::Es384),
t => Err(format!("{}: unsupported key type", t).into()), t => Err(format!("{}: unsupported key type", t).into()),
@ -42,6 +47,7 @@ impl SignatureAlgorithm {
pub fn gen_key_pair(&self) -> Result<KeyPair, Error> { pub fn gen_key_pair(&self) -> Result<KeyPair, Error> {
match self { match self {
SignatureAlgorithm::Rs256 => gen_keypair(KeyType::Rsa2048),
SignatureAlgorithm::Es256 => gen_keypair(KeyType::EcdsaP256), SignatureAlgorithm::Es256 => gen_keypair(KeyType::EcdsaP256),
SignatureAlgorithm::Es384 => gen_keypair(KeyType::EcdsaP384), SignatureAlgorithm::Es384 => gen_keypair(KeyType::EcdsaP384),
} }

Loading…
Cancel
Save