diff --git a/Cargo.lock b/Cargo.lock index 56a7680b22c..c86638b5815 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1922,6 +1922,7 @@ dependencies = [ "oasis-core-keymanager-client", "oasis-core-runtime", "rand 0.7.3", + "rustc-hex", "sgx-isa 0.3.3", "sp800-185", "tiny-keccak 2.0.2", diff --git a/keymanager-lib/Cargo.toml b/keymanager-lib/Cargo.toml index 2005779415b..60024510b48 100644 --- a/keymanager-lib/Cargo.toml +++ b/keymanager-lib/Cargo.toml @@ -22,3 +22,4 @@ tiny-keccak = { version = "2.0.2", features = ["sha3"] } x25519-dalek = "1.1.0" tokio = { version = "1", features = ["rt"] } zeroize = "1.4" +rustc-hex = "2.0.1" diff --git a/keymanager-lib/src/kdf.rs b/keymanager-lib/src/kdf.rs index e7b225fc305..c0ac8c75ce1 100644 --- a/keymanager-lib/src/kdf.rs +++ b/keymanager-lib/src/kdf.rs @@ -535,7 +535,12 @@ impl Kdf { #[cfg(test)] mod tests { use lru::LruCache; - use std::sync::{Arc, RwLock}; + use rustc_hex::{FromHex, ToHex}; + use std::{ + collections::HashSet, + convert::TryInto, + sync::{Arc, RwLock}, + }; use oasis_core_keymanager_api_common::{ EphemeralKeyRequest, KeyPairId, LongTermKeyRequest, MasterSecret, PublicKey, @@ -543,17 +548,60 @@ mod tests { }; use oasis_core_runtime::common::{crypto::signature::PrivateKey, namespace::Namespace}; - use super::{Inner, KeyRequest}; + use super::{ + Inner, KeyRequest, EPHEMERAL_KDF_CUSTOM, EPHEMERAL_XOF_CUSTOM, RUNTIME_KDF_CUSTOM, + RUNTIME_XOF_CUSTOM, + }; use crate::kdf::Kdf; + struct SimpleKeyRequest<'a> { + seed: &'a str, + kdf_custom: &'a [u8], + xof_custom: &'a [u8], + } + + impl Default for SimpleKeyRequest<'_> { + fn default() -> Self { + Self { + seed: "8842befd88ea1952decf60f5c7430ee479b84a9b2472b2cc1fc796d35d5d71c3", + kdf_custom: b"kdf_custom", + xof_custom: b"xof_custom", + } + } + } + + impl KeyRequest for SimpleKeyRequest<'_> { + fn seed(&self) -> Vec { + self.seed.from_hex().unwrap() + } + + fn kdf_custom(&self) -> &[u8] { + self.kdf_custom + } + + fn xof_custom(&self) -> &[u8] { + self.xof_custom + } + } + + impl Default for Kdf { + fn default() -> Self { + Self { + inner: RwLock::new(Inner { + master_secret: Some(MasterSecret([1u8; 32])), + checksum: Some(vec![2u8; 32]), + runtime_id: Some(Namespace([3u8; 32])), + signer: Some(Arc::new(PrivateKey::from_bytes(vec![4u8; 32]))), + cache: LruCache::new(1), + }), + } + } + } + #[test] fn key_generation_is_deterministic() { - let kdf = kdf(); - - let req = LongTermKeyRequest { - runtime_id: Namespace::from(vec![1u8; 32]), - key_pair_id: KeyPairId::from(vec![1u8; 32]), - }; + let kdf = Kdf::default(); + let req = SimpleKeyRequest::default(); let sk1 = kdf .get_or_create_keys(&req) @@ -564,79 +612,47 @@ mod tests { .expect("private key should be created"); assert_eq!(sk1.input_keypair.sk.0, sk2.input_keypair.sk.0); + assert_eq!(sk1.input_keypair.pk.0, sk2.input_keypair.pk.0); } #[test] fn private_keys_are_unique() { - let kdf = kdf(); - - let mut req = LongTermKeyRequest { - runtime_id: Namespace::from(vec![1u8; 32]), - key_pair_id: KeyPairId::from(vec![1u8; 32]), - }; + let kdf = Kdf::default(); + let mut req = SimpleKeyRequest::default(); let sk1 = kdf .get_or_create_keys(&req) .expect("private key should be created"); - req.runtime_id = Namespace::from(vec![2u8; 32]); - + req.seed = "eeffe4ab608f4adad8b5168163ab95fab43a818321ad49fba897fcb435097099"; let sk2 = kdf .get_or_create_keys(&req) .expect("private key should be created"); - req.key_pair_id = KeyPairId::from(vec![2u8; 32]); - - let sk3 = kdf - .get_or_create_keys(&req) - .expect("private key should be created"); - - assert_ne!(sk1.input_keypair.pk.0, sk2.input_keypair.sk.0); - assert_ne!(sk1.input_keypair.pk.0, sk3.input_keypair.sk.0); - assert_ne!(sk2.input_keypair.pk.0, sk3.input_keypair.sk.0); + assert_ne!(sk1.input_keypair.sk.0, sk2.input_keypair.sk.0); + assert_ne!(sk1.input_keypair.pk.0, sk2.input_keypair.pk.0); } #[test] fn private_and_public_key_match() { - let kdf = kdf(); - - let req = LongTermKeyRequest { - runtime_id: Namespace::from(vec![1u8; 32]), - key_pair_id: KeyPairId::from(vec![1u8; 32]), - }; + let kdf = Kdf::default(); + let req = SimpleKeyRequest::default(); - let sk1 = kdf + let sk = kdf .get_or_create_keys(&req) .expect("private key should be created"); - let pk1 = kdf + let pk = kdf .get_public_key(&req) .unwrap() .expect("public key should be fetched"); - let req = EphemeralKeyRequest { - epoch: 1, - runtime_id: Namespace::from(vec![1u8; 32]), - key_pair_id: KeyPairId::from(vec![1u8; 32]), - }; - - let sk2 = kdf - .get_or_create_keys(&req) - .expect("private key should be created"); - - let pk2 = kdf - .get_public_key(&req) - .unwrap() - .expect("public key should be fetched"); - - assert_eq!(sk1.input_keypair.pk, pk1); - assert_eq!(sk2.input_keypair.pk, pk2); - assert_ne!(pk1, pk2); + assert_eq!(sk.input_keypair.pk, pk); } #[test] fn public_key_signature_is_valid() { - let kdf = kdf(); + let kdf = Kdf::default(); let pk = PublicKey::from(vec![1u8; 32]); let sig = kdf @@ -644,7 +660,7 @@ mod tests { .expect("public key should be signed"); let mut body = pk.as_ref().to_vec(); - let checksum = [2u8; 32]; + let checksum = kdf.inner.into_inner().unwrap().checksum.unwrap(); body.extend_from_slice(&checksum); let pk = PrivateKey::from_bytes(vec![4u8; 32]).public_key(); @@ -655,16 +671,21 @@ mod tests { #[test] fn master_secret_can_be_replicated() { - let kdf = kdf(); + let kdf = Kdf::default(); let ms = kdf .replicate_master_secret() .expect("master secret should be replicated"); - assert_eq!(ms.master_secret.0, [1u8; 32]); + assert_eq!( + ms.master_secret.0, + kdf.inner.into_inner().unwrap().master_secret.unwrap().0 + ); } #[test] fn requests_have_unique_customs() { + // All key requests must have unique customs otherwise they can + // derivate keys from the same KMac and/or CShake!!! let runtime_req = LongTermKeyRequest::default(); let ephemeral_req = EphemeralKeyRequest::default(); @@ -672,15 +693,160 @@ mod tests { assert_ne!(runtime_req.kdf_custom(), ephemeral_req.kdf_custom()); } - fn kdf() -> Kdf { - Kdf { - inner: RwLock::new(Inner { - master_secret: Some(MasterSecret([1u8; 32])), - checksum: Some(vec![2u8; 32]), - runtime_id: Some(Namespace([3u8; 32])), - signer: Some(Arc::new(PrivateKey::from_bytes(vec![4u8; 32]))), - cache: LruCache::new(1), - }), + #[test] + fn requests_generate_unique_seeds() { + // Default values. + let runtime_id = Namespace::from(vec![1u8; 32]); + let key_pair_id = KeyPairId::from(vec![1u8; 32]); + let epoch = 1; + + // LongTermKeyRequest's seed should depend on runtime_id and + // key_pair_id. + let req1 = LongTermKeyRequest { + runtime_id, + key_pair_id, + }; + let mut req2 = req1.clone(); + let mut req3 = req1.clone(); + req2.runtime_id = Namespace::from(vec![2u8; 32]); + req3.key_pair_id = KeyPairId::from(vec![3u8; 32]); + + let mut seeds = HashSet::new(); + seeds.insert(req1.seed()); + seeds.insert(req2.seed()); + seeds.insert(req3.seed()); + + assert_eq!(seeds.len(), 3); + + // EphemeralKeyRequest's seed should depend on runtime_id, key_pair_id + // and epoch. + let req1 = EphemeralKeyRequest { + epoch, + runtime_id, + key_pair_id, + }; + let mut req2 = req1.clone(); + let mut req3 = req1.clone(); + let mut req4 = req1.clone(); + req2.runtime_id = Namespace::from(vec![2u8; 32]); + req3.key_pair_id = KeyPairId::from(vec![3u8; 32]); + req4.epoch = 2; + + let mut seeds = HashSet::new(); + seeds.insert(req1.seed()); + seeds.insert(req2.seed()); + seeds.insert(req3.seed()); + seeds.insert(req4.seed()); + + assert_eq!(seeds.len(), 4); + } + + #[test] + fn vector_test() { + struct TestVector<'a> { + master_secret: &'a str, + seed: &'a str, + kdf_custom: &'a [u8], + xof_custom: &'a [u8], + sk: &'a str, + pk: &'a str, + } + + let kdf_custom = b"54761365b5a007c2bd13cf880a8a58263f56bb7057f7548b7467e871f6f4bb1f"; + let xof_custom = b"a0caee5ecac1a287f06ff8748cf37e809f049cf6866d668ecdbed3ce05b40f2c"; + + let vectors = vec![ + // A random vector. + TestVector { + master_secret: "3fa39161fe106fb770503558dad41bea3221888c09477d864507e615094f5d38", + seed: "2a9d51ed0380d11b26255ecc894dfc3aa48196c9b0da463a3073ea820a65a090", + kdf_custom: &RUNTIME_KDF_CUSTOM, + xof_custom: &RUNTIME_XOF_CUSTOM, + sk: "c818f97228a53b201e2afa383b64199c732c7ba1a67ac55ea2cb3b8fba367740", + pk: "fb99076f6a5a8c52bcf562cae5152d0410f47a615fc7bc4966dc9a4f477bd217", + }, + // Different master secret. + TestVector { + master_secret: "54083e90f05860653161bc1575765b3311f6a55d1cab84919cb1e2b02c8351ec", + seed: "2a9d51ed0380d11b26255ecc894dfc3aa48196c9b0da463a3073ea820a65a090", + kdf_custom: &RUNTIME_KDF_CUSTOM, + xof_custom: &RUNTIME_XOF_CUSTOM, + sk: "b8092ab767ddc47cb56807d4d1fd0e66eae0b02e289d1e38d4dfa900619edc47", + pk: "6782329a12e821697f1d7cc44ba5644a2d81bd827fe09208549296be51da8b66", + }, + // Different seed. + TestVector { + master_secret: "3fa39161fe106fb770503558dad41bea3221888c09477d864507e615094f5d38", + seed: "6cc9f7dfe776c7e531331eaf5fd8717d638cae65a4ebb0d6f128b1873f0f9c22", + kdf_custom: &RUNTIME_KDF_CUSTOM, + xof_custom: &RUNTIME_XOF_CUSTOM, + sk: "f0d5bf36b424f7b168fa37e1a1407f191a260dda149d78676d4ca077b1e8614c", + pk: "9099b1e19c482927eb2785c77b34ef2c4b95f812e089e3b2cd6f2a0a743b7561", + }, + // Different kdf custom. + TestVector { + master_secret: "3fa39161fe106fb770503558dad41bea3221888c09477d864507e615094f5d38", + seed: "2a9d51ed0380d11b26255ecc894dfc3aa48196c9b0da463a3073ea820a65a090", + kdf_custom: &EPHEMERAL_KDF_CUSTOM, + xof_custom: &RUNTIME_XOF_CUSTOM, + sk: "18789f16d8a8fbd75f529f0a1de3e95469eb537c283dc66eb296a6681a46c066", + pk: "1aa3e6d86c0779afde8a367dbbb025538fb77e410624ece8b25a6be9e1a5170d", + }, + // Different xof custom. + TestVector { + master_secret: "3fa39161fe106fb770503558dad41bea3221888c09477d864507e615094f5d38", + seed: "2a9d51ed0380d11b26255ecc894dfc3aa48196c9b0da463a3073ea820a65a090", + kdf_custom: &RUNTIME_KDF_CUSTOM, + xof_custom: &EPHEMERAL_XOF_CUSTOM, + sk: "e0e6faa3172634c8fdc47554f0541c7141f7ddfe07333b0dab1801bb5dcd755e", + pk: "455f877b6c977c51580e947a5a2ae57b4b1ec0a379cf6509be07f10aa88df735", + }, + // Another random vector. + TestVector { + master_secret: "b573fa13ec26d21a7a2b5117eb124dcab5883eb63ec0a5a9cc0b1d1948bcfc71", + seed: "774cbb9c1e8c634e7e136357d9994f65d72fc0e7d72c1e9ad766db1a74e0bb8c", + kdf_custom, + xof_custom, + sk: "70c077d8bd0c5c2be66d08fbacac4f1a996001883baaf62bd933e2f7de390e5f", + pk: "2d62567e9061a7cc64df3793fbee65c863862b8f0acc992e2a39e32757f2c743", + }, + ]; + + // Values that don't effect key derivation. + let checksum = "100246b37912e916e71ff79982b2f62be892ddf1025cde84804f67e7f5713b75"; + let runtime_id = "8000000000000000000000000000000000000000000000000000000000000000"; + let signer = "08e35ef2b23fc2d27281117f8ad3fa0cb4d52e803a070ebb20e7ac9aa8d1f84a"; + + // Test all vectors. + for v in vectors { + let kdf = Kdf { + inner: RwLock::new(Inner { + master_secret: Some(MasterSecret( + v.master_secret + .from_hex::>() + .unwrap() + .try_into() + .unwrap(), + )), + checksum: Some(checksum.from_hex().unwrap()), + runtime_id: Some(Namespace::from(runtime_id)), + signer: Some(Arc::new(PrivateKey::from_bytes(signer.from_hex().unwrap()))), + cache: LruCache::new(1), + }), + }; + + let req = SimpleKeyRequest { + seed: v.seed, + kdf_custom: v.kdf_custom, + xof_custom: v.xof_custom, + }; + + let sk = kdf + .get_or_create_keys(&req) + .expect("private key should be created"); + + assert_eq!(sk.input_keypair.sk.0.to_hex::(), v.sk); + assert_eq!(sk.input_keypair.pk.0.to_hex::(), v.pk); } } }