use crate::ca_pool::{EpfCaPool, EpfCaPoolOps};
use crate::util::{pretty_print_date, u64_to_st, verifying_key};
use ed25519_dalek::{Signature, SignatureError, Signer, SigningKey, Verifier, VerifyingKey};
use pem::Pem;
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use std::collections::HashMap;
use std::error::Error;
use std::fmt::{Display, Formatter};
use std::time::SystemTime;
pub const EPFPKI_PUBLIC_KEY_LENGTH: usize = 32;
pub const EPFPKI_SIGNATURE_LENGTH: usize = 64;
pub const EPFPKI_SELF_SIGNED_CERTIFICATE: &str =
"0000000000000000000000000000000000000000000000000000000000000000";
pub type EpfPublicKey = VerifyingKey;
pub type EpfPrivateKey = SigningKey;
#[derive(Serialize, Deserialize, PartialEq, Debug, Eq, Clone)]
pub struct EPFCertificate {
pub details: EPFCertificateDetails,
pub fingerprint: String,
#[serde(with = "serde_arrays")]
pub signature: [u8; EPFPKI_SIGNATURE_LENGTH],
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Eq, Clone)]
pub struct EPFCertificateDetails {
pub name: String,
pub not_before: u64,
pub not_after: u64,
pub public_key: [u8; EPFPKI_PUBLIC_KEY_LENGTH],
pub issuer_public_key: [u8; EPFPKI_PUBLIC_KEY_LENGTH],
pub claims: HashMap<String, String>,
}
pub trait EpfPkiSerializable {
const PEM_BANNER: &'static str;
fn as_bytes_pki(&self) -> Result<Vec<u8>, rmp_serde::encode::Error>;
fn from_bytes_pki(bytes: &[u8]) -> Result<Self, rmp_serde::decode::Error>
where
Self: Sized;
fn as_pem(&self) -> Result<Vec<u8>, Box<dyn Error>>;
fn from_pem(bytes: &[u8]) -> Result<Self, Box<dyn Error>>
where
Self: Sized;
}
pub fn fingerprint(cert: &EPFCertificateDetails) -> Result<String, rmp_serde::encode::Error> {
let cert_bytes = rmp_serde::to_vec(cert)?;
let mut hasher = Sha256::new();
hasher.update(cert_bytes);
let hash = hasher.finalize();
Ok(hex::encode(hash))
}
#[derive(Debug)]
pub enum EpfPkiCertificateValidationError {
NoLongerValid { expired_at: SystemTime },
NotValidYet { valid_at: SystemTime },
InvalidCertificateData { e: rmp_serde::encode::Error },
FingerprintDoesNotMatch { expected: String, got: String },
InvalidSignature { e: SignatureError },
ExpiresAfterSigner,
ValidAfterSigner,
}
impl Display for EpfPkiCertificateValidationError {
#[cfg_attr(tarpaulin, ignore)]
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
EpfPkiCertificateValidationError::NoLongerValid { expired_at } => write!(
f,
"Certificate no longer valid (expired at {})",
pretty_print_date(expired_at)
),
EpfPkiCertificateValidationError::NotValidYet { valid_at } => write!(
f,
"Certificate not valid yet (valid at {})",
pretty_print_date(valid_at)
),
EpfPkiCertificateValidationError::InvalidCertificateData { e } => {
write!(f, "Unable to serialize cert data: {}", e)
}
EpfPkiCertificateValidationError::FingerprintDoesNotMatch { expected, got } => write!(
f,
"Fingerprint mismatch (expected {}, got {})",
expected, got
),
EpfPkiCertificateValidationError::InvalidSignature { e } => {
write!(f, "Certificate validation error: {}", e)
}
EpfPkiCertificateValidationError::ExpiresAfterSigner => {
write!(f, "Certificate expires after it's signing certificate")
}
EpfPkiCertificateValidationError::ValidAfterSigner => write!(
f,
"Certificate is valid longer than it's signing certificate"
),
}
}
}
pub trait EpfPkiCertificateOps {
fn recalculate_fingerprint(&mut self) -> Result<(), rmp_serde::encode::Error>;
fn sign(&mut self, private_key: &EpfPrivateKey) -> Result<(), Box<dyn Error>>;
fn verify_with_time(
&self,
time: SystemTime,
ca_pool: &EpfCaPool,
) -> Result<bool, EpfPkiCertificateValidationError>;
fn verify(&self, ca_pool: &EpfCaPool) -> Result<bool, EpfPkiCertificateValidationError>;
}
impl EpfPkiCertificateOps for EPFCertificate {
fn recalculate_fingerprint(&mut self) -> Result<(), rmp_serde::encode::Error> {
self.fingerprint = fingerprint(&self.details)?;
Ok(())
}
fn sign(&mut self, private_key: &EpfPrivateKey) -> Result<(), Box<dyn Error>> {
self.recalculate_fingerprint()?;
self.details.issuer_public_key = *private_key.verifying_key().as_bytes();
let cert_data_bytes = rmp_serde::to_vec(&self.details)?;
let signature = private_key.sign(&cert_data_bytes).to_vec();
self.signature = signature.try_into().unwrap();
self.recalculate_fingerprint()?;
Ok(())
}
fn verify_with_time(
&self,
time: SystemTime,
ca_pool: &EpfCaPool,
) -> Result<bool, EpfPkiCertificateValidationError> {
if u64_to_st(self.details.not_after) < time {
return Err(EpfPkiCertificateValidationError::NoLongerValid {
expired_at: u64_to_st(self.details.not_after),
});
}
if u64_to_st(self.details.not_before) > time {
return Err(EpfPkiCertificateValidationError::NotValidYet {
valid_at: u64_to_st(self.details.not_before),
});
}
let fingerprint_on_cert = fingerprint(&self.details)
.map_err(|e| EpfPkiCertificateValidationError::InvalidCertificateData { e })?;
if fingerprint_on_cert != self.fingerprint {
return Err(EpfPkiCertificateValidationError::FingerprintDoesNotMatch {
expected: self.fingerprint.clone(),
got: fingerprint_on_cert,
});
}
let signature = Signature::from_slice(&self.signature)
.map_err(|e| EpfPkiCertificateValidationError::InvalidSignature { e })?;
let is_self_signed;
let public_key = if self.details.issuer_public_key == self.details.public_key {
is_self_signed = true;
verifying_key(&self.details.public_key)
} else {
is_self_signed = false;
verifying_key(&self.details.issuer_public_key)
};
let cert_data_bytes = rmp_serde::to_vec(&self.details)
.map_err(|e| EpfPkiCertificateValidationError::InvalidCertificateData { e })?;
public_key
.verify(&cert_data_bytes, &signature)
.map_err(|e| EpfPkiCertificateValidationError::InvalidSignature { e })?;
let ca_cert = if is_self_signed {
if let Some(cert) = ca_pool.get_ca(&verifying_key(&self.details.public_key)) {
cert
} else {
return Ok(false);
}
} else if let Some(cert) = ca_pool.get_ca(&verifying_key(&self.details.issuer_public_key)) {
cert
} else {
return Ok(false);
};
if ca_cert.details.not_after < self.details.not_after {
return Err(EpfPkiCertificateValidationError::ExpiresAfterSigner);
}
if ca_cert.details.not_before > self.details.not_before {
return Err(EpfPkiCertificateValidationError::ValidAfterSigner);
}
Ok(true)
}
fn verify(&self, ca_pool: &EpfCaPool) -> Result<bool, EpfPkiCertificateValidationError> {
self.verify_with_time(SystemTime::now(), ca_pool)
}
}
#[cfg_attr(tarpaulin, ignore)]
impl Display for EPFCertificate {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
writeln!(f, "EPFCertificate {{")?;
writeln!(f, "\tDetails: {{")?;
writeln!(f, "\t\tName: {}", self.details.name)?;
writeln!(
f,
"\t\tNot Before: {}",
pretty_print_date(&u64_to_st(self.details.not_before))
)?;
writeln!(
f,
"\t\tNot After: {}",
pretty_print_date(&u64_to_st(self.details.not_after))
)?;
writeln!(
f,
"\t\tPublic Key: {}",
hex::encode(self.details.public_key)
)?;
writeln!(
f,
"\t\tIssuer Public Key: {}",
hex::encode(self.details.issuer_public_key)
)?;
writeln!(f, "\t}}")?;
writeln!(f, "\tFingerprint: {}", self.fingerprint)?;
writeln!(f, "\tSignature: {}", hex::encode(self.signature))?;
writeln!(f, "}}")
}
}
impl EpfPkiSerializable for EPFCertificate {
const PEM_BANNER: &'static str = "EPF CERTIFICATE";
fn as_bytes_pki(&self) -> Result<Vec<u8>, rmp_serde::encode::Error> {
rmp_serde::to_vec(self)
}
fn from_bytes_pki(bytes: &[u8]) -> Result<Self, rmp_serde::decode::Error> {
rmp_serde::from_slice(bytes)
}
fn as_pem(&self) -> Result<Vec<u8>, Box<dyn Error>> {
Ok(
pem::encode(&Pem::new(Self::PEM_BANNER, self.as_bytes_pki()?))
.as_bytes()
.to_vec(),
)
}
fn from_pem(bytes: &[u8]) -> Result<Self, Box<dyn Error>>
where
Self: Sized,
{
let pem = pem::parse(bytes)?;
if pem.tag() != Self::PEM_BANNER {
return Err("Not a certificate".into());
}
Ok(Self::from_bytes_pki(pem.contents())?)
}
}
impl EpfPkiSerializable for EpfPublicKey {
const PEM_BANNER: &'static str = "EPF PUBLIC KEY";
fn as_bytes_pki(&self) -> Result<Vec<u8>, rmp_serde::encode::Error> {
Ok(self.as_bytes().to_vec())
}
fn from_bytes_pki(bytes: &[u8]) -> Result<Self, rmp_serde::decode::Error> {
bytes
.try_into()
.map_err(|_| rmp_serde::decode::Error::LengthMismatch(bytes.len() as u32))
}
fn as_pem(&self) -> Result<Vec<u8>, Box<dyn Error>> {
Ok(
pem::encode(&Pem::new(Self::PEM_BANNER, self.as_bytes().to_vec()))
.as_bytes()
.to_vec(),
)
}
fn from_pem(bytes: &[u8]) -> Result<Self, Box<dyn Error>>
where
Self: Sized,
{
let pem = pem::parse(bytes)?;
if pem.tag() != Self::PEM_BANNER {
return Err("Not a public key".into());
}
Ok(Self::from_bytes(
pem.contents()
.try_into()
.map_err(|_| -> Box<dyn Error> { "Wrong size".into() })?,
)?)
}
}
impl EpfPkiSerializable for EpfPrivateKey {
const PEM_BANNER: &'static str = "EPF PRIVATE KEY";
fn as_bytes_pki(&self) -> Result<Vec<u8>, rmp_serde::encode::Error> {
Ok(self.to_keypair_bytes().to_vec())
}
fn from_bytes_pki(bytes: &[u8]) -> Result<Self, rmp_serde::decode::Error> {
bytes
.try_into()
.map_err(|_| rmp_serde::decode::Error::LengthMismatch(bytes.len() as u32))
}
fn as_pem(&self) -> Result<Vec<u8>, Box<dyn Error>> {
Ok(
pem::encode(&Pem::new(Self::PEM_BANNER, self.as_bytes_pki()?))
.as_bytes()
.to_vec(),
)
}
fn from_pem(bytes: &[u8]) -> Result<Self, Box<dyn Error>>
where
Self: Sized,
{
let pem = pem::parse(bytes)?;
if pem.tag() != Self::PEM_BANNER {
return Err("Incorrect PEM tag".into());
}
Ok(Self::from_keypair_bytes(
pem.contents()
.try_into()
.map_err(|_| -> Box<dyn Error> { "Wrong size".into() })?,
)?)
}
}
#[cfg(test)]
mod tests {
use crate::ca_pool::{EpfCaPool, EpfCaPoolOps};
use crate::pki::{
EPFCertificate, EPFCertificateDetails, EpfPkiCertificateOps,
EpfPkiCertificateValidationError, EpfPkiSerializable, EpfPrivateKey, EpfPublicKey,
EPFPKI_PUBLIC_KEY_LENGTH, EPFPKI_SIGNATURE_LENGTH,
};
use crate::util::{signing_key, verifying_key};
use ed25519_dalek::{SignatureError, SigningKey};
use hex_literal::hex;
use rand::rngs::OsRng;
use std::collections::HashMap;
use std::time::{SystemTime, UNIX_EPOCH};
#[test]
pub fn certificate_serialization() {
assert_eq!(cert().as_bytes_pki().unwrap(), cert_bytes())
}
#[test]
pub fn certificate_deserialization() {
assert_eq!(
EPFCertificate::from_bytes_pki(&cert_bytes()).unwrap(),
cert()
)
}
#[test]
pub fn certificate_serialization_pem() {
assert_eq!(cert().as_pem().unwrap(), cert_pem())
}
#[test]
pub fn certificate_deserialization_pem() {
assert_eq!(EPFCertificate::from_pem(&cert_pem()).unwrap(), cert())
}
#[test]
#[should_panic]
pub fn certificate_deserialization_pem_wrong_tag() {
EPFCertificate::from_pem(&null_public_key_pem()).unwrap();
}
#[test]
pub fn pubkey_serialization() {
assert_eq!(
(verifying_key(&[0u8; 32])).as_bytes_pki().unwrap(),
[0u8; 32].to_vec()
)
}
#[test]
pub fn pubkey_deserialization() {
assert_eq!(
EpfPublicKey::from_bytes(&[0u8; 32]).unwrap(),
verifying_key(&[0u8; 32])
)
}
#[test]
pub fn pubkey_serialization_pem() {
assert_eq!(
(verifying_key(&[0u8; 32])).as_pem().unwrap(),
null_public_key_pem()
)
}
#[test]
pub fn pubkey_deserialization_pem() {
assert_eq!(
EpfPublicKey::from_pem(&null_public_key_pem()).unwrap(),
verifying_key(&[0u8; 32])
)
}
#[test]
#[should_panic]
pub fn pubkey_deserialization_pem_wrong_tag() {
EpfPublicKey::from_pem(&null_private_key_pem()).unwrap();
}
#[test]
pub fn privkey_serialization() {
let priv_key_data = hex!("00000000000000000000000000000000000000000000000000000000000000003B6A27BCCEB6A42D62A3A8D02A6F0D73653215771DE243A63AC048A18B59DA29");
assert_eq!(
(signing_key(&priv_key_data)).as_bytes_pki().unwrap(),
priv_key_data.to_vec()
)
}
#[test]
pub fn privkey_deserialization() {
let priv_key = EpfPrivateKey::generate(&mut OsRng);
assert_eq!(
priv_key.to_keypair_bytes(),
signing_key(&priv_key.to_keypair_bytes()).to_keypair_bytes()
)
}
#[test]
pub fn privkey_serialization_pem() {
let priv_key_data = hex!("00000000000000000000000000000000000000000000000000000000000000003B6A27BCCEB6A42D62A3A8D02A6F0D73653215771DE243A63AC048A18B59DA29");
assert_eq!(
(signing_key(&priv_key_data)).as_pem().unwrap(),
null_private_key_pem()
)
}
#[test]
pub fn privkey_deserialization_pem() {
let priv_key_data = hex!("00000000000000000000000000000000000000000000000000000000000000003B6A27BCCEB6A42D62A3A8D02A6F0D73653215771DE243A63AC048A18B59DA29");
assert_eq!(
EpfPrivateKey::from_pem(&null_private_key_pem())
.unwrap()
.to_keypair_bytes(),
signing_key(&priv_key_data).to_keypair_bytes()
)
}
#[test]
#[should_panic]
pub fn privkey_deserialization_pem_wrong_tag() {
assert_eq!(
EpfPrivateKey::from_pem(&null_public_key_pem())
.unwrap()
.to_keypair_bytes(),
signing_key(&[0u8; 64]).to_keypair_bytes()
)
}
#[test]
pub fn cert_display() {
println!("{}", cert());
}
#[test]
pub fn cert_fingerprinting() {
let mut cert = cert();
cert.recalculate_fingerprint().unwrap();
assert_eq!(
cert.fingerprint,
"922c5cb83633b214d19d9aebf387314fcde67210ff92bd9691fbd059141d6adf"
);
}
#[test]
pub fn cert_validation() {
let private_key = SigningKey::generate(&mut OsRng);
let public_key = private_key.verifying_key();
let private_key2 = SigningKey::generate(&mut OsRng);
let public_key2 = private_key2.verifying_key();
let mut ca_pool = EpfCaPool::new();
let mut ca_cert = EPFCertificate {
details: EPFCertificateDetails {
name: "Testing CA".to_string(),
not_before: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs()
- 10,
not_after: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs()
+ 60,
public_key: *public_key.as_bytes(),
issuer_public_key: [0u8; 32],
claims: Default::default(),
},
fingerprint: "".to_string(),
signature: [0u8; EPFPKI_SIGNATURE_LENGTH],
};
println!("{}", ca_cert);
assert!(ca_cert.verify(&ca_pool).is_err());
ca_cert.sign(&private_key).unwrap();
assert!(!ca_cert.verify(&ca_pool).unwrap());
ca_pool.insert(&ca_cert);
assert!(ca_cert.verify(&ca_pool).unwrap());
ca_pool.insert(&ca_cert);
let mut not_ca_cert = EPFCertificate {
details: EPFCertificateDetails {
name: "Testing Certificate".to_string(),
not_before: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs()
- 10,
not_after: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs()
+ 60,
public_key: *public_key2.as_bytes(),
issuer_public_key: [0u8; 32],
claims: Default::default(),
},
fingerprint: "".to_string(),
signature: [0u8; EPFPKI_SIGNATURE_LENGTH],
};
assert!(not_ca_cert.verify(&ca_pool).is_err());
not_ca_cert.sign(&private_key).unwrap();
assert!(not_ca_cert.verify(&ca_pool).unwrap());
}
#[test]
pub fn certificate_verification_expired() {
let expired_cert = EPFCertificate {
details: EPFCertificateDetails {
name: "Testing Certificate - Expired".to_string(),
not_before: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs(),
not_after: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs()
- 20,
public_key: [0u8; 32],
issuer_public_key: [0u8; 32],
claims: Default::default(),
},
fingerprint: "".to_string(),
signature: [0u8; EPFPKI_SIGNATURE_LENGTH],
};
let ca_pool = EpfCaPool::new();
assert!(matches!(
expired_cert.verify(&ca_pool).unwrap_err(),
EpfPkiCertificateValidationError::NoLongerValid { .. }
))
}
#[test]
pub fn certificate_verification_fingerprint_does_not_match() {
let private_key = SigningKey::generate(&mut OsRng);
let public_key = private_key.verifying_key();
let mut fingerprint_does_not_match_cert = EPFCertificate {
details: EPFCertificateDetails {
name: "Testing Certificate - Fingerprint Non Matching".to_string(),
not_before: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs()
- 20,
not_after: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs()
+ 30,
public_key: [0u8; 32],
issuer_public_key: *public_key.as_bytes(),
claims: Default::default(),
},
fingerprint: "".to_string(),
signature: [0u8; EPFPKI_SIGNATURE_LENGTH],
};
fingerprint_does_not_match_cert.sign(&private_key).unwrap();
fingerprint_does_not_match_cert.fingerprint = "0".to_string();
let ca_pool = EpfCaPool::new();
assert!(matches!(
fingerprint_does_not_match_cert
.verify(&ca_pool)
.unwrap_err(),
EpfPkiCertificateValidationError::FingerprintDoesNotMatch { .. }
));
}
#[test]
pub fn certificate_verification_invalid_signature() {
let private_key = SigningKey::generate(&mut OsRng);
let public_key = private_key.verifying_key();
let mut fingerprint_does_not_match_cert = EPFCertificate {
details: EPFCertificateDetails {
name: "Testing Certificate - Fingerprint Non Matching".to_string(),
not_before: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs()
- 20,
not_after: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs()
+ 30,
public_key: [0u8; 32],
issuer_public_key: *public_key.as_bytes(),
claims: Default::default(),
},
fingerprint: "".to_string(),
signature: [0u8; EPFPKI_SIGNATURE_LENGTH],
};
fingerprint_does_not_match_cert.sign(&private_key).unwrap();
fingerprint_does_not_match_cert.signature = [0u8; 64];
let ca_pool = EpfCaPool::new();
assert!(matches!(
fingerprint_does_not_match_cert
.verify(&ca_pool)
.unwrap_err(),
EpfPkiCertificateValidationError::InvalidSignature { .. }
));
}
#[test]
pub fn certificate_verification_not_valid_yet() {
let not_yet_valid_cert = EPFCertificate {
details: EPFCertificateDetails {
name: "Testing Certificate - Not Yet Valid".to_string(),
not_before: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs()
+ 20,
not_after: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs()
+ 30,
public_key: [0u8; 32],
issuer_public_key: [0u8; 32],
claims: Default::default(),
},
fingerprint: "".to_string(),
signature: [0u8; EPFPKI_SIGNATURE_LENGTH],
};
let ca_pool = EpfCaPool::new();
assert!(matches!(
not_yet_valid_cert.verify(&ca_pool).unwrap_err(),
EpfPkiCertificateValidationError::NotValidYet { .. }
))
}
#[test]
pub fn certificate_verification_not_trusted() {
let private_key = SigningKey::generate(&mut OsRng);
let public_key = private_key.verifying_key();
let mut not_trusted_cert = EPFCertificate {
details: EPFCertificateDetails {
name: "Testing Certificate - Not Trusted".to_string(),
not_before: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs()
- 20,
not_after: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs()
+ 30,
public_key: [0u8; 32],
issuer_public_key: *public_key.as_bytes(),
claims: Default::default(),
},
fingerprint: "".to_string(),
signature: [0u8; EPFPKI_SIGNATURE_LENGTH],
};
not_trusted_cert.sign(&private_key).unwrap();
let ca_pool = EpfCaPool::new();
assert!(!not_trusted_cert.verify(&ca_pool).unwrap());
}
#[test]
pub fn cert_validation_expires_after_signer() {
let private_key = SigningKey::generate(&mut OsRng);
let public_key = private_key.verifying_key();
let private_key2 = SigningKey::generate(&mut OsRng);
let public_key2 = private_key2.verifying_key();
let mut ca_pool = EpfCaPool::new();
let mut ca_cert = EPFCertificate {
details: EPFCertificateDetails {
name: "Testing CA".to_string(),
not_before: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs()
- 10,
not_after: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs()
+ 60,
public_key: *public_key.as_bytes(),
issuer_public_key: [0u8; 32],
claims: Default::default(),
},
fingerprint: "".to_string(),
signature: [0u8; EPFPKI_SIGNATURE_LENGTH],
};
ca_cert.sign(&private_key).unwrap();
ca_pool.insert(&ca_cert);
let mut not_ca_cert = EPFCertificate {
details: EPFCertificateDetails {
name: "Testing Certificate - Valid After Signer".to_string(),
not_before: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs()
- 10,
not_after: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs()
+ 120,
public_key: *public_key2.as_bytes(),
issuer_public_key: [0u8; 32],
claims: Default::default(),
},
fingerprint: "".to_string(),
signature: [0u8; EPFPKI_SIGNATURE_LENGTH],
};
assert!(not_ca_cert.verify(&ca_pool).is_err());
not_ca_cert.sign(&private_key).unwrap();
assert!(matches!(
not_ca_cert.verify(&ca_pool).unwrap_err(),
EpfPkiCertificateValidationError::ExpiresAfterSigner
));
}
#[test]
pub fn cert_validation_valid_after_signer() {
let private_key = SigningKey::generate(&mut OsRng);
let public_key = private_key.verifying_key();
let private_key2 = SigningKey::generate(&mut OsRng);
let public_key2 = private_key2.verifying_key();
let mut ca_pool = EpfCaPool::new();
let mut ca_cert = EPFCertificate {
details: EPFCertificateDetails {
name: "Testing CA".to_string(),
not_before: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs()
- 10,
not_after: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs()
+ 60,
public_key: *public_key.as_bytes(),
issuer_public_key: [0u8; 32],
claims: Default::default(),
},
fingerprint: "".to_string(),
signature: [0u8; EPFPKI_SIGNATURE_LENGTH],
};
ca_cert.sign(&private_key).unwrap();
ca_pool.insert(&ca_cert);
let mut not_ca_cert = EPFCertificate {
details: EPFCertificateDetails {
name: "Testing Certificate - Valid After Signer".to_string(),
not_before: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs()
- 200,
not_after: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs()
+ 10,
public_key: *public_key2.as_bytes(),
issuer_public_key: [0u8; 32],
claims: Default::default(),
},
fingerprint: "".to_string(),
signature: [0u8; EPFPKI_SIGNATURE_LENGTH],
};
assert!(not_ca_cert.verify(&ca_pool).is_err());
not_ca_cert.sign(&private_key).unwrap();
assert!(matches!(
not_ca_cert.verify(&ca_pool).unwrap_err(),
EpfPkiCertificateValidationError::ValidAfterSigner
));
}
#[test]
pub fn verifying_error_display() {
println!(
"{}",
EpfPkiCertificateValidationError::NoLongerValid {
expired_at: SystemTime::now()
}
);
println!(
"{}",
EpfPkiCertificateValidationError::NotValidYet {
valid_at: SystemTime::now()
}
);
println!(
"{}",
EpfPkiCertificateValidationError::InvalidCertificateData {
e: rmp_serde::encode::Error::UnknownLength
}
);
println!(
"{}",
EpfPkiCertificateValidationError::FingerprintDoesNotMatch {
expected: "".to_string(),
got: "".to_string()
}
);
println!(
"{}",
EpfPkiCertificateValidationError::InvalidSignature {
e: SignatureError::new()
}
);
println!("{}", EpfPkiCertificateValidationError::ExpiresAfterSigner);
println!("{}", EpfPkiCertificateValidationError::ValidAfterSigner);
}
fn cert() -> EPFCertificate {
EPFCertificate {
details: EPFCertificateDetails {
name: "Invalid Testing Certificate".to_string(),
not_before: 0,
not_after: 0,
public_key: [0u8; EPFPKI_PUBLIC_KEY_LENGTH],
issuer_public_key: [0u8; EPFPKI_PUBLIC_KEY_LENGTH],
claims: HashMap::new(),
},
fingerprint: "0000000000000000000000000000000000000000000000000000000000000000"
.to_string(),
signature: [0u8; EPFPKI_SIGNATURE_LENGTH],
}
}
fn cert_bytes() -> Vec<u8> {
vec![
147, 150, 187, 73, 110, 118, 97, 108, 105, 100, 32, 84, 101, 115, 116, 105, 110, 103,
32, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 0, 0, 220, 0, 32, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
220, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 128, 217, 64, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 48, 220, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
]
}
fn cert_pem() -> Vec<u8> {
vec![
45, 45, 45, 45, 45, 66, 69, 71, 73, 78, 32, 69, 80, 70, 32, 67, 69, 82, 84, 73, 70, 73,
67, 65, 84, 69, 45, 45, 45, 45, 45, 13, 10, 107, 53, 97, 55, 83, 87, 53, 50, 89, 87,
120, 112, 90, 67, 66, 85, 90, 88, 78, 48, 97, 87, 53, 110, 73, 69, 78, 108, 99, 110,
82, 112, 90, 109, 108, 106, 89, 88, 82, 108, 65, 65, 68, 99, 65, 67, 65, 65, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 13, 10, 65, 65, 65, 65, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 78, 119,
65, 73, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 13, 10, 65, 65, 65, 65, 65,
65, 65, 65, 103, 78, 108, 65, 77, 68, 65, 119, 77, 68, 65, 119, 77, 68, 65, 119, 77,
68, 65, 119, 77, 68, 65, 119, 77, 68, 65, 119, 77, 68, 65, 119, 77, 68, 65, 119, 77,
68, 65, 119, 77, 68, 65, 119, 77, 68, 65, 119, 77, 68, 65, 119, 77, 68, 65, 119, 13,
10, 77, 68, 65, 119, 77, 68, 65, 119, 77, 68, 65, 119, 77, 68, 65, 119, 77, 68, 65,
119, 77, 68, 65, 119, 77, 68, 65, 119, 77, 68, 65, 119, 77, 78, 119, 65, 81, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
65, 65, 65, 13, 10, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 61, 13,
10, 45, 45, 45, 45, 45, 69, 78, 68, 32, 69, 80, 70, 32, 67, 69, 82, 84, 73, 70, 73, 67,
65, 84, 69, 45, 45, 45, 45, 45, 13, 10,
]
}
fn null_public_key_pem() -> Vec<u8> {
vec![
45, 45, 45, 45, 45, 66, 69, 71, 73, 78, 32, 69, 80, 70, 32, 80, 85, 66, 76, 73, 67, 32,
75, 69, 89, 45, 45, 45, 45, 45, 13, 10, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 61, 13, 10, 45, 45, 45, 45, 45, 69, 78, 68, 32, 69,
80, 70, 32, 80, 85, 66, 76, 73, 67, 32, 75, 69, 89, 45, 45, 45, 45, 45, 13, 10,
]
}
fn null_private_key_pem() -> Vec<u8> {
vec![
45, 45, 45, 45, 45, 66, 69, 71, 73, 78, 32, 69, 80, 70, 32, 80, 82, 73, 86, 65, 84, 69,
32, 75, 69, 89, 45, 45, 45, 45, 45, 13, 10, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 55, 97, 105, 101, 56, 122, 114, 97, 107, 76,
87, 75, 106, 113, 78, 65, 113, 98, 119, 49, 122, 13, 10, 90, 84, 73, 86, 100, 120, 51,
105, 81, 54, 89, 54, 119, 69, 105, 104, 105, 49, 110, 97, 75, 81, 61, 61, 13, 10, 45,
45, 45, 45, 45, 69, 78, 68, 32, 69, 80, 70, 32, 80, 82, 73, 86, 65, 84, 69, 32, 75, 69,
89, 45, 45, 45, 45, 45, 13, 10,
]
}
}