test work
This commit is contained in:
		
							
								
								
									
										
											BIN
										
									
								
								veilid-core/0qrl21wlR1IjCA13sIOjw7Byk8ruCfPcnVBRxMLHCrk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								veilid-core/0qrl21wlR1IjCA13sIOjw7Byk8ruCfPcnVBRxMLHCrk
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								veilid-core/BrpdAUI1bcti0_vJinSu42N9w-vNQRfWBGaR8DLGnAY
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								veilid-core/BrpdAUI1bcti0_vJinSu42N9w-vNQRfWBGaR8DLGnAY
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								veilid-core/bazGk6a59NnYJyQ-s5bQu3GogeYnRpkHJss5vba1khA
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								veilid-core/bazGk6a59NnYJyQ-s5bQu3GogeYnRpkHJss5vba1khA
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -5,11 +5,7 @@ fn fake_routing_table() -> routing_table::RoutingTable { | ||||
|     let block_store = BlockStore::new(veilid_config.clone()); | ||||
|     let protected_store = ProtectedStore::new(veilid_config.clone()); | ||||
|     let table_store = TableStore::new(veilid_config.clone(), protected_store.clone()); | ||||
|     let crypto = Crypto::new( | ||||
|         veilid_config.clone(), | ||||
|         table_store.clone(), | ||||
|         protected_store.clone(), | ||||
|     ); | ||||
|     let crypto = Crypto::new(veilid_config.clone(), table_store.clone()); | ||||
|     let storage_manager = storage_manager::StorageManager::new( | ||||
|         veilid_config.clone(), | ||||
|         crypto.clone(), | ||||
|   | ||||
| @@ -5,6 +5,8 @@ mod table_store; | ||||
| pub use table_db::*; | ||||
| pub use table_store::*; | ||||
|  | ||||
| pub mod tests; | ||||
|  | ||||
| #[cfg(target_arch = "wasm32")] | ||||
| mod wasm; | ||||
| #[cfg(target_arch = "wasm32")] | ||||
|   | ||||
| @@ -163,15 +163,11 @@ impl TableStore { | ||||
|         self.flush().await; | ||||
|     } | ||||
|  | ||||
|     async fn load_device_encryption_key(&self) -> EyreResult<Option<TypedSharedSecret>> { | ||||
|         let dek_bytes: Option<Vec<u8>> = self | ||||
|             .protected_store | ||||
|             .load_user_secret("device_encryption_key") | ||||
|             .await?; | ||||
|         let Some(dek_bytes) = dek_bytes else { | ||||
|             return Ok(None); | ||||
|         }; | ||||
|  | ||||
|     pub fn maybe_unprotect_device_encryption_key( | ||||
|         &self, | ||||
|         dek_bytes: &[u8], | ||||
|         device_encryption_key_password: &str, | ||||
|     ) -> EyreResult<TypedSharedSecret> { | ||||
|         // Ensure the key is at least as long as necessary if unencrypted | ||||
|         if dek_bytes.len() < (4 + SHARED_SECRET_LENGTH) { | ||||
|             bail!("device encryption key is not valid"); | ||||
| @@ -184,11 +180,6 @@ impl TableStore { | ||||
|             bail!("unsupported cryptosystem"); | ||||
|         }; | ||||
|  | ||||
|         // Decrypt encryption key if we have it | ||||
|         let device_encryption_key_password = { | ||||
|             let c = self.config.get(); | ||||
|             c.protected_store.device_encryption_key_password.clone() | ||||
|         }; | ||||
|         if !device_encryption_key_password.is_empty() { | ||||
|             if dek_bytes.len() | ||||
|                 != (4 + SHARED_SECRET_LENGTH + vcrypto.aead_overhead() + NONCE_LENGTH) | ||||
| @@ -209,28 +200,126 @@ impl TableStore { | ||||
|                     None, | ||||
|                 ) | ||||
|                 .wrap_err("failed to decrypt device encryption key")?; | ||||
|             return Ok(Some(TypedSharedSecret::new( | ||||
|             return Ok(TypedSharedSecret::new( | ||||
|                 kind, | ||||
|                 SharedSecret::try_from(unprotected_key.as_slice()) | ||||
|                     .wrap_err("invalid shared secret")?, | ||||
|             ))); | ||||
|             )); | ||||
|         } | ||||
|  | ||||
|         Ok(Some(TypedSharedSecret::new( | ||||
|         Ok(TypedSharedSecret::new( | ||||
|             kind, | ||||
|             SharedSecret::try_from(&dek_bytes[4..])?, | ||||
|         ))) | ||||
|         )) | ||||
|     } | ||||
|  | ||||
|     pub fn maybe_protect_device_encryption_key( | ||||
|         &self, | ||||
|         dek: TypedSharedSecret, | ||||
|         device_encryption_key_password: &str, | ||||
|     ) -> EyreResult<Vec<u8>> { | ||||
|         // Check if we are to protect the key | ||||
|         if device_encryption_key_password.is_empty() { | ||||
|             // Return the unprotected key bytes | ||||
|             let mut out = Vec::with_capacity(4 + SHARED_SECRET_LENGTH); | ||||
|             out.extend_from_slice(&dek.kind.0); | ||||
|             out.extend_from_slice(&dek.value.bytes); | ||||
|             return Ok(out); | ||||
|         } | ||||
|  | ||||
|         // Get cryptosystem | ||||
|         let crypto = self.inner.lock().crypto.as_ref().unwrap().clone(); | ||||
|         let Some(vcrypto) = crypto.get(dek.kind) else { | ||||
|             bail!("unsupported cryptosystem"); | ||||
|         }; | ||||
|  | ||||
|         let nonce = vcrypto.random_nonce(); | ||||
|         let shared_secret = vcrypto | ||||
|             .derive_shared_secret(device_encryption_key_password.as_bytes(), &nonce.bytes) | ||||
|             .wrap_err("failed to derive shared secret")?; | ||||
|         let mut protected_key = vcrypto | ||||
|             .encrypt_aead( | ||||
|                 &dek.value.bytes, | ||||
|                 &Nonce::try_from(nonce).wrap_err("invalid nonce")?, | ||||
|                 &shared_secret, | ||||
|                 None, | ||||
|             ) | ||||
|             .wrap_err("failed to decrypt device encryption key")?; | ||||
|         let mut out = | ||||
|             Vec::with_capacity(4 + SHARED_SECRET_LENGTH + vcrypto.aead_overhead() + NONCE_LENGTH); | ||||
|         out.extend_from_slice(&dek.kind.0); | ||||
|         out.append(&mut protected_key); | ||||
|         out.extend_from_slice(&nonce.bytes); | ||||
|         assert!(out.len() == 4 + SHARED_SECRET_LENGTH + vcrypto.aead_overhead() + NONCE_LENGTH); | ||||
|         Ok(out) | ||||
|     } | ||||
|  | ||||
|     async fn load_device_encryption_key(&self) -> EyreResult<Option<TypedSharedSecret>> { | ||||
|         let dek_bytes: Option<Vec<u8>> = self | ||||
|             .protected_store | ||||
|             .load_user_secret("device_encryption_key") | ||||
|             .await?; | ||||
|         let Some(dek_bytes) = dek_bytes else { | ||||
|             return Ok(None); | ||||
|         }; | ||||
|  | ||||
|         // Get device encryption key protection password if we have it | ||||
|         let device_encryption_key_password = { | ||||
|             let c = self.config.get(); | ||||
|             c.protected_store.device_encryption_key_password.clone() | ||||
|         }; | ||||
|  | ||||
|         Ok(Some(self.maybe_unprotect_device_encryption_key( | ||||
|             &dek_bytes, | ||||
|             &device_encryption_key_password, | ||||
|         )?)) | ||||
|     } | ||||
|     async fn save_device_encryption_key( | ||||
|         &self, | ||||
|         device_encryption_key: Option<TypedSharedSecret>, | ||||
|     ) -> EyreResult<()> { | ||||
|         // Save the new device encryption key | ||||
|         self.protected_store | ||||
|             .save_user_secret_json("device_encryption_key", &device_encryption_key) | ||||
|             .await?; | ||||
|         let Some(device_encryption_key) = device_encryption_key else { | ||||
|             // Remove the device encryption key | ||||
|             let existed = self | ||||
|                 .protected_store | ||||
|                 .remove_user_secret("device_encryption_key") | ||||
|                 .await?; | ||||
|             trace!("removed device encryption key. existed: {}", existed); | ||||
|             return Ok(()); | ||||
|         }; | ||||
|  | ||||
| xxxx | ||||
|         // Get new device encryption key protection password if we are changing it | ||||
|         let new_device_encryption_key_password = { | ||||
|             let c = self.config.get(); | ||||
|             c.protected_store.new_device_encryption_key_password.clone() | ||||
|         }; | ||||
|         let device_encryption_key_password = | ||||
|             if let Some(new_device_encryption_key_password) = new_device_encryption_key_password { | ||||
|                 // Change password | ||||
|                 self.config | ||||
|                     .with_mut(|c| { | ||||
|                         c.protected_store.device_encryption_key_password = | ||||
|                             new_device_encryption_key_password.clone(); | ||||
|                         Ok(new_device_encryption_key_password) | ||||
|                     }) | ||||
|                     .unwrap() | ||||
|             } else { | ||||
|                 // Get device encryption key protection password if we have it | ||||
|                 let c = self.config.get(); | ||||
|                 c.protected_store.device_encryption_key_password.clone() | ||||
|             }; | ||||
|  | ||||
|         let dek_bytes = self.maybe_protect_device_encryption_key( | ||||
|             device_encryption_key, | ||||
|             &device_encryption_key_password, | ||||
|         )?; | ||||
|  | ||||
|         // Save the new device encryption key | ||||
|         let existed = self | ||||
|             .protected_store | ||||
|             .save_user_secret("device_encryption_key", &dek_bytes) | ||||
|             .await?; | ||||
|         trace!("saving device encryption key. existed: {}", existed); | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|   | ||||
							
								
								
									
										1
									
								
								veilid-core/src/table_store/tests/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								veilid-core/src/table_store/tests/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| pub mod test_table_store; | ||||
| @@ -1,4 +1,4 @@ | ||||
| use super::test_veilid_config::*; | ||||
| use crate::tests::test_veilid_config::*; | ||||
| use crate::*; | ||||
| 
 | ||||
| async fn startup() -> VeilidAPI { | ||||
| @@ -208,6 +208,56 @@ pub async fn test_json(vcrypto: CryptoSystemVersion, ts: TableStore) { | ||||
|     ); | ||||
| } | ||||
| 
 | ||||
| pub async fn test_protect_unprotect(vcrypto: CryptoSystemVersion, ts: TableStore) { | ||||
|     trace!("test_protect_unprotect"); | ||||
| 
 | ||||
|     let dek1 = TypedSharedSecret::new( | ||||
|         vcrypto.kind(), | ||||
|         SharedSecret::new([ | ||||
|             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||||
|             0, 0, 0, | ||||
|         ]), | ||||
|     ); | ||||
|     let dek2 = TypedSharedSecret::new( | ||||
|         vcrypto.kind(), | ||||
|         SharedSecret::new([ | ||||
|             1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||||
|             0, 0, 0xFF, | ||||
|         ]), | ||||
|     ); | ||||
|     let dek3 = TypedSharedSecret::new( | ||||
|         vcrypto.kind(), | ||||
|         SharedSecret::new([0x80u8; SHARED_SECRET_LENGTH]), | ||||
|     ); | ||||
| 
 | ||||
|     let deks = [dek1, dek2, dek3]; | ||||
|     let passwords = ["", " ", "  ", "12345678", "|/\\!@#$%^&*()_+", "Ⓜ️", "🔥🔥♾️"]; | ||||
| 
 | ||||
|     for dek in deks { | ||||
|         for password in passwords { | ||||
|             let dek_bytes = ts | ||||
|                 .maybe_protect_device_encryption_key(dek, password) | ||||
|                 .expect(&format!("protect: dek: '{}' pw: '{}'", dek, password)); | ||||
|             let unprotected = ts | ||||
|                 .maybe_unprotect_device_encryption_key(&dek_bytes, password) | ||||
|                 .expect(&format!("unprotect: dek: '{}' pw: '{}'", dek, password)); | ||||
|             assert_eq!(unprotected, dek); | ||||
|             let invalid_password = format!("{}x", password); | ||||
|             let _ = ts | ||||
|                 .maybe_unprotect_device_encryption_key(&dek_bytes, &invalid_password) | ||||
|                 .expect_err(&format!( | ||||
|                     "invalid_password: dek: '{}' pw: '{}'", | ||||
|                     dek, &invalid_password | ||||
|                 )); | ||||
|             if password != "" { | ||||
|                 let _ = ts | ||||
|                     .maybe_unprotect_device_encryption_key(&dek_bytes, "") | ||||
|                     .expect_err(&format!("empty_password: dek: '{}' pw: ''", dek)); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub async fn test_all() { | ||||
|     let api = startup().await; | ||||
|     let crypto = api.crypto().unwrap(); | ||||
| @@ -215,6 +265,7 @@ pub async fn test_all() { | ||||
| 
 | ||||
|     for ck in VALID_CRYPTO_KINDS { | ||||
|         let vcrypto = crypto.get(ck).unwrap(); | ||||
|         test_protect_unprotect(vcrypto.clone(), ts.clone()).await; | ||||
|         test_delete_open_delete(ts.clone()).await; | ||||
|         test_store_delete_load(ts.clone()).await; | ||||
|         test_rkyv(vcrypto.clone(), ts.clone()).await; | ||||
| @@ -1,5 +1,4 @@ | ||||
| pub mod test_host_interface; | ||||
| pub mod test_protected_store; | ||||
| pub mod test_table_store; | ||||
| pub mod test_veilid_config; | ||||
| pub mod test_veilid_core; | ||||
|   | ||||
| @@ -166,7 +166,7 @@ pub fn setup_veilid_core() -> (UpdateCallback, ConfigCallback) { | ||||
|  | ||||
| fn config_callback(key: String) -> ConfigCallbackReturn { | ||||
|     match key.as_str() { | ||||
|         "program_name" => Ok(Box::new(String::from("Veilid"))), | ||||
|         "program_name" => Ok(Box::new(String::from("VeilidCoreTests"))), | ||||
|         "namespace" => Ok(Box::new(String::from(""))), | ||||
|         "capabilities.protocol_udp" => Ok(Box::new(true)), | ||||
|         "capabilities.protocol_connect_tcp" => Ok(Box::new(true)), | ||||
| @@ -176,13 +176,17 @@ fn config_callback(key: String) -> ConfigCallbackReturn { | ||||
|         "capabilities.protocol_connect_wss" => Ok(Box::new(true)), | ||||
|         "capabilities.protocol_accept_wss" => Ok(Box::new(true)), | ||||
|         "table_store.directory" => Ok(Box::new(get_table_store_path())), | ||||
|         "table_store.delete" => Ok(Box::new(false)), | ||||
|         "table_store.delete" => Ok(Box::new(true)), | ||||
|         "block_store.directory" => Ok(Box::new(get_block_store_path())), | ||||
|         "block_store.delete" => Ok(Box::new(false)), | ||||
|         "block_store.delete" => Ok(Box::new(true)), | ||||
|         "protected_store.allow_insecure_fallback" => Ok(Box::new(true)), | ||||
|         "protected_store.always_use_insecure_storage" => Ok(Box::new(false)), | ||||
|         "protected_store.directory" => Ok(Box::new(get_protected_store_path())), | ||||
|         "protected_store.delete" => Ok(Box::new(false)), | ||||
|         "protected_store.delete" => Ok(Box::new(true)), | ||||
|         "protected_store.device_encryption_key_password" => Ok(Box::new("".to_owned())), | ||||
|         "protected_store.new_device_encryption_key_password" => { | ||||
|             Ok(Box::new(Option::<String>::None)) | ||||
|         } | ||||
|         "network.connection_initial_timeout_ms" => Ok(Box::new(2_000u32)), | ||||
|         "network.connection_inactivity_timeout_ms" => Ok(Box::new(60_000u32)), | ||||
|         "network.max_connections_per_ip4" => Ok(Box::new(8u32)), | ||||
| @@ -302,13 +306,21 @@ pub async fn test_config() { | ||||
|     assert_eq!(inner.capabilities.protocol_connect_wss, true); | ||||
|     assert_eq!(inner.capabilities.protocol_accept_wss, true); | ||||
|     assert_eq!(inner.table_store.directory, get_table_store_path()); | ||||
|     assert_eq!(inner.table_store.delete, false); | ||||
|     assert_eq!(inner.table_store.delete, true); | ||||
|     assert_eq!(inner.block_store.directory, get_block_store_path()); | ||||
|     assert_eq!(inner.block_store.delete, false); | ||||
|     assert_eq!(inner.block_store.delete, true); | ||||
|     assert_eq!(inner.protected_store.allow_insecure_fallback, true); | ||||
|     assert_eq!(inner.protected_store.always_use_insecure_storage, false); | ||||
|     assert_eq!(inner.protected_store.directory, get_protected_store_path()); | ||||
|     assert_eq!(inner.protected_store.delete, false); | ||||
|     assert_eq!(inner.protected_store.delete, true); | ||||
|     assert_eq!( | ||||
|         inner.protected_store.device_encryption_key_password, | ||||
|         "".to_owned() | ||||
|     ); | ||||
|     assert_eq!( | ||||
|         inner.protected_store.new_device_encryption_key_password, | ||||
|         Option::<String>::None | ||||
|     ); | ||||
|     assert_eq!(inner.network.connection_initial_timeout_ms, 2_000u32); | ||||
|     assert_eq!(inner.network.connection_inactivity_timeout_ms, 60_000u32); | ||||
|     assert_eq!(inner.network.max_connections_per_ip4, 8u32); | ||||
|   | ||||
| @@ -13,4 +13,5 @@ pub use common::*; | ||||
| pub use crypto::tests::*; | ||||
| pub use network_manager::tests::*; | ||||
| pub use routing_table::tests::*; | ||||
| pub use table_store::tests::*; | ||||
| pub use veilid_api::tests::*; | ||||
|   | ||||
| @@ -3,6 +3,7 @@ | ||||
| use crate::crypto::tests::*; | ||||
| use crate::network_manager::tests::*; | ||||
| use crate::routing_table; | ||||
| use crate::table_store::tests::*; | ||||
| use crate::tests::common::*; | ||||
| use crate::veilid_api; | ||||
| use crate::*; | ||||
|   | ||||
| @@ -734,6 +734,9 @@ impl VeilidConfig { | ||||
|  | ||||
|         // Remove secrets | ||||
|         safe_cfg.network.routing_table.node_id_secret = TypedSecretSet::new(); | ||||
|         safe_cfg.protected_store.device_encryption_key_password = "".to_owned(); | ||||
|         safe_cfg.protected_store.new_device_encryption_key_password = None; | ||||
|  | ||||
|  | ||||
|         safe_cfg | ||||
|     } | ||||
|   | ||||
| @@ -1,4 +1,8 @@ | ||||
| //! Test suite for the Web and headless browsers. | ||||
|  | ||||
| //XXXXXXXXXXXXXXX | ||||
| //XXX DOES NOT WORK. | ||||
|  | ||||
| #![cfg(target_arch = "wasm32")] | ||||
|  | ||||
| extern crate alloc; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user