|
@@ -7,7 +7,7 @@ use super::*;
|
|
|
use openssl::{
|
|
|
error::ErrorStack,
|
|
|
encrypt::{Encrypter as OsslEncrypter, Decrypter as OsslDecrypter},
|
|
|
- pkey::{PKey, Public as OsslPublic, Private as OsslPrivate, HasPublic, HasPrivate},
|
|
|
+ pkey::{PKey, HasPublic, HasPrivate},
|
|
|
symm::{Cipher, encrypt as openssl_encrypt, decrypt as openssl_decrypt},
|
|
|
rand::rand_bytes,
|
|
|
rsa::{Rsa, Padding as OpensslPadding},
|
|
@@ -43,6 +43,8 @@ pub enum Error {
|
|
|
KeyVariantUnsupported,
|
|
|
BlockNotEncrypted,
|
|
|
InvalidHashFormat,
|
|
|
+ InvalidSignature,
|
|
|
+ WritecapAuthzErr(WritecapAuthzErr),
|
|
|
Serde(serde_block_tree::Error),
|
|
|
Io(std::io::Error),
|
|
|
Custom(Box<dyn std::fmt::Debug>)
|
|
@@ -63,13 +65,21 @@ impl Display for Error {
|
|
|
Error::KeyVariantUnsupported => write!(f, "unsupported key variant"),
|
|
|
Error::BlockNotEncrypted => write!(f, "block was not encrypted"),
|
|
|
Error::InvalidHashFormat => write!(f, "invalid format"),
|
|
|
- Error::Serde(serde_err) => serde_err.fmt(f),
|
|
|
- Error::Io(io_err) => io_err.fmt(f),
|
|
|
+ Error::InvalidSignature => write!(f, "invalid signature"),
|
|
|
+ Error::WritecapAuthzErr(err) => err.fmt(f),
|
|
|
+ Error::Serde(err) => err.fmt(f),
|
|
|
+ Error::Io(err) => err.fmt(f),
|
|
|
Error::Custom(cus) => cus.fmt(f),
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+impl From<WritecapAuthzErr> for Error {
|
|
|
+ fn from(err: WritecapAuthzErr) -> Self {
|
|
|
+ Error::WritecapAuthzErr(err)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
impl From<ErrorStack> for Error {
|
|
|
fn from(error: ErrorStack) -> Error {
|
|
|
Error::custom(error)
|
|
@@ -303,8 +313,8 @@ pub trait Scheme: for<'de> Deserialize<'de> + Serialize
|
|
|
fn as_enum(self) -> SchemeKind;
|
|
|
fn message_digest(&self) -> MessageDigest;
|
|
|
fn padding(&self) -> Option<OpensslPadding>;
|
|
|
- fn public_from_der(self, der: &[u8]) -> Result<PKey<OsslPublic>>;
|
|
|
- fn private_from_der(self, der: &[u8]) -> Result<PKey<OsslPrivate>>;
|
|
|
+ fn public_from_der(self, der: &[u8]) -> Result<PKey<Public>>;
|
|
|
+ fn private_from_der(self, der: &[u8]) -> Result<PKey<Private>>;
|
|
|
fn generate(self) -> Result<AsymKeyPair<Self::Kind>>;
|
|
|
}
|
|
|
|
|
@@ -337,13 +347,13 @@ impl Scheme for Encrypt {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- fn public_from_der(self, der: &[u8]) -> Result<PKey<OsslPublic>> {
|
|
|
+ fn public_from_der(self, der: &[u8]) -> Result<PKey<Public>> {
|
|
|
match self {
|
|
|
Encrypt::RsaEsOaep(inner) => inner.public_from_der(der),
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- fn private_from_der(self, der: &[u8]) -> Result<PKey<OsslPrivate>> {
|
|
|
+ fn private_from_der(self, der: &[u8]) -> Result<PKey<Private>> {
|
|
|
match self {
|
|
|
Encrypt::RsaEsOaep(inner) => inner.private_from_der(der),
|
|
|
}
|
|
@@ -387,13 +397,13 @@ impl Scheme for Sign {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- fn public_from_der(self, der: &[u8]) -> Result<PKey<OsslPublic>> {
|
|
|
+ fn public_from_der(self, der: &[u8]) -> Result<PKey<Public>> {
|
|
|
match self {
|
|
|
Sign::RsaSsaPss(inner) => inner.public_from_der(der),
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- fn private_from_der(self, der: &[u8]) -> Result<PKey<OsslPrivate>> {
|
|
|
+ fn private_from_der(self, der: &[u8]) -> Result<PKey<Private>> {
|
|
|
match self {
|
|
|
Sign::RsaSsaPss(inner) => inner.private_from_der(der),
|
|
|
}
|
|
@@ -451,12 +461,12 @@ impl Scheme for RsaEsOaep {
|
|
|
Some(OpensslPadding::PKCS1_OAEP)
|
|
|
}
|
|
|
|
|
|
- fn public_from_der(self, der: &[u8]) -> Result<PKey<OsslPublic>> {
|
|
|
- Ok(PKey::public_key_from_der(der)?)
|
|
|
+ fn public_from_der(self, der: &[u8]) -> Result<PKey<Public>> {
|
|
|
+ Ok(PKey::public_key_from_der(der)?.conv_pub())
|
|
|
}
|
|
|
|
|
|
- fn private_from_der(self, der: &[u8]) -> Result<PKey<OsslPrivate>> {
|
|
|
- Ok(PKey::private_key_from_der(der)?)
|
|
|
+ fn private_from_der(self, der: &[u8]) -> Result<PKey<Private>> {
|
|
|
+ Ok(PKey::private_key_from_der(der)?.conv_priv())
|
|
|
}
|
|
|
|
|
|
fn generate(self) -> Result<AsymKeyPair<Self::Kind>> {
|
|
@@ -491,12 +501,12 @@ impl Scheme for RsaSsaPss {
|
|
|
Some(OpensslPadding::PKCS1_PSS)
|
|
|
}
|
|
|
|
|
|
- fn public_from_der(self, der: &[u8]) -> Result<PKey<OsslPublic>> {
|
|
|
- Ok(PKey::public_key_from_der(der)?)
|
|
|
+ fn public_from_der(self, der: &[u8]) -> Result<PKey<Public>> {
|
|
|
+ Ok(PKey::public_key_from_der(der)?.conv_pub())
|
|
|
}
|
|
|
|
|
|
- fn private_from_der(self, der: &[u8]) -> Result<PKey<OsslPrivate>> {
|
|
|
- Ok(PKey::private_key_from_der(der)?)
|
|
|
+ fn private_from_der(self, der: &[u8]) -> Result<PKey<Private>> {
|
|
|
+ Ok(PKey::private_key_from_der(der)?.conv_priv())
|
|
|
}
|
|
|
|
|
|
fn generate(self) -> Result<AsymKeyPair<Self::Kind>> {
|
|
@@ -568,18 +578,14 @@ pub type AsymKeyPub<S> = AsymKey<Public, S>;
|
|
|
|
|
|
impl<S: Scheme> AsymKey<Public, S> {
|
|
|
pub(crate) fn new(scheme: S, der: &[u8]) -> Result<AsymKey<Public, S>> {
|
|
|
- let pkey = scheme.public_from_der(der)?.conv_pub();
|
|
|
+ let pkey = scheme.public_from_der(der)?;
|
|
|
Ok(AsymKey { scheme, pkey })
|
|
|
}
|
|
|
-
|
|
|
- fn to_der(&self) -> Result<Vec<u8>> {
|
|
|
- Ok(self.pkey.public_key_to_der()?)
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
impl<S: Scheme> AsymKey<Private, S> {
|
|
|
pub(crate) fn new(scheme: S, der: &[u8]) -> Result<AsymKey<Private, S>> {
|
|
|
- let pkey = scheme.private_from_der(der)?.conv_priv();
|
|
|
+ let pkey = scheme.private_from_der(der)?;
|
|
|
Ok(AsymKey { scheme, pkey })
|
|
|
}
|
|
|
}
|
|
@@ -639,22 +645,11 @@ impl<S: Scheme> PartialEq for AsymKey<Public, S> {
|
|
|
|
|
|
impl Owned for AsymKey<Public, Sign> {
|
|
|
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))
|
|
|
- }
|
|
|
- }
|
|
|
+ let der = self.pkey.public_key_to_der().unwrap();
|
|
|
+ let bytes = hash(kind.into(), der.as_slice()).unwrap();
|
|
|
+ let mut hash_buf = Hash::from(kind);
|
|
|
+ hash_buf.as_mut().copy_from_slice(&bytes);
|
|
|
+ Principal(hash_buf)
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -710,7 +705,7 @@ impl Signer for AsymKey<Private, Sign> {
|
|
|
}
|
|
|
|
|
|
impl Verifier for AsymKey<Public, Sign> {
|
|
|
- fn verify<'a, I: Iterator<Item=&'a [u8]>>(&self, parts: I, signature: &[u8]) -> Result<bool> {
|
|
|
+ fn verify<'a, I: Iterator<Item=&'a [u8]>>(&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)?;
|
|
@@ -718,7 +713,12 @@ impl Verifier for AsymKey<Public, Sign> {
|
|
|
for part in parts {
|
|
|
verifier.update(part)?;
|
|
|
}
|
|
|
- Ok(verifier.verify(signature)?)
|
|
|
+ if verifier.verify(signature)? {
|
|
|
+ Ok(())
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ Err(Error::InvalidSignature)
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -760,7 +760,7 @@ impl Signer for AsymKeyPair<Sign> {
|
|
|
}
|
|
|
|
|
|
impl Verifier for AsymKeyPair<Sign> {
|
|
|
- fn verify<'a, I: Iterator<Item=&'a [u8]>>(&self, parts: I, signature: &[u8]) -> Result<bool> {
|
|
|
+ fn verify<'a, I: Iterator<Item=&'a [u8]>>(&self, parts: I, signature: &[u8]) -> Result<()> {
|
|
|
self.public.verify(parts, signature)
|
|
|
}
|
|
|
}
|
|
@@ -784,7 +784,7 @@ impl ConcreteCreds {
|
|
|
}
|
|
|
|
|
|
impl Verifier for ConcreteCreds {
|
|
|
- fn verify<'a, I: Iterator<Item=&'a [u8]>>(&self, parts: I, signature: &[u8]) -> Result<bool> {
|
|
|
+ fn verify<'a, I: Iterator<Item=&'a [u8]>>(&self, parts: I, signature: &[u8]) -> Result<()> {
|
|
|
self.sign.verify(parts, signature)
|
|
|
}
|
|
|
}
|
|
@@ -801,7 +801,11 @@ impl Owned for ConcreteCreds {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl CredsPub for ConcreteCreds {}
|
|
|
+impl CredsPub for ConcreteCreds {
|
|
|
+ fn public_sign(&self) -> &AsymKey<Public, Sign> {
|
|
|
+ &self.sign.public
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
impl Signer for ConcreteCreds {
|
|
|
fn sign<'a, I: Iterator<Item=&'a [u8]>>(&self, parts: I) -> Result<Signature> {
|
|
@@ -817,11 +821,7 @@ impl Decrypter for ConcreteCreds {
|
|
|
|
|
|
impl CredsPriv for ConcreteCreds {}
|
|
|
|
|
|
-impl Creds for ConcreteCreds {
|
|
|
- fn public(&self) -> &AsymKey<Public, Sign> {
|
|
|
- &self.sign.public
|
|
|
- }
|
|
|
-}
|
|
|
+impl Creds for ConcreteCreds {}
|
|
|
|
|
|
pub(crate) trait Encrypter {
|
|
|
fn encrypt(&self, slice: &[u8]) -> Result<Vec<u8>>;
|
|
@@ -836,19 +836,20 @@ pub(crate) trait Signer {
|
|
|
}
|
|
|
|
|
|
pub(crate) trait Verifier {
|
|
|
- fn verify<'a, I: Iterator<Item=&'a [u8]>>(&self, parts: I, signature: &[u8]) -> Result<bool>;
|
|
|
+ fn verify<'a, I: Iterator<Item=&'a [u8]>>(&self, parts: I, signature: &[u8]) -> Result<()>;
|
|
|
}
|
|
|
|
|
|
/// Trait for types which can be used as public credentials.
|
|
|
-pub(crate) trait CredsPub: Verifier + Encrypter + Owned {}
|
|
|
+pub(crate) trait CredsPub: Verifier + Encrypter + Owned {
|
|
|
+ /// Returns a reference to the public signing key which can be used to verify signatures.
|
|
|
+ fn public_sign(&self) -> &AsymKey<Public, Sign>;
|
|
|
+}
|
|
|
|
|
|
/// Trait for types which contain private credentials.
|
|
|
pub(crate) trait CredsPriv: Decrypter + Signer {}
|
|
|
|
|
|
/// Trait for types which contain both public and private credentials.
|
|
|
-pub(crate) trait Creds: CredsPriv + CredsPub {
|
|
|
- fn public(&self) -> &AsymKey<Public, Sign>;
|
|
|
-}
|
|
|
+pub(crate) trait Creds: CredsPriv + CredsPub {}
|
|
|
|
|
|
/// A trait for types which store credentials.
|
|
|
pub(crate) trait CredStore {
|
|
@@ -942,9 +943,8 @@ fn get_body(block: &Block) -> Result<&[u8]> {
|
|
|
}
|
|
|
|
|
|
pub(crate) fn sign_block<K: Signer>(
|
|
|
- block: &mut Block, writecap: Writecap, priv_key: &K
|
|
|
+ block: &mut Block, priv_key: &K
|
|
|
) -> Result<()> {
|
|
|
- block.writecap = writecap;
|
|
|
let body = get_body(block)?;
|
|
|
let sig_input = HeaderSigInput::from(&*block);
|
|
|
let header = to_vec(&sig_input)?;
|
|
@@ -953,9 +953,10 @@ pub(crate) fn sign_block<K: Signer>(
|
|
|
Ok(())
|
|
|
}
|
|
|
|
|
|
-pub(crate) fn verify_block(block: &Block) -> Result<bool> {
|
|
|
+pub(crate) fn verify_block(block: &Block) -> Result<()> {
|
|
|
+ verify_writecap(&block.writecap, &block.path)?;
|
|
|
let body = get_body(block)?;
|
|
|
- let sig_input = HeaderSigInput::from(&*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())
|
|
@@ -988,52 +989,46 @@ pub(crate) fn sign_writecap<K: Signer>(writecap: &mut Writecap, priv_key: &K) ->
|
|
|
|
|
|
/// 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 {
|
|
|
+#[derive(Debug, PartialEq, 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,
|
|
|
- /// 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),
|
|
|
+ /// The write cap chain was too long to be validated. The value contained in this error is
|
|
|
+ /// the maximum allowed length.
|
|
|
+ ChainTooLong(usize),
|
|
|
}
|
|
|
|
|
|
/// 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> {
|
|
|
+pub(crate) fn verify_writecap(mut writecap: &Writecap, path: &Path) -> Result<()> {
|
|
|
+ const CHAIN_LEN_LIMIT: usize = 256;
|
|
|
let mut prev: Option<&Writecap> = None;
|
|
|
let mut sig_input = Vec::new();
|
|
|
let now = Epoch::now();
|
|
|
- loop {
|
|
|
+ for _ in 0..CHAIN_LEN_LIMIT {
|
|
|
if !writecap.path.contains(path) {
|
|
|
- return Err(WritecapAuthzErr::UnauthorizedPath);
|
|
|
+ return Err(WritecapAuthzErr::UnauthorizedPath.into());
|
|
|
}
|
|
|
if writecap.expires <= now {
|
|
|
- return Err(WritecapAuthzErr::Expired);
|
|
|
+ return Err(WritecapAuthzErr::Expired.into());
|
|
|
}
|
|
|
if let Some(prev) = &prev {
|
|
|
if prev.signing_key.owner_of_kind(writecap.issued_to.kind()) != writecap.issued_to {
|
|
|
- return Err(WritecapAuthzErr::NotChained);
|
|
|
+ return Err(WritecapAuthzErr::NotChained.into());
|
|
|
}
|
|
|
}
|
|
|
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);
|
|
|
- }
|
|
|
+ writecap.signing_key
|
|
|
+ .verify([sig_input.as_slice()].into_iter(), writecap.signature.as_slice())?;
|
|
|
match &writecap.next {
|
|
|
Some(next) => {
|
|
|
prev = Some(writecap);
|
|
@@ -1046,11 +1041,12 @@ pub(crate) fn verify_writecap(
|
|
|
return Ok(());
|
|
|
}
|
|
|
else {
|
|
|
- return Err(WritecapAuthzErr::RootDoesNotOwnPath)
|
|
|
+ return Err(WritecapAuthzErr::RootDoesNotOwnPath.into())
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+ Err(WritecapAuthzErr::ChainTooLong(CHAIN_LEN_LIMIT).into())
|
|
|
}
|
|
|
|
|
|
#[cfg(test)]
|
|
@@ -1097,9 +1093,7 @@ mod tests {
|
|
|
let header = b"About: lyrics".as_slice();
|
|
|
let message = b"Everything that feels so good is bad bad bad.".as_slice();
|
|
|
let signature = key.sign([header, message].into_iter())?;
|
|
|
- let verified = key.verify([header, message].into_iter(), signature.as_slice())?;
|
|
|
- assert_eq!(true, verified);
|
|
|
- Ok(())
|
|
|
+ key.verify([header, message].into_iter(), signature.as_slice())
|
|
|
}
|
|
|
|
|
|
#[test]
|
|
@@ -1108,17 +1102,9 @@ mod tests {
|
|
|
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)?);
|
|
|
+ sign_block(&mut block, &key)?;
|
|
|
+ verify_block(&block)?;
|
|
|
Ok(())
|
|
|
}
|
|
|
|
|
@@ -1140,40 +1126,51 @@ mod tests {
|
|
|
|
|
|
#[test]
|
|
|
fn verify_writecap_valid() -> Result<()> {
|
|
|
- let writecap = make_writecap()?;
|
|
|
- let result = verify_writecap(&writecap, &writecap.path);
|
|
|
- assert_eq!(Ok(()), result);
|
|
|
- Ok(())
|
|
|
+ let writecap = make_writecap(vec!["apps", "verse"])?;
|
|
|
+ verify_writecap(&writecap, &writecap.path)
|
|
|
}
|
|
|
|
|
|
#[test]
|
|
|
fn verify_writecap_invalid_signature() -> Result<()> {
|
|
|
- let mut writecap = make_writecap()?;
|
|
|
+ let mut writecap = make_writecap(vec!["apps", "verse"])?;
|
|
|
writecap.signature = Signature::default();
|
|
|
let result = verify_writecap(&writecap, &writecap.path);
|
|
|
- assert_eq!(Err(WritecapAuthzErr::InvalidSignature), result);
|
|
|
- Ok(())
|
|
|
+ if let Err(Error::InvalidSignature) = result {
|
|
|
+ Ok(())
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ Err(Error::custom(format!("unexpected result {:?}", result)))
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ fn assert_authz_err<T: std::fmt::Debug>(
|
|
|
+ expected: WritecapAuthzErr, result: Result<T>
|
|
|
+ ) -> Result<()> {
|
|
|
+ if let Err(Error::WritecapAuthzErr(actual)) = &result {
|
|
|
+ if *actual == expected {
|
|
|
+ return Ok(());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ Err(Error::custom(format!("unexpected result: {:?}", result)))
|
|
|
}
|
|
|
|
|
|
#[test]
|
|
|
fn verify_writecap_invalid_path_not_contained() -> Result<()> {
|
|
|
- let writecap = make_writecap()?;
|
|
|
+ let writecap = make_writecap(vec!["apps", "verse"])?;
|
|
|
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(())
|
|
|
+ assert_authz_err(WritecapAuthzErr::UnauthorizedPath, result)
|
|
|
}
|
|
|
|
|
|
#[test]
|
|
|
fn verify_writecap_invalid_expired() -> Result<()> {
|
|
|
- let mut writecap = make_writecap()?;
|
|
|
+ let mut writecap = make_writecap(vec!["apps", "verse"])?;
|
|
|
writecap.expires = Epoch::now() - Duration::from_secs(1);
|
|
|
let result = verify_writecap(&writecap, &writecap.path);
|
|
|
- assert_eq!(Err(WritecapAuthzErr::Expired), result);
|
|
|
- Ok(())
|
|
|
+ assert_authz_err(WritecapAuthzErr::Expired, result)
|
|
|
}
|
|
|
|
|
|
#[test]
|
|
@@ -1186,8 +1183,7 @@ mod tests {
|
|
|
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(())
|
|
|
+ assert_authz_err(WritecapAuthzErr::NotChained, result)
|
|
|
}
|
|
|
|
|
|
#[test]
|
|
@@ -1201,8 +1197,7 @@ mod tests {
|
|
|
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(())
|
|
|
+ assert_authz_err(WritecapAuthzErr::RootDoesNotOwnPath, result)
|
|
|
}
|
|
|
|
|
|
/// Tests that validate the dependencies of this module.
|