/// Functions for performing cryptographic operations on the main data structures. mod tpm; use super::*; use openssl::{ error::ErrorStack, encrypt::{Encrypter as OsslEncrypter, Decrypter as OsslDecrypter}, pkey::{PKey, Public as OsslPublic, Private as OsslPrivate, HasPublic, HasPrivate}, 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, num::TryFromIntError, marker::PhantomData, }; use strum_macros::{EnumString, EnumDiscriminants, Display}; use foreign_types::ForeignType; /// 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 enum Error { NoReadCap, NoKeyAvailable, MissingPrivateKey, KeyVariantUnsupported, BlockNotEncrypted, InvalidHashFormat, Serde(serde_block_tree::Error), Io(std::io::Error), Custom(Box) } impl Error { fn custom(err: E) -> Self { Error::Custom(Box::new(err)) } } 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::Serde(serde_err) => serde_err.fmt(f), Error::Io(io_err) => io_err.fmt(f), Error::Custom(cus) => cus.fmt(f), } } } impl From for Error { fn from(error: ErrorStack) -> Error { Error::custom(error) } } 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) } } impl From for Error { fn from(err: TryFromIntError) -> Self { Error::custom(err) } } pub(crate) type Result = std::result::Result; trait ConvErr { fn conv_err(self) -> Result; } impl> ConvErr for std::result::Result { /// Converts the error value in self to a `crypto::Error`. fn conv_err(self) -> Result { self.map_err(|e| e.into()) } } /// A cryptographic hash. #[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Hashable, Clone, EnumDiscriminants)] #[strum_discriminants(derive(EnumString, Display, Serialize, Deserialize))] #[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 From for MessageDigest { fn from(kind: HashKind) -> Self { match kind { HashKind::Sha2_256 => MessageDigest::sha256(), HashKind::Sha2_512 => MessageDigest::sha512(), } } } 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) } } pub(crate) const RSA_KEY_BYTES: usize = 384; /// A cryptographic signature. #[derive(Debug, PartialEq, Serialize, Deserialize, Clone, EnumDiscriminants)] #[strum_discriminants(name(SignatureKind))] pub(crate) enum Signature { #[serde(with = "BigArray")] Rsa([u8; RSA_KEY_BYTES]), } impl Signature { fn new(id: SignatureKind) -> Signature { match id { SignatureKind::Rsa => Signature::Rsa([0; RSA_KEY_BYTES]) } } 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_KEY_BYTES]) } } #[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).conv_err()?; 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 } } } impl Encrypter for SymKey { fn encrypt(&self, slice: &[u8]) -> Result> { let SymParams { cipher, key, iv } = self.params(); openssl_encrypt(cipher, key, iv, slice).conv_err() } } impl Decrypter for SymKey { fn decrypt(&self, slice: &[u8]) -> Result> { let SymParams { cipher, key, iv } = self.params(); openssl_decrypt(cipher, key, iv, slice).conv_err() } } pub trait Scheme: for<'de> Deserialize<'de> + Serialize + Copy + std::fmt::Debug + PartialEq { type Kind: Scheme; fn kind(self) -> Self::Kind; fn as_enum(self) -> SchemeKind; fn message_digest(&self) -> MessageDigest; fn padding(&self) -> Option; fn public_from_der(self, der: &[u8]) -> Result>; fn private_from_der(self, der: &[u8]) -> Result>; fn generate(self) -> Result>; } pub enum SchemeKind { Sign(Sign), Encrypt(Encrypt), } #[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Copy)] pub enum Encrypt { RsaEsOaep(RsaEsOaep), } impl Scheme for Encrypt { type Kind = Encrypt; fn kind(self) -> Encrypt { self } fn as_enum(self) -> SchemeKind { SchemeKind::Encrypt(self.kind()) } fn message_digest(&self) -> MessageDigest { match self { Encrypt::RsaEsOaep(inner) => inner.message_digest(), } } fn padding(&self) -> Option { match self { Encrypt::RsaEsOaep(inner) => inner.padding(), } } fn public_from_der(self, der: &[u8]) -> Result> { match self { Encrypt::RsaEsOaep(inner) => inner.public_from_der(der), } } fn private_from_der(self, der: &[u8]) -> Result> { match self { Encrypt::RsaEsOaep(inner) => inner.private_from_der(der), } } fn generate(self) -> Result> { match self { Encrypt::RsaEsOaep(inner) => inner.generate(), } } } impl Encrypt { pub const RSA_OAEP_3072_SHA_256: Encrypt = Encrypt::RsaEsOaep(RsaEsOaep { key_bytes: 384, hash_kind: HashKind::Sha2_256, }); } #[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Copy)] pub enum Sign { RsaSsaPss(RsaSsaPss), } impl Scheme for Sign { type Kind = Sign; fn kind(self) -> Sign { self } fn as_enum(self) -> SchemeKind { SchemeKind::Sign(self.kind()) } fn message_digest(&self) -> MessageDigest { match self { Sign::RsaSsaPss(inner) => inner.message_digest(), } } fn padding(&self) -> Option { match self { Sign::RsaSsaPss(inner) => inner.padding(), } } fn public_from_der(self, der: &[u8]) -> Result> { match self { Sign::RsaSsaPss(inner) => inner.public_from_der(der), } } fn private_from_der(self, der: &[u8]) -> Result> { match self { Sign::RsaSsaPss(inner) => inner.private_from_der(der), } } fn generate(self) -> Result> { match self { Sign::RsaSsaPss(inner) => inner.generate(), } } } impl Sign { pub const RSA_PSS_3072_SHA_256: Sign = Sign::RsaSsaPss(RsaSsaPss { key_bytes: 384, hash_kind: HashKind::Sha2_256, }); fn sig_buf(&self) -> Signature { match self { Sign::RsaSsaPss(_) => Signature::Rsa([0u8; RSA_KEY_BYTES]), } } } #[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Copy)] pub struct RsaEsOaep { key_bytes: usize, hash_kind: HashKind, } fn generate_rsa(scheme: S) -> Result> { let key_bits = 8 * u32::try_from(RSA_KEY_BYTES).conv_err()?; let key = Rsa::generate(key_bits)?; // TODO: Separating the keys this way seems inefficient. Investigate alternatives. let public_der = key.public_key_to_der().conv_err()?; let private_der = key.private_key_to_der().conv_err()?; let public = AsymKey::::new(scheme, &public_der)?; let private = AsymKey::::new(scheme, &private_der)?; Ok(AsymKeyPair { public, private }) } impl Scheme for RsaEsOaep { type Kind = Encrypt; fn kind(self) -> Encrypt { Encrypt::RsaEsOaep(self) } fn as_enum(self) -> SchemeKind { SchemeKind::Encrypt(self.kind()) } fn message_digest(&self) -> MessageDigest { self.hash_kind.into() } fn padding(&self) -> Option { Some(OpensslPadding::PKCS1_OAEP) } fn public_from_der(self, der: &[u8]) -> Result> { PKey::public_key_from_der(der).conv_err() } fn private_from_der(self, der: &[u8]) -> Result> { PKey::private_key_from_der(der).conv_err() } fn generate(self) -> Result> { generate_rsa(self.kind()) } } impl From for Encrypt { fn from(scheme: RsaEsOaep) -> Self { scheme.kind() } } #[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Copy)] pub struct RsaSsaPss { key_bytes: usize, hash_kind: HashKind, } impl Scheme for RsaSsaPss { type Kind = Sign; fn kind(self) -> Sign { Sign::RsaSsaPss(self) } fn as_enum(self) -> SchemeKind { SchemeKind::Sign(self.kind()) } fn message_digest(&self) -> MessageDigest { self.hash_kind.into() } fn padding(&self) -> Option { Some(OpensslPadding::PKCS1_PSS) } fn public_from_der(self, der: &[u8]) -> Result> { PKey::public_key_from_der(der).conv_err() } fn private_from_der(self, der: &[u8]) -> Result> { PKey::private_key_from_der(der).conv_err() } fn generate(self) -> Result> { generate_rsa(self.kind()) } } impl From for Sign { fn from(scheme: RsaSsaPss) -> Self { scheme.kind() } } pub trait KeyPrivacy {} #[derive(Clone, Debug)] pub enum Public {} impl KeyPrivacy for Public {} unsafe impl HasPublic for Public {} pub enum Private {} impl KeyPrivacy for Private {} unsafe impl HasPrivate for Private {} fn conv_pkey(pkey: PKey) -> PKey { let ptr = pkey.as_ptr(); let new_pkey = unsafe { PKey::from_ptr(ptr) }; std::mem::forget(pkey); new_pkey } fn conv_pkey_pub(pkey: PKey) -> PKey { conv_pkey(pkey) } fn conv_pkey_priv(pkey: PKey) -> PKey { conv_pkey(pkey) } #[derive(Debug, Clone)] pub struct AsymKey { scheme: S, pkey: PKey

, } pub type AsymKeyPub = AsymKey; impl AsymKey { fn digest(&self) -> MessageDigest { self.scheme.message_digest() } fn padding(&self) -> Option { self.scheme.padding() } } impl AsymKey { pub(crate) fn new(scheme: S, der: &[u8]) -> Result> { let pkey = conv_pkey_pub(scheme.public_from_der(der)?); Ok(AsymKey { scheme, pkey }) } fn to_der(&self) -> Result> { self.pkey.public_key_to_der().conv_err() } } impl AsymKey { pub(crate) fn new(scheme: S, der: &[u8]) -> Result> { let pkey = conv_pkey_priv(scheme.private_from_der(der)?); Ok(AsymKey { scheme, pkey }) } } impl AsymKey { fn signature_buf(&self) -> Signature { self.scheme.sig_buf() } } impl<'de, S: Scheme> Deserialize<'de> for AsymKey { fn deserialize>(d: D) -> std::result::Result { const FIELDS: &[&str] = &["scheme", "pkey"]; struct StructVisitor(PhantomData); impl<'de, S: Scheme> Visitor<'de> for StructVisitor { type Value = AsymKey; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_fmt(format_args!("struct {}", stringify!(AsymKey))) } fn visit_seq>( self, mut seq: V ) -> std::result::Result { let scheme: S = 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]))?; AsymKey::::new(scheme, der.as_slice()) .map_err(de::Error::custom) } } d.deserialize_struct( stringify!(AsymKey), FIELDS, StructVisitor(PhantomData) ) } } impl Serialize for AsymKey { fn serialize(&self, s: T) -> std::result::Result { let mut struct_s = s.serialize_struct(stringify!(AsymKey), 2)?; struct_s.serialize_field("scheme", &self.scheme)?; let der = self.pkey.public_key_to_der().unwrap(); struct_s.serialize_field("pkey", der.as_slice())?; struct_s.end() } } impl PartialEq for AsymKey { fn eq(&self, other: &Self) -> bool { self.scheme == other.scheme && self.pkey.public_eq(&other.pkey) } } impl Owned for AsymKey { 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 Encrypter for AsymKey { fn encrypt(&self, slice: &[u8]) -> Result> { let mut encrypter = OsslEncrypter::new(&self.pkey)?; if let Some(padding) = self.padding() { encrypter.set_rsa_padding(padding)?; } { let Encrypt::RsaEsOaep(inner) = self.scheme; encrypter.set_rsa_oaep_md(inner.message_digest())?; } let buffer_len = encrypter.encrypt_len(slice)?; let mut ciphertext = vec![0; buffer_len]; let ciphertext_len = encrypter.encrypt(slice, &mut ciphertext)?; ciphertext.truncate(ciphertext_len); Ok(ciphertext) } } impl Decrypter for AsymKey { fn decrypt(&self, slice: &[u8]) -> Result> { let mut decrypter = OsslDecrypter::new(&self.pkey).conv_err()?; if let Some(padding) = self.padding() { decrypter.set_rsa_padding(padding).conv_err()?; } { let Encrypt::RsaEsOaep(inner) = self.scheme; decrypter.set_rsa_oaep_md(inner.message_digest())?; } let buffer_len = decrypter.decrypt_len(slice).conv_err()?; let mut plaintext = vec![0; buffer_len]; let plaintext_len = decrypter.decrypt(slice, &mut plaintext).conv_err()?; plaintext.truncate(plaintext_len); Ok(plaintext) } } impl Signer for AsymKey { fn sign<'a, I: Iterator>(&self, parts: I) -> Result { let mut signer = OsslSigner::new(self.scheme.message_digest(), &self.pkey)?; if let Some(padding) = self.scheme.padding() { signer.set_rsa_padding(padding)?; } for part in parts { signer.update(part)?; } let mut signature = self.scheme.sig_buf(); signer.sign(signature.as_mut_slice())?; Ok(signature) } } impl Verifier for AsymKey { fn verify<'a, I: Iterator>(&self, parts: I, signature: &[u8]) -> Result { let mut verifier = OsslVerifier::new(self.digest(), &self.pkey)?; if let Some(padding) = self.scheme.padding() { verifier.set_rsa_padding(padding)?; } for part in parts { verifier.update(part)?; } Ok(verifier.verify(signature)?) } } pub struct AsymKeyPair { public: AsymKey, private: AsymKey, } impl AsymKeyPair { pub fn new(scheme: S, public_der: &[u8], private_der: &[u8]) -> Result> { let public = AsymKey::::new(scheme, public_der)?; let private = AsymKey::::new(scheme, private_der)?; Ok(AsymKeyPair { public, private }) } } impl Owned for AsymKeyPair { fn owner_of_kind(&self, kind: HashKind) -> Principal { self.public.owner_of_kind(kind) } } impl Encrypter for AsymKeyPair { fn encrypt(&self, slice: &[u8]) -> Result> { self.public.encrypt(slice) } } impl Decrypter for AsymKeyPair { fn decrypt(&self, slice: &[u8]) -> Result> { self.private.decrypt(slice) } } impl Signer for AsymKeyPair { fn sign<'a, I: Iterator>(&self, parts: I) -> Result { self.private.sign(parts) } } impl Verifier for AsymKeyPair { fn verify<'a, I: Iterator>(&self, parts: I, signature: &[u8]) -> Result { self.public.verify(parts, signature) } } pub struct ConcreteCreds { sign: AsymKeyPair, encrypt: AsymKeyPair, } impl ConcreteCreds { pub(crate) fn new(sign: AsymKeyPair, encrypt: AsymKeyPair) -> ConcreteCreds { ConcreteCreds { sign, encrypt } } pub(crate) fn generate() -> Result { let encrypt = Encrypt::RSA_OAEP_3072_SHA_256.generate()?; let sign = Sign::RSA_PSS_3072_SHA_256.generate()?; Ok(ConcreteCreds { sign, encrypt }) } } impl Verifier for ConcreteCreds { fn verify<'a, I: Iterator>(&self, parts: I, signature: &[u8]) -> Result { self.sign.verify(parts, signature) } } impl Encrypter for ConcreteCreds { fn encrypt(&self, slice: &[u8]) -> Result> { self.encrypt.encrypt(slice) } } impl Owned for ConcreteCreds { fn owner_of_kind(&self, kind: HashKind) -> Principal { self.sign.owner_of_kind(kind) } } impl CredsPub for ConcreteCreds {} impl Signer for ConcreteCreds { fn sign<'a, I: Iterator>(&self, parts: I) -> Result { self.sign.sign(parts) } } impl Decrypter for ConcreteCreds { fn decrypt(&self, slice: &[u8]) -> Result> { self.encrypt.decrypt(slice) } } impl CredsPriv for ConcreteCreds {} impl Creds for ConcreteCreds { fn public(&self) -> &AsymKey { &self.sign.public } } pub(crate) trait Encrypter { fn encrypt(&self, slice: &[u8]) -> Result>; } pub(crate) trait Decrypter { fn decrypt(&self, slice: &[u8]) -> Result>; } pub(crate) trait Signer { fn sign<'a, I: Iterator>(&self, parts: I) -> Result; } pub(crate) trait Verifier { fn verify<'a, I: Iterator>(&self, parts: I, signature: &[u8]) -> Result; } /// Trait for types which can be used as public credentials. pub(crate) trait CredsPub: Verifier + Encrypter + Owned {} /// Trait for types which contain private credentials. pub(crate) trait CredsPriv: Decrypter + Signer {} /// Trait for types which contain both public and private credentials. pub(crate) trait Creds: CredsPriv + CredsPub { fn public(&self) -> &AsymKey; } /// 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; /// 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; /// Generates the root credentials 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; } 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, creds: &C ) -> 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, creds)?; 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).conv_err()?; 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?).conv_err() } #[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([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 AsymKey, } 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([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([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::new(Sign::RSA_PSS_3072_SHA_256, 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::new(Sign::RSA_PSS_3072_SHA_256, 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([NODE_PUBLIC_KEY.as_slice()].into_iter())?; let length = match signature { Signature::Rsa(data) => data.len(), }; assert_eq!(RSA_KEY_BYTES, length); Ok(()) } } }