1
0
mirror of https://gitlab.com/veilid/veilid.git synced 2025-03-13 01:16:47 -04:00

289 lines
8.5 KiB
Rust
Raw Normal View History

2023-02-07 21:44:50 -05:00
mod byte_array_types;
2023-02-11 15:54:55 -05:00
mod dh_cache;
2022-10-30 19:29:31 -04:00
mod envelope;
mod receipt;
2023-02-07 21:44:50 -05:00
mod types;
2022-10-30 19:29:31 -04:00
mod value;
2023-01-29 13:13:50 -05:00
pub mod crypto_system;
2022-10-30 19:29:31 -04:00
pub mod tests;
2023-02-07 21:44:50 -05:00
pub mod vld0;
2022-10-30 19:29:31 -04:00
2023-02-07 21:44:50 -05:00
pub use byte_array_types::*;
2023-01-29 13:13:50 -05:00
pub use crypto_system::*;
2023-02-11 15:54:55 -05:00
pub use dh_cache::*;
2022-10-30 19:29:31 -04:00
pub use envelope::*;
pub use receipt::*;
2023-02-07 21:44:50 -05:00
pub use types::*;
2022-10-30 19:29:31 -04:00
pub use value::*;
2023-02-07 21:44:50 -05:00
pub use vld0::*;
2022-10-30 19:29:31 -04:00
2021-11-22 11:28:30 -05:00
use crate::*;
use core::convert::TryInto;
2022-03-20 10:52:03 -04:00
use hashlink::linked_hash_map::Entry;
use hashlink::LruCache;
2021-11-22 11:28:30 -05:00
use serde::{Deserialize, Serialize};
2022-11-29 19:22:33 -05:00
2023-02-11 15:54:55 -05:00
// Handle to a particular cryptosystem
2023-01-29 13:13:50 -05:00
pub type CryptoSystemVersion = Arc<dyn CryptoSystem + Send + Sync>;
2023-02-11 15:54:55 -05:00
/// Crypto kinds in order of preference, best cryptosystem is the first one, worst is the last one
pub const VALID_CRYPTO_KINDS: [CryptoKind; 1] = [CRYPTO_KIND_VLD0];
2023-02-13 21:12:27 -05:00
/// Number of cryptosystem signatures to keep on structures if many are present beyond the ones we consider valid
pub const MAX_CRYPTO_KINDS: usize = 3;
/// Return the best cryptosystem kind we support
2023-02-11 15:54:55 -05:00
pub fn best_crypto_kind() -> CryptoKind {
VALID_CRYPTO_KINDS[0]
2021-11-22 11:28:30 -05:00
}
2023-02-15 18:18:08 -05:00
// Version number of envelope format
2023-02-11 15:54:55 -05:00
pub type EnvelopeVersion = u8;
2023-02-15 18:18:08 -05:00
/// Envelope versions in order of preference, best envelope version is the first one, worst is the last one
2023-02-11 15:54:55 -05:00
pub const VALID_ENVELOPE_VERSIONS: [EnvelopeVersion; 1] = [0u8];
2023-02-15 18:18:08 -05:00
/// Number of envelope versions to keep on structures if many are present beyond the ones we consider valid
pub const MAX_ENVELOPE_VERSIONS: usize = 3;
/// Return the best envelope version we support
2023-02-11 15:54:55 -05:00
pub fn best_envelope_version() -> EnvelopeVersion {
VALID_ENVELOPE_VERSIONS[0]
2021-11-22 11:28:30 -05:00
}
struct CryptoInner {
dh_cache: DHCache,
2022-07-14 16:57:34 -04:00
flush_future: Option<SendPinBoxFuture<()>>,
2023-02-07 21:44:50 -05:00
crypto_vld0: Option<Arc<dyn CryptoSystem + Send + Sync>>,
}
struct CryptoUnlockedInner {
config: VeilidConfig,
table_store: TableStore,
protected_store: ProtectedStore,
2021-11-22 11:28:30 -05:00
}
2023-02-07 21:44:50 -05:00
/// Crypto factory implementation
2021-11-22 11:28:30 -05:00
#[derive(Clone)]
pub struct Crypto {
2023-02-07 21:44:50 -05:00
unlocked_inner: Arc<CryptoUnlockedInner>,
2021-11-22 11:28:30 -05:00
inner: Arc<Mutex<CryptoInner>>,
}
impl Crypto {
2023-02-07 21:44:50 -05:00
fn new_inner() -> CryptoInner {
2021-11-22 11:28:30 -05:00
CryptoInner {
2022-03-20 10:52:03 -04:00
dh_cache: DHCache::new(DH_CACHE_SIZE),
2021-11-22 11:28:30 -05:00
flush_future: None,
2023-02-07 21:44:50 -05:00
crypto_vld0: None,
2021-11-22 11:28:30 -05:00
}
}
2023-02-07 21:44:50 -05:00
pub fn new(
config: VeilidConfig,
table_store: TableStore,
protected_store: ProtectedStore,
) -> Self {
2023-01-29 13:13:50 -05:00
let out = Self {
2023-02-07 21:44:50 -05:00
unlocked_inner: Arc::new(CryptoUnlockedInner {
config,
table_store,
protected_store,
}),
inner: Arc::new(Mutex::new(Self::new_inner())),
2023-01-29 13:13:50 -05:00
};
2023-02-07 21:44:50 -05:00
out.inner.lock().crypto_vld0 = Some(Arc::new(vld0::CryptoSystemVLD0::new(out.clone())));
2023-01-29 13:13:50 -05:00
out
2021-11-22 11:28:30 -05:00
}
2023-02-13 21:12:27 -05:00
pub fn config(&self) -> VeilidConfig {
self.unlocked_inner.config.clone()
}
2022-07-10 17:36:50 -04:00
pub async fn init(&self) -> EyreResult<()> {
2021-11-22 11:28:30 -05:00
trace!("Crypto::init");
2023-02-07 21:44:50 -05:00
let table_store = self.unlocked_inner.table_store.clone();
// Init node id from config
if let Err(e) = self
.unlocked_inner
.config
.init_node_ids(self.clone(), self.unlocked_inner.protected_store.clone())
.await
{
return Err(e).wrap_err("init node id failed");
}
2021-11-22 11:28:30 -05:00
// make local copy of node id for easy access
2023-02-07 21:44:50 -05:00
let mut cache_validity_key: Vec<u8> = Vec::new();
{
let c = self.unlocked_inner.config.get();
for ck in &VALID_CRYPTO_KINDS {
cache_validity_key.append(
&mut c
.network
.routing_table
.node_ids
.get(ck)
.unwrap()
.node_id
.unwrap()
.bytes
.to_vec(),
);
}
2022-02-06 21:18:42 -05:00
};
2021-11-22 11:28:30 -05:00
// load caches if they are valid for this node id
2022-02-06 21:18:42 -05:00
let mut db = table_store.open("crypto_caches", 1).await?;
2023-02-07 21:44:50 -05:00
let caches_valid = match db.load(0, b"cache_validity_key")? {
Some(v) => v == cache_validity_key,
2021-11-22 11:28:30 -05:00
None => false,
};
if caches_valid {
2022-11-06 16:07:56 -05:00
if let Some(b) = db.load(0, b"dh_cache")? {
2022-02-06 21:18:42 -05:00
let mut inner = self.inner.lock();
2021-11-26 11:50:49 -05:00
bytes_to_cache(&b, &mut inner.dh_cache);
}
2021-11-22 11:28:30 -05:00
} else {
drop(db);
2022-02-06 21:18:42 -05:00
table_store.delete("crypto_caches").await?;
db = table_store.open("crypto_caches", 1).await?;
2023-02-07 21:44:50 -05:00
db.store(0, b"cache_validity_key", &cache_validity_key)
.await?;
2021-11-22 11:28:30 -05:00
}
// Schedule flushing
let this = self.clone();
2022-11-26 21:37:23 -05:00
let flush_future = interval(60000, move || {
2021-11-22 11:28:30 -05:00
let this = this.clone();
async move {
if let Err(e) = this.flush().await {
warn!("flush failed: {}", e);
}
}
2022-02-06 21:18:42 -05:00
});
self.inner.lock().flush_future = Some(flush_future);
2021-11-22 11:28:30 -05:00
Ok(())
}
2022-07-10 17:36:50 -04:00
pub async fn flush(&self) -> EyreResult<()> {
2021-11-22 11:28:30 -05:00
//trace!("Crypto::flush");
2023-02-07 21:44:50 -05:00
let cache_bytes = {
2021-11-22 11:28:30 -05:00
let inner = self.inner.lock();
2023-02-07 21:44:50 -05:00
cache_to_bytes(&inner.dh_cache)
2021-11-22 11:28:30 -05:00
};
2023-02-07 21:44:50 -05:00
let db = self
.unlocked_inner
.table_store
.open("crypto_caches", 1)
.await?;
2022-12-28 12:12:04 -05:00
db.store(0, b"dh_cache", &cache_bytes).await?;
2021-11-22 11:28:30 -05:00
Ok(())
}
pub async fn terminate(&self) {
trace!("Crypto::terminate");
let flush_future = self.inner.lock().flush_future.take();
if let Some(f) = flush_future {
f.await;
}
trace!("starting termination flush");
match self.flush().await {
Ok(_) => {
trace!("finished termination flush");
}
Err(e) => {
error!("failed termination flush: {}", e);
}
};
}
2023-02-07 21:44:50 -05:00
/// Factory method to get a specific crypto version
pub fn get(&self, kind: CryptoKind) -> Option<CryptoSystemVersion> {
2023-01-29 13:13:50 -05:00
let inner = self.inner.lock();
2023-02-07 21:44:50 -05:00
match kind {
CRYPTO_KIND_VLD0 => Some(inner.crypto_vld0.clone().unwrap()),
_ => None,
}
}
2023-02-11 15:54:55 -05:00
// Factory method to get the best crypto version
pub fn best(&self) -> CryptoSystemVersion {
self.get(best_crypto_kind()).unwrap()
}
2023-02-07 21:44:50 -05:00
/// Signature set verification
/// Returns the set of signature cryptokinds that validate and are supported
/// If any cryptokinds are supported and do not validate, the whole operation
/// returns an error
2023-02-08 16:50:07 -05:00
pub fn verify_signatures(
2023-02-07 21:44:50 -05:00
&self,
2023-02-08 16:50:07 -05:00
node_ids: &[TypedKey],
2023-02-07 21:44:50 -05:00
data: &[u8],
2023-02-08 16:50:07 -05:00
typed_signatures: &[TypedSignature],
2023-02-15 18:18:08 -05:00
) -> Result<Vec<CryptoKind>, VeilidAPIError> {
let mut out = Vec::with_capacity(node_ids.len());
2023-02-08 16:50:07 -05:00
for sig in typed_signatures {
for nid in node_ids {
if nid.kind == sig.kind {
if let Some(vcrypto) = self.get(sig.kind) {
2023-03-01 15:50:30 -05:00
vcrypto.verify(&nid.value, data, &sig.value)?;
2023-02-15 18:18:08 -05:00
out.push(nid.kind);
2023-02-08 16:50:07 -05:00
}
}
2023-02-07 21:44:50 -05:00
}
}
2023-02-15 18:18:08 -05:00
Ok(out)
2023-02-07 21:44:50 -05:00
}
/// Signature set generation
/// Generates the set of signatures that are supported
/// Any cryptokinds that are not supported are silently dropped
pub fn generate_signatures<F, R>(
&self,
data: &[u8],
2023-02-08 16:50:07 -05:00
typed_key_pairs: &[TypedKeyPair],
2023-02-07 21:44:50 -05:00
transform: F,
) -> Result<Vec<R>, VeilidAPIError>
where
F: Fn(&TypedKeyPair, Signature) -> R,
{
2023-02-08 16:50:07 -05:00
let mut out = Vec::<R>::with_capacity(typed_key_pairs.len());
for kp in typed_key_pairs {
2023-02-07 21:44:50 -05:00
if let Some(vcrypto) = self.get(kp.kind) {
2023-03-01 15:50:30 -05:00
let sig = vcrypto.sign(&kp.value.key, &kp.value.secret, data)?;
2023-02-07 21:44:50 -05:00
out.push(transform(kp, sig))
}
2023-01-29 13:13:50 -05:00
}
2023-02-07 21:44:50 -05:00
Ok(out)
2021-11-22 11:28:30 -05:00
}
2023-01-29 13:13:50 -05:00
// Internal utilities
fn cached_dh_internal<T: CryptoSystem>(
2022-07-10 17:36:50 -04:00
&self,
2023-01-29 13:13:50 -05:00
vcrypto: &T,
2023-02-07 21:44:50 -05:00
key: &PublicKey,
secret: &SecretKey,
2022-07-10 17:36:50 -04:00
) -> Result<SharedSecret, VeilidAPIError> {
2022-03-20 10:52:03 -04:00
Ok(
2023-02-23 21:07:46 -05:00
match self.inner.lock().dh_cache.entry(
DHCacheKey {
key: *key,
secret: *secret,
},
|_k, _v| {},
) {
2022-03-20 10:52:03 -04:00
Entry::Occupied(e) => e.get().shared_secret,
Entry::Vacant(e) => {
2023-01-29 13:13:50 -05:00
let shared_secret = vcrypto.compute_dh(key, secret)?;
2022-03-20 10:52:03 -04:00
e.insert(DHCacheValue { shared_secret });
shared_secret
}
},
)
2021-11-22 11:28:30 -05:00
}
}