|
@@ -4,7 +4,7 @@ use super::*;
|
|
|
use openssl::{
|
|
|
error::ErrorStack,
|
|
|
encrypt::{Encrypter, Decrypter},
|
|
|
- pkey::{PKey, Public, Private},
|
|
|
+ pkey::{PKey, Public as OsslPublic, Private as OsslPrivate},
|
|
|
symm::{Cipher, encrypt as openssl_encrypt, decrypt as openssl_decrypt},
|
|
|
rand::rand_bytes,
|
|
|
rsa::{Rsa, Padding as OpensslPadding},
|
|
@@ -77,10 +77,20 @@ pub enum Hash {
|
|
|
Sha2_512([u8; 64]),
|
|
|
}
|
|
|
|
|
|
+impl Default for HashType {
|
|
|
+ fn default() -> HashType {
|
|
|
+ HashType::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) -> HashType {
|
|
|
+ HashType::from(self)
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
impl From<HashType> for Hash {
|
|
@@ -201,10 +211,9 @@ impl From<RsaPadding> for OpensslPadding {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-/// A cryptographic key.
|
|
|
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, EnumDiscriminants)]
|
|
|
-#[strum_discriminants(name(KeyType))]
|
|
|
-pub enum Key {
|
|
|
+#[strum_discriminants(name(SymKeyType))]
|
|
|
+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.
|
|
@@ -217,71 +226,115 @@ pub enum Key {
|
|
|
key: [u8; 32],
|
|
|
iv: [u8; 16]
|
|
|
},
|
|
|
- Rsa {
|
|
|
- public: Vec<u8>,
|
|
|
- private: Option<Vec<u8>>,
|
|
|
- padding: RsaPadding,
|
|
|
- },
|
|
|
}
|
|
|
|
|
|
-impl Key {
|
|
|
- /// Returns the key part of this `Key`. Note that if this `Key` is for an asymmetric algorithm,
|
|
|
- /// then this returns the *private* key (if it is present).
|
|
|
- fn key_slice(&self) -> Option<&[u8]> {
|
|
|
- match self {
|
|
|
- Key::Aes256Cbc { key, .. } => Some(key),
|
|
|
- Key::Aes256Ctr { key, .. } => Some(key),
|
|
|
- Key::Rsa { private, .. } => match private {
|
|
|
- Some(key) => Some(key.as_slice()),
|
|
|
- None => None,
|
|
|
+fn generate_key_and_iv<const KEY_LEN: usize, const IV_LEN: usize>(
|
|
|
+) -> Result<([u8; KEY_LEN], [u8; IV_LEN])> {
|
|
|
+ let mut key = [0; KEY_LEN];
|
|
|
+ let mut iv = [0; IV_LEN];
|
|
|
+ rand_bytes(&mut key).map_err(Error::from)?;
|
|
|
+ rand_bytes(&mut iv).map_err(Error::from)?;
|
|
|
+ Ok((key, iv))
|
|
|
+}
|
|
|
+
|
|
|
+/// 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 fn generate(kind: SymKeyType) -> Result<SymKey> {
|
|
|
+ match kind {
|
|
|
+ SymKeyType::Aes256Cbc => {
|
|
|
+ Ok(SymKey::Aes256Cbc { key: rand_array()?, iv: rand_array()? })
|
|
|
+ },
|
|
|
+ SymKeyType::Aes256Ctr => {
|
|
|
+ Ok(SymKey::Aes256Ctr { key: rand_array()?, iv: rand_array()? })
|
|
|
},
|
|
|
}
|
|
|
}
|
|
|
+}
|
|
|
+
|
|
|
+#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
|
|
+pub struct Public;
|
|
|
+
|
|
|
+#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
|
|
+pub struct Private;
|
|
|
+
|
|
|
+#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, EnumDiscriminants)]
|
|
|
+#[strum_discriminants(name(AsymKeyType))]
|
|
|
+pub enum AsymKey<T> {
|
|
|
+ Rsa {
|
|
|
+ der: Vec<u8>,
|
|
|
+ padding: RsaPadding,
|
|
|
+ kind: T,
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
- /// Returns the IV part of this`Key`.
|
|
|
- fn iv_slice(&self) -> Option<&[u8]> {
|
|
|
+impl<T> AsymKey<T> {
|
|
|
+ pub fn as_slice(&self) -> &[u8] {
|
|
|
match self {
|
|
|
- Key::Aes256Cbc { iv, .. } => Some(iv),
|
|
|
- _ => None,
|
|
|
+ AsymKey::Rsa { der, .. } => der.as_slice()
|
|
|
}
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- pub fn generate(id: KeyType) -> Result<Key> {
|
|
|
- match id {
|
|
|
- KeyType::Aes256Cbc => {
|
|
|
- let mut key = [0; 32];
|
|
|
- let mut iv = [0; 16];
|
|
|
- rand_bytes(&mut key).map_err(Error::from)?;
|
|
|
- rand_bytes(&mut iv).map_err(Error::from)?;
|
|
|
- Ok(Key::Aes256Cbc { key, iv })
|
|
|
- },
|
|
|
- KeyType::Aes256Ctr => {
|
|
|
- let mut key = [0; 32];
|
|
|
- let mut iv = [0; 16];
|
|
|
- rand_bytes(&mut key).map_err(Error::from)?;
|
|
|
- rand_bytes(&mut iv).map_err(Error::from)?;
|
|
|
- Ok(Key::Aes256Ctr { key, iv })
|
|
|
+impl<T> Owned for AsymKey<T> {
|
|
|
+ fn owner_of_kind(&self, kind: HashType) -> Principal {
|
|
|
+ let slice = match self {
|
|
|
+ AsymKey::Rsa { der, .. } => der.as_slice(),
|
|
|
+ };
|
|
|
+ match kind {
|
|
|
+ HashType::Sha2_256 => {
|
|
|
+ let mut buf = [0; 32];
|
|
|
+ let bytes = hash(MessageDigest::sha256(), slice).unwrap();
|
|
|
+ buf.copy_from_slice(&*bytes);
|
|
|
+ Principal(Hash::Sha2_256(buf))
|
|
|
},
|
|
|
- KeyType::Rsa => {
|
|
|
+ HashType::Sha2_512 => {
|
|
|
+ let mut buf = [0; 64];
|
|
|
+ let bytes = hash(MessageDigest::sha512(), slice).unwrap();
|
|
|
+ buf.copy_from_slice(&*bytes);
|
|
|
+ Principal(Hash::Sha2_512(buf))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+pub struct KeyPair {
|
|
|
+ pub public: AsymKey<Public>,
|
|
|
+ pub private: AsymKey<Private>,
|
|
|
+}
|
|
|
+
|
|
|
+impl KeyPair {
|
|
|
+ pub fn generate(kind: AsymKeyType) -> Result<KeyPair> {
|
|
|
+ match kind {
|
|
|
+ AsymKeyType::Rsa => {
|
|
|
let key = PKey::from_rsa(Rsa::generate(4096)?)?;
|
|
|
- let public= key.public_key_to_der().map_err(Error::from)?;
|
|
|
- let private = Some(key.private_key_to_der().map_err(Error::from)?);
|
|
|
- Ok(Key::Rsa { public, private, padding: RsaPadding::Pkcs1 })
|
|
|
+ let public = key.public_key_to_der().map_err(Error::from)?;
|
|
|
+ let private = key.private_key_to_der().map_err(Error::from)?;
|
|
|
+ Ok(KeyPair {
|
|
|
+ public: AsymKey::Rsa {
|
|
|
+ der: public,
|
|
|
+ padding: RsaPadding::default(),
|
|
|
+ kind: Public,
|
|
|
+ },
|
|
|
+ private: AsymKey::Rsa {
|
|
|
+ der: private,
|
|
|
+ padding: RsaPadding::default(),
|
|
|
+ kind: Private,
|
|
|
+ },
|
|
|
+ })
|
|
|
},
|
|
|
}
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- /// Hashes this key and returns the `Principal` it is for.
|
|
|
- pub fn to_principal(&self) -> Principal {
|
|
|
- let slice = match self {
|
|
|
- Key::Rsa { public, .. } => public.as_slice(),
|
|
|
- Key::Aes256Cbc { key, .. } => key,
|
|
|
- Key::Aes256Ctr { key, .. } => key,
|
|
|
- };
|
|
|
- let mut buf = [0; 32];
|
|
|
- let bytes = hash(MessageDigest::sha256(), slice).unwrap();
|
|
|
- buf.copy_from_slice(&*bytes);
|
|
|
- Principal(Hash::Sha2_256(buf))
|
|
|
+impl Owned for KeyPair {
|
|
|
+ fn owner_of_kind(&self, kind: HashType) -> Principal {
|
|
|
+ self.public.owner_of_kind(kind)
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -292,7 +345,7 @@ enum EncryptionAlgo<'a> {
|
|
|
iv: Option<&'a [u8]>
|
|
|
},
|
|
|
Asymmetric {
|
|
|
- key: PKey<Public>,
|
|
|
+ key: PKey<OsslPublic>,
|
|
|
rsa_padding: Option<OpensslPadding>,
|
|
|
}
|
|
|
}
|
|
@@ -319,22 +372,30 @@ impl<'a> EncryptionAlgo<'a> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<'a> TryFrom<&'a Key> for EncryptionAlgo<'a> {
|
|
|
+impl<'a> TryFrom<&'a SymKey> for EncryptionAlgo<'a> {
|
|
|
type Error = Error;
|
|
|
- fn try_from(key: &'a Key) -> Result<EncryptionAlgo<'a>> {
|
|
|
+ fn try_from(key: &'a SymKey) -> Result<EncryptionAlgo<'a>> {
|
|
|
match key {
|
|
|
- Key::Aes256Cbc { key: key_slice, iv } => Ok(EncryptionAlgo::Symmetric {
|
|
|
+ SymKey::Aes256Cbc { key: key_slice, iv } => Ok(EncryptionAlgo::Symmetric {
|
|
|
cipher: Cipher::aes_256_cbc(),
|
|
|
key: key_slice,
|
|
|
iv: Some(iv),
|
|
|
}),
|
|
|
- Key::Aes256Ctr { key: key_slice, iv } => Ok(EncryptionAlgo::Symmetric {
|
|
|
+ SymKey::Aes256Ctr { key: key_slice, iv } => Ok(EncryptionAlgo::Symmetric {
|
|
|
cipher: Cipher::aes_256_ctr(),
|
|
|
key: key_slice,
|
|
|
iv: Some(iv),
|
|
|
}),
|
|
|
- Key::Rsa { public, padding, .. } => {
|
|
|
- let pkey = PKey::public_key_from_der(public.as_slice())
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<'a> TryFrom<&'a AsymKey<Public>> for EncryptionAlgo<'a> {
|
|
|
+ type Error = Error;
|
|
|
+ fn try_from(key: &'a AsymKey<Public>) -> Result<EncryptionAlgo<'a>> {
|
|
|
+ match key {
|
|
|
+ AsymKey::Rsa { der, padding, .. } => {
|
|
|
+ let pkey = PKey::public_key_from_der(der.as_slice())
|
|
|
.map_err(|err| Error::Message(err.to_string()));
|
|
|
Ok(EncryptionAlgo::Asymmetric { key: pkey?, rsa_padding: Some((*padding).into()) })
|
|
|
},
|
|
@@ -348,7 +409,7 @@ enum DecryptionAlgo<'a> {
|
|
|
key: &'a [u8],
|
|
|
iv: Option<&'a [u8]>
|
|
|
},
|
|
|
- Asymmetric(PKey<Private>),
|
|
|
+ Asymmetric(PKey<OsslPrivate>),
|
|
|
}
|
|
|
|
|
|
impl<'a> DecryptionAlgo<'a> {
|
|
@@ -370,23 +431,30 @@ impl<'a> DecryptionAlgo<'a> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<'a> TryFrom<&'a Key> for DecryptionAlgo<'a> {
|
|
|
+impl<'a> TryFrom<&'a SymKey> for DecryptionAlgo<'a> {
|
|
|
type Error = Error;
|
|
|
- fn try_from(key: &'a Key) -> Result<DecryptionAlgo<'a>> {
|
|
|
+ fn try_from(key: &'a SymKey) -> Result<DecryptionAlgo<'a>> {
|
|
|
match key {
|
|
|
- Key::Aes256Cbc { key: key_slice, iv } => Ok(DecryptionAlgo::Symmetric {
|
|
|
+ SymKey::Aes256Cbc { key: key_slice, iv } => Ok(DecryptionAlgo::Symmetric {
|
|
|
cipher: Cipher::aes_256_cbc(),
|
|
|
key: key_slice,
|
|
|
iv: Some(iv),
|
|
|
}),
|
|
|
- Key::Aes256Ctr { key: key_slice, iv } => Ok(DecryptionAlgo::Symmetric {
|
|
|
+ SymKey::Aes256Ctr { key: key_slice, iv } => Ok(DecryptionAlgo::Symmetric {
|
|
|
cipher: Cipher::aes_256_ctr(),
|
|
|
key: key_slice,
|
|
|
iv: Some(iv),
|
|
|
}),
|
|
|
- Key::Rsa { private, .. } => {
|
|
|
- let private = private.as_ref().ok_or(Error::MissingPrivateKey)?;
|
|
|
- let pkey = PKey::private_key_from_der(private.as_slice()).map_err(Error::from);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<'a> TryFrom<&'a AsymKey<Private>> for DecryptionAlgo<'a> {
|
|
|
+ type Error = Error;
|
|
|
+ fn try_from(key: &'a AsymKey<Private>) -> Result<DecryptionAlgo<'a>> {
|
|
|
+ match key {
|
|
|
+ AsymKey::Rsa { der, .. } => {
|
|
|
+ let pkey = PKey::private_key_from_der(der.as_slice()).map_err(Error::from);
|
|
|
Ok(DecryptionAlgo::Asymmetric(pkey?))
|
|
|
}
|
|
|
}
|
|
@@ -394,7 +462,7 @@ impl<'a> TryFrom<&'a Key> for DecryptionAlgo<'a> {
|
|
|
}
|
|
|
|
|
|
struct SignAlgo {
|
|
|
- key: PKey<Private>,
|
|
|
+ key: PKey<OsslPrivate>,
|
|
|
digest: MessageDigest,
|
|
|
signature: Signature
|
|
|
}
|
|
@@ -411,25 +479,24 @@ impl SignAlgo {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl TryFrom<&Key> for SignAlgo {
|
|
|
+impl TryFrom<&AsymKey<Private>> for SignAlgo {
|
|
|
type Error = Error;
|
|
|
- fn try_from(key: &Key) -> Result<SignAlgo> {
|
|
|
+ fn try_from(key: &AsymKey<Private>) -> Result<SignAlgo> {
|
|
|
match key {
|
|
|
- Key::Rsa { private: Some(private), .. } => {
|
|
|
- let rsa = Rsa::private_key_from_der(private.as_slice()).map_err(Error::from)?;
|
|
|
+ AsymKey::Rsa { der, .. } => {
|
|
|
+ let rsa = Rsa::private_key_from_der(der.as_slice()).map_err(Error::from)?;
|
|
|
Ok(SignAlgo {
|
|
|
key: PKey::from_rsa(rsa).map_err(Error::from)?,
|
|
|
digest: MessageDigest::sha256(),
|
|
|
signature: Signature::new(SignatureId::Rsa)
|
|
|
})
|
|
|
},
|
|
|
- _ => Err(Error::KeyVariantUnsupported)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
struct VerifyAlgo {
|
|
|
- key: PKey<Public>,
|
|
|
+ key: PKey<OsslPublic>,
|
|
|
digest: MessageDigest,
|
|
|
}
|
|
|
|
|
@@ -445,24 +512,23 @@ impl VerifyAlgo {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl TryFrom<&Key> for VerifyAlgo {
|
|
|
+impl TryFrom<&AsymKey<Public>> for VerifyAlgo {
|
|
|
type Error = Error;
|
|
|
- fn try_from(key: &Key) -> Result<VerifyAlgo> {
|
|
|
+ fn try_from(key: &AsymKey<Public>) -> Result<VerifyAlgo> {
|
|
|
match key {
|
|
|
- Key::Rsa { public, .. } => {
|
|
|
- let rsa = Rsa::public_key_from_der(public.as_slice()).map_err(Error::from)?;
|
|
|
+ AsymKey::Rsa { der, .. } => {
|
|
|
+ let rsa = Rsa::public_key_from_der(der.as_slice()).map_err(Error::from)?;
|
|
|
Ok(VerifyAlgo {
|
|
|
key: PKey::from_rsa(rsa).map_err(Error::from)?,
|
|
|
digest: MessageDigest::sha256()
|
|
|
})
|
|
|
},
|
|
|
- _ => Err(Error::KeyVariantUnsupported)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
pub(crate) fn encrypt_block(
|
|
|
- versioned_block: VersionedBlock, principal: &Principal, key: &Key
|
|
|
+ versioned_block: VersionedBlock, principal: &Principal, key: &KeyPair
|
|
|
) -> Result<VersionedBlock> {
|
|
|
let VersionedBlock::V0(mut block) = versioned_block;
|
|
|
let body = match block.body {
|
|
@@ -471,15 +537,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)?;
|
|
|
+ let block_key = decrypt(read_cap, &key.private)?;
|
|
|
let new_body = encrypt_slice(&body, &block_key)?;
|
|
|
block.body = Cryptotext::Cipher(new_body);
|
|
|
- block.readcaps.insert(principal_owned, encrypt(&block_key, key)?);
|
|
|
+ block.readcaps.insert(principal_owned, encrypt(&block_key, &key.public)?);
|
|
|
Ok(VersionedBlock::V0(block))
|
|
|
}
|
|
|
|
|
|
pub(crate) fn decrypt_block(
|
|
|
- versioned_block: VersionedBlock, principal: &Principal, key: &Key
|
|
|
+ versioned_block: VersionedBlock, principal: &Principal, key: &AsymKey<Private>
|
|
|
) -> Result<VersionedBlock> {
|
|
|
let VersionedBlock::V0(mut block) = versioned_block;
|
|
|
let body = match block.body {
|
|
@@ -495,13 +561,17 @@ pub(crate) fn decrypt_block(
|
|
|
Ok(VersionedBlock::V0(block))
|
|
|
}
|
|
|
|
|
|
-fn encrypt<T: Serialize>(value: &T, key: &Key) -> Result<Cryptotext<T>> {
|
|
|
+fn encrypt<'a, K: TryInto<EncryptionAlgo<'a>, Error = Error>, T: Serialize>(
|
|
|
+ value: &T, key: K
|
|
|
+) -> Result<Cryptotext<T>> {
|
|
|
let data = to_vec(value).map_err(Error::from)?;
|
|
|
let vec = encrypt_slice(&data, key);
|
|
|
Ok(Cryptotext::Cipher(vec?))
|
|
|
}
|
|
|
|
|
|
-fn decrypt<T: Serialize + DeserializeOwned>(cryptotext: Cryptotext<T>, key: &Key) -> Result<T> {
|
|
|
+fn decrypt<'a, K: TryInto<DecryptionAlgo<'a>, Error = Error>, T: Serialize + DeserializeOwned>(
|
|
|
+ cryptotext: Cryptotext<T>, key: K
|
|
|
+) -> Result<T> {
|
|
|
let data = match cryptotext {
|
|
|
Cryptotext::Plain(value) => return Ok(value),
|
|
|
Cryptotext::Cipher(data) => data
|
|
@@ -510,20 +580,24 @@ fn decrypt<T: Serialize + DeserializeOwned>(cryptotext: Cryptotext<T>, key: &Key
|
|
|
from_vec(&vec?).map_err(Error::from)
|
|
|
}
|
|
|
|
|
|
-fn encrypt_slice(plaintext: &[u8], key: &Key) -> Result<Vec<u8>> {
|
|
|
- let algo = EncryptionAlgo::try_from(key)?;
|
|
|
- algo.encrypt(plaintext)
|
|
|
+fn encrypt_slice<'a, K: TryInto<EncryptionAlgo<'a>, Error = Error>>(
|
|
|
+ plaintext: &[u8], key: K
|
|
|
+) -> Result<Vec<u8>> {
|
|
|
+ let algo: EncryptionAlgo<'a> = key.try_into()?;
|
|
|
+ algo.encrypt(plaintext)
|
|
|
}
|
|
|
|
|
|
-fn decrypt_slice(ciphertext: &[u8], key: &Key) -> Result<Vec<u8>> {
|
|
|
- let algo = DecryptionAlgo::try_from(key)?;
|
|
|
+fn decrypt_slice<'a, K: TryInto<DecryptionAlgo<'a>, Error = Error>>(
|
|
|
+ ciphertext: &[u8], key: K
|
|
|
+) -> Result<Vec<u8>> {
|
|
|
+ let algo: DecryptionAlgo<'a> = key.try_into()?;
|
|
|
algo.decrypt(ciphertext)
|
|
|
}
|
|
|
|
|
|
#[derive(Serialize)]
|
|
|
struct SigHeader<'a> {
|
|
|
path: &'a Path,
|
|
|
- readcaps: &'a HashMap<Principal, Cryptotext<Key>>,
|
|
|
+ readcaps: &'a HashMap<Principal, Cryptotext<SymKey>>,
|
|
|
writecap: &'a Writecap,
|
|
|
}
|
|
|
|
|
@@ -547,13 +621,15 @@ fn get_body(block: &Block) -> Result<&[u8]> {
|
|
|
Ok(body)
|
|
|
}
|
|
|
|
|
|
-pub(crate) fn sign_block(versioned_block: &mut VersionedBlock, writecap: Writecap) -> Result<()> {
|
|
|
+pub(crate) fn sign_block(
|
|
|
+ versioned_block: &mut VersionedBlock, writecap: Writecap, priv_key: AsymKey<Private>
|
|
|
+) -> Result<()> {
|
|
|
let VersionedBlock::V0(block) = versioned_block;
|
|
|
block.writecap = writecap;
|
|
|
let body = get_body(block)?;
|
|
|
let sig_header = SigHeader::from(&*block);
|
|
|
let header = to_vec(&sig_header)?;
|
|
|
- let mut sign_algo = SignAlgo::try_from(&block.writecap.signing_key)?;
|
|
|
+ let mut sign_algo = SignAlgo::try_from(&priv_key)?;
|
|
|
sign_algo.sign([header.as_slice(), body].into_iter())?;
|
|
|
block.signature = sign_algo.signature;
|
|
|
Ok(())
|
|
@@ -577,7 +653,7 @@ struct WritecapSig<'a> {
|
|
|
issued_to: &'a Principal,
|
|
|
path: &'a Path,
|
|
|
expires: &'a Epoch,
|
|
|
- signing_key: &'a Key,
|
|
|
+ signing_key: &'a AsymKey<Public>,
|
|
|
}
|
|
|
|
|
|
impl<'a> From<&'a Writecap> for WritecapSig<'a> {
|
|
@@ -591,8 +667,8 @@ impl<'a> From<&'a Writecap> for WritecapSig<'a> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-pub(crate) fn sign_writecap(writecap: &mut Writecap, key: &Key) -> Result<()> {
|
|
|
- let mut sign_algo = SignAlgo::try_from(key)?;
|
|
|
+pub(crate) fn sign_writecap(writecap: &mut Writecap, priv_key: &AsymKey<Private>) -> Result<()> {
|
|
|
+ let mut sign_algo = SignAlgo::try_from(priv_key)?;
|
|
|
let sig_input = to_vec(&WritecapSig::from(&*writecap))?;
|
|
|
sign_algo.sign([sig_input.as_slice()].into_iter())?;
|
|
|
writecap.signature = sign_algo.signature;
|
|
@@ -634,7 +710,7 @@ pub(crate) fn verify_writecap(
|
|
|
return Err(WritecapAuthzErr::Expired);
|
|
|
}
|
|
|
if let Some(prev) = &prev {
|
|
|
- if prev.signing_key.to_principal() != writecap.issued_to {
|
|
|
+ if prev.signing_key.owner_of_kind(writecap.issued_to.kind()) != writecap.issued_to {
|
|
|
return Err(WritecapAuthzErr::NotChained);
|
|
|
}
|
|
|
}
|
|
@@ -657,7 +733,7 @@ pub(crate) fn verify_writecap(
|
|
|
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.to_principal() == path.owner {
|
|
|
+ if writecap.signing_key.owner_of_kind(path.owner.kind()) == path.owner {
|
|
|
return Ok(());
|
|
|
}
|
|
|
else {
|
|
@@ -673,32 +749,17 @@ mod tests {
|
|
|
use super::*;
|
|
|
use test_helpers::*;
|
|
|
|
|
|
- #[test]
|
|
|
- fn key_aes256cbc_key_slice_is_correct() -> Result<()> {
|
|
|
- let key = Key::Aes256Cbc { key: KEY, iv: IV };
|
|
|
- let key_part = key.key_slice().ok_or(Error::NoKeyAvailable);
|
|
|
- assert_eq!(KEY, key_part?);
|
|
|
- Ok(())
|
|
|
- }
|
|
|
-
|
|
|
- #[test]
|
|
|
- fn key_aes256cbc_iv_slice_is_correct() {
|
|
|
- let key = Key::Aes256Cbc { key: KEY, iv: IV };
|
|
|
- let iv_part = key.iv_slice().unwrap();
|
|
|
- assert_eq!(IV, iv_part);
|
|
|
- }
|
|
|
-
|
|
|
fn encrypt_decrypt_block_test_case(
|
|
|
- mut actual: VersionedBlock, principal: &Principal, key: &Key
|
|
|
+ mut actual: VersionedBlock, principal: &Principal, key: &KeyPair
|
|
|
) -> Result<()> {
|
|
|
let expected = actual.clone();
|
|
|
actual = encrypt_block(actual, principal, key)?;
|
|
|
- actual = decrypt_block(actual, principal, key)?;
|
|
|
+ actual = decrypt_block(actual, principal, &key.private)?;
|
|
|
assert_eq!(expected, actual);
|
|
|
Ok(())
|
|
|
}
|
|
|
|
|
|
- fn make_versioned_block(principal: Principal, block_key: Key) -> Result<VersionedBlock> {
|
|
|
+ fn make_versioned_block(principal: Principal, block_key: SymKey) -> Result<VersionedBlock> {
|
|
|
let mut block = make_block()?;
|
|
|
block.readcaps.clear();
|
|
|
block.readcaps.insert(principal, Cryptotext::Plain(block_key));
|
|
@@ -708,38 +769,29 @@ mod tests {
|
|
|
#[test]
|
|
|
fn encrypt_decrypt_block_aes256cbc() -> Result<()> {
|
|
|
let principal = make_principal();
|
|
|
- let block_key = Key::Aes256Cbc { key: BLOCK_KEY, iv: BLOCK_IV };
|
|
|
+ let block_key = SymKey::Aes256Cbc { key: BLOCK_KEY, iv: BLOCK_IV };
|
|
|
let block = make_versioned_block(principal.clone(), block_key)?;
|
|
|
- let key = Key::Aes256Cbc { key: KEY, iv: IV };
|
|
|
+ let key = make_key_pair();
|
|
|
encrypt_decrypt_block_test_case(block, &principal, &key)
|
|
|
}
|
|
|
|
|
|
#[test]
|
|
|
fn encrypt_decrypt_block_aes256ctr() -> Result<()> {
|
|
|
let principal = make_principal();
|
|
|
- let block_key = Key::Aes256Ctr { key: BLOCK_KEY, iv: BLOCK_IV };
|
|
|
- let block = make_versioned_block(principal.clone(), block_key)?;
|
|
|
- let key = Key::Aes256Ctr { key: KEY, iv: IV };
|
|
|
- encrypt_decrypt_block_test_case(block, &principal, &key)
|
|
|
- }
|
|
|
-
|
|
|
- #[test]
|
|
|
- fn encrypt_decrypt_block_rsa() -> Result<()> {
|
|
|
- let principal = make_principal();
|
|
|
- let block_key = Key::Aes256Ctr { key: BLOCK_KEY, iv: BLOCK_IV };
|
|
|
+ let block_key = SymKey::Aes256Ctr { key: BLOCK_KEY, iv: BLOCK_IV };
|
|
|
let block = make_versioned_block(principal.clone(), block_key)?;
|
|
|
- let key = Key::generate(KeyType::Rsa)?;
|
|
|
+ let key = make_key_pair();
|
|
|
encrypt_decrypt_block_test_case(block, &principal, &key)
|
|
|
}
|
|
|
|
|
|
#[test]
|
|
|
fn rsa_sign_and_verify() -> Result<()> {
|
|
|
- let key = Key::generate(KeyType::Rsa)?;
|
|
|
+ let key = make_key_pair();
|
|
|
let header = b"About: lyrics".as_slice();
|
|
|
let message = b"Everything that feels so good is bad bad bad.".as_slice();
|
|
|
- let mut signer = SignAlgo::try_from(&key)?;
|
|
|
+ let mut signer = SignAlgo::try_from(&key.private)?;
|
|
|
signer.sign([header, message].into_iter())?;
|
|
|
- let verifier = VerifyAlgo::try_from(&key)?;
|
|
|
+ let verifier = VerifyAlgo::try_from(&key.public)?;
|
|
|
let verified = verifier.verify([header, message].into_iter(), signer.signature.as_slice())?;
|
|
|
assert_eq!(true, verified);
|
|
|
Ok(())
|
|
@@ -748,19 +800,19 @@ mod tests {
|
|
|
#[test]
|
|
|
fn sign_verify_block_rsa() -> Result<()> {
|
|
|
let principal = make_principal();
|
|
|
- let block_key = Key::Aes256Ctr { key: BLOCK_KEY, iv: BLOCK_IV };
|
|
|
+ let block_key = SymKey::Aes256Ctr { key: BLOCK_KEY, iv: BLOCK_IV };
|
|
|
let mut block = make_versioned_block(principal.clone(), block_key)?;
|
|
|
- let key = Key::generate(KeyType::Rsa)?;
|
|
|
+ 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,
|
|
|
+ signing_key: key.public.clone(),
|
|
|
signature: Signature::Rsa(SIGNATURE),
|
|
|
next: None,
|
|
|
};
|
|
|
- block = encrypt_block(block, &principal, &writecap.signing_key)?;
|
|
|
- sign_block(&mut block, writecap)?;
|
|
|
+ block = encrypt_block(block, &principal, &key)?;
|
|
|
+ sign_block(&mut block, writecap, key.private)?;
|
|
|
assert_eq!(true, verify_block(&block)?);
|
|
|
Ok(())
|
|
|
}
|
|
@@ -823,12 +875,15 @@ 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)?;
|
|
|
- let node_key = Key::Rsa {
|
|
|
- public: Vec::from(NODE_PUBLIC_KEY), private: None, padding: RsaPadding::Pkcs1
|
|
|
+ sign_writecap(&mut root_writecap, &root_key.private)?;
|
|
|
+ let node_key = AsymKey::Rsa {
|
|
|
+ der: Vec::from(NODE_PUBLIC_KEY),
|
|
|
+ padding: RsaPadding::Pkcs1,
|
|
|
+ kind: Public {},
|
|
|
};
|
|
|
+ let node_principal = node_key.owner();
|
|
|
let writecap = make_writecap_trusted_by(
|
|
|
- root_writecap, &root_key, &node_key, vec!["apps", "contacts"])?;
|
|
|
+ root_writecap, root_key, node_principal, vec!["apps", "contacts"])?;
|
|
|
let result = verify_writecap(&writecap, &writecap.path);
|
|
|
assert_eq!(Err(WritecapAuthzErr::NotChained), result);
|
|
|
Ok(())
|
|
@@ -839,12 +894,15 @@ 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)?;
|
|
|
- let node_key = Key::Rsa {
|
|
|
- public: Vec::from(NODE_PUBLIC_KEY), private: None, padding: RsaPadding::Pkcs1
|
|
|
+ sign_writecap(&mut root_writecap, &root_key.private)?;
|
|
|
+ let node_key = AsymKey::Rsa {
|
|
|
+ der: Vec::from(NODE_PUBLIC_KEY),
|
|
|
+ padding: RsaPadding::Pkcs1,
|
|
|
+ kind: Public {}
|
|
|
};
|
|
|
+ let node_owner = node_key.owner();
|
|
|
let writecap = make_writecap_trusted_by(
|
|
|
- root_writecap, &root_key, &node_key, vec!["apps", "contacts"])?;
|
|
|
+ root_writecap, root_key, node_owner, vec!["apps", "contacts"])?;
|
|
|
let result = verify_writecap(&writecap, &writecap.path);
|
|
|
assert_eq!(Err(WritecapAuthzErr::RootDoesNotOwnPath), result);
|
|
|
Ok(())
|
|
@@ -898,13 +956,12 @@ mod tests {
|
|
|
#[test]
|
|
|
fn rsa_signature_len() -> Result<()> {
|
|
|
use openssl::rsa::Rsa;
|
|
|
- let key = Key::generate(KeyType::Rsa)?;
|
|
|
- let sign_algo = SignAlgo::try_from(&key)?;
|
|
|
- let private = match &key {
|
|
|
- Key::Rsa { private: Some(private), .. } => private,
|
|
|
- _ => return Err(Error::Message("Incorrect key returned.".to_string()))
|
|
|
+ let key = make_key_pair();
|
|
|
+ let sign_algo = SignAlgo::try_from(&key.private)?;
|
|
|
+ let der = match &key.private {
|
|
|
+ AsymKey::Rsa { der, .. } => der,
|
|
|
};
|
|
|
- let rsa = Rsa::private_key_from_der(private)?;
|
|
|
+ let rsa = Rsa::private_key_from_der(der)?;
|
|
|
let pkey = PKey::from_rsa(rsa)?;
|
|
|
let signer = Signer::new(sign_algo.digest, &pkey)?;
|
|
|
assert_eq!(RSA_SIG_LEN, signer.len()?);
|