|
@@ -6,6 +6,9 @@ pub mod x509;
|
|
pub use merkle_stream::MerkleStream;
|
|
pub use merkle_stream::MerkleStream;
|
|
pub mod secret_stream;
|
|
pub mod secret_stream;
|
|
pub use secret_stream::SecretStream;
|
|
pub use secret_stream::SecretStream;
|
|
|
|
+mod envelope;
|
|
|
|
+pub mod file_cred_store;
|
|
|
|
+pub use envelope::Envelope;
|
|
//mod sign_stream;
|
|
//mod sign_stream;
|
|
//pub use sign_stream::SignStream;
|
|
//pub use sign_stream::SignStream;
|
|
|
|
|
|
@@ -22,6 +25,7 @@ use openssl::{
|
|
error::ErrorStack,
|
|
error::ErrorStack,
|
|
hash::{hash, DigestBytes, Hasher, MessageDigest},
|
|
hash::{hash, DigestBytes, Hasher, MessageDigest},
|
|
nid::Nid,
|
|
nid::Nid,
|
|
|
|
+ pkcs5::pbkdf2_hmac,
|
|
pkey::{HasPrivate, HasPublic, PKey, PKeyRef},
|
|
pkey::{HasPrivate, HasPublic, PKey, PKeyRef},
|
|
rand::rand_bytes,
|
|
rand::rand_bytes,
|
|
rsa::{Padding as OpensslPadding, Rsa as OsslRsa},
|
|
rsa::{Padding as OpensslPadding, Rsa as OsslRsa},
|
|
@@ -30,7 +34,7 @@ use openssl::{
|
|
};
|
|
};
|
|
use serde::{
|
|
use serde::{
|
|
de::{self, DeserializeOwned, Deserializer, SeqAccess, Visitor},
|
|
de::{self, DeserializeOwned, Deserializer, SeqAccess, Visitor},
|
|
- ser::{SerializeStruct, Serializer},
|
|
|
|
|
|
+ ser::{Error as SerError, SerializeStruct, Serializer},
|
|
};
|
|
};
|
|
use std::{
|
|
use std::{
|
|
cell::RefCell,
|
|
cell::RefCell,
|
|
@@ -41,7 +45,7 @@ use std::{
|
|
sync::Arc,
|
|
sync::Arc,
|
|
};
|
|
};
|
|
use strum_macros::{Display, EnumDiscriminants, FromRepr};
|
|
use strum_macros::{Display, EnumDiscriminants, FromRepr};
|
|
-use zeroize::ZeroizeOnDrop;
|
|
|
|
|
|
+use zeroize::{ZeroizeOnDrop, Zeroizing};
|
|
|
|
|
|
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)]
|
|
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)]
|
|
pub struct Ciphertext<T> {
|
|
pub struct Ciphertext<T> {
|
|
@@ -843,13 +847,13 @@ impl AsMut<[u8]> for Signature {
|
|
}
|
|
}
|
|
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
#[derive(Serialize, Deserialize)]
|
|
-struct TaggedCiphertext<T, U> {
|
|
|
|
|
|
+pub struct TaggedCiphertext<T, U> {
|
|
aad: U,
|
|
aad: U,
|
|
ciphertext: Ciphertext<T>,
|
|
ciphertext: Ciphertext<T>,
|
|
tag: Vec<u8>,
|
|
tag: Vec<u8>,
|
|
}
|
|
}
|
|
|
|
|
|
-#[derive(EnumDiscriminants, ZeroizeOnDrop)]
|
|
|
|
|
|
+#[derive(EnumDiscriminants, ZeroizeOnDrop, Serialize, Deserialize, PartialEq, Eq)]
|
|
#[strum_discriminants(name(AeadKeyKind))]
|
|
#[strum_discriminants(name(AeadKeyKind))]
|
|
#[strum_discriminants(derive(Serialize, Deserialize))]
|
|
#[strum_discriminants(derive(Serialize, Deserialize))]
|
|
pub enum AeadKey {
|
|
pub enum AeadKey {
|
|
@@ -873,6 +877,56 @@ impl AeadKeyKind {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+#[derive(Serialize, Deserialize)]
|
|
|
|
+/// Parameters used to derive cryptographic keys from passwords.
|
|
|
|
+pub struct DerivationParams {
|
|
|
|
+ iter: usize,
|
|
|
|
+ hash: HashKind,
|
|
|
|
+ kind: AeadKeyKind,
|
|
|
|
+ salt: Vec<u8>,
|
|
|
|
+ iv: Vec<u8>,
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl DerivationParams {
|
|
|
|
+ const PBKDF2_ITER: usize = 1000000;
|
|
|
|
+ const PBKDF2_HASH: HashKind = HashKind::Sha2_256;
|
|
|
|
+ /// The [AeadKeyKind] of the key derived from this struct.
|
|
|
|
+ pub const EXPORT_KEY_KIND: AeadKeyKind = AeadKeyKind::AesGcm256;
|
|
|
|
+
|
|
|
|
+ /// Creates a new struct containing the default value of all parameters.
|
|
|
|
+ pub fn new() -> Result<DerivationParams> {
|
|
|
|
+ const_assert!(
|
|
|
|
+ DerivationParams::PBKDF2_HASH.len() == DerivationParams::EXPORT_KEY_KIND.key_len()
|
|
|
|
+ );
|
|
|
|
+ Ok(DerivationParams {
|
|
|
|
+ iter: Self::PBKDF2_ITER,
|
|
|
|
+ hash: Self::PBKDF2_HASH,
|
|
|
|
+ kind: Self::EXPORT_KEY_KIND,
|
|
|
|
+ salt: rand_vec(Self::PBKDF2_HASH.len())?,
|
|
|
|
+ iv: rand_vec(Self::EXPORT_KEY_KIND.iv_len())?,
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// Returns an HMAC of the given password based on the parameters in this struct.
|
|
|
|
+ pub fn hmac(&self, password: &str) -> Result<Zeroizing<[u8; Self::EXPORT_KEY_KIND.key_len()]>> {
|
|
|
|
+ let mut key = Zeroizing::new([0u8; Self::EXPORT_KEY_KIND.key_len()]);
|
|
|
|
+ pbkdf2_hmac(
|
|
|
|
+ password.as_bytes(),
|
|
|
|
+ self.salt.as_slice(),
|
|
|
|
+ self.iter,
|
|
|
|
+ self.hash.into(),
|
|
|
|
+ key.as_mut_slice(),
|
|
|
|
+ )?;
|
|
|
|
+ Ok(key)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// Derives an [AeadKey] from the given password using the parameters in this struct.
|
|
|
|
+ fn derive_key(&self, password: &str) -> Result<AeadKey> {
|
|
|
|
+ let key = self.hmac(password)?;
|
|
|
|
+ AeadKey::copy_components(self.kind, key.as_slice(), &self.iv)
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
fn array_from<const N: usize>(slice: &[u8]) -> Result<[u8; N]> {
|
|
fn array_from<const N: usize>(slice: &[u8]) -> Result<[u8; N]> {
|
|
let slice_len = slice.len();
|
|
let slice_len = slice.len();
|
|
btensure!(
|
|
btensure!(
|
|
@@ -1084,7 +1138,7 @@ impl TryFrom<u32> for BitLen {
|
|
/// A Cryptographic Scheme. This is a common type for operations such as encrypting, decrypting,
|
|
/// A Cryptographic Scheme. This is a common type for operations such as encrypting, decrypting,
|
|
/// signing and verifying.
|
|
/// signing and verifying.
|
|
pub trait Scheme:
|
|
pub trait Scheme:
|
|
- for<'de> Deserialize<'de> + Serialize + Copy + std::fmt::Debug + PartialEq + Into<Self::Kind>
|
|
|
|
|
|
+ DeserializeOwned + Serialize + Copy + std::fmt::Debug + PartialEq + Into<Self::Kind>
|
|
{
|
|
{
|
|
type Kind: Scheme;
|
|
type Kind: Scheme;
|
|
fn as_enum(self) -> SchemeKind;
|
|
fn as_enum(self) -> SchemeKind;
|
|
@@ -1423,46 +1477,61 @@ impl<S: Scheme> AsymKey<Private, S> {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-impl<'de, S: Scheme> Deserialize<'de> for AsymKey<Public, S> {
|
|
|
|
- fn deserialize<D: Deserializer<'de>>(d: D) -> std::result::Result<Self, D::Error> {
|
|
|
|
- const FIELDS: &[&str] = &["scheme", "pkey"];
|
|
|
|
|
|
+macro_rules! impl_asym_key_serialize {
|
|
|
|
+ ($privacy:ty, $ser_lambda:expr) => {
|
|
|
|
+ impl<S: Scheme> Serialize for AsymKey<$privacy, S> {
|
|
|
|
+ fn serialize<T: Serializer>(&self, s: T) -> std::result::Result<T::Ok, T::Error> {
|
|
|
|
+ let mut struct_s = s.serialize_struct(stringify!(AsymKey), 2)?;
|
|
|
|
+ struct_s.serialize_field("scheme", &self.scheme)?;
|
|
|
|
+ let der = $ser_lambda(&self.pkey).map_err(T::Error::custom)?;
|
|
|
|
+ struct_s.serialize_field("pkey", der.as_slice())?;
|
|
|
|
+ struct_s.end()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+}
|
|
|
|
|
|
- struct StructVisitor<S: Scheme>(PhantomData<S>);
|
|
|
|
|
|
+impl_asym_key_serialize!(Public, |pkey: &PKey<Public>| pkey.public_key_to_der());
|
|
|
|
+impl_asym_key_serialize!(Private, |pkey: &PKey<Private>| pkey.private_key_to_der());
|
|
|
|
|
|
- impl<'de, S: Scheme> Visitor<'de> for StructVisitor<S> {
|
|
|
|
- type Value = AsymKey<Public, S>;
|
|
|
|
|
|
+macro_rules! impl_asym_key_deserialize {
|
|
|
|
+ ($privacy:ty) => {
|
|
|
|
+ impl<'de, S: Scheme> Deserialize<'de> for AsymKey<$privacy, S> {
|
|
|
|
+ fn deserialize<D: Deserializer<'de>>(d: D) -> std::result::Result<Self, D::Error> {
|
|
|
|
+ const FIELDS: &[&str] = &["scheme", "pkey"];
|
|
|
|
|
|
- fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
- formatter.write_fmt(format_args!("struct {}", stringify!(AsymKey)))
|
|
|
|
- }
|
|
|
|
|
|
+ struct StructVisitor<S: Scheme>(PhantomData<S>);
|
|
|
|
|
|
- fn visit_seq<V: SeqAccess<'de>>(
|
|
|
|
- self,
|
|
|
|
- mut seq: V,
|
|
|
|
- ) -> std::result::Result<Self::Value, V::Error> {
|
|
|
|
- let scheme: S = 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]))?;
|
|
|
|
- AsymKey::<Public, _>::new(scheme, der.as_slice()).map_err(de::Error::custom)
|
|
|
|
|
|
+ impl<'de, S: Scheme> Visitor<'de> for StructVisitor<S> {
|
|
|
|
+ type Value = AsymKey<$privacy, S>;
|
|
|
|
+
|
|
|
|
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
+ formatter.write_fmt(format_args!("struct {}", stringify!(AsymKey)))
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn visit_seq<V: SeqAccess<'de>>(
|
|
|
|
+ self,
|
|
|
|
+ mut seq: V,
|
|
|
|
+ ) -> std::result::Result<Self::Value, V::Error> {
|
|
|
|
+ let scheme: S = 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]))?;
|
|
|
|
+ AsymKey::<$privacy, _>::new(scheme, der.as_slice())
|
|
|
|
+ .map_err(de::Error::custom)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ d.deserialize_struct(stringify!(AsymKey), FIELDS, StructVisitor(PhantomData))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
- d.deserialize_struct(stringify!(AsymKey), FIELDS, StructVisitor(PhantomData))
|
|
|
|
- }
|
|
|
|
|
|
+ };
|
|
}
|
|
}
|
|
|
|
|
|
-impl<S: Scheme> Serialize for AsymKey<Public, S> {
|
|
|
|
- fn serialize<T: Serializer>(&self, s: T) -> std::result::Result<T::Ok, T::Error> {
|
|
|
|
- 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_asym_key_deserialize!(Public);
|
|
|
|
+impl_asym_key_deserialize!(Private);
|
|
|
|
|
|
impl<S: Scheme> PartialEq for AsymKey<Public, S> {
|
|
impl<S: Scheme> PartialEq for AsymKey<Public, S> {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
@@ -1568,12 +1637,43 @@ impl Verifier for AsymKey<Public, Sign> {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-#[derive(Clone)]
|
|
|
|
|
|
+#[derive(Clone, Serialize)]
|
|
pub struct AsymKeyPair<S: Scheme> {
|
|
pub struct AsymKeyPair<S: Scheme> {
|
|
public: AsymKey<Public, S>,
|
|
public: AsymKey<Public, S>,
|
|
private: AsymKey<Private, S>,
|
|
private: AsymKey<Private, S>,
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+impl<'de, S: Scheme> Deserialize<'de> for AsymKeyPair<S> {
|
|
|
|
+ fn deserialize<D: Deserializer<'de>>(d: D) -> std::result::Result<Self, D::Error> {
|
|
|
|
+ const FIELDS: &[&str] = &["public", "private"];
|
|
|
|
+
|
|
|
|
+ struct StructVisitor<S: Scheme>(PhantomData<S>);
|
|
|
|
+
|
|
|
|
+ impl<'de, S: Scheme> Visitor<'de> for StructVisitor<S> {
|
|
|
|
+ type Value = AsymKeyPair<S>;
|
|
|
|
+
|
|
|
|
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
+ formatter.write_fmt(format_args!("struct {}", stringify!(AsymKeyPair)))
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn visit_seq<V: SeqAccess<'de>>(
|
|
|
|
+ self,
|
|
|
|
+ mut seq: V,
|
|
|
|
+ ) -> std::result::Result<Self::Value, V::Error> {
|
|
|
|
+ let public: AsymKey<Public, S> = seq
|
|
|
|
+ .next_element()?
|
|
|
|
+ .ok_or_else(|| de::Error::missing_field(FIELDS[0]))?;
|
|
|
|
+ let private: AsymKey<Private, S> = seq
|
|
|
|
+ .next_element()?
|
|
|
|
+ .ok_or_else(|| de::Error::missing_field(FIELDS[1]))?;
|
|
|
|
+ Ok(AsymKeyPair { public, private })
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ d.deserialize_struct(stringify!(AsymKey), FIELDS, StructVisitor(PhantomData))
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
impl<S: Scheme> AsymKeyPair<S> {
|
|
impl<S: Scheme> AsymKeyPair<S> {
|
|
pub fn new(scheme: S, public_der: &[u8], private_der: &[u8]) -> Result<AsymKeyPair<S>> {
|
|
pub fn new(scheme: S, public_der: &[u8], private_der: &[u8]) -> Result<AsymKeyPair<S>> {
|
|
let public = AsymKey::<Public, _>::new(scheme, public_der)?;
|
|
let public = AsymKey::<Public, _>::new(scheme, public_der)?;
|
|
@@ -1688,7 +1788,7 @@ impl PartialEq for ConcretePub {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-#[derive(Clone)]
|
|
|
|
|
|
+#[derive(Clone, Serialize, Deserialize)]
|
|
pub struct ConcreteCreds {
|
|
pub struct ConcreteCreds {
|
|
sign: AsymKeyPair<Sign>,
|
|
sign: AsymKeyPair<Sign>,
|
|
encrypt: AsymKeyPair<Encrypt>,
|
|
encrypt: AsymKeyPair<Encrypt>,
|
|
@@ -2225,8 +2325,10 @@ impl<C: CredsPriv + CredsPub + Clone> Creds for C {}
|
|
|
|
|
|
/// A trait for types which store credentials.
|
|
/// A trait for types which store credentials.
|
|
pub trait CredStore {
|
|
pub trait CredStore {
|
|
|
|
+ /// The type of the credential handle returned by this store.
|
|
type CredHandle: Creds;
|
|
type CredHandle: Creds;
|
|
- type ExportedCreds: Serialize + for<'de> Deserialize<'de>;
|
|
|
|
|
|
+ /// The type of the exported credentials returned by this store.
|
|
|
|
+ type ExportedCreds: Serialize + DeserializeOwned;
|
|
|
|
|
|
/// Returns the node credentials. If credentials haven't been generated, they are generated
|
|
/// Returns the node credentials. If credentials haven't been generated, they are generated
|
|
/// stored and returned.
|
|
/// stored and returned.
|
|
@@ -2237,18 +2339,29 @@ pub trait CredStore {
|
|
/// Generates the root credentials and protects them using the given password. If the root
|
|
/// Generates the root credentials and protects them using the given password. If the root
|
|
/// credentials have already been generated then an error is returned.
|
|
/// credentials have already been generated then an error is returned.
|
|
fn gen_root_creds(&self, password: &str) -> Result<Self::CredHandle>;
|
|
fn gen_root_creds(&self, password: &str) -> Result<Self::CredHandle>;
|
|
|
|
+ /// Returns a public key which can be used to encrypt data intended only to be accessed by this
|
|
|
|
+ /// node. The returned key can be given as the `new_parent` parameter to the [export_root_creds]
|
|
|
|
+ /// method.
|
|
fn storage_key(&self) -> Result<AsymKeyPub<Encrypt>>;
|
|
fn storage_key(&self) -> Result<AsymKeyPub<Encrypt>>;
|
|
|
|
+ /// Exports the root credentials. These can be serialized and persisted external to the
|
|
|
|
+ /// application and later loaded and deserialized and passed to the [import_root_creds] method.
|
|
|
|
+ /// The `password` argument must match the value provided when the [root_creds] method was
|
|
|
|
+ /// called. The `new_parent` argument is the public key of the node that is to import the root
|
|
|
|
+ /// key, which can be obtained using the [gen_root_creds] method on the importing node.
|
|
fn export_root_creds(
|
|
fn export_root_creds(
|
|
&self,
|
|
&self,
|
|
root_creds: &Self::CredHandle,
|
|
root_creds: &Self::CredHandle,
|
|
password: &str,
|
|
password: &str,
|
|
new_parent: &AsymKeyPub<Encrypt>,
|
|
new_parent: &AsymKeyPub<Encrypt>,
|
|
) -> Result<Self::ExportedCreds>;
|
|
) -> Result<Self::ExportedCreds>;
|
|
|
|
+ /// Imports root credentials that were previously created with [export_root_creds]. The provided
|
|
|
|
+ /// password must match the value that given to that method.
|
|
fn import_root_creds(
|
|
fn import_root_creds(
|
|
&self,
|
|
&self,
|
|
password: &str,
|
|
password: &str,
|
|
exported: Self::ExportedCreds,
|
|
exported: Self::ExportedCreds,
|
|
) -> Result<Self::CredHandle>;
|
|
) -> Result<Self::CredHandle>;
|
|
|
|
+ /// Assigns the given [Writecap] to the node credentials referred to by the given handle.
|
|
fn assign_node_writecap(&self, handle: &mut Self::CredHandle, writecap: Writecap)
|
|
fn assign_node_writecap(&self, handle: &mut Self::CredHandle, writecap: Writecap)
|
|
-> Result<()>;
|
|
-> Result<()>;
|
|
}
|
|
}
|