mirror of
https://github.com/zerotier/identity.git
synced 2026-05-22 16:29:03 -07:00
added key domains
This commit is contained in:
+2
-1
@@ -9,4 +9,5 @@ version = "0.1.0"
|
||||
serde = { version = "^1", features = ["derive"], default-features = false }
|
||||
serde_cbor = { package = "serde_cbor_2", git = "https://github.com/kanidm/cbor", rev = "ab3296b35322aa5caa79a4ad9ce00a49c000864e" }
|
||||
zerotier-common-utils = { git = "https://github.com/zerotier/common-utils.git", branch = "main" }
|
||||
zerotier-crypto-glue = { git = "https://github.com/zerotier/crypto-glue.git", branch = "main" }
|
||||
zerotier-crypto-glue = { git = "https://github.com/zerotier/crypto-glue.git", branch = "xoshiro" }
|
||||
zeroize = { version = "1.6.0", features = ["zeroize_derive"], default-features = false }
|
||||
|
||||
+3
-1
@@ -43,13 +43,15 @@ pub fn decode_11to8(s: &[u8]) -> Result<u64, InvalidParameterError> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use zerotier_crypto_glue::random::{rand_core::RngCore, SecureRandom};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn base62_encode_decode() {
|
||||
let mut tmp = String::with_capacity(16);
|
||||
for _ in 0..10000 {
|
||||
let r = zerotier_crypto_glue::random::next_u64_secure();
|
||||
let r = SecureRandom.next_u64();
|
||||
tmp.clear();
|
||||
encode_8to11(r, &mut tmp);
|
||||
assert_eq!(decode_11to8(tmp.as_bytes()).unwrap(), r);
|
||||
|
||||
+44
-26
@@ -13,7 +13,7 @@ use std::str::FromStr;
|
||||
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
use zerotier_common_utils::arrayvec::ArrayVec;
|
||||
use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||
use zerotier_common_utils::base64;
|
||||
use zerotier_common_utils::blob::Blob;
|
||||
use zerotier_common_utils::error::InvalidParameterError;
|
||||
@@ -24,6 +24,8 @@ use zerotier_crypto_glue::p384::*;
|
||||
use crate::{base24, base62};
|
||||
use crate::{ADDRESS_ERR, IDENTITY_ERR};
|
||||
|
||||
const IDENTITY_DOMAIN: &[u8] = b"zerotier_p384_identity";
|
||||
|
||||
// Implementation note: the addresses use u64 arrays that are actually treated as flat byte
|
||||
// array memory arenas in order to optimize for fast lookup when these are used as map keys.
|
||||
// This reduces the number of instructions required to perform equality comparisons and
|
||||
@@ -396,15 +398,16 @@ pub struct Identity {
|
||||
|
||||
impl Identity {
|
||||
fn locally_validate(&self) -> bool {
|
||||
let mut sign_tmp = ArrayVec::<u8, 256>::new();
|
||||
sign_tmp.push_slice(self.address.as_bytes());
|
||||
sign_tmp.push_slice(&self.timestamp.to_be_bytes());
|
||||
sign_tmp.push_slice(self.ecdh.as_bytes());
|
||||
sign_tmp.push_slice(self.ecdsa.as_bytes());
|
||||
self.address.is_valid()
|
||||
&& self
|
||||
.master_signing_key
|
||||
.verify(sign_tmp.as_bytes(), &self.master_signature)
|
||||
&& self.master_signing_key.verify_all(
|
||||
IDENTITY_DOMAIN,
|
||||
&[
|
||||
&self.timestamp.to_be_bytes(),
|
||||
self.ecdh.as_bytes(),
|
||||
self.ecdsa.as_bytes(),
|
||||
],
|
||||
&self.master_signature,
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns true if this identity should replace the other.
|
||||
@@ -523,7 +526,11 @@ impl crate::Identity for Identity {
|
||||
|
||||
#[inline(always)]
|
||||
fn verify_signature(&self, data: &[u8], signature: &[u8]) -> bool {
|
||||
self.ecdsa.verify(data, signature)
|
||||
if let Ok(sig) = signature.try_into() {
|
||||
self.ecdsa.verify_raw(data, sig)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -553,16 +560,22 @@ impl Clone for IdentitySecret {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Serialize, Deserialize, Zeroize, ZeroizeOnDrop)]
|
||||
struct IdentitySecretSerialized {
|
||||
#[zeroize(skip)]
|
||||
a: Address,
|
||||
#[zeroize(skip)]
|
||||
pm: Blob<P384_PUBLIC_KEY_SIZE>,
|
||||
sm: Option<Blob<P384_SECRET_KEY_SIZE>>,
|
||||
#[zeroize(skip)]
|
||||
ts: u64,
|
||||
#[zeroize(skip)]
|
||||
p0: Blob<P384_PUBLIC_KEY_SIZE>,
|
||||
s0: Blob<P384_SECRET_KEY_SIZE>,
|
||||
#[zeroize(skip)]
|
||||
p1: Blob<P384_PUBLIC_KEY_SIZE>,
|
||||
s1: Blob<P384_SECRET_KEY_SIZE>,
|
||||
#[zeroize(skip)]
|
||||
ms: Blob<P384_ECDSA_SIGNATURE_SIZE>,
|
||||
}
|
||||
|
||||
@@ -571,21 +584,24 @@ impl Serialize for IdentitySecret {
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
IdentitySecretSerialized {
|
||||
let mut tmp = IdentitySecretSerialized {
|
||||
a: self.public.address,
|
||||
pm: (*self.public.master_signing_key.as_bytes()).into(),
|
||||
sm: self
|
||||
.master_signing_key
|
||||
.as_ref()
|
||||
.map(|sk| (*sk.secret_key_bytes().as_bytes()).into()),
|
||||
sm: None,
|
||||
ts: self.public.timestamp,
|
||||
p0: (*self.public.ecdh.as_bytes()).into(),
|
||||
s0: (*self.ecdh.secret_key_bytes().as_bytes()).into(),
|
||||
s0: Blob::default(),
|
||||
p1: (*self.public.ecdsa.as_bytes()).into(),
|
||||
s1: (*self.ecdsa.secret_key_bytes().as_bytes()).into(),
|
||||
s1: Blob::default(),
|
||||
ms: self.public.master_signature.into(),
|
||||
};
|
||||
self.ecdh.secret_key_bytes(&mut tmp.s0);
|
||||
self.ecdsa.secret_key_bytes(&mut tmp.s1);
|
||||
if let Some(ecdsa) = self.master_signing_key.as_ref() {
|
||||
tmp.sm = Some(Blob::default());
|
||||
ecdsa.secret_key_bytes(tmp.sm.as_mut().unwrap());
|
||||
}
|
||||
.serialize(serializer)
|
||||
tmp.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -651,11 +667,6 @@ impl crate::IdentitySecret for IdentitySecret {
|
||||
let ecdh = P384KeyPair::generate();
|
||||
let ecdsa = P384KeyPair::generate();
|
||||
|
||||
let mut sign_tmp = ArrayVec::<u8, 256>::new();
|
||||
sign_tmp.push_slice(address.as_bytes());
|
||||
sign_tmp.push_slice(×tamp.to_be_bytes());
|
||||
sign_tmp.push_slice(ecdh.public_key_bytes());
|
||||
sign_tmp.push_slice(ecdsa.public_key_bytes());
|
||||
Self {
|
||||
public: Identity {
|
||||
address,
|
||||
@@ -663,7 +674,14 @@ impl crate::IdentitySecret for IdentitySecret {
|
||||
timestamp,
|
||||
ecdh: ecdh.to_public_key(),
|
||||
ecdsa: ecdsa.to_public_key(),
|
||||
master_signature: master_signing_key.sign(sign_tmp.as_bytes()),
|
||||
master_signature: master_signing_key.sign_all(
|
||||
IDENTITY_DOMAIN,
|
||||
&[
|
||||
×tamp.to_be_bytes(),
|
||||
ecdh.public_key_bytes(),
|
||||
ecdsa.public_key_bytes(),
|
||||
],
|
||||
),
|
||||
},
|
||||
master_signing_key: Some(master_signing_key),
|
||||
ecdh,
|
||||
@@ -678,7 +696,7 @@ impl crate::IdentitySecret for IdentitySecret {
|
||||
|
||||
#[inline(always)]
|
||||
fn sign(&self, data: &[u8]) -> Self::Signature {
|
||||
self.ecdsa.sign(data)
|
||||
self.ecdsa.sign_raw(data)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+27
-12
@@ -14,6 +14,7 @@ use std::str::FromStr;
|
||||
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||
use zerotier_common_utils::blob::Blob;
|
||||
use zerotier_common_utils::error::InvalidParameterError;
|
||||
use zerotier_common_utils::hex;
|
||||
@@ -305,8 +306,11 @@ impl ToString for IdentitySecret {
|
||||
tmp.push_str(hex::to_string(&self.public.ecdh).as_str());
|
||||
tmp.push_str(hex::to_string(&self.public.eddsa).as_str());
|
||||
tmp.push(':');
|
||||
tmp.push_str(hex::to_string(self.ecdh.secret_bytes().as_bytes()).as_str());
|
||||
tmp.push_str(hex::to_string(self.eddsa.secret_bytes().as_bytes()).as_str());
|
||||
let mut buf = [0u8; ED25519_SECRET_KEY_SIZE];
|
||||
self.ecdh.secret_bytes(&mut buf);
|
||||
tmp.push_str(hex::to_string(&buf).as_str());
|
||||
self.eddsa.secret_bytes(&mut buf);
|
||||
tmp.push_str(hex::to_string(&buf).as_str());
|
||||
tmp
|
||||
}
|
||||
}
|
||||
@@ -324,10 +328,16 @@ impl FromStr for IdentitySecret {
|
||||
if secret_bytes.len() != C25519_SECRET_KEY_SIZE + ED25519_SECRET_KEY_SIZE {
|
||||
return Err(IDENTITY_ERR);
|
||||
}
|
||||
let ecdh = X25519KeyPair::from_bytes(&public.ecdh, &secret_bytes.as_slice()[..C25519_SECRET_KEY_SIZE])
|
||||
.ok_or(IDENTITY_ERR)?;
|
||||
let eddsa = Ed25519KeyPair::from_bytes(&public.eddsa, &secret_bytes.as_slice()[C25519_SECRET_KEY_SIZE..])
|
||||
.ok_or(IDENTITY_ERR)?;
|
||||
let ecdh = X25519KeyPair::from_bytes(
|
||||
&public.ecdh,
|
||||
&secret_bytes.as_slice()[..C25519_SECRET_KEY_SIZE].try_into().unwrap(),
|
||||
)
|
||||
.ok_or(IDENTITY_ERR)?;
|
||||
let eddsa = Ed25519KeyPair::from_bytes(
|
||||
&public.eddsa,
|
||||
&secret_bytes.as_slice()[C25519_SECRET_KEY_SIZE..].try_into().unwrap(),
|
||||
)
|
||||
.ok_or(IDENTITY_ERR)?;
|
||||
return Ok(Self { public, ecdh, eddsa });
|
||||
}
|
||||
}
|
||||
@@ -385,11 +395,14 @@ impl crate::IdentitySecret for IdentitySecret {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Serialize, Deserialize, Zeroize, ZeroizeOnDrop)]
|
||||
struct IdentitySecretSerialized {
|
||||
#[zeroize(skip)]
|
||||
a: Address,
|
||||
#[zeroize(skip)]
|
||||
p0: Blob<C25519_PUBLIC_KEY_SIZE>,
|
||||
s0: Blob<C25519_SECRET_KEY_SIZE>,
|
||||
#[zeroize(skip)]
|
||||
p1: Blob<ED25519_PUBLIC_KEY_SIZE>,
|
||||
s1: Blob<ED25519_SECRET_KEY_SIZE>,
|
||||
}
|
||||
@@ -399,14 +412,16 @@ impl Serialize for IdentitySecret {
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
IdentitySecretSerialized {
|
||||
let mut tmp = IdentitySecretSerialized {
|
||||
a: self.public.address,
|
||||
p0: self.public.ecdh.into(),
|
||||
s0: (*self.ecdh.secret_bytes().as_bytes()).into(),
|
||||
s0: Blob::default(),
|
||||
p1: self.public.eddsa.into(),
|
||||
s1: (*self.eddsa.secret_bytes().as_bytes()).into(),
|
||||
}
|
||||
.serialize(serializer)
|
||||
s1: Blob::default(),
|
||||
};
|
||||
self.ecdh.secret_bytes(&mut tmp.s0);
|
||||
self.eddsa.secret_bytes(&mut tmp.s1);
|
||||
tmp.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user