fix tests

This commit is contained in:
John Smith 2023-03-03 10:55:31 -05:00
parent dfd1af0c6b
commit ff9b421631
21 changed files with 292 additions and 246 deletions

10
.vscode/launch.json vendored
View File

@ -42,16 +42,6 @@
],
"terminal": "console"
},
// {
// "type": "lldb",
// "request": "launch",
// "name": "Debug veilid-server",
// "cargo": {
// "args": ["run", "--manifest-path", "veilid-server/Cargo.toml"]
// },
// "args": ["--trace"],
// "cwd": "${workspaceFolder}/veilid-server"
// }
{
"type": "lldb",
"request": "launch",

View File

@ -195,45 +195,55 @@ impl ClientApiConnection {
let rpc_jh = spawn_local(rpc_system);
// Send the request and get the state object and the registration object
let response = request
.send()
.promise
.await
.map_err(|e| format!("failed to send register request: {}", e))?;
let response = response
.get()
.map_err(|e| format!("failed to get register response: {}", e))?;
let reg_res: Result<registration::Client, String> = (async {
// Send the request and get the state object and the registration object
let response = request
.send()
.promise
.await
.map_err(|e| format!("failed to send register request: {}", e))?;
let response = response
.get()
.map_err(|e| format!("failed to get register response: {}", e))?;
// Get the registration object, which drops our connection when it is dropped
let _registration = response
.get_registration()
.map_err(|e| format!("failed to get registration object: {}", e))?;
// Get the registration object, which drops our connection when it is dropped
let registration = response
.get_registration()
.map_err(|e| format!("failed to get registration object: {}", e))?;
// Get the initial veilid state
let veilid_state = response
.get_state()
.map_err(|e| format!("failed to get initial veilid state: {}", e))?;
// Get the initial veilid state
let veilid_state = response
.get_state()
.map_err(|e| format!("failed to get initial veilid state: {}", e))?;
// Set up our state for the first time
let veilid_state: VeilidState = deserialize_json(veilid_state)
.map_err(|e| format!("failed to get deserialize veilid state: {}", e))?;
self.process_veilid_state(veilid_state).await?;
// Set up our state for the first time
let veilid_state: VeilidState = deserialize_json(veilid_state)
.map_err(|e| format!("failed to get deserialize veilid state: {}", e))?;
self.process_veilid_state(veilid_state).await?;
// Save server settings
let server_settings = response
.get_settings()
.map_err(|e| format!("failed to get initial veilid server settings: {}", e))?
.to_owned();
self.inner.borrow_mut().server_settings = Some(server_settings.clone());
// Save server settings
let server_settings = response
.get_settings()
.map_err(|e| format!("failed to get initial veilid server settings: {}", e))?
.to_owned();
self.inner.borrow_mut().server_settings = Some(server_settings.clone());
// Don't drop the registration, doing so will remove the client
// object mapping from the server which we need for the update backchannel
// Don't drop the registration, doing so will remove the client
// object mapping from the server which we need for the update backchannel
Ok(registration)
})
.await;
let _registration = match reg_res {
Ok(v) => v,
Err(e) => {
rpc_jh.abort().await;
return Err(e);
}
};
// Wait until rpc system completion or disconnect was requested
let res = rpc_jh.await;
// #[cfg(feature = "rt-tokio")]
// let res = res.map_err(|e| format!("join error: {}", e))?;
res.map_err(|e| format!("client RPC system error: {}", e))
}

View File

@ -882,16 +882,10 @@ impl UI {
pub fn set_config(&mut self, config: VeilidConfigInner) {
let mut inner = self.inner.borrow_mut();
let tkv: Vec<TypedKey> = config
.network
.routing_table
.node_ids
.iter()
.filter_map(|(k, v)| v.node_id.map(|nid| TypedKey::new(*k, nid)))
.collect();
let tks = TypedKeySet::from(tkv);
inner.ui_state.node_id.set(tks.to_string());
inner
.ui_state
.node_id
.set(config.network.routing_table.node_id.to_string());
}
pub fn set_connection_state(&mut self, state: ConnectionState) {
let mut inner = self.inner.borrow_mut();

View File

@ -20,7 +20,7 @@ pub trait CryptoSystem {
key: &PublicKey,
secret: &SecretKey,
) -> Result<SharedSecret, VeilidAPIError>;
fn generate_keypair(&self) -> (PublicKey, SecretKey);
fn generate_keypair(&self) -> KeyPair;
fn generate_hash(&self, data: &[u8]) -> PublicKey;
fn generate_hash_reader(
&self,

View File

@ -117,16 +117,15 @@ impl Crypto {
let mut cache_validity_key: Vec<u8> = Vec::new();
{
let c = self.unlocked_inner.config.get();
for ck in &VALID_CRYPTO_KINDS {
for ck in VALID_CRYPTO_KINDS {
cache_validity_key.append(
&mut c
.network
.routing_table
.node_ids
.node_id
.get(ck)
.unwrap()
.node_id
.unwrap()
.value
.bytes
.to_vec(),
);
@ -223,14 +222,14 @@ impl Crypto {
node_ids: &[TypedKey],
data: &[u8],
typed_signatures: &[TypedSignature],
) -> Result<Vec<CryptoKind>, VeilidAPIError> {
let mut out = Vec::with_capacity(node_ids.len());
) -> Result<TypedKeySet, VeilidAPIError> {
let mut out = TypedKeySet::with_capacity(node_ids.len());
for sig in typed_signatures {
for nid in node_ids {
if nid.kind == sig.kind {
if let Some(vcrypto) = self.get(sig.kind) {
vcrypto.verify(&nid.value, data, &sig.value)?;
out.push(nid.kind);
out.add(*nid);
}
}
}
@ -260,6 +259,16 @@ impl Crypto {
Ok(out)
}
/// Generate keypair
/// Does not require startup/init
pub fn generate_keypair(crypto_kind: CryptoKind) -> Result<TypedKeyPair, VeilidAPIError> {
if crypto_kind == CRYPTO_KIND_VLD0 {
let kp = vld0_generate_keypair();
return Ok(TypedKeyPair::new(crypto_kind, kp));
}
Err(VeilidAPIError::generic("invalid crypto kind"))
}
// Internal utilities
fn cached_dh_internal<T: CryptoSystem>(

View File

@ -138,8 +138,8 @@ pub async fn test_no_auth(vcrypto: CryptoSystemVersion) {
pub async fn test_dh(vcrypto: CryptoSystemVersion) {
trace!("test_dh");
let (dht_key, dht_key_secret) = vcrypto.generate_keypair();
let (dht_key2, dht_key_secret2) = vcrypto.generate_keypair();
let (dht_key, dht_key_secret) = vcrypto.generate_keypair().into_split();
let (dht_key2, dht_key_secret2) = vcrypto.generate_keypair().into_split();
let r1 = vcrypto.compute_dh(&dht_key, &dht_key_secret2).unwrap();
let r2 = vcrypto.compute_dh(&dht_key2, &dht_key_secret).unwrap();

View File

@ -9,8 +9,8 @@ pub async fn test_envelope_round_trip(
// Create envelope
let ts = Timestamp::from(0x12345678ABCDEF69u64);
let nonce = vcrypto.random_nonce();
let (sender_id, sender_secret) = vcrypto.generate_keypair();
let (recipient_id, recipient_secret) = vcrypto.generate_keypair();
let (sender_id, sender_secret) = vcrypto.generate_keypair().into_split();
let (recipient_id, recipient_secret) = vcrypto.generate_keypair().into_split();
let envelope = Envelope::new(
envelope_version,
vcrypto.kind(),
@ -66,7 +66,7 @@ pub async fn test_receipt_round_trip(
// Create receipt
let nonce = vcrypto.random_nonce();
let (sender_id, sender_secret) = vcrypto.generate_keypair();
let (sender_id, sender_secret) = vcrypto.generate_keypair().into_split();
let receipt = Receipt::try_new(envelope_version, vcrypto.kind(), nonce, sender_id, body)
.expect("should not fail");

View File

@ -10,8 +10,8 @@ static EMPTY_KEY_SECRET: [u8; SECRET_KEY_LENGTH] = [0u8; SECRET_KEY_LENGTH];
pub async fn test_generate_secret(vcrypto: CryptoSystemVersion) {
// Verify keys generate
let (dht_key, dht_key_secret) = vcrypto.generate_keypair();
let (dht_key2, dht_key_secret2) = vcrypto.generate_keypair();
let (dht_key, dht_key_secret) = vcrypto.generate_keypair().into_split();
let (dht_key2, dht_key_secret2) = vcrypto.generate_keypair().into_split();
// Verify byte patterns are different between public and secret
assert_ne!(dht_key.bytes, dht_key_secret.bytes);
@ -24,8 +24,8 @@ pub async fn test_generate_secret(vcrypto: CryptoSystemVersion) {
pub async fn test_sign_and_verify(vcrypto: CryptoSystemVersion) {
// Make two keys
let (dht_key, dht_key_secret) = vcrypto.generate_keypair();
let (dht_key2, dht_key_secret2) = vcrypto.generate_keypair();
let (dht_key, dht_key_secret) = vcrypto.generate_keypair().into_split();
let (dht_key2, dht_key_secret2) = vcrypto.generate_keypair().into_split();
// Sign the same message twice
let dht_sig = vcrypto
.sign(&dht_key, &dht_key_secret, LOREM_IPSUM.as_bytes())
@ -133,10 +133,10 @@ pub async fn test_key_conversions(vcrypto: CryptoSystemVersion) {
assert_eq!(dht_key_secret_string, dht_key_string);
// Make different keys
let (dht_key2, dht_key_secret2) = vcrypto.generate_keypair();
let (dht_key2, dht_key_secret2) = vcrypto.generate_keypair().into_split();
trace!("dht_key2: {:?}", dht_key2);
trace!("dht_key_secret2: {:?}", dht_key_secret2);
let (dht_key3, _dht_key_secret3) = vcrypto.generate_keypair();
let (dht_key3, _dht_key_secret3) = vcrypto.generate_keypair().into_split();
trace!("dht_key3: {:?}", dht_key3);
trace!("_dht_key_secret3: {:?}", _dht_key_secret3);
@ -196,7 +196,7 @@ pub async fn test_encode_decode(vcrypto: CryptoSystemVersion) {
assert_eq!(dht_key, dht_key_b);
assert_eq!(dht_key_secret, dht_key_secret_b);
let (dht_key2, dht_key_secret2) = vcrypto.generate_keypair();
let (dht_key2, dht_key_secret2) = vcrypto.generate_keypair().into_split();
let e1 = dht_key.encode();
trace!("e1: {:?}", e1);

View File

@ -24,6 +24,12 @@ impl KeyPair {
pub fn new(key: PublicKey, secret: SecretKey) -> Self {
Self { key, secret }
}
pub fn split(&self) -> (PublicKey, SecretKey) {
(self.key, self.secret)
}
pub fn into_split(self) -> (PublicKey, SecretKey) {
(self.key, self.secret)
}
}
impl Encodable for KeyPair {

View File

@ -32,13 +32,13 @@ fn ed25519_to_x25519_sk(key: &ed::SecretKey) -> Result<xd::StaticSecret, VeilidA
Ok(xd::StaticSecret::from(lowbytes))
}
pub fn vld0_generate_keypair() -> (PublicKey, SecretKey) {
pub fn vld0_generate_keypair() -> KeyPair {
let mut csprng = VeilidRng {};
let keypair = ed::Keypair::generate(&mut csprng);
let dht_key = PublicKey::new(keypair.public.to_bytes());
let dht_key_secret = SecretKey::new(keypair.secret.to_bytes());
(dht_key, dht_key_secret)
KeyPair::new(dht_key, dht_key_secret)
}
/// V0 CryptoSystem
@ -95,7 +95,7 @@ impl CryptoSystem for CryptoSystemVLD0 {
let sk_xd = ed25519_to_x25519_sk(&sk_ed)?;
Ok(SharedSecret::new(sk_xd.diffie_hellman(&pk_xd).to_bytes()))
}
fn generate_keypair(&self) -> (PublicKey, SecretKey) {
fn generate_keypair(&self) -> KeyPair {
vld0_generate_keypair()
}
fn generate_hash(&self, data: &[u8]) -> PublicKey {

View File

@ -527,7 +527,7 @@ impl NetworkManager {
let nonce = vcrypto.random_nonce();
let node_id = routing_table.node_id(vcrypto.kind());
let node_id_secret = routing_table.node_id_secret(vcrypto.kind());
let node_id_secret = routing_table.node_id_secret_key(vcrypto.kind());
let receipt = Receipt::try_new(best_envelope_version(), node_id.kind, nonce, node_id.value, extra_data)?;
let out = receipt
@ -556,7 +556,7 @@ impl NetworkManager {
let nonce = vcrypto.random_nonce();
let node_id = routing_table.node_id(vcrypto.kind());
let node_id_secret = routing_table.node_id_secret(vcrypto.kind());
let node_id_secret = routing_table.node_id_secret_key(vcrypto.kind());
let receipt = Receipt::try_new(best_envelope_version(), node_id.kind, nonce, node_id.value, extra_data)?;
let out = receipt
@ -754,7 +754,7 @@ impl NetworkManager {
};
let node_id = routing_table.node_id(vcrypto.kind());
let node_id_secret = routing_table.node_id_secret(vcrypto.kind());
let node_id_secret = routing_table.node_id_secret_key(vcrypto.kind());
// Get timestamp, nonce
let ts = get_aligned_timestamp();
@ -1427,7 +1427,7 @@ impl NetworkManager {
}
// DH to get decryption key (cached)
let node_id_secret = routing_table.node_id_secret(envelope.get_crypto_kind());
let node_id_secret = routing_table.node_id_secret_key(envelope.get_crypto_kind());
// Decrypt the envelope body
let body = match envelope

View File

@ -72,8 +72,10 @@ pub struct RoutingTableUnlockedInner {
config: VeilidConfig,
network_manager: NetworkManager,
/// The current node's public DHT keys and secrets
node_id_keypairs: BTreeMap<CryptoKind, KeyPair>,
/// The current node's public DHT keys
node_id: TypedKeySet,
/// The current node's public DHT secrets
node_id_secret: TypedSecretSet,
/// Buckets to kick on our next kick task
kick_queue: Mutex<BTreeSet<BucketIndex>>,
/// Background process for computing statistics
@ -113,33 +115,32 @@ impl RoutingTableUnlockedInner {
}
pub fn node_id(&self, kind: CryptoKind) -> TypedKey {
TypedKey::new(kind, self.node_id_keypairs.get(&kind).unwrap().key)
self.node_id.get(kind).unwrap()
}
pub fn node_id_secret_key(&self, kind: CryptoKind) -> SecretKey {
self.node_id_secret.get(kind).unwrap().value
}
pub fn node_ids(&self) -> TypedKeySet {
let mut tks = TypedKeySet::new();
for x in &self.node_id_keypairs {
tks.add(TypedKey::new(*x.0, x.1.key));
}
tks
self.node_id.clone()
}
pub fn node_id_typed_key_pairs(&self) -> Vec<TypedKeyPair> {
let mut tkps = Vec::new();
for (ck, v) in &self.node_id_keypairs {
tkps.push(TypedKeyPair::new(*ck, *v));
for ck in VALID_CRYPTO_KINDS {
tkps.push(TypedKeyPair::new(
ck,
KeyPair::new(self.node_id(ck).value, self.node_id_secret_key(ck)),
));
}
tkps
}
pub fn node_id_secret(&self, kind: CryptoKind) -> SecretKey {
self.node_id_keypairs.get(&kind).unwrap().secret
}
pub fn matches_own_node_id(&self, node_ids: &[TypedKey]) -> bool {
for ni in node_ids {
if let Some(v) = self.node_id_keypairs.get(&ni.kind) {
if v.key == ni.value {
if let Some(v) = self.node_id.get(ni.kind) {
if v.value == ni.value {
return true;
}
}
@ -148,8 +149,8 @@ impl RoutingTableUnlockedInner {
}
pub fn matches_own_node_id_key(&self, node_id_key: &PublicKey) -> bool {
for (_ck, v) in &self.node_id_keypairs {
if v.key == *node_id_key {
for tk in self.node_id.iter() {
if tk.value == *node_id_key {
return true;
}
}
@ -158,12 +159,12 @@ impl RoutingTableUnlockedInner {
pub fn calculate_bucket_index(&self, node_id: &TypedKey) -> BucketIndex {
let crypto = self.crypto();
let self_node_id = self.node_id_keypairs.get(&node_id.kind).unwrap().key;
let self_node_id_key = self.node_id(node_id.kind).value;
let vcrypto = crypto.get(node_id.kind).unwrap();
(
node_id.kind,
vcrypto
.distance(&node_id.value, &self_node_id)
.distance(&node_id.value, &self_node_id_key)
.first_nonzero_bit()
.unwrap(),
)
@ -182,22 +183,12 @@ impl RoutingTable {
network_manager: NetworkManager,
) -> RoutingTableUnlockedInner {
let c = config.get();
RoutingTableUnlockedInner {
config: config.clone(),
network_manager,
node_id_keypairs: c
.network
.routing_table
.node_ids
.iter()
.map(|(k, v)| {
(
*k,
KeyPair::new(v.node_id.unwrap(), v.node_id_secret.unwrap()),
)
})
.collect(),
node_id: c.network.routing_table.node_id.clone(),
node_id_secret: c.network.routing_table.node_id_secret.clone(),
kick_queue: Mutex::new(BTreeSet::default()),
rolling_transfers_task: TickTask::new(ROLLING_TRANSFERS_INTERVAL_SECS),
kick_buckets_task: TickTask::new(1),

View File

@ -490,12 +490,12 @@ impl RouteSpecStore {
let mut route_set = BTreeMap::<PublicKey, RouteSpecDetail>::new();
for crypto_kind in crypto_kinds.iter().copied() {
let vcrypto = self.unlocked_inner.routing_table.crypto().get(crypto_kind).unwrap();
let (public_key, secret_key) = vcrypto.generate_keypair();
let keypair = vcrypto.generate_keypair();
let hops: Vec<PublicKey> = route_nodes.iter().map(|v| nodes[*v].node_ids().get(crypto_kind).unwrap().value).collect();
route_set.insert(public_key, RouteSpecDetail {
route_set.insert(keypair.key, RouteSpecDetail {
crypto_kind,
secret_key,
secret_key: keypair.secret,
hops,
});
}
@ -888,7 +888,7 @@ impl RouteSpecStore {
//println!("compile_safety_route profile (stub): {} us", (get_timestamp() - profile_start_ts));
return Ok(Some(CompiledRoute {
safety_route: SafetyRoute::new_stub(routing_table.node_id(crypto_kind), private_route),
secret: routing_table.node_id_secret(crypto_kind),
secret: routing_table.node_id_secret_key(crypto_kind),
first_hop,
}));
}

View File

@ -109,7 +109,7 @@ impl RPCProcessor {
) -> Result<NetworkResult<()>, RPCError> {
// Now that things are valid, decrypt the routed operation with DEC(nonce, DH(the SR's public key, the PR's (or node's) secret)
// xxx: punish nodes that send messages that fail to decrypt eventually? How to do this for safety routes?
let node_id_secret = self.routing_table.node_id_secret(remote_sr_pubkey.kind);
let node_id_secret = self.routing_table.node_id_secret_key(remote_sr_pubkey.kind);
let dh_secret = vcrypto
.cached_dh(&remote_sr_pubkey.value, &node_id_secret)
.map_err(RPCError::protocol)?;
@ -313,7 +313,7 @@ impl RPCProcessor {
};
// Decrypt the blob with DEC(nonce, DH(the PR's public key, this hop's secret)
let node_id_secret = self.routing_table.node_id_secret(crypto_kind);
let node_id_secret = self.routing_table.node_id_secret_key(crypto_kind);
let dh_secret = vcrypto
.cached_dh(&pr_pubkey.value, &node_id_secret)
.map_err(RPCError::protocol)?;
@ -345,7 +345,7 @@ impl RPCProcessor {
// as the last hop is already signed by the envelope
if route_hop.next_hop.is_some() {
let node_id = self.routing_table.node_id(crypto_kind);
let node_id_secret = self.routing_table.node_id_secret(crypto_kind);
let node_id_secret = self.routing_table.node_id_secret_key(crypto_kind);
let sig = vcrypto
.sign(&node_id.value, &node_id_secret, &route_operation.data)
.map_err(RPCError::internal)?;
@ -392,7 +392,7 @@ impl RPCProcessor {
// There is a safety route hop
SafetyRouteHops::Data(ref route_hop_data) => {
// Decrypt the blob with DEC(nonce, DH(the SR's public key, this hop's secret)
let node_id_secret = self.routing_table.node_id_secret(crypto_kind);
let node_id_secret = self.routing_table.node_id_secret_key(crypto_kind);
let dh_secret = vcrypto
.cached_dh(&route.safety_route.public_key.value, &node_id_secret)
.map_err(RPCError::protocol)?;

View File

@ -128,19 +128,19 @@ pub async fn test_frozen(vcrypto: CryptoSystemVersion, ts: TableStore) {
let _ = ts.delete("test");
let db = ts.open("test", 3).await.expect("should have opened");
let (dht_key, _) = vcrypto.generate_keypair();
let keypair = vcrypto.generate_keypair();
assert!(db.store_rkyv(0, b"asdf", &dht_key).await.is_ok());
assert!(db.store_rkyv(0, b"asdf", &keypair).await.is_ok());
assert_eq!(db.load_rkyv::<PublicKey>(0, b"qwer").unwrap(), None);
assert_eq!(db.load_rkyv::<KeyPair>(0, b"qwer").unwrap(), None);
let d = match db.load_rkyv::<PublicKey>(0, b"asdf") {
let d = match db.load_rkyv::<KeyPair>(0, b"asdf") {
Ok(x) => x,
Err(e) => {
panic!("couldn't decode: {}", e);
}
};
assert_eq!(d, Some(dht_key), "keys should be equal");
assert_eq!(d, Some(keypair), "keys should be equal");
assert!(
db.store(1, b"foo", b"1234567890").await.is_ok(),

View File

@ -320,7 +320,8 @@ pub async fn test_config() {
assert_eq!(inner.network.rpc.timeout_ms, 10_000u32);
assert_eq!(inner.network.rpc.max_route_hop_count, 4u8);
assert_eq!(inner.network.rpc.default_route_hop_count, 1u8);
assert_eq!(inner.network.routing_table.node_ids.len(), 0);
assert_eq!(inner.network.routing_table.node_id.len(), 0);
assert_eq!(inner.network.routing_table.node_id_secret.len(), 0);
assert_eq!(inner.network.routing_table.bootstrap, Vec::<String>::new());
assert_eq!(inner.network.routing_table.limit_over_attached, 64u32);
assert_eq!(inner.network.routing_table.limit_fully_attached, 32u32);

View File

@ -67,15 +67,15 @@ pub async fn test_signed_node_info() {
}],
};
let (pkey, skey) = vcrypto.generate_keypair();
// Test correct validation
let keypair = vcrypto.generate_keypair();
let sni = SignedDirectNodeInfo::make_signatures(
crypto.clone(),
vec![TypedKeyPair::new(ck, KeyPair::new(pkey, skey))],
vec![TypedKeyPair::new(ck, keypair)],
node_info.clone(),
)
.unwrap();
let mut tks: TypedKeySet = TypedKey::new(ck, pkey).into();
let mut tks: TypedKeySet = TypedKey::new(ck, keypair.key).into();
let oldtkslen = tks.len();
let _ = SignedDirectNodeInfo::new(
crypto.clone(),
@ -88,6 +88,38 @@ pub async fn test_signed_node_info() {
assert_eq!(tks.len(), oldtkslen);
assert_eq!(tks.len(), sni.signatures.len());
// Test incorrect validation
let keypair1 = vcrypto.generate_keypair();
let mut tks1: TypedKeySet = TypedKey::new(ck, keypair1.key).into();
let oldtks1len = tks1.len();
let _ = SignedDirectNodeInfo::new(
crypto.clone(),
&mut tks1,
node_info.clone(),
sni.timestamp,
sni.signatures.clone(),
)
.unwrap_err();
assert_eq!(tks1.len(), oldtks1len);
assert_eq!(tks1.len(), sni.signatures.len());
// Test unsupported cryptosystem validation
let fake_crypto_kind: CryptoKind = FourCC::from([0, 1, 2, 3]);
let mut tksfake: TypedKeySet = TypedKey::new(fake_crypto_kind, PublicKey::default()).into();
let mut sigsfake = sni.signatures.clone();
sigsfake.push(TypedSignature::new(fake_crypto_kind, Signature::default()));
tksfake.add(TypedKey::new(ck, keypair.key));
let sdnifake = SignedDirectNodeInfo::new(
crypto.clone(),
&mut tksfake,
node_info.clone(),
sni.timestamp,
sigsfake.clone(),
)
.unwrap();
assert_eq!(tksfake.len(), 1);
assert_eq!(sdnifake.signatures.len(), sigsfake.len());
// Test relayed
let node_info2 = NodeInfo {
network_class: NetworkClass::OutboundOnly,
@ -101,13 +133,14 @@ pub async fn test_signed_node_info() {
}],
};
let (pkey2, skey2) = vcrypto.generate_keypair();
let mut tks2: TypedKeySet = TypedKey::new(ck, pkey2).into();
// Test correct validation
let keypair2 = vcrypto.generate_keypair();
let mut tks2: TypedKeySet = TypedKey::new(ck, keypair2.key).into();
let oldtks2len = tks2.len();
let sni2 = SignedRelayedNodeInfo::make_signatures(
crypto.clone(),
vec![TypedKeyPair::new(ck, KeyPair::new(pkey2, skey2))],
vec![TypedKeyPair::new(ck, keypair2)],
node_info2.clone(),
tks.clone(),
sni.clone(),
@ -116,9 +149,9 @@ pub async fn test_signed_node_info() {
let _ = SignedRelayedNodeInfo::new(
crypto.clone(),
&mut tks2,
node_info2,
tks,
sni,
node_info2.clone(),
tks.clone(),
sni.clone(),
sni2.timestamp,
sni2.signatures.clone(),
)
@ -126,6 +159,45 @@ pub async fn test_signed_node_info() {
assert_eq!(tks2.len(), oldtks2len);
assert_eq!(tks2.len(), sni2.signatures.len());
// Test incorrect validation
let keypair3 = vcrypto.generate_keypair();
let mut tks3: TypedKeySet = TypedKey::new(ck, keypair3.key).into();
let oldtks3len = tks3.len();
let _ = SignedRelayedNodeInfo::new(
crypto.clone(),
&mut tks3,
node_info2.clone(),
tks.clone(),
sni.clone(),
sni2.timestamp,
sni2.signatures.clone(),
)
.unwrap_err();
assert_eq!(tks3.len(), oldtks3len);
assert_eq!(tks3.len(), sni2.signatures.len());
// Test unsupported cryptosystem validation
let fake_crypto_kind: CryptoKind = FourCC::from([0, 1, 2, 3]);
let mut tksfake3: TypedKeySet =
TypedKey::new(fake_crypto_kind, PublicKey::default()).into();
let mut sigsfake3 = sni2.signatures.clone();
sigsfake3.push(TypedSignature::new(fake_crypto_kind, Signature::default()));
tksfake3.add(TypedKey::new(ck, keypair2.key));
let srnifake = SignedRelayedNodeInfo::new(
crypto.clone(),
&mut tksfake3,
node_info2.clone(),
tks.clone(),
sni.clone(),
sni2.timestamp,
sigsfake3.clone(),
)
.unwrap();
assert_eq!(tksfake3.len(), 1);
assert_eq!(srnifake.signatures.len(), sigsfake3.len());
}
api.shutdown().await;

View File

@ -1869,7 +1869,8 @@ pub struct SignedDirectNodeInfo {
pub signatures: Vec<TypedSignature>,
}
impl SignedDirectNodeInfo {
/// Returns a new SignedDirectNodeInfo that has its signatures validated. Will modify the node_ids set to only include node_ids whose signatures validate
/// Returns a new SignedDirectNodeInfo that has its signatures validated.
/// On success, this will modify the node_ids set to only include node_ids whose signatures validate.
/// All signatures are stored however, as this can be passed to other nodes that may be able to validate those signatures.
pub fn new(
crypto: Crypto,
@ -1881,9 +1882,9 @@ impl SignedDirectNodeInfo {
let node_info_bytes = Self::make_signature_bytes(&node_info, timestamp)?;
// Verify the signatures that we can
let valid_crypto_kinds =
let validated_node_ids =
crypto.verify_signatures(node_ids, &node_info_bytes, &typed_signatures)?;
xx wrong! should remove only the kinds that are not valid! also fix relayed node_ids.remove_all(&valid_crypto_kinds);
*node_ids = validated_node_ids;
if node_ids.len() == 0 {
apibail_generic!("no valid node ids in direct node info");
}
@ -1956,7 +1957,8 @@ pub struct SignedRelayedNodeInfo {
}
impl SignedRelayedNodeInfo {
/// Returns a new SignedRelayedNodeInfo that has its signatures validated. Will modify the node_ids set to only include node_ids whose signatures validate
/// Returns a new SignedRelayedNodeInfo that has its signatures validated.
/// On success, this will modify the node_ids set to only include node_ids whose signatures validate.
/// All signatures are stored however, as this can be passed to other nodes that may be able to validate those signatures.
pub fn new(
crypto: Crypto,
@ -1969,10 +1971,9 @@ impl SignedRelayedNodeInfo {
) -> Result<Self, VeilidAPIError> {
let node_info_bytes =
Self::make_signature_bytes(&node_info, &relay_ids, &relay_info, timestamp)?;
let valid_crypto_kinds =
let validated_node_ids =
crypto.verify_signatures(node_ids, &node_info_bytes, &typed_signatures)?;
node_ids.remove_all(&valid_crypto_kinds);
*node_ids = validated_node_ids;
if node_ids.len() == 0 {
apibail_generic!("no valid node ids in relayed node info");
}

View File

@ -316,25 +316,6 @@ pub struct VeilidConfigRPC {
pub default_route_hop_count: u8,
}
/// Configure the per-crypto version configuration
///
#[derive(
Default,
Debug,
Clone,
PartialEq,
Eq,
Serialize,
Deserialize,
RkyvArchive,
RkyvSerialize,
RkyvDeserialize,
)]
pub struct VeilidConfigNodeId {
pub node_id: Option<PublicKey>,
pub node_id_secret: Option<SecretKey>,
}
/// Configure the network routing table
///
#[derive(
@ -350,7 +331,8 @@ pub struct VeilidConfigNodeId {
RkyvDeserialize,
)]
pub struct VeilidConfigRoutingTable {
pub node_ids: BTreeMap<CryptoKind, VeilidConfigNodeId>,
pub node_id: TypedKeySet,
pub node_id_secret: TypedSecretSet,
pub bootstrap: Vec<String>,
pub limit_over_attached: u32,
pub limit_fully_attached: u32,
@ -621,58 +603,15 @@ impl VeilidConfig {
let keyname = &stringify!($key)[6..];
let v = cb(keyname.to_owned())?;
$key = match v.downcast() {
Ok(v) => *v,
Err(e) => {
apibail_generic!(format!("incorrect type for key {}: {:?}", keyname, type_name_of_val(&*e)))
}
};
};
}
// More complicated optional fields for node ids
macro_rules! get_config_node_ids {
() => {
let keys = cb("network.routing_table.node_id".to_owned())?;
let keys: TypedKeySet = match keys.downcast() {
Ok(v) => *v,
Err(e) => {
apibail_generic!(format!(
"incorrect type for key 'network.routing_table.node_id': {:?}",
"incorrect type for key {}: {:?}",
keyname,
type_name_of_val(&*e)
))
}
};
let secrets = cb("network.routing_table.node_id_secret".to_owned())?;
let secrets: TypedSecretSet = match secrets.downcast() {
Ok(v) => *v,
Err(e) => {
apibail_generic!(format!(
"incorrect type for key 'network.routing_table.node_id_secret': {:?}",
type_name_of_val(&*e)
))
}
};
for ck in VALID_CRYPTO_KINDS {
if let Some(key) = keys.get(ck) {
inner
.network
.routing_table
.node_ids
.entry(ck)
.or_default()
.node_id = Some(key.value);
}
if let Some(secret) = secrets.get(ck) {
inner
.network
.routing_table
.node_ids
.entry(ck)
.or_default()
.node_id_secret = Some(secret.value);
}
}
};
}
@ -701,7 +640,9 @@ impl VeilidConfig {
get_config!(inner.network.max_connection_frequency_per_min);
get_config!(inner.network.client_whitelist_timeout_ms);
get_config!(inner.network.reverse_connection_receipt_time_ms);
get_config_node_ids!();
get_config!(inner.network.hole_punch_receipt_time_ms);
get_config!(inner.network.routing_table.node_id);
get_config!(inner.network.routing_table.node_id_secret);
get_config!(inner.network.routing_table.bootstrap);
get_config!(inner.network.routing_table.limit_over_attached);
get_config!(inner.network.routing_table.limit_fully_attached);
@ -778,11 +719,20 @@ impl VeilidConfig {
self.inner.read()
}
fn safe_config(&self) -> VeilidConfigInner {
let mut safe_cfg = self.inner.read().clone();
// Remove secrets
safe_cfg.network.routing_table.node_id_secret = TypedSecretSet::new();
safe_cfg
}
pub fn with_mut<F, R>(&self, f: F) -> Result<R, VeilidAPIError>
where
F: FnOnce(&mut VeilidConfigInner) -> Result<R, VeilidAPIError>,
{
let (out, config) = {
let out = {
let inner = &mut *self.inner.write();
// Edit a copy
let mut editedinner = inner.clone();
@ -792,12 +742,13 @@ impl VeilidConfig {
Self::validate(&mut editedinner)?;
// Commit changes
*inner = editedinner.clone();
(out, editedinner)
out
};
// Send configuration update to clients
if let Some(update_cb) = &self.update_cb {
update_cb(VeilidUpdate::Config(VeilidStateConfig { config }));
let safe_cfg = self.safe_config();
update_cb(VeilidUpdate::Config(VeilidStateConfig { config: safe_cfg }));
}
Ok(out)
@ -975,29 +926,23 @@ impl VeilidConfig {
crypto: Crypto,
protected_store: intf::ProtectedStore,
) -> Result<(), VeilidAPIError> {
let mut out_node_id = TypedKeySet::new();
let mut out_node_id_secret = TypedSecretSet::new();
for ck in VALID_CRYPTO_KINDS {
let vcrypto = crypto
.get(ck)
.expect("Valid crypto kind is not actually valid.");
let mut node_id = self
.inner
.read()
.network
.routing_table
.node_ids
.get(&ck)
.map(|n| n.node_id)
.flatten();
let mut node_id = self.inner.read().network.routing_table.node_id.get(ck);
let mut node_id_secret = self
.inner
.read()
.network
.routing_table
.node_ids
.get(&ck)
.map(|n| n.node_id_secret)
.flatten();
.node_id_secret
.get(ck);
// See if node id was previously stored in the protected store
if node_id.is_none() {
debug!("pulling node_id_{} from storage", ck);
@ -1007,8 +952,13 @@ impl VeilidConfig {
.map_err(VeilidAPIError::internal)?
{
debug!("node_id_{} found in storage", ck);
node_id =
Some(PublicKey::try_decode(s.as_str()).map_err(VeilidAPIError::internal)?);
node_id = match TypedKey::from_str(s.as_str()) {
Ok(v) => Some(v),
Err(_) => {
debug!("node id in protected store is not valid");
None
}
}
} else {
debug!("node_id_{} not found in storage", ck);
}
@ -1023,8 +973,13 @@ impl VeilidConfig {
.map_err(VeilidAPIError::internal)?
{
debug!("node_id_secret_{} found in storage", ck);
node_id_secret =
Some(SecretKey::try_decode(s.as_str()).map_err(VeilidAPIError::internal)?);
node_id_secret = match TypedSecret::from_str(s.as_str()) {
Ok(v) => Some(v),
Err(_) => {
debug!("node id secret in protected store is not valid");
None
}
}
} else {
debug!("node_id_secret_{} not found in storage", ck);
}
@ -1034,7 +989,7 @@ impl VeilidConfig {
let (node_id, node_id_secret) =
if let (Some(node_id), Some(node_id_secret)) = (node_id, node_id_secret) {
// Validate node id
if !vcrypto.validate_keypair(&node_id, &node_id_secret) {
if !vcrypto.validate_keypair(&node_id.value, &node_id_secret.value) {
apibail_generic!(format!(
"node_id_secret_{} and node_id_key_{} don't match",
ck, ck
@ -1044,30 +999,36 @@ impl VeilidConfig {
} else {
// If we still don't have a valid node id, generate one
debug!("generating new node_id_{}", ck);
vcrypto.generate_keypair()
let kp = vcrypto.generate_keypair();
(TypedKey::new(ck, kp.key), TypedSecret::new(ck, kp.secret))
};
info!("Node Id ({}) is {}", ck, node_id.encode());
info!("Node Id: {}", node_id);
// Save the node id / secret in storage
protected_store
.save_user_secret_string(format!("node_id_{}", ck), node_id.encode().as_str())
.save_user_secret_string(format!("node_id_{}", ck), node_id.to_string())
.await
.map_err(VeilidAPIError::internal)?;
protected_store
.save_user_secret_string(
format!("node_id_secret_{}", ck),
node_id_secret.encode().as_str(),
node_id_secret.to_string(),
)
.await
.map_err(VeilidAPIError::internal)?;
self.with_mut(|c| {
let n = c.network.routing_table.node_ids.entry(ck).or_default();
n.node_id = Some(node_id);
n.node_id_secret = Some(node_id_secret);
Ok(())
})?;
// Save for config
out_node_id.add(node_id);
out_node_id_secret.add(node_id_secret);
}
// Commit back to config
self.with_mut(|c| {
c.network.routing_table.node_id = out_node_id;
c.network.routing_table.node_id_secret = out_node_id_secret;
Ok(())
})?;
trace!("init_node_ids complete");
Ok(())

View File

@ -18,9 +18,9 @@ use cfg_if::*;
#[allow(unused_imports)]
use color_eyre::eyre::{bail, ensure, eyre, Result as EyreResult, WrapErr};
use server::*;
use std::str::FromStr;
use tools::*;
use tracing::*;
use veilid_core::Encodable as _;
use veilid_logs::*;
#[allow(clippy::all)]
@ -44,9 +44,15 @@ fn main() -> EyreResult<()> {
// --- Generate DHT Key ---
if matches.occurrences_of("generate-key-pair") != 0 {
let (key, secret) = veilid_core::vld0_generate_keypair();
println!("Public: {}\nSecret: {}", key.encode(), secret.encode());
return Ok(());
if let Some(ckstr) = matches.get_one::<String>("generate-key-pair") {
let ck: veilid_core::CryptoKind =
veilid_core::FourCC::from_str(ckstr).wrap_err("couldn't parse crypto kind")?;
let tkp = veilid_core::Crypto::generate_keypair(ck).wrap_err("invalid crypto kind")?;
println!("{}", tkp.to_string());
return Ok(());
} else {
bail!("missing crypto kind");
}
}
// See if we're just running a quick command

View File

@ -37,9 +37,14 @@ fn init_callbacks() {
case "capabilities.protocol_connect_wss": return true;
case "capabilities.protocol_accept_wss": return false;
case "tablestore.directory": return "";
case "network.node_id": return "ZLd4uMYdP4qYLtxF6GqrzBb32Z6T3rE2FWMkWup1pdY";
case "network.node_id_secret": return "s2Gvq6HJOxgQh-3xIgfWSL3I-DWZ2c1RjZLJl2Xmg2E";
case "network.bootstrap": return [];
case "network.routing_table.node_id": return [];
case "network.routing_table.node_id_secret": return [];
case "network.routing_table.bootstrap": return [];
case "network.routing_table.limit_over_attached": return 64;
case "network.routing_table.limit_fully_attached": return 32;
case "network.routing_table.limit_attached_strong": return 16;
case "network.routing_table.limit_attached_good": return 8;
case "network.routing_table.limit_attached_weak": return 4;
case "network.rpc.concurrency": return 2;
case "network.rpc.queue_size": return 128;
case "network.rpc.max_timestamp_behind": return 10000000;