/// Functions for performing cryptographic operations on the main data structures. use super::*; use openssl::{ error::ErrorStack, encrypt::{Encrypter, Decrypter}, pkey::{PKey, Public as OsslPublic, Private as OsslPrivate}, symm::{Cipher, encrypt as openssl_encrypt, decrypt as openssl_decrypt}, rand::rand_bytes, rsa::{Rsa, Padding as OpensslPadding}, hash::{hash, MessageDigest}, sign::{Signer, Verifier} }; use serde_block_tree::{self, to_vec, from_vec, write_to}; use serde::de::{DeserializeOwned}; use std::str::FromStr; use strum_macros::{EnumString, EnumDiscriminants, Display}; /// Data that may or may not be encrypted. #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] pub(crate) enum Cryptotext { /// The inner value of `T` is plaintext. Plain(T), /// The inner value is ciphertext. Cipher(Vec), } /// Errors that can occur during cryptographic operations. #[derive(Debug)] pub(crate) enum Error { NoReadCap, NoKeyAvailable, MissingPrivateKey, KeyVariantUnsupported, BlockNotEncrypted, InvalidHashFormat, Message(String), Serde(serde_block_tree::Error), } impl Display for Error { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { Error::NoReadCap => write!(f, "no readcap"), Error::NoKeyAvailable => write!(f, "no key available"), Error::MissingPrivateKey => write!(f, "private key was missing"), Error::KeyVariantUnsupported => write!(f, "unsupported key variant"), Error::BlockNotEncrypted => write!(f, "block was not encrypted"), Error::InvalidHashFormat => write!(f, "invalid format"), Error::Message(message) => f.write_str(message.as_str()), Error::Serde(serde_err) => serde_err.fmt(f), } } } impl From for Error { fn from(error: ErrorStack) -> Error { Error::Message(error.to_string()) } } impl From for Error { fn from(error: serde_block_tree::Error) -> Error { Error::Serde(error) } } pub(crate) type Result = std::result::Result; /// A cryptographic hash. #[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Hashable, Clone, EnumDiscriminants)] #[strum_discriminants(derive(EnumString, Display))] #[strum_discriminants(name(HashKind))] pub(crate) enum Hash { Sha2_256([u8; 32]), #[serde(with = "BigArray")] Sha2_512([u8; 64]), } impl Default for HashKind { fn default() -> HashKind { HashKind::Sha2_256 } } impl Hash { /// The character that's used to separate a hash type from its value in its string /// representation. const HASH_SEP: char = ':'; fn kind(&self) -> HashKind { HashKind::from(self) } } impl From for Hash { fn from(discriminant: HashKind) -> Hash { match discriminant { HashKind::Sha2_512 => Hash::Sha2_512([0u8; 64]), HashKind::Sha2_256 => Hash::Sha2_256([0u8; 32]) } } } impl AsRef<[u8]> for Hash { fn as_ref(&self) -> &[u8] { match self { Hash::Sha2_256(arr) => arr, Hash::Sha2_512(arr) => arr } } } impl AsMut<[u8]> for Hash { fn as_mut(&mut self) -> &mut [u8] { match self { Hash::Sha2_256(arr) => arr, Hash::Sha2_512(arr) => arr } } } impl TryFrom<&str> for Hash { type Error = Error; fn try_from(string: &str) -> Result { let mut split: Vec<&str> = string.split(Self::HASH_SEP).collect(); if split.len() != 2 { return Err(Error::InvalidHashFormat) }; let second = split.pop().ok_or(Error::InvalidHashFormat)?; let first = split.pop().ok_or(Error::InvalidHashFormat)?; let mut hash = Hash::from(HashKind::from_str(first) .map_err(|_| Error::InvalidHashFormat)?); base64_url::decode_to_slice(second, hash.as_mut()) .map_err(|_| Error::InvalidHashFormat)?; Ok(hash) } } impl Display for Hash { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let hash_type: HashKind = self.into(); let hash_data = base64_url::encode(self.as_ref()); write!(f, "{}{}{}", hash_type, Hash::HASH_SEP, hash_data) } } const RSA_SIG_LEN: usize = 512; /// A cryptographic signature. #[derive(Debug, PartialEq, Serialize, Deserialize, Clone, EnumDiscriminants)] #[strum_discriminants(name(SignatureKind))] pub(crate) enum Signature { #[serde(with = "BigArray")] Rsa([u8; RSA_SIG_LEN]), } impl Signature { fn new(id: SignatureKind) -> Signature { match id { SignatureKind::Rsa => Signature::Rsa([0; RSA_SIG_LEN]) } } fn as_slice(&self) -> &[u8] { match self { Signature::Rsa(buf) => buf.as_slice() } } fn as_mut_slice(&mut self) -> &mut [u8] { match self { Signature::Rsa(buf) => buf.as_mut_slice() } } } impl AsRef<[u8]> for Signature { fn as_ref(&self) -> &[u8] { self.as_slice() } } impl AsMut<[u8]> for Signature { fn as_mut(&mut self) -> &mut [u8] { self.as_mut_slice() } } impl Default for Signature { fn default() -> Self { Signature::Rsa([0; RSA_SIG_LEN]) } } #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] pub(crate) enum RsaPadding { None, Pkcs1, Pkcs1Oaep, Pkcs1Pss, } impl Default for RsaPadding { fn default() -> Self { RsaPadding::Pkcs1 } } impl Copy for RsaPadding {} impl From for OpensslPadding { fn from(padding: RsaPadding) -> OpensslPadding { match padding { RsaPadding::None => OpensslPadding::NONE, RsaPadding::Pkcs1 => OpensslPadding::PKCS1, RsaPadding::Pkcs1Oaep => OpensslPadding::PKCS1_OAEP, RsaPadding::Pkcs1Pss => OpensslPadding::PKCS1_PSS, } } } #[derive(Debug, PartialEq, Serialize, Deserialize, Clone, EnumDiscriminants)] #[strum_discriminants(name(SymKeyKind))] pub(crate) enum SymKey { /// A key for the AES 256 cipher in Cipher Block Chaining mode. Note that this includes the /// initialization vector, so that a value of this variant contains all the information needed /// to fully initialize a cipher context. Aes256Cbc { key: [u8; 32], iv: [u8; 16], }, /// A key for the AES 256 cipher in counter mode. Aes256Ctr { key: [u8; 32], iv: [u8; 16] }, } /// Returns an array of the given length filled with cryptographically random data. fn rand_array() -> Result<[u8; LEN]> { let mut array = [0; LEN]; rand_bytes(&mut array).map_err(Error::from)?; Ok(array) } impl SymKey { pub(crate) fn generate(kind: SymKeyKind) -> Result { match kind { SymKeyKind::Aes256Cbc => { Ok(SymKey::Aes256Cbc { key: rand_array()?, iv: rand_array()? }) }, SymKeyKind::Aes256Ctr => { Ok(SymKey::Aes256Ctr { key: rand_array()?, iv: rand_array()? }) }, } } } #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] pub(crate) struct Public; #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] pub(crate) struct Private; #[derive(Debug, PartialEq, Serialize, Deserialize, Clone, EnumDiscriminants)] #[strum_discriminants(name(AsymKeyKind))] pub(crate) enum AsymKey { Rsa { der: Vec, padding: RsaPadding, kind: T, } } impl AsymKey { pub(crate) fn as_slice(&self) -> &[u8] { match self { AsymKey::Rsa { der, .. } => der.as_slice() } } } impl Owned for AsymKey { fn owner_of_kind(&self, kind: HashKind) -> Principal { match kind { HashKind::Sha2_256 => { let mut buf = [0; 32]; let bytes = hash(MessageDigest::sha256(), self.as_slice()).unwrap(); buf.copy_from_slice(&*bytes); Principal(Hash::Sha2_256(buf)) }, HashKind::Sha2_512 => { let mut buf = [0; 64]; let bytes = hash(MessageDigest::sha512(), self.as_slice()).unwrap(); buf.copy_from_slice(&*bytes); Principal(Hash::Sha2_512(buf)) } } } } pub(crate) struct KeyPair { pub(crate) public: AsymKey, pub(crate) private: AsymKey, } impl KeyPair { pub(crate) fn generate(kind: AsymKeyKind) -> Result { match kind { AsymKeyKind::Rsa => { let key = PKey::from_rsa(Rsa::generate(4096)?)?; let public = key.public_key_to_der().map_err(Error::from)?; let private = key.private_key_to_der().map_err(Error::from)?; Ok(KeyPair { public: AsymKey::Rsa { der: public, padding: RsaPadding::default(), kind: Public, }, private: AsymKey::Rsa { der: private, padding: RsaPadding::default(), kind: Private, }, }) }, } } } impl Owned for KeyPair { fn owner_of_kind(&self, kind: HashKind) -> Principal { self.public.owner_of_kind(kind) } } enum EncryptionAlgo<'a> { Symmetric { cipher: Cipher, key: &'a [u8], iv: Option<&'a [u8]> }, Asymmetric { key: PKey, rsa_padding: Option, } } impl<'a> EncryptionAlgo<'a> { fn encrypt(&self, slice: &[u8]) -> Result> { match self { EncryptionAlgo::Symmetric { cipher, key, iv } => { openssl_encrypt(*cipher, key, *iv, slice).map_err(Error::from) }, EncryptionAlgo::Asymmetric { key, rsa_padding } => { let mut encrypter = Encrypter::new(key).map_err(Error::from)?; if let Some(padding) = rsa_padding { encrypter.set_rsa_padding(*padding).map_err(Error::from)?; } let buffer_len = encrypter.encrypt_len(slice).map_err(Error::from)?; let mut ciphertext = vec![0; buffer_len]; let ciphertext_len = encrypter.encrypt(slice, &mut ciphertext) .map_err(Error::from)?; ciphertext.truncate(ciphertext_len); Ok(ciphertext) } } } } impl<'a> TryFrom<&'a SymKey> for EncryptionAlgo<'a> { type Error = Error; fn try_from(key: &'a SymKey) -> Result> { match key { SymKey::Aes256Cbc { key: key_slice, iv } => Ok(EncryptionAlgo::Symmetric { cipher: Cipher::aes_256_cbc(), key: key_slice, iv: Some(iv), }), SymKey::Aes256Ctr { key: key_slice, iv } => Ok(EncryptionAlgo::Symmetric { cipher: Cipher::aes_256_ctr(), key: key_slice, iv: Some(iv), }), } } } impl<'a> TryFrom<&'a AsymKey> for EncryptionAlgo<'a> { type Error = Error; fn try_from(key: &'a AsymKey) -> Result> { match key { AsymKey::Rsa { der, padding, .. } => { let key = PKey::public_key_from_der(der.as_slice()).map_err(Error::from)?; Ok(EncryptionAlgo::Asymmetric { key, rsa_padding: Some((*padding).into()) }) }, } } } enum DecryptionAlgo<'a> { Symmetric { cipher: Cipher, key: &'a [u8], iv: Option<&'a [u8]> }, Asymmetric(PKey), } impl<'a> DecryptionAlgo<'a> { fn decrypt(&self, slice: &[u8]) -> Result> { match self { DecryptionAlgo::Symmetric { cipher, key, iv } => { openssl_decrypt(*cipher, key, *iv, slice).map_err(Error::from) }, DecryptionAlgo::Asymmetric(pkey) => { let decrypter = Decrypter::new(pkey).map_err(Error::from)?; let buffer_len = decrypter.decrypt_len(slice).map_err(Error::from)?; let mut plaintext = vec![0; buffer_len]; let plaintext_len = decrypter.decrypt(slice, &mut plaintext) .map_err(Error::from)?; plaintext.truncate(plaintext_len); Ok(plaintext) }, } } } impl<'a> TryFrom<&'a SymKey> for DecryptionAlgo<'a> { type Error = Error; fn try_from(key: &'a SymKey) -> Result> { match key { SymKey::Aes256Cbc { key: key_slice, iv } => Ok(DecryptionAlgo::Symmetric { cipher: Cipher::aes_256_cbc(), key: key_slice, iv: Some(iv), }), SymKey::Aes256Ctr { key: key_slice, iv } => Ok(DecryptionAlgo::Symmetric { cipher: Cipher::aes_256_ctr(), key: key_slice, iv: Some(iv), }), } } } impl<'a> TryFrom<&'a AsymKey> for DecryptionAlgo<'a> { type Error = Error; fn try_from(key: &'a AsymKey) -> Result> { match key { AsymKey::Rsa { der, .. } => { let pkey = PKey::private_key_from_der(der.as_slice()).map_err(Error::from); Ok(DecryptionAlgo::Asymmetric(pkey?)) } } } } struct SignAlgo { key: PKey, digest: MessageDigest, signature: Signature } impl SignAlgo { fn sign<'a, I: Iterator>(&mut self, parts: I) -> Result<()> { let mut signer = Signer::new(self.digest, &self.key).map_err(Error::from)?; for part in parts { signer.update(part).map_err(Error::from)?; } let buf = self.signature.as_mut_slice(); signer.sign(buf).map_err(Error::from)?; Ok(()) } } impl TryFrom<&AsymKey> for SignAlgo { type Error = Error; fn try_from(key: &AsymKey) -> Result { match key { AsymKey::Rsa { der, .. } => { let rsa = Rsa::private_key_from_der(der.as_slice()).map_err(Error::from)?; Ok(SignAlgo { key: PKey::from_rsa(rsa).map_err(Error::from)?, digest: MessageDigest::sha256(), signature: Signature::new(SignatureKind::Rsa) }) }, } } } struct VerifyAlgo { key: PKey, digest: MessageDigest, } impl VerifyAlgo { fn verify<'a, I: Iterator>( &'a self, parts: I, signature: &[u8] ) -> Result { let mut verifier = Verifier::new(self.digest, &self.key).map_err(Error::from)?; for part in parts { verifier.update(part).map_err(Error::from)?; } verifier.verify(signature).map_err(Error::from) } } impl TryFrom<&AsymKey> for VerifyAlgo { type Error = Error; fn try_from(key: &AsymKey) -> Result { match key { AsymKey::Rsa { der, .. } => { let rsa = Rsa::public_key_from_der(der.as_slice()).map_err(Error::from)?; Ok(VerifyAlgo { key: PKey::from_rsa(rsa).map_err(Error::from)?, digest: MessageDigest::sha256() }) }, } } } pub(crate) fn encrypt_block( mut block: Block, principal: &Principal, key: &KeyPair ) -> Result { let body = match block.body { Cryptotext::Cipher(_) => return Ok(block), Cryptotext::Plain(body) => body }; let (principal_owned, read_cap) = block.readcaps.remove_entry(principal) .ok_or(Error::NoReadCap)?; let block_key = decrypt(read_cap, &key.private)?; let new_body = encrypt_slice(&body, &block_key)?; block.body = Cryptotext::Cipher(new_body); block.readcaps.insert(principal_owned, encrypt(&block_key, &key.public)?); Ok(block) } pub(crate) fn decrypt_block( mut block: Block, principal: &Principal, key: &AsymKey ) -> Result { let body = match block.body { Cryptotext::Plain(_) => return Ok(block), Cryptotext::Cipher(body) => body }; let (principal_owned, read_cap) = block.readcaps.remove_entry(principal) .ok_or(Error::NoReadCap)?; let block_key = decrypt(read_cap, key)?; let new_body = decrypt_slice(&body, &block_key)?; block.body = Cryptotext::Plain(new_body); block.readcaps.insert(principal_owned, Cryptotext::Plain(block_key)); Ok(block) } fn encrypt<'a, T: Serialize, K: TryInto, Error = Error>>( value: &T, key: K ) -> Result> { let data = to_vec(value).map_err(Error::from)?; let vec = encrypt_slice(&data, key); Ok(Cryptotext::Cipher(vec?)) } fn decrypt<'a, T: Serialize + DeserializeOwned, K: TryInto, Error = Error>>( cryptotext: Cryptotext, key: K ) -> Result { let data = match cryptotext { Cryptotext::Plain(value) => return Ok(value), Cryptotext::Cipher(data) => data }; let vec = decrypt_slice(&data, key); from_vec(&vec?).map_err(Error::from) } fn encrypt_slice<'a, K: TryInto, Error = Error>>( plaintext: &[u8], key: K ) -> Result> { let algo: EncryptionAlgo<'a> = key.try_into()?; algo.encrypt(plaintext) } fn decrypt_slice<'a, K: TryInto, Error = Error>>( ciphertext: &[u8], key: K ) -> Result> { let algo: DecryptionAlgo<'a> = key.try_into()?; algo.decrypt(ciphertext) } #[derive(Serialize)] struct SigHeader<'a> { path: &'a Path, readcaps: &'a HashMap>, writecap: &'a Writecap, } impl<'a> From<&'a Block> for SigHeader<'a> { fn from(block: &'a Block) -> SigHeader<'a> { SigHeader { path: &block.path, readcaps: &block.readcaps, writecap: &block.writecap, } } } fn get_body(block: &Block) -> Result<&[u8]> { let body = match &block.body { Cryptotext::Cipher(body) => body, Cryptotext::Plain(_) => { return Err(Error::BlockNotEncrypted); } }; Ok(body) } pub(crate) fn sign_block( block: &mut Block, writecap: Writecap, priv_key: AsymKey ) -> Result<()> { block.writecap = writecap; let body = get_body(block)?; let sig_header = SigHeader::from(&*block); let header = to_vec(&sig_header)?; let mut sign_algo = SignAlgo::try_from(&priv_key)?; sign_algo.sign([header.as_slice(), body].into_iter())?; block.signature = sign_algo.signature; Ok(()) } pub(crate) fn verify_block(block: &Block) -> Result { let body = get_body(block)?; let sig_header = SigHeader::from(&*block); let header = to_vec(&sig_header)?; let verify_algo = VerifyAlgo::try_from(&block.writecap.signing_key)?; let parts = [header.as_slice(), body].into_iter(); Ok(verify_algo.verify(parts, block.signature.as_slice())?) } #[derive(Serialize)] struct WritecapSig<'a> { issued_to: &'a Principal, path: &'a Path, expires: &'a Epoch, signing_key: &'a AsymKey, } impl<'a> From<&'a Writecap> for WritecapSig<'a> { fn from(writecap: &'a Writecap) -> WritecapSig<'a> { WritecapSig { issued_to: &writecap.issued_to, path: &writecap.path, expires: &writecap.expires, signing_key: &writecap.signing_key, } } } pub(crate) fn sign_writecap(writecap: &mut Writecap, priv_key: &AsymKey) -> Result<()> { let mut sign_algo = SignAlgo::try_from(priv_key)?; let sig_input = to_vec(&WritecapSig::from(&*writecap))?; sign_algo.sign([sig_input.as_slice()].into_iter())?; writecap.signature = sign_algo.signature; Ok(()) } /// The types of errors which can occur when verifying a writecap chain is authorized to write to /// a given path. #[derive(Debug, PartialEq)] pub(crate) enum WritecapAuthzErr { /// The chain is not valid for use on the given path. UnauthorizedPath, /// At least one writecap in the chain is expired. Expired, /// The given writecaps do not actually form a chain. NotChained, /// There is an invalid signature in the chain. InvalidSignature, /// The principal the root writecap was issued to does not own the given path. RootDoesNotOwnPath, /// An error occured while serializing a writecap. Serde(String), /// A cryptographic error occurred while attempting to verify a writecap. Crypto(String), } /// Verifies that the given `Writecap` actually grants permission to write to the given `Path`. pub(crate) fn verify_writecap( mut writecap: &Writecap, path: &Path ) -> std::result::Result<(), WritecapAuthzErr> { let mut prev: Option<&Writecap> = None; let mut sig_input = Vec::new(); let now = Epoch::now(); loop { if !writecap.path.contains(path) { return Err(WritecapAuthzErr::UnauthorizedPath); } if writecap.expires <= now { return Err(WritecapAuthzErr::Expired); } if let Some(prev) = &prev { if prev.signing_key.owner_of_kind(writecap.issued_to.kind()) != writecap.issued_to { return Err(WritecapAuthzErr::NotChained); } } let sig = WritecapSig::from(writecap); sig_input.clear(); write_to(&sig, &mut sig_input).map_err(|e| WritecapAuthzErr::Serde(e.to_string()))?; let verify_algo = VerifyAlgo::try_from(&writecap.signing_key) .map_err(|e| WritecapAuthzErr::Crypto(e.to_string()))?; let valid = verify_algo .verify([sig_input.as_slice()].into_iter(), writecap.signature.as_slice()) .map_err(|e| WritecapAuthzErr::Crypto(e.to_string()))?; if !valid { return Err(WritecapAuthzErr::InvalidSignature); } match &writecap.next { Some(next) => { prev = Some(writecap); writecap = next; }, None => { // We're at the root key. As long as the signer of this writecap is the owner of // the path, then the writecap is valid. if writecap.signing_key.owner_of_kind(path.owner.kind()) == path.owner { return Ok(()); } else { return Err(WritecapAuthzErr::RootDoesNotOwnPath) } } } } } #[cfg(test)] mod tests { use super::*; use test_helpers::*; fn encrypt_decrypt_block_test_case( mut actual: Block, principal: &Principal, key: &KeyPair ) -> Result<()> { let expected = actual.clone(); actual = encrypt_block(actual, principal, key)?; let encrypted = match &actual.body { Cryptotext::Cipher(_) => true, Cryptotext::Plain(_) => false }; assert!(encrypted); actual = decrypt_block(actual, principal, &key.private)?; assert_eq!(expected, actual); Ok(()) } #[test] fn encrypt_decrypt_block_aes256cbc() -> Result<()> { let readcap = make_readcap(); let principal = readcap.issued_to.clone(); let block = make_block_with(readcap)?; let key = make_key_pair(); encrypt_decrypt_block_test_case(block, &principal, &key) } #[test] fn encrypt_decrypt_block_aes256ctr() -> Result<()> { let readcap = make_readcap(); let principal = readcap.issued_to.clone(); let block = make_block_with(readcap)?; let key = make_key_pair(); encrypt_decrypt_block_test_case(block, &principal, &key) } #[test] fn rsa_sign_and_verify() -> Result<()> { let key = make_key_pair(); let header = b"About: lyrics".as_slice(); let message = b"Everything that feels so good is bad bad bad.".as_slice(); let mut signer = SignAlgo::try_from(&key.private)?; signer.sign([header, message].into_iter())?; let verifier = VerifyAlgo::try_from(&key.public)?; let verified = verifier.verify([header, message].into_iter(), signer.signature.as_slice())?; assert_eq!(true, verified); Ok(()) } #[test] fn sign_verify_block_rsa() -> Result<()> { let readcap = make_readcap(); let principal = readcap.issued_to.clone(); let mut block = make_block_with(readcap)?; let key = make_key_pair(); let writecap = Writecap { issued_to: Principal(Hash::Sha2_256(PRINCIPAL)), path: make_path(vec!["contacts", "emergency"]), expires: Epoch(1649904316), signing_key: key.public.clone(), signature: Signature::Rsa(SIGNATURE), next: None, }; block = encrypt_block(block, &principal, &key)?; sign_block(&mut block, writecap, key.private)?; assert_eq!(true, verify_block(&block)?); Ok(()) } #[test] fn hash_to_string() { let hash = make_principal().0; let string = hash.to_string(); assert_eq!("Sha2_256:dSip4J0kurN5VhVo_aTipM-ywOOWrqJuRRVQ7aa-bew", string) } #[test] fn hash_to_string_round_trip() -> Result<()> { let expected = make_principal().0; let string = expected.to_string(); let actual = Hash::try_from(string.as_str())?; assert_eq!(expected, actual); Ok(()) } #[test] fn verify_writecap_valid() -> Result<()> { let writecap = make_writecap()?; let result = verify_writecap(&writecap, &writecap.path); assert_eq!(Ok(()), result); Ok(()) } #[test] fn verify_writecap_invalid_signature() -> Result<()> { let mut writecap = make_writecap()?; writecap.signature = Signature::default(); let result = verify_writecap(&writecap, &writecap.path); assert_eq!(Err(WritecapAuthzErr::InvalidSignature), result); Ok(()) } #[test] fn verify_writecap_invalid_path_not_contained() -> Result<()> { let writecap = make_writecap()?; let mut path = writecap.path.clone(); path.components.pop(); // `path` is now a superpath of `writecap.path`, thus the writecap is not authorized to // write to it. let result = verify_writecap(&writecap, &path); assert_eq!(Err(WritecapAuthzErr::UnauthorizedPath), result); Ok(()) } #[test] fn verify_writecap_invalid_expired() -> Result<()> { let mut writecap = make_writecap()?; writecap.expires = Epoch::now() - Duration::from_secs(1); let result = verify_writecap(&writecap, &writecap.path); assert_eq!(Err(WritecapAuthzErr::Expired), result); Ok(()) } #[test] fn verify_writecap_invalid_not_chained() -> Result<()> { let (mut root_writecap, root_key) = make_self_signed_writecap()?; root_writecap.issued_to = Principal(Hash::Sha2_256([0; 32])); sign_writecap(&mut root_writecap, &root_key.private)?; let node_key = AsymKey::Rsa { der: Vec::from(NODE_PUBLIC_KEY), padding: RsaPadding::Pkcs1, kind: Public {}, }; let node_principal = node_key.owner(); let writecap = make_writecap_trusted_by( root_writecap, root_key, node_principal, vec!["apps", "contacts"])?; let result = verify_writecap(&writecap, &writecap.path); assert_eq!(Err(WritecapAuthzErr::NotChained), result); Ok(()) } #[test] fn verify_writecap_invalid_root_doesnt_own_path() -> Result<()> { let (mut root_writecap, root_key) = make_self_signed_writecap()?; let owner = Principal(Hash::Sha2_256([0; 32])); root_writecap.path = make_path_with_owner(owner, vec![]); sign_writecap(&mut root_writecap, &root_key.private)?; let node_key = AsymKey::Rsa { der: Vec::from(NODE_PUBLIC_KEY), padding: RsaPadding::Pkcs1, kind: Public {} }; let node_owner = node_key.owner(); let writecap = make_writecap_trusted_by( root_writecap, root_key, node_owner, vec!["apps", "contacts"])?; let result = verify_writecap(&writecap, &writecap.path); assert_eq!(Err(WritecapAuthzErr::RootDoesNotOwnPath), result); Ok(()) } /// Tests that validate the dependencies of this module. mod dependency_tests { use super::*; use openssl::{ ec::{EcGroup, EcKey}, nid::Nid, }; /// This test validates that data encrypted with AES 256 CBC can later be decrypted. #[test] fn aes_256_cbc_roundtrip() { use super::*; let expected = b"We attack at the crack of noon!"; let cipher = Cipher::aes_256_cbc(); let ciphertext = openssl_encrypt(cipher, &KEY, Some(&IV), expected).unwrap(); let actual = openssl_decrypt(cipher, &KEY, Some(&IV), ciphertext.as_slice()).unwrap(); assert_eq!(expected, actual.as_slice()); } /// Tests that the keys for the SECP256K1 curve are the expected sizes. #[test] fn secp256k1_key_lengths() { let group = EcGroup::from_curve_name(Nid::SECP256K1).unwrap(); let key = EcKey::generate(&group).unwrap(); let public = key.public_key_to_der().unwrap(); let private = key.private_key_to_der().unwrap(); let public_len = public.len(); let private_len = private.len(); assert_eq!(88, public_len); assert_eq!(118, private_len); } #[test] fn ed25519_key_lengths() { let key = PKey::generate_x25519().unwrap(); let public = key.public_key_to_der().unwrap(); let private = key.private_key_to_der().unwrap(); let public_len = public.len(); let private_len = private.len(); assert_eq!(44, public_len); assert_eq!(48, private_len); } #[test] fn rsa_signature_len() -> Result<()> { use openssl::rsa::Rsa; let key = make_key_pair(); let sign_algo = SignAlgo::try_from(&key.private)?; let der = match &key.private { AsymKey::Rsa { der, .. } => der, }; let rsa = Rsa::private_key_from_der(der)?; let pkey = PKey::from_rsa(rsa)?; let signer = Signer::new(sign_algo.digest, &pkey)?; assert_eq!(RSA_SIG_LEN, signer.len()?); Ok(()) } } }