123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958 |
- /// 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<T: Serialize> {
- /// The inner value of `T` is plaintext.
- Plain(T),
- /// The inner value is ciphertext.
- Cipher(Vec<u8>),
- }
- /// 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<ErrorStack> for Error {
- fn from(error: ErrorStack) -> Error {
- Error::Message(error.to_string())
- }
- }
- impl From<serde_block_tree::Error> for Error {
- fn from(error: serde_block_tree::Error) -> Error {
- Error::Serde(error)
- }
- }
- pub(crate) type Result<T> = std::result::Result<T, Error>;
- /// 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<HashKind> 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<Hash> {
- 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<RsaPadding> 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<const LEN: usize>() -> 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<SymKey> {
- 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<T> {
- Rsa {
- der: Vec<u8>,
- padding: RsaPadding,
- kind: T,
- }
- }
- impl<T> AsymKey<T> {
- pub(crate) fn as_slice(&self) -> &[u8] {
- match self {
- AsymKey::Rsa { der, .. } => der.as_slice()
- }
- }
- }
- impl<T> Owned for AsymKey<T> {
- 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<Public>,
- pub(crate) private: AsymKey<Private>,
- }
- impl KeyPair {
- pub(crate) fn generate(kind: AsymKeyKind) -> Result<KeyPair> {
- 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<OsslPublic>,
- rsa_padding: Option<OpensslPadding>,
- }
- }
- impl<'a> EncryptionAlgo<'a> {
- fn encrypt(&self, slice: &[u8]) -> Result<Vec<u8>> {
- 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<EncryptionAlgo<'a>> {
- 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<Public>> for EncryptionAlgo<'a> {
- type Error = Error;
- fn try_from(key: &'a AsymKey<Public>) -> Result<EncryptionAlgo<'a>> {
- 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<OsslPrivate>),
- }
- impl<'a> DecryptionAlgo<'a> {
- fn decrypt(&self, slice: &[u8]) -> Result<Vec<u8>> {
- 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<DecryptionAlgo<'a>> {
- 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<Private>> for DecryptionAlgo<'a> {
- type Error = Error;
- fn try_from(key: &'a AsymKey<Private>) -> Result<DecryptionAlgo<'a>> {
- 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<OsslPrivate>,
- digest: MessageDigest,
- signature: Signature
- }
- impl SignAlgo {
- fn sign<'a, I: Iterator<Item = &'a [u8]>>(&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<Private>> for SignAlgo {
- type Error = Error;
- fn try_from(key: &AsymKey<Private>) -> Result<SignAlgo> {
- 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<OsslPublic>,
- digest: MessageDigest,
- }
- impl VerifyAlgo {
- fn verify<'a, I: Iterator<Item = &'a [u8]>>(
- &'a self, parts: I, signature: &[u8]
- ) -> Result<bool> {
- 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<Public>> for VerifyAlgo {
- type Error = Error;
- fn try_from(key: &AsymKey<Public>) -> Result<VerifyAlgo> {
- 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<Block> {
- 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<Private>
- ) -> Result<Block> {
- 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<EncryptionAlgo<'a>, Error = Error>>(
- value: &T, key: K
- ) -> Result<Cryptotext<T>> {
- 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<DecryptionAlgo<'a>, Error = Error>>(
- cryptotext: Cryptotext<T>, key: K
- ) -> Result<T> {
- 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<EncryptionAlgo<'a>, Error = Error>>(
- plaintext: &[u8], key: K
- ) -> Result<Vec<u8>> {
- let algo: EncryptionAlgo<'a> = key.try_into()?;
- algo.encrypt(plaintext)
- }
- fn decrypt_slice<'a, K: TryInto<DecryptionAlgo<'a>, Error = Error>>(
- ciphertext: &[u8], key: K
- ) -> Result<Vec<u8>> {
- let algo: DecryptionAlgo<'a> = key.try_into()?;
- algo.decrypt(ciphertext)
- }
- #[derive(Serialize)]
- struct SigHeader<'a> {
- path: &'a Path,
- readcaps: &'a HashMap<Principal, Cryptotext<SymKey>>,
- 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<Private>
- ) -> 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<bool> {
- 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<Public>,
- }
- 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<Private>) -> 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(())
- }
- }
- }
|