123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972 |
- /// Functions for performing cryptographic operations on the main data structures.
- mod tpm;
- use super::*;
- use openssl::{
- error::ErrorStack,
- encrypt::{Encrypter, Decrypter},
- pkey::{PKey, Public, Private},
- symm::{Cipher, encrypt as openssl_encrypt, decrypt as openssl_decrypt},
- rand::rand_bytes,
- rsa::{Rsa, Padding as OpensslPadding},
- hash::{hash, MessageDigest},
- sign::{Signer as OsslSigner, Verifier as OsslVerifier}
- };
- use serde_block_tree::{self, to_vec, from_vec, write_to};
- use serde::{
- de::{self, DeserializeOwned, Deserializer, SeqAccess, Visitor},
- ser::{Serializer, SerializeStruct},
- };
- use std::{
- str::FromStr,
- };
- use strum_macros::{EnumString, EnumDiscriminants, Display};
- /// Data that may or may not be encrypted.
- #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
- pub(crate) enum Cryptotext<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),
- Io(std::io::Error),
- }
- impl Display for Error {
- fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
- match self {
- Error::NoReadCap => write!(f, "no readcap"),
- Error::NoKeyAvailable => write!(f, "no key available"),
- Error::MissingPrivateKey => write!(f, "private key was missing"),
- Error::KeyVariantUnsupported => write!(f, "unsupported key variant"),
- Error::BlockNotEncrypted => write!(f, "block was not encrypted"),
- Error::InvalidHashFormat => write!(f, "invalid format"),
- Error::Message(message) => f.write_str(message.as_str()),
- Error::Serde(serde_err) => serde_err.fmt(f),
- Error::Io(io_err) => io_err.fmt(f),
- }
- }
- }
- impl From<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)
- }
- }
- impl From<std::io::Error> for Error {
- fn from(error: std::io::Error) -> Error {
- Error::Io(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, 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<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()? })
- },
- }
- }
- fn params(&self) -> SymParams {
- let (cipher, key, iv) = match self {
- SymKey::Aes256Cbc { key, iv } => (Cipher::aes_256_cbc(), key, Some(iv.as_slice())),
- SymKey::Aes256Ctr { key, iv } => (Cipher::aes_256_ctr(), key, Some(iv.as_slice())),
- };
- SymParams { cipher, key, iv }
- }
- }
- #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
- pub(crate) enum AsymKeyKind {
- Rsa,
- }
- #[derive(Debug, Clone)]
- pub(crate) struct AsymKeyPub {
- kind: AsymKeyKind,
- pkey: PKey<Public>,
- }
- impl AsymKeyPub {
- pub(crate) fn new(kind: AsymKeyKind, der: &[u8]) -> Result<AsymKeyPub> {
- let pkey = match kind {
- AsymKeyKind::Rsa => {
- let rsa = Rsa::public_key_from_der(der).map_err(Error::from)?;
- PKey::from_rsa(rsa).map_err(Error::from)?
- }
- };
- Ok(AsymKeyPub { kind, pkey })
- }
- fn digest(&self) -> MessageDigest {
- match self.kind {
- AsymKeyKind::Rsa => MessageDigest::sha256(),
- }
- }
- fn signature_buf(&self) -> Signature {
- match self.kind {
- AsymKeyKind::Rsa => Signature::new(SignatureKind::Rsa),
- }
- }
- fn padding(&self) -> Option<OpensslPadding> {
- match self.kind {
- AsymKeyKind::Rsa => Some(OpensslPadding::PKCS1),
- }
- }
- fn to_der(&self) -> Result<Vec<u8>> {
- self.pkey.public_key_to_der().map_err(Error::from)
- }
- }
- impl<'de> Deserialize<'de> for AsymKeyPub {
- fn deserialize<D: Deserializer<'de>>(d: D) -> std::result::Result<Self, D::Error> {
- const FIELDS: &[&str] = &["kind", "pkey"];
- struct StructVisitor;
- impl<'de> Visitor<'de> for StructVisitor {
- type Value = AsymKeyPub;
- fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- formatter.write_fmt(format_args!("struct {}", stringify!(AsymKeyPub)))
- }
- fn visit_seq<V: SeqAccess<'de>>(
- self, mut seq: V
- ) -> std::result::Result<AsymKeyPub, V::Error> {
- let kind: AsymKeyKind = seq.next_element()?
- .ok_or_else(|| de::Error::missing_field(FIELDS[0]))?;
- let der: Vec<u8> = seq.next_element()?
- .ok_or_else(|| de::Error::missing_field(FIELDS[1]))?;
- AsymKeyPub::new(kind, der.as_slice())
- .map_err(|e| de::Error::custom(e.to_string()))
- }
- }
- d.deserialize_struct(stringify!(AsymKeyPub), FIELDS, StructVisitor)
- }
- }
- impl Serialize for AsymKeyPub {
- fn serialize<S: Serializer>(&self, s: S) -> std::result::Result<S::Ok, S::Error> {
- let mut struct_s = s.serialize_struct(stringify!(AsymKeyPub), 2)?;
- struct_s.serialize_field("kind", &self.kind)?;
- let der = self.pkey.public_key_to_der().unwrap();
- struct_s.serialize_field("pkey", der.as_slice())?;
- struct_s.end()
- }
- }
- impl PartialEq for AsymKeyPub {
- fn eq(&self, other: &Self) -> bool {
- self.kind == other.kind && self.pkey.public_eq(&other.pkey)
- }
- }
- impl Owned for AsymKeyPub {
- fn owner_of_kind(&self, kind: HashKind) -> Principal {
- match kind {
- HashKind::Sha2_256 => {
- let mut buf = [0; 32];
- let der = self.to_der().unwrap();
- let bytes = hash(MessageDigest::sha256(), der.as_slice()).unwrap();
- buf.copy_from_slice(&*bytes);
- Principal(Hash::Sha2_256(buf))
- },
- HashKind::Sha2_512 => {
- let mut buf = [0; 64];
- let der = self.to_der().unwrap();
- let bytes = hash(MessageDigest::sha512(), der.as_slice()).unwrap();
- buf.copy_from_slice(&*bytes);
- Principal(Hash::Sha2_512(buf))
- }
- }
- }
- }
- impl CredsPub for AsymKeyPub {}
- pub(crate) struct RsaPriv {
- pkey: PKey<Private>,
- }
- impl RsaPriv {
- pub(crate) fn new(der: &[u8]) -> Result<RsaPriv> {
- let rsa = Rsa::private_key_from_der(der).map_err(Error::from)?;
- let pkey = PKey::from_rsa(rsa).map_err(Error::from)?;
- Ok(RsaPriv { pkey })
- }
- fn digest() -> MessageDigest {
- MessageDigest::sha256()
- }
- fn signature_buf() -> Signature {
- Signature::new(SignatureKind::Rsa)
- }
- }
- impl Decryptor for RsaPriv {
- fn decrypt(&self, slice: &[u8]) -> Result<Vec<u8>> {
- let decrypter = Decrypter::new(&self.pkey).map_err(Error::from)?;
- let buffer_len = decrypter.decrypt_len(slice).map_err(Error::from)?;
- let mut plaintext = vec![0; buffer_len];
- let plaintext_len = decrypter.decrypt(slice, &mut plaintext).map_err(Error::from)?;
- plaintext.truncate(plaintext_len);
- Ok(plaintext)
- }
- }
- impl Signer for RsaPriv {
- fn sign<'a, I: Iterator<Item=&'a [u8]>>(&self, parts: &mut I) -> Result<Signature> {
- let digest = RsaPriv::digest();
- let mut signature = RsaPriv::signature_buf();
- let mut signer = OsslSigner::new(digest, &self.pkey).map_err(Error::from)?;
- for part in parts {
- signer.update(part).map_err(Error::from)?;
- }
- let buf = signature.as_mut_slice();
- signer.sign(buf).map_err(Error::from)?;
- Ok(signature)
- }
- }
- impl CredsPriv for RsaPriv {}
- pub(crate) struct ConcreteCreds<T: CredsPriv> {
- public: AsymKeyPub,
- private: T,
- }
- impl<T: CredsPriv> ConcreteCreds<T> {
- pub(crate) fn new(public: AsymKeyPub, private: T) -> ConcreteCreds<T> {
- ConcreteCreds { public, private }
- }
- }
- impl ConcreteCreds<RsaPriv> {
- pub(crate) fn generate() -> Result<ConcreteCreds<RsaPriv>> {
- let key = Rsa::generate(4096)?;
- // TODO: Separating the keys this way seems inefficient. Investigate alternatives.
- let public_der = key.public_key_to_der().map_err(Error::from)?;
- let private_der = key.private_key_to_der().map_err(Error::from)?;
- Ok(ConcreteCreds {
- public: AsymKeyPub::new(AsymKeyKind::Rsa, public_der.as_slice())?,
- private: RsaPriv::new(private_der.as_slice())?,
- })
- }
- }
- impl<T: CredsPriv> Verifier for ConcreteCreds<T> {
- fn verify<'a, I: Iterator<Item=&'a [u8]>>(&self, parts: I, signature: &[u8]) -> Result<bool> {
- self.public.verify(parts, signature)
- }
- }
- impl<T: CredsPriv> Encryptor for ConcreteCreds<T> {
- fn encrypt(&self, slice: &[u8]) -> Result<Vec<u8>> {
- self.public.encrypt(slice)
- }
- }
- impl<T: CredsPriv> Owned for ConcreteCreds<T> {
- fn owner_of_kind(&self, kind: HashKind) -> Principal {
- self.public.owner_of_kind(kind)
- }
- }
- impl<T: CredsPriv> CredsPub for ConcreteCreds<T> {}
- impl<T: CredsPriv> Signer for ConcreteCreds<T> {
- fn sign<'a, I: Iterator<Item=&'a [u8]>>(&self, parts: &mut I) -> Result<Signature> {
- self.private.sign(parts)
- }
- }
- impl<T: CredsPriv> Decryptor for ConcreteCreds<T> {
- fn decrypt(&self, slice: &[u8]) -> Result<Vec<u8>> {
- self.private.decrypt(slice)
- }
- }
- impl<T: CredsPriv> CredsPriv for ConcreteCreds<T> {}
- impl<T: CredsPriv> Creds for ConcreteCreds<T> {
- fn public(&self) -> &AsymKeyPub {
- &self.public
- }
- }
- pub(crate) trait Encryptor {
- fn encrypt(&self, slice: &[u8]) -> Result<Vec<u8>>;
- }
- impl Encryptor for SymKey {
- fn encrypt(&self, slice: &[u8]) -> Result<Vec<u8>> {
- let SymParams { cipher, key, iv } = self.params();
- openssl_encrypt(cipher, key, iv, slice).map_err(Error::from)
- }
- }
- impl Encryptor for AsymKeyPub {
- fn encrypt(&self, slice: &[u8]) -> Result<Vec<u8>> {
- let mut encrypter = Encrypter::new(&self.pkey).map_err(Error::from)?;
- if let Some(padding) = self.padding() {
- encrypter.set_rsa_padding(padding).map_err(Error::from)?;
- }
- let buffer_len = encrypter.encrypt_len(slice).map_err(Error::from)?;
- let mut ciphertext = vec![0; buffer_len];
- let ciphertext_len = encrypter.encrypt(slice, &mut ciphertext)
- .map_err(Error::from)?;
- ciphertext.truncate(ciphertext_len);
- Ok(ciphertext)
- }
- }
- pub(crate) trait Decryptor {
- fn decrypt(&self, slice: &[u8]) -> Result<Vec<u8>>;
- }
- impl Decryptor for SymKey {
- fn decrypt(&self, slice: &[u8]) -> Result<Vec<u8>> {
- let SymParams { cipher, key, iv } = self.params();
- openssl_decrypt(cipher, key, iv, slice).map_err(Error::from)
- }
- }
- pub(crate) trait Signer {
- fn sign<'a, I: Iterator<Item=&'a [u8]>>(&self, parts: &mut I) -> Result<Signature>;
- }
- pub(crate) trait Verifier {
- fn verify<'a, I: Iterator<Item=&'a [u8]>>(&self, parts: I, signature: &[u8]) -> Result<bool>;
- }
- impl Verifier for AsymKeyPub {
- fn verify<'a, I: Iterator<Item=&'a [u8]>>(&self, parts: I, signature: &[u8]) -> Result<bool> {
- let mut verifier = OsslVerifier::new(self.digest(), &self.pkey).map_err(Error::from)?;
- for part in parts {
- verifier.update(part).map_err(Error::from)?;
- }
- verifier.verify(signature).map_err(Error::from)
- }
- }
- /// Trait for types which can be used as public credentials.
- pub(crate) trait CredsPub: Verifier + Encryptor + Owned {}
- /// Trait for types which contain private credentials.
- pub(crate) trait CredsPriv: Decryptor + Signer {}
- /// Trait for types which contain both public and private credentials.
- pub(crate) trait Creds: CredsPriv + CredsPub {
- fn public(&self) -> &AsymKeyPub;
- }
- /// A trait for types which store credentials.
- pub(crate) trait CredStore {
- type CredHandle: Creds;
- /// Returns the node credentials. If credentials haven't been generated, they are generated
- /// stored and returned.
- fn node_creds(&self) -> Result<&Self::CredHandle>;
- /// Returns the root credentials. If no root credentials have been generated, or the provided
- /// password is incorrect, then an error is returned.
- fn root_creds(&self, password: &str) -> Result<&Self::CredHandle>;
- /// Generates the root crednetials and protects them using the given password. If the root
- /// credentials have already been generated then an error is returned.
- fn gen_root_creds(&self, password: &str) -> Result<&Self::CredHandle>;
- }
- pub(crate) fn encrypt_block<C: Creds>(
- mut block: Block, principal: &Principal, creds: &C
- ) -> 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, 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<K: CredsPriv>(
- mut block: Block, principal: &Principal, key: &K
- ) -> 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 = block_key.decrypt(&body)?;
- block.body = Cryptotext::Plain(new_body);
- block.readcaps.insert(principal_owned, Cryptotext::Plain(block_key));
- Ok(block)
- }
- fn encrypt<T: Serialize, K: Encryptor>(value: &T, key: &K) -> Result<Cryptotext<T>> {
- let data = to_vec(value).map_err(Error::from)?;
- let vec = key.encrypt(&data);
- Ok(Cryptotext::Cipher(vec?))
- }
- fn decrypt<T: Serialize + DeserializeOwned, K: CredsPriv>(
- cryptotext: Cryptotext<T>, key: &K
- ) -> Result<T> {
- let data = match cryptotext {
- Cryptotext::Plain(value) => return Ok(value),
- Cryptotext::Cipher(data) => data
- };
- let vec = key.decrypt(&data);
- from_vec(&vec?).map_err(Error::from)
- }
- #[derive(Serialize)]
- struct HeaderSigInput<'a> {
- path: &'a Path,
- readcaps: &'a HashMap<Principal, Cryptotext<SymKey>>,
- 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<K: Signer>(
- block: &mut Block, writecap: Writecap, priv_key: &K
- ) -> Result<()> {
- block.writecap = writecap;
- let body = get_body(block)?;
- let sig_input = HeaderSigInput::from(&*block);
- let header = to_vec(&sig_input)?;
- let signature = priv_key.sign(&mut [header.as_slice(), body].into_iter())?;
- block.signature = signature;
- Ok(())
- }
- pub(crate) fn verify_block(block: &Block) -> Result<bool> {
- let body = get_body(block)?;
- let sig_input = HeaderSigInput::from(&*block);
- let header = to_vec(&sig_input)?;
- let parts = [header.as_slice(), body].into_iter();
- block.writecap.signing_key.verify(parts, block.signature.as_slice())
- }
- #[derive(Serialize)]
- struct WritecapSigInput<'a> {
- issued_to: &'a Principal,
- path: &'a Path,
- expires: &'a Epoch,
- signing_key: &'a AsymKeyPub,
- }
- impl<'a> From<&'a Writecap> for WritecapSigInput<'a> {
- fn from(writecap: &'a Writecap) -> WritecapSigInput<'a> {
- WritecapSigInput {
- issued_to: &writecap.issued_to,
- path: &writecap.path,
- expires: &writecap.expires,
- signing_key: &writecap.signing_key,
- }
- }
- }
- pub(crate) fn sign_writecap<K: Signer>(writecap: &mut Writecap, priv_key: &K) -> Result<()> {
- let sig_input = to_vec(&WritecapSigInput::from(&*writecap))?;
- writecap.signature = priv_key.sign(&mut [sig_input.as_slice()].into_iter())?;
- Ok(())
- }
- /// The types of errors which can occur when verifying a writecap chain is authorized to write to
- /// a given path.
- #[derive(Debug, PartialEq)]
- pub(crate) enum WritecapAuthzErr {
- /// The chain is not valid for use on the given path.
- UnauthorizedPath,
- /// At least one writecap in the chain is expired.
- Expired,
- /// The given writecaps do not actually form a chain.
- NotChained,
- /// There is an invalid signature in the chain.
- InvalidSignature,
- /// The principal the root writecap was issued to does not own the given path.
- RootDoesNotOwnPath,
- /// An error occurred while serializing a writecap.
- Serde(String),
- /// A cryptographic error occurred while attempting to verify a writecap.
- Crypto(String),
- }
- /// Verifies that the given `Writecap` actually grants permission to write to the given `Path`.
- pub(crate) fn verify_writecap(
- mut writecap: &Writecap, path: &Path
- ) -> std::result::Result<(), WritecapAuthzErr> {
- let mut prev: Option<&Writecap> = None;
- let mut sig_input = Vec::new();
- let now = Epoch::now();
- loop {
- if !writecap.path.contains(path) {
- return Err(WritecapAuthzErr::UnauthorizedPath);
- }
- if writecap.expires <= now {
- return Err(WritecapAuthzErr::Expired);
- }
- if let Some(prev) = &prev {
- if prev.signing_key.owner_of_kind(writecap.issued_to.kind()) != writecap.issued_to {
- return Err(WritecapAuthzErr::NotChained);
- }
- }
- let sig = WritecapSigInput::from(writecap);
- sig_input.clear();
- write_to(&sig, &mut sig_input).map_err(|e| WritecapAuthzErr::Serde(e.to_string()))?;
- let valid = writecap.signing_key
- .verify([sig_input.as_slice()].into_iter(), writecap.signature.as_slice())
- .map_err(|e| WritecapAuthzErr::Crypto(e.to_string()))?;
- if !valid {
- return Err(WritecapAuthzErr::InvalidSignature);
- }
- match &writecap.next {
- Some(next) => {
- prev = Some(writecap);
- writecap = next;
- },
- None => {
- // We're at the root key. As long as the signer of this writecap is the owner of
- // the path, then the writecap is valid.
- if writecap.signing_key.owner_of_kind(path.owner.kind()) == path.owner {
- return Ok(());
- }
- else {
- return Err(WritecapAuthzErr::RootDoesNotOwnPath)
- }
- }
- }
- }
- }
- #[cfg(test)]
- mod tests {
- use super::*;
- use test_helpers::*;
- fn encrypt_decrypt_block_test_case<C: Creds>(
- mut actual: Block, principal: &Principal, creds: &C
- ) -> Result<()> {
- let expected = actual.clone();
- actual = encrypt_block(actual, principal, creds)?;
- let encrypted = match &actual.body {
- Cryptotext::Cipher(_) => true,
- Cryptotext::Plain(_) => false
- };
- assert!(encrypted);
- actual = decrypt_block(actual, principal, creds)?;
- assert_eq!(expected, actual);
- Ok(())
- }
- #[test]
- fn encrypt_decrypt_block_aes256cbc() -> Result<()> {
- let readcap = make_readcap();
- let principal = readcap.issued_to.clone();
- let block = make_block_with(readcap)?;
- let key = make_key_pair();
- encrypt_decrypt_block_test_case(block, &principal, &key)
- }
- #[test]
- fn encrypt_decrypt_block_aes256ctr() -> Result<()> {
- let readcap = make_readcap();
- let principal = readcap.issued_to.clone();
- let block = make_block_with(readcap)?;
- let key = make_key_pair();
- encrypt_decrypt_block_test_case(block, &principal, &key)
- }
- #[test]
- fn rsa_sign_and_verify() -> Result<()> {
- let key = make_key_pair();
- let header = b"About: lyrics".as_slice();
- let message = b"Everything that feels so good is bad bad bad.".as_slice();
- let signature = key.sign(&mut [header, message].into_iter())?;
- let verified = key.verify([header, message].into_iter(), signature.as_slice())?;
- assert_eq!(true, verified);
- Ok(())
- }
- #[test]
- fn sign_verify_block_rsa() -> Result<()> {
- let readcap = make_readcap();
- let principal = readcap.issued_to.clone();
- let mut block = make_block_with(readcap)?;
- let key = make_key_pair();
- let writecap = Writecap {
- issued_to: Principal(Hash::Sha2_256(PRINCIPAL)),
- path: make_path(vec!["contacts", "emergency"]),
- expires: Epoch(1649904316),
- signing_key: key.public().clone(),
- signature: Signature::Rsa(SIGNATURE),
- next: None,
- };
- block = encrypt_block(block, &principal, &key)?;
- sign_block(&mut block, writecap, &key)?;
- assert_eq!(true, verify_block(&block)?);
- Ok(())
- }
- #[test]
- fn hash_to_string() {
- let hash = make_principal().0;
- let string = hash.to_string();
- assert_eq!("Sha2_256:dSip4J0kurN5VhVo_aTipM-ywOOWrqJuRRVQ7aa-bew", string)
- }
- #[test]
- fn hash_to_string_round_trip() -> Result<()> {
- let expected = make_principal().0;
- let string = expected.to_string();
- let actual = Hash::try_from(string.as_str())?;
- assert_eq!(expected, actual);
- Ok(())
- }
- #[test]
- fn verify_writecap_valid() -> Result<()> {
- let writecap = make_writecap()?;
- let result = verify_writecap(&writecap, &writecap.path);
- assert_eq!(Ok(()), result);
- Ok(())
- }
- #[test]
- fn verify_writecap_invalid_signature() -> Result<()> {
- let mut writecap = make_writecap()?;
- writecap.signature = Signature::default();
- let result = verify_writecap(&writecap, &writecap.path);
- assert_eq!(Err(WritecapAuthzErr::InvalidSignature), result);
- Ok(())
- }
- #[test]
- fn verify_writecap_invalid_path_not_contained() -> Result<()> {
- let writecap = make_writecap()?;
- let mut path = writecap.path.clone();
- path.components.pop();
- // `path` is now a superpath of `writecap.path`, thus the writecap is not authorized to
- // write to it.
- let result = verify_writecap(&writecap, &path);
- assert_eq!(Err(WritecapAuthzErr::UnauthorizedPath), result);
- Ok(())
- }
- #[test]
- fn verify_writecap_invalid_expired() -> Result<()> {
- let mut writecap = make_writecap()?;
- writecap.expires = Epoch::now() - Duration::from_secs(1);
- let result = verify_writecap(&writecap, &writecap.path);
- assert_eq!(Err(WritecapAuthzErr::Expired), result);
- Ok(())
- }
- #[test]
- fn verify_writecap_invalid_not_chained() -> Result<()> {
- let (mut root_writecap, root_key) = make_self_signed_writecap()?;
- root_writecap.issued_to = Principal(Hash::Sha2_256([0; 32]));
- sign_writecap(&mut root_writecap, &root_key)?;
- let node_key = AsymKeyPub {
- kind: AsymKeyKind::Rsa,
- pkey: PKey::from_rsa(Rsa::public_key_from_der(NODE_PUBLIC_KEY.as_slice())?)?
- };
- let node_principal = node_key.owner();
- let writecap = make_writecap_trusted_by(
- root_writecap, root_key, node_principal, vec!["apps", "contacts"])?;
- let result = verify_writecap(&writecap, &writecap.path);
- assert_eq!(Err(WritecapAuthzErr::NotChained), result);
- Ok(())
- }
- #[test]
- fn verify_writecap_invalid_root_doesnt_own_path() -> Result<()> {
- let (mut root_writecap, root_key) = make_self_signed_writecap()?;
- let owner = Principal(Hash::Sha2_256([0; 32]));
- root_writecap.path = make_path_with_owner(owner, vec![]);
- sign_writecap(&mut root_writecap, &root_key)?;
- let node_key = AsymKeyPub {
- kind: AsymKeyKind::Rsa,
- pkey: PKey::from_rsa(Rsa::public_key_from_der(NODE_PUBLIC_KEY.as_slice())?)?
- };
- let node_owner = node_key.owner();
- let writecap = make_writecap_trusted_by(
- root_writecap, root_key, node_owner, vec!["apps", "contacts"])?;
- let result = verify_writecap(&writecap, &writecap.path);
- assert_eq!(Err(WritecapAuthzErr::RootDoesNotOwnPath), result);
- Ok(())
- }
- /// Tests that validate the dependencies of this module.
- mod dependency_tests {
- use super::*;
- use openssl::{
- ec::{EcGroup, EcKey},
- nid::Nid,
- };
- /// This test validates that data encrypted with AES 256 CBC can later be decrypted.
- #[test]
- fn aes_256_cbc_roundtrip() {
- use super::*;
- let expected = b"We attack at the crack of noon!";
- let cipher = Cipher::aes_256_cbc();
- let ciphertext = openssl_encrypt(cipher, &KEY, Some(&IV), expected).unwrap();
- let actual = openssl_decrypt(cipher, &KEY, Some(&IV), ciphertext.as_slice()).unwrap();
- assert_eq!(expected, actual.as_slice());
- }
- /// Tests that the keys for the SECP256K1 curve are the expected sizes.
- #[test]
- fn secp256k1_key_lengths() {
- let group = EcGroup::from_curve_name(Nid::SECP256K1).unwrap();
- let key = EcKey::generate(&group).unwrap();
- let public = key.public_key_to_der().unwrap();
- let private = key.private_key_to_der().unwrap();
- let public_len = public.len();
- let private_len = private.len();
- assert_eq!(88, public_len);
- assert_eq!(118, private_len);
- }
- #[test]
- fn ed25519_key_lengths() {
- let key = PKey::generate_x25519().unwrap();
- let public = key.public_key_to_der().unwrap();
- let private = key.private_key_to_der().unwrap();
- let public_len = public.len();
- let private_len = private.len();
- assert_eq!(44, public_len);
- assert_eq!(48, private_len);
- }
- #[test]
- fn rsa_signature_len() -> Result<()> {
- let key = make_key_pair();
- let signature = key.sign(&mut [NODE_PUBLIC_KEY.as_slice()].into_iter())?;
- let length = match signature {
- Signature::Rsa(data) => data.len(),
- };
- assert_eq!(RSA_SIG_LEN, length);
- Ok(())
- }
- }
- }
|