// SPDX-License-Identifier: AGPL-3.0-or-later pub mod tpm; pub mod merkle_stream; pub mod x509; pub use merkle_stream::MerkleStream; pub mod secret_stream; pub use secret_stream::SecretStream; //mod sign_stream; //pub use sign_stream::SignStream; use crate::{ btensure, bterr, fmt, io, BigArray, BlockMeta, BlockPath, Deserialize, Epoch, Formatter, Hashable, Principal, Principaled, Result, Serialize, Writecap, WritecapBody, }; use btserde::{self, from_vec, to_vec, write_to}; use foreign_types::ForeignType; use log::error; use openssl::{ encrypt::{Decrypter as OsslDecrypter, Encrypter as OsslEncrypter}, error::ErrorStack, hash::{hash, DigestBytes, Hasher, MessageDigest}, nid::Nid, pkey::{HasPrivate, HasPublic, PKey, PKeyRef}, rand::rand_bytes, rsa::{Padding as OpensslPadding, Rsa as OsslRsa}, sign::{Signer as OsslSigner, Verifier as OsslVerifier}, symm::{decrypt as openssl_decrypt, encrypt as openssl_encrypt, Cipher, Crypter, Mode}, }; use serde::{ de::{self, DeserializeOwned, Deserializer, SeqAccess, Visitor}, ser::{SerializeStruct, Serializer}, }; use std::{ cell::RefCell, fmt::Display, io::{Read, Write}, marker::PhantomData, }; use strum_macros::{Display, EnumDiscriminants, FromRepr}; use zeroize::ZeroizeOnDrop; #[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)] pub struct Ciphertext { data: Vec, phantom: PhantomData, } impl Ciphertext { pub fn new(data: Vec) -> Ciphertext { Ciphertext { data, phantom: PhantomData, } } } pub struct Signed { _data: Vec, sig: Signature, phantom: PhantomData, } impl Signed { pub fn new(data: Vec, sig: Signature) -> Signed { Signed { _data: data, sig, phantom: PhantomData, } } } /// Errors that can occur during cryptographic operations. #[derive(Debug)] pub enum Error { NoReadCap, NoKeyAvailable, MissingPrivateKey, KeyVariantUnsupported, BlockNotEncrypted, InvalidHashFormat, InvalidSignature, IncorrectSize { expected: usize, actual: usize, }, IndexOutOfBounds { index: usize, limit: usize, }, IndivisibleSize { divisor: usize, actual: usize, }, InvalidOffset { actual: usize, limit: usize, }, HashCmpFailure, RootHashNotVerified, SignatureMismatch(Box), /// This variant is used to convey errors that originated in an underlying library. Library(Box), } impl Error { fn signature_mismatch(expected: Principal, actual: Principal) -> Error { Error::SignatureMismatch(Box::new(SignatureMismatch { expected, actual })) } fn library(err: E) -> Error { Error::Library(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::InvalidSignature => write!(f, "invalid signature"), Error::IncorrectSize { expected, actual } => { write!(f, "expected size {expected} but got {actual}") } Error::IndexOutOfBounds { index, limit } => write!( f, "index {index} is out of bounds, it must be strictly less than {limit}", ), Error::IndivisibleSize { divisor, actual } => write!( f, "expected a size which is divisible by {divisor} but got {actual}", ), Error::InvalidOffset { actual, limit } => write!( f, "offset {actual} is out of bounds, it must be strictly less than {limit}", ), Error::HashCmpFailure => write!(f, "hash data are not equal"), Error::RootHashNotVerified => write!(f, "root hash is not verified"), Error::SignatureMismatch(mismatch) => { let actual = &mismatch.actual; let expected = &mismatch.expected; write!( f, "expected a signature from {expected} but found one from {actual}" ) } Error::Library(err) => err.fmt(f), } } } impl std::error::Error for Error {} impl From for Error { fn from(error: ErrorStack) -> Error { Error::library(error) } } #[derive(Debug)] pub struct SignatureMismatch { pub actual: Principal, pub expected: Principal, } /// Returns an array of the given length filled with cryptographically strong random data. pub fn rand_array() -> Result<[u8; LEN]> { let mut array = [0; LEN]; rand_bytes(&mut array)?; Ok(array) } /// Returns a vector of the given length with with cryptographically strong random data. pub fn rand_vec(len: usize) -> Result> { let mut vec = vec![0; len]; rand_bytes(&mut vec)?; Ok(vec) } /// An ongoing Init-Update-Finish operation. pub trait Op: Sized { /// The type of the argument given to `init`. type Arg; /// Initialize a new operation. fn init(arg: Self::Arg) -> Result; /// Update this operation using the given data. fn update(&mut self, data: &[u8]) -> Result<()>; /// Finish this operation and write the result into the given buffer. If the given buffer is not /// large enough the implementation must return Error::IncorrectSize. fn finish_into(self, buf: &mut [u8]) -> Result; } /// An ongoing hash hash operation. pub trait HashOp: Op { /// The specific hash type which is returned by the finish method. type Hash: Hash; /// Returns the kind of hash this operation is computing. fn kind(&self) -> HashKind; /// Finish this operation and return a hash type containing the result. fn finish(self) -> Result; } // A hash operation which uses OpenSSL. pub struct OsslHashOp { hasher: Hasher, phantom: PhantomData, kind: HashKind, } impl Op for OsslHashOp { type Arg = HashKind; fn init(arg: Self::Arg) -> Result { let hasher = Hasher::new(arg.into())?; let phantom = PhantomData; Ok(OsslHashOp { hasher, phantom, kind: arg, }) } fn update(&mut self, data: &[u8]) -> Result<()> { Ok(self.hasher.update(data)?) } fn finish_into(mut self, buf: &mut [u8]) -> Result { if buf.len() < self.kind.len() { return Err(bterr!(Error::IncorrectSize { expected: self.kind.len(), actual: buf.len(), })); } let digest = self.hasher.finish()?; let slice = digest.as_ref(); buf.copy_from_slice(slice); Ok(slice.len()) } } impl> HashOp for OsslHashOp { type Hash = H; fn kind(&self) -> HashKind { self.kind } fn finish(mut self) -> Result { let digest = self.hasher.finish()?; Ok(H::from(digest)) } } /// A wrapper which updates a `HashOp` when data is read or written. pub struct HashStream { inner: T, op: Op, update_failed: bool, } impl HashStream { /// Create a new `HashWrap`. pub fn new(inner: T, op: Op) -> HashStream { HashStream { inner, op, update_failed: false, } } /// Finish this hash operation and write the result into the given buffer. The number of bytes /// written is returned. pub fn finish_into(self, buf: &mut [u8]) -> Result { if self.update_failed { return Err(bterr!( "HashStream::finish_into can't produce result due to HashOp update failure", )); } self.op.finish_into(buf) } /// Finish this hash operation and return the resulting hash. pub fn finish(self) -> Result { if self.update_failed { return Err(bterr!( "HashStream::finish can't produce result due to HashOp update failure", )); } self.op.finish() } } impl Read for HashStream { fn read(&mut self, buf: &mut [u8]) -> io::Result { if self.update_failed { return Err(bterr!( "HashStream::read can't continue due to previous HashOp update failure", ) .into()); } let read = self.inner.read(buf)?; if read > 0 { if let Err(err) = self.op.update(&buf[..read]) { self.update_failed = true; error!("HashWrap::read failed to update HashOp: {}", err); } } Ok(read) } } impl Write for HashStream { fn write(&mut self, buf: &[u8]) -> io::Result { self.op.update(buf)?; self.inner.write(buf) } fn flush(&mut self) -> io::Result<()> { self.inner.flush() } } /// A cryptographic hash. pub trait Hash: AsRef<[u8]> + AsMut<[u8]> + Sized { /// The hash operation associated with this `Hash`. type Op: HashOp; /// The type of the argument required by `new`. type Arg; /// Returns a new `Hash` instance. fn new(arg: Self::Arg) -> Self; /// Returns the `HashKind` of self. fn kind(&self) -> HashKind; /// Starts a new hash operation. fn start_op(&self) -> Result; } /// Trait for hash types which can be created with no arguments. pub trait DefaultHash: Hash { fn default() -> Self; } impl> DefaultHash for T { fn default() -> Self { Self::new(A::default()) } } #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Hashable, Clone)] pub struct Sha2_256([u8; Self::LEN]); impl Sha2_256 { pub const KIND: HashKind = HashKind::Sha2_256; pub const LEN: usize = Self::KIND.len(); } impl AsRef<[u8]> for Sha2_256 { fn as_ref(&self) -> &[u8] { self.0.as_slice() } } impl AsMut<[u8]> for Sha2_256 { fn as_mut(&mut self) -> &mut [u8] { self.0.as_mut_slice() } } impl From for Sha2_256 { fn from(value: DigestBytes) -> Self { let mut hash = Sha2_256::new(()); // TODO: It would be great if there was a way to avoid this copy. hash.as_mut().copy_from_slice(value.as_ref()); hash } } impl From<[u8; Self::LEN]> for Sha2_256 { fn from(value: [u8; Self::LEN]) -> Self { Sha2_256(value) } } impl From for [u8; Sha2_256::LEN] { fn from(value: Sha2_256) -> Self { value.0 } } impl Hash for Sha2_256 { type Op = OsslHashOp; type Arg = (); fn new(_: Self::Arg) -> Self { Sha2_256([0u8; Self::KIND.len()]) } fn kind(&self) -> HashKind { Self::KIND } fn start_op(&self) -> Result { OsslHashOp::init(Self::KIND) } } #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Hashable, Clone)] pub struct Sha2_512(#[serde(with = "BigArray")] [u8; Self::LEN]); impl Sha2_512 { pub const KIND: HashKind = HashKind::Sha2_512; pub const LEN: usize = Self::KIND.len(); } impl AsRef<[u8]> for Sha2_512 { fn as_ref(&self) -> &[u8] { self.0.as_slice() } } impl AsMut<[u8]> for Sha2_512 { fn as_mut(&mut self) -> &mut [u8] { self.0.as_mut_slice() } } impl From for Sha2_512 { fn from(value: DigestBytes) -> Self { let mut hash = Sha2_512::new(()); hash.as_mut().copy_from_slice(value.as_ref()); hash } } impl From<[u8; Self::LEN]> for Sha2_512 { fn from(value: [u8; Self::LEN]) -> Self { Self(value) } } impl From for [u8; Sha2_512::LEN] { fn from(value: Sha2_512) -> Self { value.0 } } impl Hash for Sha2_512 { type Op = OsslHashOp; type Arg = (); fn new(_: Self::Arg) -> Self { Sha2_512([0u8; Self::LEN]) } fn kind(&self) -> HashKind { Self::KIND } fn start_op(&self) -> Result { OsslHashOp::init(Self::KIND) } } /// One of several concrete hash types. #[derive( Debug, PartialEq, Eq, Serialize, Deserialize, Hashable, Clone, EnumDiscriminants, PartialOrd, Ord, )] #[strum_discriminants(derive(FromRepr, Display, Serialize, Deserialize))] #[strum_discriminants(name(HashKind))] pub enum VarHash { Sha2_256(Sha2_256), Sha2_512(Sha2_512), } #[allow(clippy::derivable_impls)] impl Default for HashKind { fn default() -> HashKind { HashKind::Sha2_256 } } impl Default for VarHash { fn default() -> Self { HashKind::default().into() } } impl HashKind { #[allow(clippy::len_without_is_empty)] pub const fn len(self) -> usize { match self { HashKind::Sha2_256 => 32, HashKind::Sha2_512 => 64, } } pub fn digest<'a, I: Iterator>(self, dest: &mut [u8], parts: I) -> Result<()> { btensure!( dest.len() == self.len(), Error::IncorrectSize { expected: self.len(), actual: dest.len(), } ); let mut hasher = Hasher::new(self.into())?; for part in parts { hasher.update(part)?; } let hash = hasher.finish()?; dest.copy_from_slice(&hash); Ok(()) } } /// An implementation of [std::hash::Hasher] which allows cryptographic hash algorithms to be used. pub struct BtHasher { hasher: RefCell, } impl BtHasher { pub fn new(kind: HashKind) -> Result { btensure!( kind.len() >= 8, bterr!("only digests which produce at least 8 bytes are supported") ); let hasher = RefCell::new(Hasher::new(kind.into())?); Ok(Self { hasher }) } } impl std::hash::Hasher for BtHasher { fn write(&mut self, bytes: &[u8]) { let hasher = self.hasher.get_mut(); hasher.update(bytes).unwrap(); } fn finish(&self) -> u64 { let mut hasher = self.hasher.borrow_mut(); let hash = hasher.finish().unwrap(); let mut buf = [0u8; 8]; buf.copy_from_slice(&hash[..8]); u64::from_le_bytes(buf) } fn write_u8(&mut self, i: u8) { self.write(&[i]) } fn write_u16(&mut self, i: u16) { self.write(&i.to_le_bytes()) } fn write_u32(&mut self, i: u32) { self.write(&i.to_le_bytes()) } fn write_u64(&mut self, i: u64) { self.write(&i.to_le_bytes()) } fn write_u128(&mut self, i: u128) { self.write(&i.to_le_bytes()) } fn write_usize(&mut self, i: usize) { self.write(&i.to_le_bytes()) } fn write_i8(&mut self, i: i8) { self.write_u8(i as u8) } fn write_i16(&mut self, i: i16) { self.write_u16(i as u16) } fn write_i32(&mut self, i: i32) { self.write_u32(i as u32) } fn write_i64(&mut self, i: i64) { self.write_u64(i as u64) } fn write_i128(&mut self, i: i128) { self.write_u128(i as u128) } fn write_isize(&mut self, i: isize) { self.write_usize(i as usize) } } impl TryFrom for HashKind { type Error = crate::Error; fn try_from(value: MessageDigest) -> Result { let nid = value.type_(); if Nid::SHA256 == nid { Ok(HashKind::Sha2_256) } else if Nid::SHA512 == nid { Ok(HashKind::Sha2_512) } else { Err(bterr!("Unsupported MessageDigest with NID: {:?}", nid)) } } } impl From for MessageDigest { fn from(kind: HashKind) -> Self { match kind { HashKind::Sha2_256 => MessageDigest::sha256(), HashKind::Sha2_512 => MessageDigest::sha512(), } } } impl VarHash { /// The character that's used to separate a hash type from its value in its string /// representation. const HASH_SEP: char = '!'; pub fn kind(&self) -> HashKind { self.into() } pub fn as_slice(&self) -> &[u8] { self.as_ref() } pub fn as_mut_slice(&mut self) -> &mut [u8] { self.as_mut() } } impl From for VarHash { fn from(kind: HashKind) -> VarHash { match kind { HashKind::Sha2_256 => VarHash::Sha2_256(Sha2_256::default()), HashKind::Sha2_512 => VarHash::Sha2_512(Sha2_512::default()), } } } impl AsRef<[u8]> for VarHash { fn as_ref(&self) -> &[u8] { match self { VarHash::Sha2_256(arr) => arr.as_ref(), VarHash::Sha2_512(arr) => arr.as_ref(), } } } impl AsMut<[u8]> for VarHash { fn as_mut(&mut self) -> &mut [u8] { match self { VarHash::Sha2_256(arr) => arr.as_mut(), VarHash::Sha2_512(arr) => arr.as_mut(), } } } impl TryFrom for VarHash { type Error = crate::Error; fn try_from(value: MessageDigest) -> Result { let kind: HashKind = value.try_into()?; Ok(kind.into()) } } impl Hash for VarHash { type Op = VarHashOp; type Arg = HashKind; fn new(arg: Self::Arg) -> Self { arg.into() } fn kind(&self) -> HashKind { self.kind() } fn start_op(&self) -> Result { VarHashOp::init(self.kind()) } } impl TryFrom<&str> for VarHash { type Error = crate::Error; fn try_from(string: &str) -> Result { let mut split: Vec<&str> = string.split(Self::HASH_SEP).collect(); if split.len() != 2 { return Err(bterr!(Error::InvalidHashFormat)); }; let second = split.pop().ok_or(Error::InvalidHashFormat)?; let first = split .pop() .ok_or(Error::InvalidHashFormat)? .parse::() .map_err(|_| Error::InvalidHashFormat)?; let mut hash = VarHash::from(HashKind::from_repr(first).ok_or(Error::InvalidHashFormat)?); base64_url::decode_to_slice(second, hash.as_mut()).map_err(|_| Error::InvalidHashFormat)?; Ok(hash) } } impl Display for VarHash { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let hash_kind: HashKind = self.into(); let hash_data = base64_url::encode(self.as_ref()); write!(f, "{}{}{hash_data}", hash_kind as u32, VarHash::HASH_SEP) } } pub struct VarHashOp { kind: HashKind, hasher: Hasher, } impl Op for VarHashOp { type Arg = HashKind; fn init(arg: Self::Arg) -> Result { let hasher = Hasher::new(arg.into())?; Ok(VarHashOp { kind: arg, hasher }) } fn update(&mut self, data: &[u8]) -> Result<()> { Ok(self.hasher.update(data)?) } fn finish_into(mut self, buf: &mut [u8]) -> Result { btensure!( buf.len() >= self.kind.len(), bterr!(Error::IncorrectSize { expected: self.kind.len(), actual: buf.len(), }) ); let digest = self.hasher.finish()?; let slice = digest.as_ref(); buf.copy_from_slice(slice); Ok(slice.len()) } } impl HashOp for VarHashOp { type Hash = VarHash; fn kind(&self) -> HashKind { self.kind } fn finish(mut self) -> Result { let digest = self.hasher.finish()?; let mut hash: VarHash = self.kind.into(); hash.as_mut().copy_from_slice(digest.as_ref()); Ok(hash) } } /// A cryptographic signature. #[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone, Default)] pub struct Signature { kind: Sign, data: Vec, } impl Signature { pub fn new(kind: Sign, data: Vec) -> Self { Self { kind, data } } pub fn empty(kind: Sign) -> Signature { let data = vec![0; kind.key_len() as usize]; Signature { kind, data } } pub fn copy_from(kind: Sign, from: &[u8]) -> Signature { let mut data = vec![0; kind.key_len() as usize]; data.as_mut_slice().copy_from_slice(from); Signature { kind, data } } pub fn as_slice(&self) -> &[u8] { self.data.as_slice() } pub fn as_mut_slice(&mut self) -> &mut [u8] { self.data.as_mut_slice() } pub fn scheme(&self) -> Sign { self.kind } pub fn take_data(self) -> Vec { self.data } } 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() } } #[derive(Serialize, Deserialize)] struct TaggedCiphertext { aad: U, ciphertext: Ciphertext, tag: Vec, } #[derive(EnumDiscriminants, ZeroizeOnDrop)] #[strum_discriminants(name(AeadKeyKind))] #[strum_discriminants(derive(Serialize, Deserialize))] pub enum AeadKey { AesGcm256 { key: [u8; AeadKeyKind::AesGcm256.key_len()], iv: [u8; AeadKeyKind::AesGcm256.iv_len()], }, } impl AeadKeyKind { const fn key_len(self) -> usize { match self { AeadKeyKind::AesGcm256 => 32, } } const fn iv_len(self) -> usize { match self { AeadKeyKind::AesGcm256 => 16, } } } fn array_from(slice: &[u8]) -> Result<[u8; N]> { let slice_len = slice.len(); btensure!( N == slice_len, Error::IncorrectSize { actual: slice_len, expected: N, } ); let mut array = [0u8; N]; array.copy_from_slice(slice); Ok(array) } impl AeadKey { pub fn new(kind: AeadKeyKind) -> Result { match kind { AeadKeyKind::AesGcm256 => Ok(AeadKey::AesGcm256 { key: rand_array()?, iv: rand_array()?, }), } } fn copy_components(kind: AeadKeyKind, key_buf: &[u8], iv_buf: &[u8]) -> Result { match kind { AeadKeyKind::AesGcm256 => Ok(AeadKey::AesGcm256 { key: array_from(key_buf)?, iv: array_from(iv_buf)?, }), } } fn encrypt( &self, aad: U, plaintext: &T, ) -> Result> { let (cipher, key, iv, mut tag) = match self { AeadKey::AesGcm256 { key, iv } => ( Cipher::aes_256_gcm(), key.as_slice(), iv.as_slice(), vec![0u8; 16], ), }; let aad_data = to_vec(&aad)?; let plaintext_buf = to_vec(&plaintext)?; let mut ciphertext = vec![0u8; plaintext_buf.len() + cipher.block_size()]; let mut crypter = Crypter::new(cipher, Mode::Encrypt, key, Some(iv))?; crypter.aad_update(&aad_data)?; let mut count = crypter.update(&plaintext_buf, &mut ciphertext)?; count += crypter.finalize(&mut ciphertext[count..])?; ciphertext.truncate(count); crypter.get_tag(&mut tag)?; Ok(TaggedCiphertext { aad, ciphertext: Ciphertext::new(ciphertext), tag, }) } fn decrypt( &self, tagged: &TaggedCiphertext, ) -> Result { let ciphertext = &tagged.ciphertext.data; let (cipher, key, iv) = match self { AeadKey::AesGcm256 { key, iv } => { (Cipher::aes_256_gcm(), key.as_slice(), iv.as_slice()) } }; let mut plaintext = vec![0u8; ciphertext.len() + cipher.block_size()]; let mut crypter = Crypter::new(cipher, Mode::Decrypt, key, Some(iv))?; crypter.set_tag(&tagged.tag)?; let aad_buf = to_vec(&tagged.aad)?; crypter.aad_update(&aad_buf)?; let mut count = crypter.update(ciphertext, &mut plaintext)?; count += crypter.finalize(&mut plaintext[count..])?; plaintext.truncate(count); Ok(from_vec(&plaintext)?) } } #[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone, EnumDiscriminants, ZeroizeOnDrop)] #[strum_discriminants(name(SymKeyKind))] pub 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]>, } 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 } } fn block_size(&self) -> usize { let SymParams { cipher, .. } = self.params(); cipher.block_size() } // The number of bytes that the plaintext expands by when encrypted. fn expansion_sz(&self) -> usize { match self { SymKey::Aes256Cbc { .. } => 16, SymKey::Aes256Ctr { .. } => 0, } } fn to_encrypter(&self) -> Result { let SymParams { cipher, key, iv } = self.params(); Ok(Crypter::new(cipher, Mode::Encrypt, key, iv)?) } fn to_decrypter(&self) -> Result { let SymParams { cipher, key, iv } = self.params(); Ok(Crypter::new(cipher, Mode::Decrypt, key, iv)?) } pub fn key_slice(&self) -> &[u8] { let SymParams { key, .. } = self.params(); key } pub fn iv_slice(&self) -> Option<&[u8]> { let SymParams { iv, .. } = self.params(); iv } } impl Encrypter for SymKey { fn encrypt(&self, slice: &[u8]) -> Result> { let SymParams { cipher, key, iv } = self.params(); Ok(openssl_encrypt(cipher, key, iv, slice)?) } } impl Decrypter for SymKey { fn decrypt(&self, slice: &[u8]) -> Result> { let SymParams { cipher, key, iv } = self.params(); Ok(openssl_decrypt(cipher, key, iv, slice)?) } } #[allow(clippy::derivable_impls)] impl Default for SymKeyKind { fn default() -> Self { SymKeyKind::Aes256Ctr } } #[repr(u32)] #[derive(Debug, Display, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] pub enum BitLen { Bits128 = 16, Bits256 = 32, Bits512 = 64, Bits2048 = 256, Bits3072 = 384, Bits4096 = 512, } impl BitLen { const fn bits(self) -> u32 { 8 * self as u32 } fn try_from_u32(value: u32) -> Result { match value { 16 => Ok(Self::Bits128), 32 => Ok(Self::Bits256), 64 => Ok(Self::Bits512), 256 => Ok(Self::Bits2048), 384 => Ok(Self::Bits3072), 512 => Ok(Self::Bits4096), _ => Err(bterr!("invalid KeyLen value: {value}")), } } } impl TryFrom for BitLen { type Error = crate::Error; fn try_from(value: u32) -> std::result::Result { Self::try_from_u32(value) } } /// A Cryptographic Scheme. This is a common type for operations such as encrypting, decrypting, /// signing and verifying. pub trait Scheme: for<'de> Deserialize<'de> + Serialize + Copy + std::fmt::Debug + PartialEq + Into { type Kind: Scheme; fn as_enum(self) -> SchemeKind; fn hash_kind(&self) -> HashKind; fn padding(&self) -> Option; fn public_from_der(self, der: &[u8]) -> Result>; fn private_from_der(self, der: &[u8]) -> Result>; fn generate(self) -> Result>; fn key_len(self) -> BitLen; fn message_digest(&self) -> MessageDigest { self.hash_kind().into() } } pub enum SchemeKind { Sign(Sign), Encrypt(Encrypt), } #[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq, Copy)] pub enum Encrypt { RsaEsOaep(RsaEsOaep), } impl Scheme for Encrypt { type Kind = Encrypt; fn as_enum(self) -> SchemeKind { SchemeKind::Encrypt(self) } fn hash_kind(&self) -> HashKind { match self { Encrypt::RsaEsOaep(inner) => inner.hash_kind(), } } 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(), } } fn key_len(self) -> BitLen { match self { Encrypt::RsaEsOaep(inner) => inner.key_len(), } } } impl Encrypt { pub const RSA_OAEP_2048_SHA_256: Encrypt = Encrypt::RsaEsOaep(RsaEsOaep { key_len: BitLen::Bits2048, hash_kind: HashKind::Sha2_256, }); pub const RSA_OAEP_3072_SHA_256: Encrypt = Encrypt::RsaEsOaep(RsaEsOaep { key_len: BitLen::Bits3072, hash_kind: HashKind::Sha2_256, }); } #[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq, Copy)] pub enum Sign { RsaSsaPss(RsaSsaPss), } impl Default for Sign { fn default() -> Self { Self::RSA_PSS_2048_SHA_256 } } impl Scheme for Sign { type Kind = Sign; fn as_enum(self) -> SchemeKind { SchemeKind::Sign(self) } fn hash_kind(&self) -> HashKind { match self { Sign::RsaSsaPss(inner) => inner.hash_kind(), } } 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(), } } fn key_len(self) -> BitLen { self.key_len_const() } } impl Sign { pub const RSA_PSS_2048_SHA_256: Sign = Sign::RsaSsaPss(RsaSsaPss { key_bits: BitLen::Bits2048, hash_kind: HashKind::Sha2_256, }); pub const RSA_PSS_3072_SHA_256: Sign = Sign::RsaSsaPss(RsaSsaPss { key_bits: BitLen::Bits3072, hash_kind: HashKind::Sha2_256, }); const fn key_len_const(self) -> BitLen { match self { Sign::RsaSsaPss(inner) => inner.key_bits, } } } enum Rsa {} impl Rsa { /// The default public exponent to use for generated RSA keys. const EXP: u32 = 65537; // 2**16 + 1 fn generate(scheme: S) -> Result> { let key = OsslRsa::generate(scheme.key_len().bits())?; // TODO: Separating the keys this way seems inefficient. Investigate alternatives. let public_der = key.public_key_to_der()?; let private_der = key.private_key_to_der()?; let public = AsymKey::::new(scheme, &public_der)?; let private = AsymKey::::new(scheme, &private_der)?; Ok(AsymKeyPair { public, private }) } } #[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq, Copy)] pub struct RsaEsOaep { key_len: BitLen, hash_kind: HashKind, } impl Scheme for RsaEsOaep { type Kind = Encrypt; fn as_enum(self) -> SchemeKind { SchemeKind::Encrypt(self.into()) } fn hash_kind(&self) -> HashKind { self.hash_kind } fn padding(&self) -> Option { Some(OpensslPadding::PKCS1_OAEP) } fn public_from_der(self, der: &[u8]) -> Result> { Ok(PKey::public_key_from_der(der)?.conv_pub()) } fn private_from_der(self, der: &[u8]) -> Result> { Ok(PKey::private_key_from_der(der)?.conv_priv()) } fn generate(self) -> Result> { Rsa::generate(self.into()) } fn key_len(self) -> BitLen { self.key_len } } impl From for Encrypt { fn from(scheme: RsaEsOaep) -> Self { Encrypt::RsaEsOaep(scheme) } } #[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq, Copy)] pub struct RsaSsaPss { key_bits: BitLen, hash_kind: HashKind, } impl Scheme for RsaSsaPss { type Kind = Sign; fn as_enum(self) -> SchemeKind { SchemeKind::Sign(self.into()) } fn hash_kind(&self) -> HashKind { self.hash_kind } fn padding(&self) -> Option { Some(OpensslPadding::PKCS1_PSS) } fn public_from_der(self, der: &[u8]) -> Result> { Ok(PKey::public_key_from_der(der)?.conv_pub()) } fn private_from_der(self, der: &[u8]) -> Result> { Ok(PKey::private_key_from_der(der)?.conv_priv()) } fn generate(self) -> Result> { Rsa::generate(self.into()) } fn key_len(self) -> BitLen { self.key_bits } } impl From for Sign { fn from(scheme: RsaSsaPss) -> Self { Sign::RsaSsaPss(scheme) } } /// Marker trait for the `Public` and `Private` key privacy types. pub trait KeyPrivacy {} /// Represents keys which can be shared freely. #[derive(Clone, Debug)] pub enum Public {} impl KeyPrivacy for Public {} unsafe impl HasPublic for Public {} #[derive(Debug, Clone)] /// Represents keys which must be kept confidential. pub enum Private {} impl KeyPrivacy for Private {} unsafe impl HasPrivate for Private {} trait PKeyExt { /// Converts a PKey to a PKey. This hack allows for converting between openssl's /// Public and Private types and ours. fn conv_pkey(self) -> PKey; /// Convert from openssl's Public type to `crypto::Public`. fn conv_pub(self) -> PKey; /// Convert from openssl's Private type to `crypto::Private`. fn conv_priv(self) -> PKey; } impl PKeyExt for PKey { fn conv_pkey(self) -> PKey { let ptr = self.as_ptr(); let new_pkey = unsafe { PKey::from_ptr(ptr) }; std::mem::forget(self); new_pkey } fn conv_pub(self) -> PKey { self.conv_pkey() } fn conv_priv(self) -> PKey { self.conv_pkey() } } /// Represents any kind of asymmetric key. #[derive(Debug, Clone)] pub struct AsymKey { scheme: S, pkey: PKey

, } impl AsymKey { pub fn scheme(&self) -> S { self.scheme } } pub type AsymKeyPub = AsymKey; impl AsymKey { pub(crate) fn new(scheme: S, der: &[u8]) -> Result> { let pkey = scheme.public_from_der(der)?; Ok(AsymKey { scheme, pkey }) } } impl AsymKey { pub(crate) fn new(scheme: S, der: &[u8]) -> Result> { let pkey = scheme.private_from_der(der)?; Ok(AsymKey { scheme, pkey }) } pub fn to_der(&self) -> Result> { self.pkey.private_key_to_der().map_err(|err| err.into()) } } 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 Principaled for AsymKey { fn principal_of_kind(&self, kind: HashKind) -> Principal { let der = self.pkey.public_key_to_der().unwrap(); let bytes = hash(kind.into(), der.as_slice()).unwrap(); let mut hash_buf = VarHash::from(kind); hash_buf.as_mut().copy_from_slice(&bytes); Principal(hash_buf) } } impl Encrypter for AsymKey { fn encrypt(&self, slice: &[u8]) -> Result> { let mut encrypter = OsslEncrypter::new(&self.pkey)?; if let Some(padding) = self.scheme.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)?; if let Some(padding) = self.scheme.padding() { decrypter.set_rsa_padding(padding)?; } { let Encrypt::RsaEsOaep(inner) = self.scheme; decrypter.set_rsa_oaep_md(inner.message_digest())?; } let buffer_len = decrypter.decrypt_len(slice)?; let mut plaintext = vec![0; buffer_len]; let plaintext_len = decrypter.decrypt(slice, &mut plaintext)?; plaintext.truncate(plaintext_len); Ok(plaintext) } } impl Signer for AsymKey { type Op<'s> = OsslSignOp<'s>; fn init_sign(&self) -> Result> { OsslSignOp::init((self.scheme, self.pkey.as_ref())) } 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 = Signature::empty(self.scheme); signer.sign(signature.as_mut_slice())?; Ok(signature) } fn kind(&self) -> Sign { self.scheme } } impl Verifier for AsymKey { type Op<'v> = OsslVerifyOp<'v>; fn init_verify(&self) -> Result> { OsslVerifyOp::init((self.scheme, self.pkey.as_ref())) } fn verify<'a, I: Iterator>(&self, parts: I, signature: &[u8]) -> Result<()> { let mut verifier = OsslVerifier::new(self.scheme.message_digest(), &self.pkey)?; if let Some(padding) = self.scheme.padding() { verifier.set_rsa_padding(padding)?; } for part in parts { verifier.update(part)?; } if verifier.verify(signature)? { Ok(()) } else { Err(bterr!(Error::InvalidSignature)) } } fn kind(&self) -> Sign { self.scheme } } #[derive(Clone)] 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 }) } pub fn public(&self) -> &AsymKey { &self.public } pub fn private(&self) -> &AsymKey { &self.private } } // Note that only signing keys are associated with a Principal. impl Principaled for AsymKeyPair { fn principal_of_kind(&self, kind: HashKind) -> Principal { self.public.principal_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 { type Op<'s> = as Signer>::Op<'s>; fn init_sign(&self) -> Result> { self.private.init_sign() } fn sign<'a, I: Iterator>(&self, parts: I) -> Result { self.private.sign(parts) } fn kind(&self) -> Sign { self.private.kind() } } impl Verifier for AsymKeyPair { type Op<'v> = OsslVerifyOp<'v>; fn init_verify(&self) -> Result> { self.public.init_verify() } fn verify<'a, I: Iterator>(&self, parts: I, signature: &[u8]) -> Result<()> { self.public.verify(parts, signature) } fn kind(&self) -> Sign { self.public.kind() } } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ConcretePub { pub sign: AsymKeyPub, pub enc: AsymKeyPub, } impl Principaled for ConcretePub { fn principal_of_kind(&self, kind: HashKind) -> Principal { self.sign.principal_of_kind(kind) } } impl Encrypter for ConcretePub { fn encrypt(&self, slice: &[u8]) -> Result> { self.enc.encrypt(slice) } } impl Verifier for ConcretePub { type Op<'v> = OsslVerifyOp<'v>; fn init_verify(&self) -> Result> { self.sign.init_verify() } fn verify<'a, I: Iterator>(&self, parts: I, signature: &[u8]) -> Result<()> { self.sign.verify(parts, signature) } fn kind(&self) -> Sign { self.sign.kind() } } impl CredsPub for ConcretePub { fn public_sign(&self) -> &AsymKey { &self.sign } fn concrete_pub(&self) -> ConcretePub { self.clone() } } impl PartialEq for ConcretePub { fn eq(&self, other: &Self) -> bool { self.principal() == other.principal() } } #[derive(Clone)] pub struct ConcreteCreds { sign: AsymKeyPair, encrypt: AsymKeyPair, writecap: Option, } impl ConcreteCreds { pub fn new(sign: AsymKeyPair, encrypt: AsymKeyPair) -> ConcreteCreds { ConcreteCreds { sign, encrypt, writecap: None, } } pub 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, writecap: None, }) } pub fn set_writecap(&mut self, writecap: Writecap) { self.writecap = Some(writecap) } pub fn sign_pair(&self) -> &AsymKeyPair { &self.sign } pub fn encrypt_pair(&self) -> &AsymKeyPair { &self.encrypt } } impl Verifier for ConcreteCreds { type Op<'v> = OsslVerifyOp<'v>; fn init_verify(&self) -> Result> { self.sign.init_verify() } fn verify<'a, I: Iterator>(&self, parts: I, signature: &[u8]) -> Result<()> { self.sign.verify(parts, signature) } fn kind(&self) -> Sign { Verifier::kind(&self.sign) } } impl Encrypter for ConcreteCreds { fn encrypt(&self, slice: &[u8]) -> Result> { self.encrypt.encrypt(slice) } } impl Principaled for ConcreteCreds { fn principal_of_kind(&self, kind: HashKind) -> Principal { self.sign.principal_of_kind(kind) } } impl CredsPub for ConcreteCreds { fn public_sign(&self) -> &AsymKey { &self.sign.public } fn concrete_pub(&self) -> ConcretePub { ConcretePub { sign: self.sign.public.clone(), enc: self.encrypt.public.clone(), } } } impl Signer for ConcreteCreds { type Op<'s> = as Signer>::Op<'s>; fn init_sign(&self) -> Result> { self.sign.init_sign() } fn sign<'a, I: Iterator>(&self, parts: I) -> Result { self.sign.sign(parts) } fn kind(&self) -> Sign { Signer::kind(&self.sign) } } impl Decrypter for ConcreteCreds { fn decrypt(&self, slice: &[u8]) -> Result> { self.encrypt.decrypt(slice) } } impl CredsPriv for ConcreteCreds { fn writecap(&self) -> Option<&Writecap> { self.writecap.as_ref() } } pub trait Encrypter { fn encrypt(&self, slice: &[u8]) -> Result>; } impl Encrypter for &T { fn encrypt(&self, slice: &[u8]) -> Result> { (*self).encrypt(slice) } } pub trait EncrypterExt: Encrypter { /// Serializes the given value into a new vector, then encrypts it and returns the resulting /// ciphertext. fn ser_encrypt(&self, value: &T) -> Result> { let data = to_vec(value)?; let data = self.encrypt(&data)?; Ok(Ciphertext::new(data)) } } impl EncrypterExt for T {} pub trait Decrypter { fn decrypt(&self, slice: &[u8]) -> Result>; } impl Decrypter for &T { fn decrypt(&self, slice: &[u8]) -> Result> { (*self).decrypt(slice) } } pub trait DecrypterExt: Decrypter { fn ser_decrypt(&self, ct: &Ciphertext) -> Result { let pt = self.decrypt(ct.data.as_slice())?; Ok(from_vec(&pt)?) } } impl DecrypterExt for T {} /// Represents an ongoing signing operation. pub trait SignOp: Op { /// Returns the signature scheme that this operation is using. fn scheme(&self) -> Sign; /// Finishes this signature operation and returns a new signature containing the result. fn finish(self) -> Result { let scheme = self.scheme(); let mut sig = Signature::empty(scheme); self.finish_into(sig.as_mut())?; Ok(sig) } } pub struct OsslSignOp<'a> { signer: OsslSigner<'a>, scheme: Sign, } impl<'a> Op for OsslSignOp<'a> { type Arg = (Sign, &'a PKeyRef); fn init(arg: Self::Arg) -> Result { let scheme = arg.0; let mut signer = OsslSigner::new(arg.0.message_digest(), arg.1)?; if let Some(padding) = scheme.padding() { signer.set_rsa_padding(padding)?; } Ok(OsslSignOp { signer, scheme }) } fn update(&mut self, data: &[u8]) -> Result<()> { Ok(self.signer.update(data)?) } fn finish_into(self, buf: &mut [u8]) -> Result { Ok(self.signer.sign(buf)?) } } impl<'a> SignOp for OsslSignOp<'a> { fn scheme(&self) -> Sign { self.scheme } } /// A struct which computes a signature over data as it is written to it. pub struct SignWrite { inner: T, op: Op, } impl SignWrite { pub fn new(inner: T, op: Op) -> Self { SignWrite { inner, op } } pub fn finish_into(self, buf: &mut [u8]) -> Result<(usize, T)> { Ok((self.op.finish_into(buf)?, self.inner)) } pub fn finish(self) -> Result<(Signature, T)> { Ok((self.op.finish()?, self.inner)) } } impl Write for SignWrite { fn write(&mut self, buf: &[u8]) -> io::Result { self.op.update(buf)?; self.inner.write(buf) } fn flush(&mut self) -> io::Result<()> { self.inner.flush() } } pub trait Signer { type Op<'s>: SignOp where Self: 's; /// Starts a new signing operation and returns the struct representing it. fn init_sign(&self) -> Result>; /// Returns a signature over the given parts. It's critical that subsequent invocations /// of this method on the same instance return a [Signature] with `data` fields of the same /// length. fn sign<'a, I: Iterator>(&self, parts: I) -> Result; fn ser_sign(&self, value: &T) -> Result> { let data = to_vec(value)?; let sig = self.sign(std::iter::once(data.as_slice()))?; Ok(Signed::new(data, sig)) } fn sign_writecap(&self, writecap: &mut Writecap) -> Result<()> { let signed = self.ser_sign(&writecap.body)?; writecap.signature = signed.sig; Ok(()) } fn ser_sign_into(&self, value: &T, buf: &mut Vec) -> Result { write_to(value, &mut *buf)?; self.sign(std::iter::once(buf.as_slice())) } fn kind(&self) -> Sign; } impl Signer for &T { type Op<'s> = T::Op<'s> where Self: 's; fn init_sign(&self) -> Result> { (*self).init_sign() } fn sign<'a, I: Iterator>(&self, parts: I) -> Result { (*self).sign(parts) } fn kind(&self) -> Sign { (*self).kind() } } pub trait VerifyOp: Sized { type Arg; fn init(arg: Self::Arg) -> Result; fn update(&mut self, data: &[u8]) -> Result<()>; fn finish(self, sig: &[u8]) -> Result<()>; fn scheme(&self) -> Sign; } pub struct OsslVerifyOp<'a> { verifier: OsslVerifier<'a>, scheme: Sign, } impl<'a> VerifyOp for OsslVerifyOp<'a> { type Arg = (Sign, &'a PKeyRef); fn init(arg: Self::Arg) -> Result { let scheme = arg.0; let mut verifier = OsslVerifier::new(scheme.message_digest(), arg.1)?; if let Some(padding) = scheme.padding() { verifier.set_rsa_padding(padding)?; } Ok(OsslVerifyOp { verifier, scheme }) } fn update(&mut self, data: &[u8]) -> Result<()> { Ok(self.verifier.update(data)?) } fn finish(self, sig: &[u8]) -> Result<()> { match self.verifier.verify(sig) { Ok(true) => Ok(()), Ok(false) => Err(bterr!(Error::InvalidSignature)), Err(err) => Err(err.into()), } } fn scheme(&self) -> Sign { self.scheme } } pub struct VerifyRead { inner: T, op: Op, update_failed: bool, } impl VerifyRead { pub fn new(inner: T, op: Op) -> Self { VerifyRead { inner, op, update_failed: false, } } pub fn finish(self, sig: &[u8]) -> std::result::Result { if self.update_failed { return Err(( self.inner, bterr!("VerifyRead::finish: update_failed was true"), )); } match self.op.finish(sig) { Ok(_) => Ok(self.inner), Err(err) => Err((self.inner, err)), } } } impl Read for VerifyRead { fn read(&mut self, buf: &mut [u8]) -> io::Result { if self.update_failed { return Err(bterr!("VerifyRead::read update previously failed").into()); } let read = self.inner.read(buf)?; if read > 0 { if let Err(err) = self.op.update(&buf[..read]) { self.update_failed = true; error!("VerifyRead::read failed to update VerifyOp: {err}"); } } Ok(read) } } pub trait Verifier { type Op<'v>: VerifyOp where Self: 'v; fn init_verify(&self) -> Result>; fn verify<'a, I: Iterator>(&self, parts: I, signature: &[u8]) -> Result<()>; fn ser_verify(&self, value: &T, signature: &[u8]) -> Result<()> { let data = to_vec(value)?; self.verify(std::iter::once(data.as_slice()), signature) } fn kind(&self) -> Sign; } impl Verifier for &T { type Op<'v> = T::Op<'v> where Self: 'v; fn init_verify(&self) -> Result> { (*self).init_verify() } fn verify<'a, I: Iterator>(&self, parts: I, signature: &[u8]) -> Result<()> { (*self).verify(parts, signature) } fn kind(&self) -> Sign { (*self).kind() } } /// Trait for types which can be used as public credentials. pub trait CredsPub: Verifier + Encrypter + Principaled { /// Returns a reference to the public signing key which can be used to verify signatures. fn public_sign(&self) -> &AsymKey; fn concrete_pub(&self) -> ConcretePub; fn sign_kind(&self) -> Sign { Verifier::kind(self) } } impl CredsPub for &T { fn public_sign(&self) -> &AsymKey { (*self).public_sign() } fn concrete_pub(&self) -> ConcretePub { (*self).concrete_pub() } } /// Trait for types which contain private credentials. pub trait CredsPriv: Decrypter + Signer { /// Returns a reference to the writecap associated with these credentials, if one has been /// issued. fn writecap(&self) -> Option<&Writecap>; fn sign_kind(&self) -> Sign { Signer::kind(self) } } impl CredsPriv for &T { fn writecap(&self) -> Option<&Writecap> { (*self).writecap() } } /// Trait for types which contain both public and private credentials. pub trait Creds: CredsPriv + CredsPub + Clone { fn issue_writecap( &self, issued_to: Principal, path_components: Vec, expires: Epoch, ) -> Result { // The root principal is given by the path in our writecap, or if we don't have a writecap, // then we assume we are the root principal. let root_principal = self .writecap() .map(|e| e.root_principal()) .unwrap_or_else(|| self.principal()); let path = BlockPath::new(root_principal, path_components); let body = WritecapBody { issued_to, path, expires, signing_key: self.public_sign().to_owned(), }; let signed = self.ser_sign(&body)?; Ok(Writecap { body, signature: signed.sig, next: self.writecap().map(|e| Box::new(e.to_owned())), }) } fn pub_sign_kind(&self) -> Sign { CredsPub::sign_kind(self) } fn priv_sign_kind(&self) -> Sign { CredsPriv::sign_kind(self) } } impl Creds for C {} /// A trait for types which store credentials. pub trait CredStore { type CredHandle: Creds; type ExportedCreds: Serialize + for<'de> Deserialize<'de>; /// 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; fn storage_key(&self) -> Result>; fn export_root_creds( &self, root_creds: &Self::CredHandle, password: &str, new_parent: &AsymKeyPub, ) -> Result; fn import_root_creds( &self, password: &str, exported: Self::ExportedCreds, ) -> Result; fn assign_node_writecap(&self, handle: &mut Self::CredHandle, writecap: Writecap) -> Result<()>; } impl BlockMeta { /// Validates that this metadata struct contains a valid writecap, that this writecap is /// permitted to write to the path of this block and that the signature in this metadata struct /// is valid and matches the key the writecap was issued to. pub fn assert_valid(&self, path: &BlockPath) -> Result<()> { let body = &self.body; let writecap = body .writecap .as_ref() .ok_or(crate::BlockError::MissingWritecap)?; writecap.assert_valid_for(path)?; let signed_by = body.signing_key.principal(); if writecap.body.issued_to != signed_by { return Err(bterr!(Error::signature_mismatch( writecap.body.issued_to.clone(), signed_by, ))); } body.signing_key.ser_verify(&body, self.sig.as_slice()) } } /// The types of errors which can occur when verifying a writecap chain is authorized to write to /// a given path. #[derive(Debug, PartialEq, Eq, Display)] pub 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, /// The principal the root writecap was issued to does not own the given path. RootDoesNotOwnPath, /// An error occurred while serializing a writecap. Serde(String), /// The write cap chain was too long to be validated. The value contained in this error is /// the maximum allowed length. ChainTooLong(usize), } impl Writecap { /// Verifies that the given [Writecap] actually grants permission to write to the given /// [BlockPath]. pub fn assert_valid_for(&self, path: &BlockPath) -> Result<()> { let mut writecap = self; const CHAIN_LEN_LIMIT: usize = 256; let mut prev: Option<&Writecap> = None; let mut sig_input_buf = Vec::new(); let now = Epoch::now(); for _ in 0..CHAIN_LEN_LIMIT { if !writecap.body.path.contains(path) { return Err(bterr!(WritecapAuthzErr::UnauthorizedPath)); } if writecap.body.expires <= now { return Err(bterr!(WritecapAuthzErr::Expired)); } if let Some(prev) = &prev { if prev .body .signing_key .principal_of_kind(writecap.body.issued_to.kind()) != writecap.body.issued_to { return Err(bterr!(WritecapAuthzErr::NotChained)); } } sig_input_buf.clear(); write_to(&writecap.body, &mut sig_input_buf) .map_err(|e| bterr!(WritecapAuthzErr::Serde(e.to_string())))?; writecap.body.signing_key.verify( std::iter::once(sig_input_buf.as_slice()), writecap.signature.as_slice(), )?; 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 .body .signing_key .principal_of_kind(path.root().kind()) == *path.root() { return Ok(()); } else { return Err(bterr!(WritecapAuthzErr::RootDoesNotOwnPath)); } } } } Err(bterr!(WritecapAuthzErr::ChainTooLong(CHAIN_LEN_LIMIT))) } } #[cfg(test)] mod tests { use std::{ io::{Seek, SeekFrom}, time::Duration, }; use super::*; use crate::{ crypto::secret_stream::SecretStream, test_helpers::{self, *}, Sectored, TryCompose, }; #[test] fn encrypt_decrypt_block() { const SECT_SZ: usize = 16; const SECT_CT: usize = 8; let creds = make_key_pair(); let mut block = make_block_with(&creds); write_fill(&mut block, SECT_SZ, SECT_CT); block.rewind().expect("rewind failed"); read_check(block, SECT_SZ, SECT_CT); } #[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())?; key.verify([header, message].into_iter(), signature.as_slice()) } #[test] fn hash_to_string() { let hash = make_principal().0; let string = hash.to_string(); assert_eq!("0!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 = VarHash::try_from(string.as_str())?; assert_eq!(expected, actual); Ok(()) } #[test] fn verify_writecap_valid() { let writecap = make_writecap(vec!["apps", "verse"]); writecap .assert_valid_for(&writecap.body.path) .expect("failed to verify writecap"); } #[test] fn verify_writecap_invalid_signature() -> Result<()> { let mut writecap = make_writecap(vec!["apps", "verse"]); writecap.signature = Signature::empty(Sign::RSA_PSS_3072_SHA_256); let result = writecap.assert_valid_for(&writecap.body.path); if let Err(ref err) = result { if let Some(err) = err.downcast_ref::() { if let Error::InvalidSignature = err { return Ok(()); } } } Err(bterr!("unexpected result {:?}", result)) } fn assert_authz_err( expected: WritecapAuthzErr, result: Result, ) -> Result<()> { if let Some(err) = result.as_ref().err() { if let Some(actual) = err.downcast_ref::() { if *actual == expected { return Ok(()); } } } Err(bterr!("unexpected result: {:?}", result)) } #[test] fn verify_writecap_invalid_path_not_contained() -> Result<()> { let writecap = make_writecap(vec!["apps", "verse"]); let mut path = writecap.body.path.clone(); path.pop_component(); // `path` is now a superpath of `writecap.path`, thus the writecap is not authorized to // write to it. let result = writecap.assert_valid_for(&path); assert_authz_err(WritecapAuthzErr::UnauthorizedPath, result) } #[test] fn verify_writecap_invalid_expired() -> Result<()> { let mut writecap = make_writecap(vec!["apps", "verse"]); writecap.body.expires = Epoch::now() - Duration::from_secs(1); let result = writecap.assert_valid_for(&writecap.body.path); assert_authz_err(WritecapAuthzErr::Expired, result) } #[test] fn verify_writecap_invalid_not_chained() -> Result<()> { let (mut root_writecap, root_key) = make_self_signed_writecap(); root_writecap.body.issued_to = Principal(VarHash::from(HashKind::Sha2_256)); root_key.sign_writecap(&mut root_writecap)?; let node_principal = NODE_CREDS.principal(); let writecap = make_writecap_trusted_by( root_writecap, &root_key, node_principal, vec!["apps", "contacts"], ); let result = writecap.assert_valid_for(&writecap.body.path); assert_authz_err(WritecapAuthzErr::NotChained, result) } #[test] fn verify_writecap_invalid_root_doesnt_own_path() -> Result<()> { let (mut root_writecap, root_key) = make_self_signed_writecap(); let owner = Principal(VarHash::from(HashKind::Sha2_256)); root_writecap.body.path = make_path_with_root(owner, vec![]); root_key.sign_writecap(&mut root_writecap)?; let node_principal = NODE_CREDS.principal(); let writecap = make_writecap_trusted_by( root_writecap, &root_key, node_principal, vec!["apps", "contacts"], ); let result = writecap.assert_valid_for(&writecap.body.path); assert_authz_err(WritecapAuthzErr::RootDoesNotOwnPath, result) } #[test] fn aeadkey_encrypt_decrypt_aes256gcm() { let key = AeadKey::new(AeadKeyKind::AesGcm256).expect("failed to create key"); let aad = [1u8; 16]; let expected = [2u8; 32]; let tagged = key.encrypt(aad, &expected).expect("encrypt failed"); let actual = key.decrypt(&tagged).expect("decrypt failed"); assert_eq!(expected, actual.as_slice()); } #[test] fn aeadkey_decrypt_fails_when_ct_modified() { let key = AeadKey::new(AeadKeyKind::AesGcm256).expect("failed to create key"); let aad = [1u8; 16]; let expected = [2u8; 32]; let mut tagged = key.encrypt(aad, &expected).expect("encrypt failed"); tagged.ciphertext.data[0] = tagged.ciphertext.data[0].wrapping_add(1); let result = key.decrypt(&tagged); assert!(result.is_err()) } #[test] fn aeadkey_decrypt_fails_when_aad_modified() { let key = AeadKey::new(AeadKeyKind::AesGcm256).expect("failed to create key"); let aad = [1u8; 16]; let expected = [2u8; 32]; let mut tagged = key.encrypt(aad, &expected).expect("encrypt failed"); tagged.aad[0] = tagged.aad[0].wrapping_add(1); let result = key.decrypt(&tagged); assert!(result.is_err()) } #[test] fn compose_merkle_and_secret_streams() { use merkle_stream::tests::make_merkle_stream_filled_with_zeros; const SECT_SZ: usize = 4096; const SECT_CT: usize = 16; let merkle = make_merkle_stream_filled_with_zeros(SECT_SZ, SECT_CT); let key = SymKey::generate(SymKeyKind::Aes256Cbc).expect("key generation failed"); let mut secret = SecretStream::new(key) .try_compose(merkle) .expect("compose for secret failed"); let secret_sect_sz = secret.sector_sz(); write_fill(&mut secret, secret_sect_sz, SECT_CT); secret.rewind().expect("rewind failed"); read_check(secret, secret_sect_sz, SECT_CT); } fn ossl_hash_op_same_as_digest_test_case>(kind: HashKind) { let parts = (0u8..32).map(|k| vec![k; kind.len()]).collect::>(); let expected = { let mut expected = vec![0u8; kind.len()]; kind.digest(expected.as_mut(), parts.iter().map(|a| a.as_slice())) .unwrap(); expected }; let mut op = OsslHashOp::::init(kind).unwrap(); for part in parts.iter() { op.update(part.as_slice()).unwrap(); } let actual = op.finish().unwrap(); assert_eq!(expected.as_slice(), actual.as_ref()); } /// Tests that the hash computed using an `OsslHashOp` is the same as the one returned by the /// `HashKind::digest` method. #[test] fn ossl_hash_op_same_as_digest() { ossl_hash_op_same_as_digest_test_case::(Sha2_256::KIND); ossl_hash_op_same_as_digest_test_case::(Sha2_512::KIND); } /// Tests that a `HashWrap` instance calculates the same hash as a call to the `digest` method. #[test] fn hash_stream_agrees_with_digest_method() { let cursor = BtCursor::new([0u8; 3 * 32]); let parts = (1u8..4).map(|k| [k; Sha2_512::LEN]).collect::>(); let expected = { let mut expected = Sha2_512::default(); HashKind::Sha2_512 .digest(expected.as_mut(), parts.iter().map(|a| a.as_slice())) .unwrap(); expected }; let op = OsslHashOp::::init(Sha2_512::KIND).unwrap(); let mut wrap = HashStream::new(cursor, op); for part in parts.iter() { wrap.write(part.as_slice()).unwrap(); } let actual = wrap.finish().unwrap(); assert_eq!(expected, actual); } /// Tests that the `VarHash` computed by `VarHashOp` is the same as the one returned by the /// `digest` method. #[test] fn var_hash_op_agress_with_digest_method() { let parts = (32..64u8).map(|k| [k; Sha2_512::LEN]).collect::>(); let expected = { let mut expected = VarHash::from(HashKind::Sha2_512); HashKind::Sha2_512 .digest(expected.as_mut(), parts.iter().map(|a| a.as_slice())) .unwrap(); expected }; let mut op = VarHashOp::init(HashKind::Sha2_512).unwrap(); for part in parts.iter() { op.update(part.as_slice()).unwrap(); } let actual = op.finish().unwrap(); assert_eq!(expected, actual); } /// Tests that the signature produced by `OsslSignOp` can be verified. #[test] fn ossl_sign_op_sig_can_be_verified() { let keys = &test_helpers::NODE_CREDS; let part_values = (1..9u8).map(|k| [k; 32]).collect::>(); let get_parts = || part_values.iter().map(|a| a.as_slice()); let mut sign_op = keys.init_sign().expect("init_sign failed"); for part in get_parts() { sign_op.update(part).expect("update failed"); } let sig = sign_op.finish().expect("finish failed"); keys.verify(get_parts(), sig.as_ref()) .expect("verify failed"); } /// Tests that the signature produced by a `SignWrite` can be verified. #[test] fn sign_write_sig_can_be_verified() { use crate::Decompose; const LEN: usize = 512; let cursor = BtCursor::new([0u8; LEN]); let keys = &test_helpers::NODE_CREDS; let sign_op = keys.sign.private.init_sign().expect("init_sign failed"); let mut sign_write = SignWrite::new(cursor, sign_op); for part in (1..9u8).map(|k| [k; LEN / 8]) { sign_write.write(part.as_slice()).expect("write failed"); } let (sig, cursor) = sign_write.finish().expect("finish failed"); let array = cursor.into_inner(); keys.verify(std::iter::once(array.as_slice()), sig.as_ref()) .expect("verify failed"); } /// Tests that data signed using a `SignWrite` can later be verified using a `VerifyRead`. #[test] fn sign_write_then_verify_read() { const LEN: usize = 512; let cursor = BtCursor::new([0u8; LEN]); let keys = &test_helpers::NODE_CREDS; let sign_op = keys.sign.private.init_sign().expect("init_sign failed"); let mut sign_write = SignWrite::new(cursor, sign_op); for part in (1..9u8).map(|k| [k; LEN / 8]) { sign_write.write(part.as_slice()).expect("write failed"); } let (sig, mut cursor) = sign_write.finish().expect("finish failed"); cursor.seek(SeekFrom::Start(0)).expect("seek failed"); let verify_op = keys.sign.public.init_verify().expect("init_verify failed"); let mut verify_read = VerifyRead::new(cursor, verify_op); let mut buf = Vec::with_capacity(LEN); verify_read .read_to_end(&mut buf) .expect("read_to_end failed"); verify_read .finish(sig.as_ref()) .expect("failed to verify signature"); } /// 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 key = BLOCK_KEY.key_slice(); let iv = BLOCK_KEY.iv_slice(); let ciphertext = openssl_encrypt(cipher, key, iv, expected).unwrap(); let actual = openssl_decrypt(cipher, key, 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); } } }