|
@@ -20,7 +20,6 @@ use serde::{
|
|
|
};
|
|
|
use std::{
|
|
|
str::FromStr,
|
|
|
- sync::Arc,
|
|
|
};
|
|
|
use strum_macros::{EnumString, EnumDiscriminants, Display};
|
|
|
|
|
@@ -363,13 +362,19 @@ impl Owned for AsymKeyPub {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-pub(crate) trait AsymKeyPriv: Decryptor + Signer {}
|
|
|
+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()
|
|
|
}
|
|
@@ -391,7 +396,7 @@ impl Decryptor for RsaPriv {
|
|
|
}
|
|
|
|
|
|
impl Signer for RsaPriv {
|
|
|
- fn sign<'a>(&self, parts: &mut dyn Iterator<Item=&'a [u8]>) -> Result<Signature> {
|
|
|
+ fn sign<'a, I: Iterator<Item=&'a [u8]>>(&self, parts: &mut I) -> Result<Signature> {
|
|
|
let digest = RsaPriv::digest();
|
|
|
let mut signature = RsaPriv::signature_buf();
|
|
|
|
|
@@ -405,45 +410,74 @@ impl Signer for RsaPriv {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl AsymKeyPriv for RsaPriv {}
|
|
|
+impl CredsPriv for RsaPriv {}
|
|
|
|
|
|
-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 })
|
|
|
+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 }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-pub(crate) struct KeyPair {
|
|
|
- pub(crate) public: AsymKeyPub,
|
|
|
- pub(crate) private: Arc<dyn AsymKeyPriv>,
|
|
|
+
|
|
|
+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 KeyPair {
|
|
|
- pub(crate) fn generate(kind: AsymKeyKind) -> Result<KeyPair> {
|
|
|
- match kind {
|
|
|
- AsymKeyKind::Rsa => {
|
|
|
- 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(KeyPair {
|
|
|
- public: AsymKeyPub::new(AsymKeyKind::Rsa, public_der.as_slice())?,
|
|
|
- private: Arc::new(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 Owned for KeyPair {
|
|
|
+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)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-trait Encryptor {
|
|
|
+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>>;
|
|
|
}
|
|
|
|
|
@@ -481,10 +515,10 @@ impl Decryptor for SymKey {
|
|
|
}
|
|
|
|
|
|
pub(crate) trait Signer {
|
|
|
- fn sign<'a>(&self, parts: &mut dyn Iterator<Item=&'a [u8]>) -> Result<Signature>;
|
|
|
+ fn sign<'a, I: Iterator<Item=&'a [u8]>>(&self, parts: &mut I) -> Result<Signature>;
|
|
|
}
|
|
|
|
|
|
-trait Verifier {
|
|
|
+pub(crate) trait Verifier {
|
|
|
fn verify<'a, I: Iterator<Item=&'a [u8]>>(&self, parts: I, signature: &[u8]) -> Result<bool>;
|
|
|
}
|
|
|
|
|
@@ -498,8 +532,19 @@ impl Verifier for AsymKeyPub {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-pub(crate) fn encrypt_block(
|
|
|
- mut block: Block, principal: &Principal, key: &KeyPair
|
|
|
+/// 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;
|
|
|
+}
|
|
|
+
|
|
|
+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),
|
|
@@ -507,15 +552,15 @@ pub(crate) fn encrypt_block(
|
|
|
};
|
|
|
let (principal_owned, read_cap) = block.readcaps.remove_entry(principal)
|
|
|
.ok_or(Error::NoReadCap)?;
|
|
|
- let block_key = decrypt(read_cap, key.private.as_ref())?;
|
|
|
+ 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, &key.public)?);
|
|
|
+ block.readcaps.insert(principal_owned, encrypt(&block_key, creds)?);
|
|
|
Ok(block)
|
|
|
}
|
|
|
|
|
|
-pub(crate) fn decrypt_block(
|
|
|
- mut block: Block, principal: &Principal, key: &dyn AsymKeyPriv
|
|
|
+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),
|
|
@@ -536,10 +581,8 @@ fn encrypt<T: Serialize, K: Encryptor>(value: &T, key: &K) -> Result<Cryptotext<
|
|
|
Ok(Cryptotext::Cipher(vec?))
|
|
|
}
|
|
|
|
|
|
-/// TODO: When the trait upcasting feature lands in the stable channel change the type of `key`
|
|
|
-/// to `dyn Decryptor`. Tracking issue: https://github.com/rust-lang/rust/issues/65991
|
|
|
-fn decrypt<T: Serialize + DeserializeOwned>(
|
|
|
- cryptotext: Cryptotext<T>, key: &dyn AsymKeyPriv
|
|
|
+fn decrypt<T: Serialize + DeserializeOwned, K: CredsPriv>(
|
|
|
+ cryptotext: Cryptotext<T>, key: &K
|
|
|
) -> Result<T> {
|
|
|
let data = match cryptotext {
|
|
|
Cryptotext::Plain(value) => return Ok(value),
|
|
@@ -550,15 +593,15 @@ fn decrypt<T: Serialize + DeserializeOwned>(
|
|
|
}
|
|
|
|
|
|
#[derive(Serialize)]
|
|
|
-struct SigHeader<'a> {
|
|
|
+struct HeaderSigInput<'a> {
|
|
|
path: &'a Path,
|
|
|
readcaps: &'a HashMap<Principal, Cryptotext<SymKey>>,
|
|
|
writecap: &'a Writecap,
|
|
|
}
|
|
|
|
|
|
-impl<'a> From<&'a Block> for SigHeader<'a> {
|
|
|
- fn from(block: &'a Block) -> SigHeader<'a> {
|
|
|
- SigHeader {
|
|
|
+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,
|
|
@@ -576,13 +619,13 @@ fn get_body(block: &Block) -> Result<&[u8]> {
|
|
|
Ok(body)
|
|
|
}
|
|
|
|
|
|
-pub(crate) fn sign_block(
|
|
|
- block: &mut Block, writecap: Writecap, priv_key: &dyn AsymKeyPriv
|
|
|
+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_header = SigHeader::from(&*block);
|
|
|
- let header = to_vec(&sig_header)?;
|
|
|
+ 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(())
|
|
@@ -590,23 +633,23 @@ pub(crate) fn sign_block(
|
|
|
|
|
|
pub(crate) fn verify_block(block: &Block) -> Result<bool> {
|
|
|
let body = get_body(block)?;
|
|
|
- let sig_header = SigHeader::from(&*block);
|
|
|
- let header = to_vec(&sig_header)?;
|
|
|
+ let 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 WritecapSig<'a> {
|
|
|
+struct WritecapSigInput<'a> {
|
|
|
issued_to: &'a Principal,
|
|
|
path: &'a Path,
|
|
|
expires: &'a Epoch,
|
|
|
signing_key: &'a AsymKeyPub,
|
|
|
}
|
|
|
|
|
|
-impl<'a> From<&'a Writecap> for WritecapSig<'a> {
|
|
|
- fn from(writecap: &'a Writecap) -> WritecapSig<'a> {
|
|
|
- WritecapSig {
|
|
|
+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,
|
|
@@ -615,10 +658,8 @@ impl<'a> From<&'a Writecap> for WritecapSig<'a> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-/// TODO: When the trait upcasting feature lands in the stable channel change the type of `priv_key`
|
|
|
-/// to `dyn Decryptor`. Tracking issue: https://github.com/rust-lang/rust/issues/65991
|
|
|
-pub(crate) fn sign_writecap(writecap: &mut Writecap, priv_key: &dyn AsymKeyPriv) -> Result<()> {
|
|
|
- let sig_input = to_vec(&WritecapSig::from(&*writecap))?;
|
|
|
+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(())
|
|
|
}
|
|
@@ -662,7 +703,7 @@ pub(crate) fn verify_writecap(
|
|
|
return Err(WritecapAuthzErr::NotChained);
|
|
|
}
|
|
|
}
|
|
|
- let sig = WritecapSig::from(writecap);
|
|
|
+ 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
|
|
@@ -695,17 +736,17 @@ mod tests {
|
|
|
use super::*;
|
|
|
use test_helpers::*;
|
|
|
|
|
|
- fn encrypt_decrypt_block_test_case(
|
|
|
- mut actual: Block, principal: &Principal, key: &KeyPair
|
|
|
+ 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, key)?;
|
|
|
+ actual = encrypt_block(actual, principal, creds)?;
|
|
|
let encrypted = match &actual.body {
|
|
|
Cryptotext::Cipher(_) => true,
|
|
|
Cryptotext::Plain(_) => false
|
|
|
};
|
|
|
assert!(encrypted);
|
|
|
- actual = decrypt_block(actual, principal, key.private.as_ref())?;
|
|
|
+ actual = decrypt_block(actual, principal, creds)?;
|
|
|
assert_eq!(expected, actual);
|
|
|
Ok(())
|
|
|
}
|
|
@@ -733,8 +774,8 @@ mod tests {
|
|
|
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.private.sign(&mut [header, message].into_iter())?;
|
|
|
- let verified = key.public.verify([header, message].into_iter(), signature.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(())
|
|
|
}
|
|
@@ -749,12 +790,12 @@ mod tests {
|
|
|
issued_to: Principal(Hash::Sha2_256(PRINCIPAL)),
|
|
|
path: make_path(vec!["contacts", "emergency"]),
|
|
|
expires: Epoch(1649904316),
|
|
|
- signing_key: key.public.clone(),
|
|
|
+ signing_key: key.public().clone(),
|
|
|
signature: Signature::Rsa(SIGNATURE),
|
|
|
next: None,
|
|
|
};
|
|
|
block = encrypt_block(block, &principal, &key)?;
|
|
|
- sign_block(&mut block, writecap, key.private.as_ref())?;
|
|
|
+ sign_block(&mut block, writecap, &key)?;
|
|
|
assert_eq!(true, verify_block(&block)?);
|
|
|
Ok(())
|
|
|
}
|
|
@@ -817,7 +858,7 @@ mod tests {
|
|
|
fn verify_writecap_invalid_not_chained() -> Result<()> {
|
|
|
let (mut root_writecap, root_key) = make_self_signed_writecap()?;
|
|
|
root_writecap.issued_to = Principal(Hash::Sha2_256([0; 32]));
|
|
|
- sign_writecap(&mut root_writecap, root_key.private.as_ref())?;
|
|
|
+ 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())?)?
|
|
@@ -835,7 +876,7 @@ mod tests {
|
|
|
let (mut root_writecap, root_key) = make_self_signed_writecap()?;
|
|
|
let owner = Principal(Hash::Sha2_256([0; 32]));
|
|
|
root_writecap.path = make_path_with_owner(owner, vec![]);
|
|
|
- sign_writecap(&mut root_writecap, root_key.private.as_ref())?;
|
|
|
+ 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())?)?
|
|
@@ -896,7 +937,7 @@ mod tests {
|
|
|
#[test]
|
|
|
fn rsa_signature_len() -> Result<()> {
|
|
|
let key = make_key_pair();
|
|
|
- let signature = key.private.sign(&mut [NODE_PUBLIC_KEY.as_slice()].into_iter())?;
|
|
|
+ let signature = key.sign(&mut [NODE_PUBLIC_KEY.as_slice()].into_iter())?;
|
|
|
let length = match signature {
|
|
|
Signature::Rsa(data) => data.len(),
|
|
|
};
|