use super::basic_crypto_functions::{
BasisCryptoError, CertificateExtension, Keystore as SslKeystore, SigningCertificate,
};
use std::{
fs, io,
path::{Path, PathBuf},
};
use thiserror::Error;
#[derive(Error, Debug)]
#[error(transparent)]
pub struct DirectTrustError(#[from] DirectTrustErrorRepr);
#[derive(Error, Debug)]
enum DirectTrustErrorRepr {
#[error("Error reading password file {path}")]
ReadPassword { path: PathBuf, source: io::Error },
#[error("Error creating the keystore from the file {path}")]
KeystoreFromFile {
path: PathBuf,
source: BasisCryptoError,
},
#[error("Error creating the keystore from the directory {path}")]
KeystoreFromDir {
path: PathBuf,
source: BasisCryptoError,
},
#[error("Error getting the public certificate {authority} from the keystore")]
PublicCertificate {
authority: String,
source: BasisCryptoError,
},
#[error("Error getting the private certificate from the keystore")]
PrivateCertificate { source: BasisCryptoError },
}
pub struct Keystore {
keystore: SslKeystore,
}
impl Keystore {
pub fn from_pkcs12(
keystore_path: &Path,
password_file_path: &Path,
) -> Result<Self, DirectTrustError> {
let pwd = fs::read_to_string(password_file_path).map_err(|e| {
DirectTrustErrorRepr::ReadPassword {
path: password_file_path.to_path_buf(),
source: e,
}
})?;
Ok(Keystore {
keystore: SslKeystore::from_pkcs12(keystore_path, &pwd).map_err(|e| {
DirectTrustErrorRepr::KeystoreFromFile {
path: keystore_path.to_path_buf(),
source: e,
}
})?,
})
}
pub fn from_directory(
keystore_path: &Path,
extension: &CertificateExtension,
) -> Result<Self, DirectTrustError> {
let mut ks = SslKeystore::from_directory(keystore_path).map_err(|e| {
DirectTrustErrorRepr::KeystoreFromDir {
path: keystore_path.to_path_buf(),
source: e,
}
})?;
ks.set_certificate_extension(extension);
Ok(Self { keystore: ks })
}
pub fn public_certificate(
&self,
authority: &str,
) -> Result<DirectTrustCertificate, DirectTrustError> {
let cert = self
.keystore
.get_public_certificate(&String::from(authority))
.map_err(|e| DirectTrustErrorRepr::PublicCertificate {
authority: authority.to_string(),
source: e,
})?;
Ok(DirectTrustCertificate { cert })
}
pub fn secret_key_certificate(&self) -> Result<DirectTrustCertificate, DirectTrustError> {
let cert = self
.keystore
.get_secret_certificate()
.map_err(|e| DirectTrustErrorRepr::PrivateCertificate { source: e })?;
Ok(DirectTrustCertificate { cert })
}
}
#[derive(Clone)]
pub struct DirectTrustCertificate {
cert: SigningCertificate,
}
impl DirectTrustCertificate {
pub fn authority(&self) -> &str {
self.cert.authority()
}
pub fn signing_certificate(&self) -> &SigningCertificate {
&self.cert
}
}
#[cfg(test)]
mod test {
use super::*;
use std::path::PathBuf;
const VERIFIER_KEYSTORE_FILE_NAME: &str = "public_keys_keystore_verifier.p12";
const VERIFIER_PASSWORD_FILE_NAME: &str = "public_keys_keystore_verifier_pw.txt";
const CANTON_KEYSTORE_FILE_NAME: &str = "signing_keystore_canton.p12";
const CANTON_PASSWORD_FILE_NAME: &str = "signing_pw_canton.txt";
fn get_location() -> PathBuf {
Path::new("./").join("test_data").join("direct-trust")
}
#[test]
fn test_create_pkcs12() {
let dt = Keystore::from_pkcs12(
&get_location().join(Path::new(VERIFIER_KEYSTORE_FILE_NAME)),
&get_location().join(Path::new(VERIFIER_PASSWORD_FILE_NAME)),
)
.unwrap();
assert!(dt.public_certificate("canton").is_ok());
assert!(dt.public_certificate("toto").is_err());
assert!(dt.secret_key_certificate().is_err());
let dt = Keystore::from_pkcs12(
&get_location().join(Path::new(CANTON_KEYSTORE_FILE_NAME)),
&get_location().join(Path::new(CANTON_PASSWORD_FILE_NAME)),
)
.unwrap();
assert!(dt.secret_key_certificate().is_ok());
let dt_err = Keystore::from_pkcs12(
Path::new("./toto"),
&get_location().join(Path::new(VERIFIER_PASSWORD_FILE_NAME)),
);
assert!(dt_err.is_err());
}
#[test]
fn test_create_dir() {
let dt =
Keystore::from_directory(&get_location(), &CertificateExtension::default()).unwrap();
assert!(dt.public_certificate("canton").is_ok());
assert!(dt.public_certificate("toto").is_err());
let dt_err =
Keystore::from_directory(Path::new("./toto"), &CertificateExtension::default());
assert!(dt_err.is_err());
}
}