|
|
|
@ -1,11 +1,12 @@ |
|
|
|
|
use std::io::{Read, Write}; |
|
|
|
|
use std::{fs, io, path, sync}; |
|
|
|
|
|
|
|
|
|
use crate::domain::acme::{AccountKey, Certificate}; |
|
|
|
|
use crate::domain::acme::{Certificate, PrivateKey}; |
|
|
|
|
use crate::error; |
|
|
|
|
use crate::error::{MapUnexpected, ToUnexpected}; |
|
|
|
|
|
|
|
|
|
use hex::ToHex; |
|
|
|
|
use serde::{Deserialize, Serialize}; |
|
|
|
|
use sha2::{Digest, Sha256}; |
|
|
|
|
|
|
|
|
|
#[derive(thiserror::Error, Debug)] |
|
|
|
@ -37,8 +38,8 @@ pub enum GetCertificateError { |
|
|
|
|
|
|
|
|
|
#[mockall::automock] |
|
|
|
|
pub trait Store { |
|
|
|
|
fn set_account_key(&self, k: &AccountKey) -> Result<(), error::Unexpected>; |
|
|
|
|
fn get_account_key(&self) -> Result<AccountKey, GetAccountKeyError>; |
|
|
|
|
fn set_account_key(&self, k: &PrivateKey) -> Result<(), error::Unexpected>; |
|
|
|
|
fn get_account_key(&self) -> Result<PrivateKey, GetAccountKeyError>; |
|
|
|
|
|
|
|
|
|
fn set_http01_challenge_key(&self, token: &str, key: &str) -> Result<(), error::Unexpected>; |
|
|
|
|
fn get_http01_challenge_key(&self, token: &str) -> Result<String, GetHttp01ChallengeKeyError>; |
|
|
|
@ -47,15 +48,25 @@ pub trait Store { |
|
|
|
|
fn set_certificate( |
|
|
|
|
&self, |
|
|
|
|
domain: &str, |
|
|
|
|
key: &PrivateKey, |
|
|
|
|
cert: Vec<Certificate>, |
|
|
|
|
) -> Result<(), error::Unexpected>; |
|
|
|
|
|
|
|
|
|
/// Returned vec is guaranteed to have len > 0
|
|
|
|
|
fn get_certificate(&self, domain: &str) -> Result<Vec<Certificate>, GetCertificateError>; |
|
|
|
|
fn get_certificate( |
|
|
|
|
&self, |
|
|
|
|
domain: &str, |
|
|
|
|
) -> Result<(PrivateKey, Vec<Certificate>), GetCertificateError>; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub trait BoxedStore: Store + Send + Sync + Clone + 'static {} |
|
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize)] |
|
|
|
|
struct StoredPKeyCert { |
|
|
|
|
private_key_pem: String, |
|
|
|
|
cert_pems: Vec<String>, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
struct FSStore { |
|
|
|
|
dir_path: path::PathBuf, |
|
|
|
|
} |
|
|
|
@ -86,21 +97,24 @@ impl FSStore { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn certificate_path(&self, domain: &str) -> path::PathBuf { |
|
|
|
|
self.dir_path.join("certificates").join(domain) |
|
|
|
|
self.dir_path |
|
|
|
|
.join("certificates") |
|
|
|
|
.join(domain) |
|
|
|
|
.with_extension("json") |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl BoxedStore for sync::Arc<FSStore> {} |
|
|
|
|
|
|
|
|
|
impl Store for sync::Arc<FSStore> { |
|
|
|
|
fn set_account_key(&self, k: &AccountKey) -> Result<(), error::Unexpected> { |
|
|
|
|
fn set_account_key(&self, k: &PrivateKey) -> Result<(), error::Unexpected> { |
|
|
|
|
let mut file = fs::File::create(self.account_key_path()).map_unexpected()?; |
|
|
|
|
let pem = k.private_key_to_pem_pkcs8().map_unexpected()?; |
|
|
|
|
file.write_all(&pem).map_unexpected()?; |
|
|
|
|
Ok(()) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn get_account_key(&self) -> Result<AccountKey, GetAccountKeyError> { |
|
|
|
|
fn get_account_key(&self) -> Result<PrivateKey, GetAccountKeyError> { |
|
|
|
|
let mut file = fs::File::open(self.account_key_path()).map_err(|e| match e.kind() { |
|
|
|
|
io::ErrorKind::NotFound => GetAccountKeyError::NotFound, |
|
|
|
|
_ => e.to_unexpected().into(), |
|
|
|
@ -109,7 +123,7 @@ impl Store for sync::Arc<FSStore> { |
|
|
|
|
let mut pem = Vec::<u8>::new(); |
|
|
|
|
file.read_to_end(&mut pem).map_unexpected()?; |
|
|
|
|
|
|
|
|
|
let k = AccountKey::private_key_from_pem(&pem).map_unexpected()?; |
|
|
|
|
let k = PrivateKey::private_key_from_pem(&pem).map_unexpected()?; |
|
|
|
|
Ok(k) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -140,38 +154,50 @@ impl Store for sync::Arc<FSStore> { |
|
|
|
|
fn set_certificate( |
|
|
|
|
&self, |
|
|
|
|
domain: &str, |
|
|
|
|
key: &PrivateKey, |
|
|
|
|
cert: Vec<Certificate>, |
|
|
|
|
) -> Result<(), error::Unexpected> { |
|
|
|
|
let cert: Vec<String> = cert |
|
|
|
|
let to_store = StoredPKeyCert { |
|
|
|
|
private_key_pem: String::from_utf8(key.private_key_to_pem_pkcs8().map_unexpected()?) |
|
|
|
|
.map_unexpected()?, |
|
|
|
|
cert_pems: cert |
|
|
|
|
.into_iter() |
|
|
|
|
.map(|cert| { |
|
|
|
|
let cert_pem = cert.to_pem().map_unexpected()?; |
|
|
|
|
let cert_pem = String::from_utf8(cert_pem).map_unexpected()?; |
|
|
|
|
Ok::<String, error::Unexpected>(cert_pem) |
|
|
|
|
}) |
|
|
|
|
.try_collect()?; |
|
|
|
|
.try_collect()?, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
let cert_file = fs::File::create(self.certificate_path(domain)).map_unexpected()?; |
|
|
|
|
|
|
|
|
|
serde_json::to_writer(cert_file, &cert).map_unexpected()?; |
|
|
|
|
serde_json::to_writer(cert_file, &to_store).map_unexpected()?; |
|
|
|
|
|
|
|
|
|
Ok(()) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn get_certificate(&self, domain: &str) -> Result<Vec<Certificate>, GetCertificateError> { |
|
|
|
|
fn get_certificate( |
|
|
|
|
&self, |
|
|
|
|
domain: &str, |
|
|
|
|
) -> Result<(PrivateKey, Vec<Certificate>), GetCertificateError> { |
|
|
|
|
let file = fs::File::open(self.certificate_path(domain)).map_err(|e| match e.kind() { |
|
|
|
|
io::ErrorKind::NotFound => GetCertificateError::NotFound, |
|
|
|
|
_ => e.to_unexpected().into(), |
|
|
|
|
})?; |
|
|
|
|
|
|
|
|
|
let cert: Vec<String> = serde_json::from_reader(file).map_unexpected()?; |
|
|
|
|
let stored: StoredPKeyCert = serde_json::from_reader(file).map_unexpected()?; |
|
|
|
|
|
|
|
|
|
let key = |
|
|
|
|
PrivateKey::private_key_from_pem(stored.private_key_pem.as_bytes()).map_unexpected()?; |
|
|
|
|
|
|
|
|
|
let cert: Vec<Certificate> = cert |
|
|
|
|
let cert: Vec<Certificate> = stored |
|
|
|
|
.cert_pems |
|
|
|
|
.into_iter() |
|
|
|
|
.map(|cert| openssl::x509::X509::from_pem(cert.as_bytes()).map_unexpected()) |
|
|
|
|
.try_collect()?; |
|
|
|
|
|
|
|
|
|
Ok(cert) |
|
|
|
|
Ok((key, cert)) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -187,7 +213,7 @@ mod tests { |
|
|
|
|
|
|
|
|
|
assert!(matches!( |
|
|
|
|
store.get_account_key(), |
|
|
|
|
Err::<AccountKey, GetAccountKeyError>(GetAccountKeyError::NotFound) |
|
|
|
|
Err::<PrivateKey, GetAccountKeyError>(GetAccountKeyError::NotFound) |
|
|
|
|
)); |
|
|
|
|
|
|
|
|
|
let k = acme2::gen_rsa_private_key(4096).expect("private key generated"); |
|
|
|
|