/// Functions for performing cryptographic operations on the main data structures. mod tpm; use super::*; use openssl::{ error::ErrorStack, encrypt::{Encrypter, Decrypter}, pkey::{PKey, Public, Private}, symm::{Cipher, encrypt as openssl_encrypt, decrypt as openssl_decrypt}, rand::rand_bytes, rsa::{Rsa, Padding as OpensslPadding}, hash::{hash, MessageDigest}, sign::{Signer as OsslSigner, Verifier as OsslVerifier} }; use serde_block_tree::{self, to_vec, from_vec, write_to}; use serde::{ de::{self, DeserializeOwned, Deserializer, SeqAccess, Visitor}, ser::{Serializer, SerializeStruct}, }; 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), Io(std::io::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), Error::Io(io_err) => io_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) } } impl From for Error { fn from(error: std::io::Error) -> Error { Error::Io(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, 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] }, } struct SymParams<'a> { cipher: Cipher, key: &'a [u8], iv: Option<&'a [u8]>, } /// 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()? }) }, } } fn params(&self) -> SymParams { let (cipher, key, iv) = match self { SymKey::Aes256Cbc { key, iv } => (Cipher::aes_256_cbc(), key, Some(iv.as_slice())), SymKey::Aes256Ctr { key, iv } => (Cipher::aes_256_ctr(), key, Some(iv.as_slice())), }; SymParams { cipher, key, iv } } } #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] pub(crate) enum AsymKeyKind { Rsa, } #[derive(Debug, Clone)] pub(crate) struct AsymKeyPub { kind: AsymKeyKind, pkey: PKey, } impl AsymKeyPub { pub(crate) fn new(kind: AsymKeyKind, der: &[u8]) -> Result { let pkey = match kind { AsymKeyKind::Rsa => { let rsa = Rsa::public_key_from_der(der).map_err(Error::from)?; PKey::from_rsa(rsa).map_err(Error::from)? } }; Ok(AsymKeyPub { kind, pkey }) } fn digest(&self) -> MessageDigest { match self.kind { AsymKeyKind::Rsa => MessageDigest::sha256(), } } fn signature_buf(&self) -> Signature { match self.kind { AsymKeyKind::Rsa => Signature::new(SignatureKind::Rsa), } } fn padding(&self) -> Option { match self.kind { AsymKeyKind::Rsa => Some(OpensslPadding::PKCS1), } } fn to_der(&self) -> Result> { self.pkey.public_key_to_der().map_err(Error::from) } } impl<'de> Deserialize<'de> for AsymKeyPub { fn deserialize>(d: D) -> std::result::Result { const FIELDS: &[&str] = &["kind", "pkey"]; struct StructVisitor; impl<'de> Visitor<'de> for StructVisitor { type Value = AsymKeyPub; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_fmt(format_args!("struct {}", stringify!(AsymKeyPub))) } fn visit_seq>( self, mut seq: V ) -> std::result::Result { let kind: AsymKeyKind = seq.next_element()? .ok_or_else(|| de::Error::missing_field(FIELDS[0]))?; let der: Vec = seq.next_element()? .ok_or_else(|| de::Error::missing_field(FIELDS[1]))?; AsymKeyPub::new(kind, der.as_slice()) .map_err(|e| de::Error::custom(e.to_string())) } } d.deserialize_struct(stringify!(AsymKeyPub), FIELDS, StructVisitor) } } impl Serialize for AsymKeyPub { fn serialize(&self, s: S) -> std::result::Result { let mut struct_s = s.serialize_struct(stringify!(AsymKeyPub), 2)?; struct_s.serialize_field("kind", &self.kind)?; let der = self.pkey.public_key_to_der().unwrap(); struct_s.serialize_field("pkey", der.as_slice())?; struct_s.end() } } impl PartialEq for AsymKeyPub { fn eq(&self, other: &Self) -> bool { self.kind == other.kind && self.pkey.public_eq(&other.pkey) } } impl Owned for AsymKeyPub { fn owner_of_kind(&self, kind: HashKind) -> Principal { match kind { HashKind::Sha2_256 => { let mut buf = [0; 32]; let der = self.to_der().unwrap(); let bytes = hash(MessageDigest::sha256(), der.as_slice()).unwrap(); buf.copy_from_slice(&*bytes); Principal(Hash::Sha2_256(buf)) }, HashKind::Sha2_512 => { let mut buf = [0; 64]; let der = self.to_der().unwrap(); let bytes = hash(MessageDigest::sha512(), der.as_slice()).unwrap(); buf.copy_from_slice(&*bytes); Principal(Hash::Sha2_512(buf)) } } } } impl CredsPub for AsymKeyPub {} pub(crate) struct RsaPriv { pkey: PKey, } impl RsaPriv { pub(crate) fn new(der: &[u8]) -> Result { let rsa = Rsa::private_key_from_der(der).map_err(Error::from)?; let pkey = PKey::from_rsa(rsa).map_err(Error::from)?; Ok(RsaPriv { pkey }) } fn digest() -> MessageDigest { MessageDigest::sha256() } fn signature_buf() -> Signature { Signature::new(SignatureKind::Rsa) } } impl Decryptor for RsaPriv { fn decrypt(&self, slice: &[u8]) -> Result> { let decrypter = Decrypter::new(&self.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 Signer for RsaPriv { fn sign<'a, I: Iterator>(&self, parts: &mut I) -> Result { let digest = RsaPriv::digest(); let mut signature = RsaPriv::signature_buf(); let mut signer = OsslSigner::new(digest, &self.pkey).map_err(Error::from)?; for part in parts { signer.update(part).map_err(Error::from)?; } let buf = signature.as_mut_slice(); signer.sign(buf).map_err(Error::from)?; Ok(signature) } } impl CredsPriv for RsaPriv {} pub(crate) struct ConcreteCreds { public: AsymKeyPub, private: T, } impl ConcreteCreds { pub(crate) fn new(public: AsymKeyPub, private: T) -> ConcreteCreds { ConcreteCreds { public, private } } } impl ConcreteCreds { pub(crate) fn generate() -> Result> { let key = Rsa::generate(4096)?; // TODO: Separating the keys this way seems inefficient. Investigate alternatives. let public_der = key.public_key_to_der().map_err(Error::from)?; let private_der = key.private_key_to_der().map_err(Error::from)?; Ok(ConcreteCreds { public: AsymKeyPub::new(AsymKeyKind::Rsa, public_der.as_slice())?, private: RsaPriv::new(private_der.as_slice())?, }) } } impl Verifier for ConcreteCreds { fn verify<'a, I: Iterator>(&self, parts: I, signature: &[u8]) -> Result { self.public.verify(parts, signature) } } impl Encryptor for ConcreteCreds { fn encrypt(&self, slice: &[u8]) -> Result> { self.public.encrypt(slice) } } impl Owned for ConcreteCreds { fn owner_of_kind(&self, kind: HashKind) -> Principal { self.public.owner_of_kind(kind) } } impl CredsPub for ConcreteCreds {} impl Signer for ConcreteCreds { fn sign<'a, I: Iterator>(&self, parts: &mut I) -> Result { self.private.sign(parts) } } impl Decryptor for ConcreteCreds { fn decrypt(&self, slice: &[u8]) -> Result> { self.private.decrypt(slice) } } impl CredsPriv for ConcreteCreds {} impl Creds for ConcreteCreds { fn public(&self) -> &AsymKeyPub { &self.public } } pub(crate) trait Encryptor { fn encrypt(&self, slice: &[u8]) -> Result>; } impl Encryptor for SymKey { fn encrypt(&self, slice: &[u8]) -> Result> { let SymParams { cipher, key, iv } = self.params(); openssl_encrypt(cipher, key, iv, slice).map_err(Error::from) } } impl Encryptor for AsymKeyPub { fn encrypt(&self, slice: &[u8]) -> Result> { let mut encrypter = Encrypter::new(&self.pkey).map_err(Error::from)?; if let Some(padding) = self.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) } } pub(crate) trait Decryptor { fn decrypt(&self, slice: &[u8]) -> Result>; } impl Decryptor for SymKey { fn decrypt(&self, slice: &[u8]) -> Result> { let SymParams { cipher, key, iv } = self.params(); openssl_decrypt(cipher, key, iv, slice).map_err(Error::from) } } pub(crate) trait Signer { fn sign<'a, I: Iterator>(&self, parts: &mut I) -> Result; } pub(crate) trait Verifier { fn verify<'a, I: Iterator>(&self, parts: I, signature: &[u8]) -> Result; } impl Verifier for AsymKeyPub { fn verify<'a, I: Iterator>(&self, parts: I, signature: &[u8]) -> Result { let mut verifier = OsslVerifier::new(self.digest(), &self.pkey).map_err(Error::from)?; for part in parts { verifier.update(part).map_err(Error::from)?; } verifier.verify(signature).map_err(Error::from) } } /// Trait for types which can be used as public credentials. pub(crate) trait CredsPub: Verifier + Encryptor + Owned {} /// Trait for types which contain private credentials. pub(crate) trait CredsPriv: Decryptor + Signer {} /// Trait for types which contain both public and private credentials. pub(crate) trait Creds: CredsPriv + CredsPub { fn public(&self) -> &AsymKeyPub; } /// A trait for types which store credentials. pub(crate) trait CredStore { type CredHandle: Creds; /// Returns the node credentials. If credentials haven't been generated, they are generated /// stored and returned. fn node_creds(&self) -> Result<&Self::CredHandle>; /// Returns the root credentials. If no root credentials have been generated, or the provided /// password is incorrect, then an error is returned. fn root_creds(&self, password: &str) -> Result<&Self::CredHandle>; /// Generates the root crednetials and protects them using the given password. If the root /// credentials have already been generated then an error is returned. fn gen_root_creds(&self, password: &str) -> Result<&Self::CredHandle>; } pub(crate) fn encrypt_block( mut block: Block, principal: &Principal, creds: &C ) -> 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, creds)?; let new_body = block_key.encrypt(&body)?; block.body = Cryptotext::Cipher(new_body); block.readcaps.insert(principal_owned, encrypt(&block_key, creds)?); Ok(block) } pub(crate) fn decrypt_block( mut block: Block, principal: &Principal, key: &K ) -> 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 = block_key.decrypt(&body)?; block.body = Cryptotext::Plain(new_body); block.readcaps.insert(principal_owned, Cryptotext::Plain(block_key)); Ok(block) } fn encrypt(value: &T, key: &K) -> Result> { let data = to_vec(value).map_err(Error::from)?; let vec = key.encrypt(&data); Ok(Cryptotext::Cipher(vec?)) } fn decrypt( cryptotext: Cryptotext, key: &K ) -> Result { let data = match cryptotext { Cryptotext::Plain(value) => return Ok(value), Cryptotext::Cipher(data) => data }; let vec = key.decrypt(&data); from_vec(&vec?).map_err(Error::from) } #[derive(Serialize)] struct HeaderSigInput<'a> { path: &'a Path, readcaps: &'a HashMap>, writecap: &'a Writecap, } impl<'a> From<&'a Block> for HeaderSigInput<'a> { fn from(block: &'a Block) -> HeaderSigInput<'a> { HeaderSigInput { 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: &K ) -> Result<()> { block.writecap = writecap; let body = get_body(block)?; let sig_input = HeaderSigInput::from(&*block); let header = to_vec(&sig_input)?; let signature = priv_key.sign(&mut [header.as_slice(), body].into_iter())?; block.signature = signature; Ok(()) } pub(crate) fn verify_block(block: &Block) -> Result { let body = get_body(block)?; let sig_input = HeaderSigInput::from(&*block); let header = to_vec(&sig_input)?; let parts = [header.as_slice(), body].into_iter(); block.writecap.signing_key.verify(parts, block.signature.as_slice()) } #[derive(Serialize)] struct WritecapSigInput<'a> { issued_to: &'a Principal, path: &'a Path, expires: &'a Epoch, signing_key: &'a AsymKeyPub, } impl<'a> From<&'a Writecap> for WritecapSigInput<'a> { fn from(writecap: &'a Writecap) -> WritecapSigInput<'a> { WritecapSigInput { 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: &K) -> Result<()> { let sig_input = to_vec(&WritecapSigInput::from(&*writecap))?; writecap.signature = priv_key.sign(&mut [sig_input.as_slice()].into_iter())?; 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 occurred 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 = WritecapSigInput::from(writecap); sig_input.clear(); write_to(&sig, &mut sig_input).map_err(|e| WritecapAuthzErr::Serde(e.to_string()))?; let valid = writecap.signing_key .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, creds: &C ) -> Result<()> { let expected = actual.clone(); actual = encrypt_block(actual, principal, creds)?; let encrypted = match &actual.body { Cryptotext::Cipher(_) => true, Cryptotext::Plain(_) => false }; assert!(encrypted); actual = decrypt_block(actual, principal, creds)?; 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 signature = key.sign(&mut [header, message].into_iter())?; let verified = key.verify([header, message].into_iter(), 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)?; 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)?; let node_key = AsymKeyPub { kind: AsymKeyKind::Rsa, pkey: PKey::from_rsa(Rsa::public_key_from_der(NODE_PUBLIC_KEY.as_slice())?)? }; 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)?; let node_key = AsymKeyPub { kind: AsymKeyKind::Rsa, pkey: PKey::from_rsa(Rsa::public_key_from_der(NODE_PUBLIC_KEY.as_slice())?)? }; 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<()> { let key = make_key_pair(); let signature = key.sign(&mut [NODE_PUBLIC_KEY.as_slice()].into_iter())?; let length = match signature { Signature::Rsa(data) => data.len(), }; assert_eq!(RSA_SIG_LEN, length); Ok(()) } } }