From 16f2b3cbb67f2c8f1958bb638f2d0f39a6f35b99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrej=20Buko=C5=A1ek?= Date: Tue, 28 Jan 2020 11:56:49 +0100 Subject: [PATCH] Flexible key manager policy signers --- .changelog/2444.feature.md | 5 + Cargo.lock | 32 ++- Cargo.toml | 2 + keymanager-api-common/Cargo.toml | 16 ++ keymanager-api-common/src/api.rs | 250 ++++++++++++++++++ keymanager-api-common/src/lib.rs | 82 ++++++ keymanager-client/src/client.rs | 3 + keymanager-lib/Cargo.toml | 20 ++ .../src/context.rs | 2 +- .../src/kdf.rs | 4 +- keymanager-lib/src/lib.rs | 16 ++ .../src/policy.rs | 2 +- keymanager-runtime/Cargo.toml | 10 +- keymanager-runtime/api/Cargo.toml | 1 + keymanager-runtime/api/src/api.rs | 230 +--------------- keymanager-runtime/api/src/lib.rs | 89 ++----- keymanager-runtime/src/main.rs | 17 +- keymanager-runtime/src/methods.rs | 2 +- 18 files changed, 462 insertions(+), 321 deletions(-) create mode 100644 .changelog/2444.feature.md create mode 100644 keymanager-api-common/Cargo.toml create mode 100644 keymanager-api-common/src/api.rs create mode 100644 keymanager-api-common/src/lib.rs create mode 100644 keymanager-lib/Cargo.toml rename {keymanager-runtime => keymanager-lib}/src/context.rs (86%) rename {keymanager-runtime => keymanager-lib}/src/kdf.rs (99%) create mode 100644 keymanager-lib/src/lib.rs rename {keymanager-runtime => keymanager-lib}/src/policy.rs (99%) diff --git a/.changelog/2444.feature.md b/.changelog/2444.feature.md new file mode 100644 index 00000000000..82fbefb743d --- /dev/null +++ b/.changelog/2444.feature.md @@ -0,0 +1,5 @@ +Flexible key manager policy signers + +The key manager runtime has been split into multiple crates to make its code +reusable. It is now possible for others to write their own key managers that +use a different set of trusted policy signers. diff --git a/Cargo.lock b/Cargo.lock index c50ea9f488e..67b75d771e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -711,6 +711,23 @@ dependencies = [ [[package]] name = "oasis-core-keymanager-api" version = "0.3.0-alpha" +dependencies = [ + "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "oasis-core-keymanager-api-common 0.3.0-alpha", + "oasis-core-runtime 0.3.0-alpha", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_bytes 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "x25519-dalek 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "oasis-core-keymanager-api-common" +version = "0.3.0-alpha" dependencies = [ "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -739,14 +756,14 @@ dependencies = [ ] [[package]] -name = "oasis-core-keymanager-runtime" +name = "oasis-core-keymanager-lib" version = "0.3.0-alpha" dependencies = [ "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "io-context 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "lru 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "oasis-core-keymanager-api 0.3.0-alpha", + "oasis-core-keymanager-api-common 0.3.0-alpha", "oasis-core-keymanager-client 0.3.0-alpha", "oasis-core-runtime 0.3.0-alpha", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -757,6 +774,17 @@ dependencies = [ "zeroize 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "oasis-core-keymanager-runtime" +version = "0.3.0-alpha" +dependencies = [ + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "oasis-core-keymanager-api 0.3.0-alpha", + "oasis-core-keymanager-lib 0.3.0-alpha", + "oasis-core-runtime 0.3.0-alpha", +] + [[package]] name = "oasis-core-runtime" version = "0.3.0-alpha" diff --git a/Cargo.toml b/Cargo.toml index d4e1ba7fb9f..ecb6823d660 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,8 @@ members = [ "runtime-loader", "client", "keymanager-client", + "keymanager-api-common", + "keymanager-lib", "keymanager-runtime", "tools", diff --git a/keymanager-api-common/Cargo.toml b/keymanager-api-common/Cargo.toml new file mode 100644 index 00000000000..8eae105502e --- /dev/null +++ b/keymanager-api-common/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "oasis-core-keymanager-api-common" +version = "0.3.0-alpha" +authors = ["Oasis Labs Inc. "] + +[dependencies] +base64 = "0.10.1" +oasis-core-runtime = { path = "../runtime" } +serde = "1.0.71" +serde_derive = "1.0" +serde_bytes = "~0.10" +rustc-hex = "2.0.1" +failure = "0.1.5" +lazy_static = "1.3.0" +x25519-dalek = "0.5.1" +rand = "0.6.5" diff --git a/keymanager-api-common/src/api.rs b/keymanager-api-common/src/api.rs new file mode 100644 index 00000000000..1fb95eab570 --- /dev/null +++ b/keymanager-api-common/src/api.rs @@ -0,0 +1,250 @@ +use std::{ + collections::{HashMap, HashSet}, + default::Default, +}; + +use base64; +use failure::Fail; +use rand::{rngs::OsRng, Rng}; +use serde_derive::{Deserialize, Serialize}; +use x25519_dalek; + +use oasis_core_runtime::{ + common::{ + crypto::signature::{PublicKey as OasisPublicKey, Signature, SignatureBundle}, + runtime::RuntimeId, + sgx::avr::EnclaveIdentity, + }, + impl_bytes, +}; + +impl_bytes!(ContractId, 32, "A 256-bit contract identifier."); +impl_bytes!(PrivateKey, 32, "A private key."); +impl_bytes!(PublicKey, 32, "A public key."); +impl_bytes!(StateKey, 32, "A state key."); +impl_bytes!(MasterSecret, 32, "A 256 bit master secret."); + +/// Key manager initialization request. +#[derive(Clone, Serialize, Deserialize)] +pub struct InitRequest { + /// Checksum for validating replication. + #[serde(with = "serde_bytes")] + pub checksum: Vec, + /// Policy for queries/replication. + #[serde(with = "serde_bytes")] + pub policy: Vec, + /// True iff the enclave may generate a new master secret. + pub may_generate: bool, +} + +/// Key manager initialization response. +#[derive(Clone, Serialize, Deserialize)] +pub struct InitResponse { + /// True iff the key manager thinks it's running in a secure mode. + pub is_secure: bool, + /// Checksum for validating replication. + #[serde(with = "serde_bytes")] + pub checksum: Vec, + /// Checksum for identifying policy. + #[serde(with = "serde_bytes")] + pub policy_checksum: Vec, +} + +/// Context used for the init response signature. +pub const INIT_RESPONSE_CONTEXT: &'static [u8] = b"oasis-core/keymanager: init response"; + +/// Signed InitResponse. +#[derive(Clone, Serialize, Deserialize)] +pub struct SignedInitResponse { + /// InitResponse. + pub init_response: InitResponse, + /// Sign(init_response). + pub signature: Signature, +} + +/// Key manager replication request. +#[derive(Clone, Serialize, Deserialize)] +pub struct ReplicateRequest { + // Empty. +} + +/// Key manager replication response. +#[derive(Clone, Serialize, Deserialize)] +pub struct ReplicateResponse { + pub master_secret: MasterSecret, +} + +/// Request runtime/contract id tuple. +#[derive(Clone, Serialize, Deserialize)] +pub struct RequestIds { + /// Runtime ID. + pub runtime_id: RuntimeId, + /// Contract ID. + pub contract_id: ContractId, +} + +impl RequestIds { + pub fn new(runtime_id: RuntimeId, contract_id: ContractId) -> Self { + Self { + runtime_id, + contract_id, + } + } + + pub fn to_cache_key(&self) -> Vec { + let mut k = self.runtime_id.as_ref().to_vec(); + k.extend_from_slice(self.contract_id.as_ref()); + k + } +} + +/// Keys for a contract. +#[derive(Clone, Serialize, Deserialize)] +pub struct ContractKey { + /// Input key pair (pk, sk) + pub input_keypair: InputKeyPair, + /// State encryption key + pub state_key: StateKey, + /// Checksum of the key manager state. + #[serde(with = "serde_bytes")] + pub checksum: Vec, +} + +impl ContractKey { + /// Generate a new random key (for testing). + pub fn generate_mock() -> Self { + let mut rng = OsRng::new().unwrap(); + let sk = x25519_dalek::StaticSecret::new(&mut rng); + let pk = x25519_dalek::PublicKey::from(&sk); + + let mut state_key = StateKey::default(); + rng.fill(&mut state_key.0); + + ContractKey::new( + PublicKey(*pk.as_bytes()), + PrivateKey(sk.to_bytes()), + state_key, + vec![], + ) + } + + /// Create a set of `ContractKey`. + pub fn new(pk: PublicKey, sk: PrivateKey, k: StateKey, sum: Vec) -> Self { + Self { + input_keypair: InputKeyPair::new(pk, sk), + state_key: k, + checksum: sum, + } + } + + /// Create a set of `ContractKey` with only the public key. + pub fn from_public_key(k: PublicKey, sum: Vec) -> Self { + Self { + input_keypair: InputKeyPair::new(k, PrivateKey::default()), + state_key: StateKey::default(), + checksum: sum, + } + } +} + +#[derive(Clone, Serialize, Deserialize)] +pub struct InputKeyPair { + /// Pk + pk: PublicKey, + /// sk + sk: PrivateKey, +} + +impl InputKeyPair { + pub fn new(pk: PublicKey, sk: PrivateKey) -> Self { + Self { pk, sk } + } + + pub fn get_pk(&self) -> PublicKey { + self.pk + } + + pub fn get_sk(&self) -> PrivateKey { + self.sk + } +} + +/// Context used for the public key signature. +pub const PUBLIC_KEY_CONTEXT: [u8; 8] = *b"EkKmPubK"; + +/// Signed public key. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct SignedPublicKey { + /// Public key. + pub key: PublicKey, + /// Checksum of the key manager state. + #[serde(with = "serde_bytes")] + pub checksum: Vec, + /// Sign(sk, (key || checksum)) from the key manager. + pub signature: Signature, +} + +/// Key manager error. +#[derive(Debug, Fail)] +pub enum KeyManagerError { + #[fail(display = "client session is not authenticated")] + NotAuthenticated, + #[fail(display = "client session authentication is invalid")] + InvalidAuthentication, + #[fail(display = "key manager is not initialized")] + NotInitialized, + #[fail(display = "key manager state corrupted")] + StateCorrupted, + #[fail(display = "key manager replication required")] + ReplicationRequired, + #[fail(display = "policy rollback")] + PolicyRollback, + #[fail(display = "policy alteration, without serial increment")] + PolicyChanged, + #[fail(display = "policy is malformed or invalid")] + PolicyInvalid, + #[fail(display = "policy failed signature verification")] + PolicyInvalidSignature, + #[fail(display = "policy has insufficient signatures")] + PolicyInsufficientSignatures, +} + +/// Key manager access control policy. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct PolicySGX { + pub serial: u32, + pub id: RuntimeId, + pub enclaves: HashMap, +} + +/// Per enclave key manager access control policy. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct EnclavePolicySGX { + pub may_query: HashMap>, + pub may_replicate: Vec, +} + +/// Signed key manager access control policy. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct SignedPolicySGX { + pub policy: PolicySGX, + pub signatures: Vec, +} + +/// Set of trusted key manager policy signing keys. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct TrustedPolicySigners { + /// Set of trusted signers. + pub signers: HashSet, + /// Threshold for determining if enough valid signatures are present. + pub threshold: usize, +} + +impl Default for TrustedPolicySigners { + fn default() -> Self { + Self { + signers: HashSet::new(), + threshold: 9001, + } + } +} diff --git a/keymanager-api-common/src/lib.rs b/keymanager-api-common/src/lib.rs new file mode 100644 index 00000000000..0990fc6dfee --- /dev/null +++ b/keymanager-api-common/src/lib.rs @@ -0,0 +1,82 @@ +//! Key manager API common types and functions. +extern crate base64; +extern crate failure; +extern crate lazy_static; +extern crate oasis_core_runtime; +extern crate rand; +extern crate rustc_hex; +extern crate serde; +extern crate serde_bytes; +extern crate serde_derive; +extern crate x25519_dalek; + +use failure::Fallible; +use lazy_static::lazy_static; +use oasis_core_runtime::common::{cbor, crypto::signature::PublicKey as OasisPublicKey}; +use std::{ + collections::HashSet, + sync::{Mutex, Once}, +}; + +#[macro_use] +pub mod api; + +// Re-exports. +pub use api::*; + +lazy_static! { + /// Set of trusted policy signers. + static ref TRUSTED_SIGNERS: Mutex = Mutex::new(TrustedPolicySigners::default()); + + /// Initializes the global TRUSTED_SIGNERS only once. + static ref INIT_TRUSTED_SIGNERS_ONCE: Once = Once::new(); +} + +/// Set the global set of trusted policy signers. +/// Changing the set of policy signers after the first call is not possible. +pub fn set_trusted_policy_signers(signers: TrustedPolicySigners) -> bool { + INIT_TRUSTED_SIGNERS_ONCE.call_once(|| { + *TRUSTED_SIGNERS.lock().unwrap() = signers; + }); + + true +} + +const POLICY_SIGN_CONTEXT: &'static [u8] = b"oasis-core/keymanager: policy"; + +impl SignedPolicySGX { + /// Verify the signatures and return the PolicySGX, if the signatures are correct. + pub fn verify(&self) -> Fallible { + // Verify the signatures. + let untrusted_policy_raw = cbor::to_vec(&self.policy); + let mut signers: HashSet = HashSet::new(); + for sig in &self.signatures { + let public_key = match sig.public_key { + Some(public_key) => public_key, + None => return Err(KeyManagerError::PolicyInvalid.into()), + }; + + if !sig + .signature + .verify(&public_key, &POLICY_SIGN_CONTEXT, &untrusted_policy_raw) + .is_ok() + { + return Err(KeyManagerError::PolicyInvalidSignature.into()); + } + signers.insert(public_key); + } + + // Ensure that enough valid signatures from trusted signers are present. + let trusted_signers = TRUSTED_SIGNERS.lock().unwrap(); + let signers: HashSet<_> = trusted_signers.signers.intersection(&signers).collect(); + let multisig_threshold = match option_env!("OASIS_UNSAFE_KM_POLICY_KEYS") { + Some(_) => 2, + None => trusted_signers.threshold, + }; + if signers.len() < multisig_threshold { + return Err(KeyManagerError::PolicyInsufficientSignatures.into()); + } + + Ok(self.policy.clone()) + } +} diff --git a/keymanager-client/src/client.rs b/keymanager-client/src/client.rs index 995f47b2f2c..2600531f812 100644 --- a/keymanager-client/src/client.rs +++ b/keymanager-client/src/client.rs @@ -93,6 +93,9 @@ impl RemoteClient { rak: Arc, keys_cache_sizes: usize, ) -> Self { + #[cfg(target_env = "sgx")] + init_trusted_policy_signers(); + #[cfg(target_env = "sgx")] let enclaves: Option> = match protocol .make_request(Context::background(), Body::HostKeyManagerPolicyRequest {}) diff --git a/keymanager-lib/Cargo.toml b/keymanager-lib/Cargo.toml new file mode 100644 index 00000000000..84933829641 --- /dev/null +++ b/keymanager-lib/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "oasis-core-keymanager-lib" +version = "0.3.0-alpha" +authors = ["Oasis Labs Inc. "] +edition = "2018" + +[dependencies] +oasis-core-runtime = { path = "../runtime" } +oasis-core-keymanager-api-common = { path = "../keymanager-api-common" } +oasis-core-keymanager-client = { path = "../keymanager-client" } +failure = "0.1.5" +lazy_static = "1.3.0" +lru = "0.1.17" +io-context = "0.2.0" +rand = "0.6.5" +sgx-isa = { version = "0.3.0", features = ["sgxstd"] } +sp800-185 = "0.2.0" +tiny-keccak = "1.4.2" +x25519-dalek = "0.5.1" +zeroize = "0.6" diff --git a/keymanager-runtime/src/context.rs b/keymanager-lib/src/context.rs similarity index 86% rename from keymanager-runtime/src/context.rs rename to keymanager-lib/src/context.rs index 629d334cb35..3879f4e64ad 100644 --- a/keymanager-runtime/src/context.rs +++ b/keymanager-lib/src/context.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use oasis_core_runtime::{common::runtime::RuntimeId, Protocol}; -pub(crate) struct Context { +pub struct Context { pub runtime_id: RuntimeId, pub protocol: Arc, } diff --git a/keymanager-runtime/src/kdf.rs b/keymanager-lib/src/kdf.rs similarity index 99% rename from keymanager-runtime/src/kdf.rs rename to keymanager-lib/src/kdf.rs index aed3e43c275..2ad79960860 100644 --- a/keymanager-runtime/src/kdf.rs +++ b/keymanager-lib/src/kdf.rs @@ -1,4 +1,4 @@ -///! Key Derivation Function +///! Key Derivation Function. use std::sync::{Arc, RwLock}; use failure::Fallible; @@ -11,7 +11,7 @@ use sp800_185::{CShake, KMac}; use x25519_dalek; use zeroize::Zeroize; -use oasis_core_keymanager_api::{ +use oasis_core_keymanager_api_common::{ ContractKey, InitRequest, InitResponse, KeyManagerError, MasterSecret, PrivateKey, PublicKey, ReplicateResponse, RequestIds, SignedInitResponse, SignedPublicKey, StateKey, INIT_RESPONSE_CONTEXT, PUBLIC_KEY_CONTEXT, diff --git a/keymanager-lib/src/lib.rs b/keymanager-lib/src/lib.rs new file mode 100644 index 00000000000..353bc42dda6 --- /dev/null +++ b/keymanager-lib/src/lib.rs @@ -0,0 +1,16 @@ +extern crate failure; +extern crate io_context; +extern crate lazy_static; +extern crate lru; +extern crate oasis_core_keymanager_api_common; +extern crate oasis_core_keymanager_client; +extern crate oasis_core_runtime; +extern crate rand; +extern crate sp800_185; +extern crate tiny_keccak; +extern crate x25519_dalek; +extern crate zeroize; + +pub mod context; +pub mod kdf; +pub mod policy; diff --git a/keymanager-runtime/src/policy.rs b/keymanager-lib/src/policy.rs similarity index 99% rename from keymanager-runtime/src/policy.rs rename to keymanager-lib/src/policy.rs index 39615175068..6048f55a79f 100644 --- a/keymanager-runtime/src/policy.rs +++ b/keymanager-lib/src/policy.rs @@ -9,7 +9,7 @@ use lazy_static::lazy_static; use sgx_isa::Keypolicy; use tiny_keccak::sha3_256; -use oasis_core_keymanager_api::*; +use oasis_core_keymanager_api_common::*; use oasis_core_runtime::{ common::{ cbor, diff --git a/keymanager-runtime/Cargo.toml b/keymanager-runtime/Cargo.toml index a03ce436104..df318cb93d0 100644 --- a/keymanager-runtime/Cargo.toml +++ b/keymanager-runtime/Cargo.toml @@ -12,14 +12,6 @@ threads = 2 [dependencies] oasis-core-runtime = { path = "../runtime" } oasis-core-keymanager-api = { path = "./api" } -oasis-core-keymanager-client = { path = "../keymanager-client" } +oasis-core-keymanager-lib = { path = "../keymanager-lib" } failure = "0.1.5" lazy_static = "1.3.0" -lru = "0.1.15" -io-context = "0.2.0" -rand = "0.6.5" -sgx-isa = { version = "0.3.0", features = ["sgxstd"] } -sp800-185 = "0.2.0" -tiny-keccak = "1.4.2" -x25519-dalek = "0.5.1" -zeroize = "0.6" diff --git a/keymanager-runtime/api/Cargo.toml b/keymanager-runtime/api/Cargo.toml index b2fa29f40f4..93e5dc103ba 100644 --- a/keymanager-runtime/api/Cargo.toml +++ b/keymanager-runtime/api/Cargo.toml @@ -5,6 +5,7 @@ authors = ["Oasis Labs Inc. "] [dependencies] base64 = "0.10.1" +oasis-core-keymanager-api-common = { path = "../../keymanager-api-common" } oasis-core-runtime = { path = "../../runtime" } serde = "1.0.71" serde_derive = "1.0" diff --git a/keymanager-runtime/api/src/api.rs b/keymanager-runtime/api/src/api.rs index 04d1cca9c94..16a85cc7bea 100644 --- a/keymanager-runtime/api/src/api.rs +++ b/keymanager-runtime/api/src/api.rs @@ -1,232 +1,4 @@ -use std::collections::HashMap; - -use base64; -use failure::Fail; -use rand::{rngs::OsRng, Rng}; -use serde_derive::{Deserialize, Serialize}; -use x25519_dalek; - -use oasis_core_runtime::{ - common::{ - crypto::signature::{Signature, SignatureBundle}, - runtime::RuntimeId, - sgx::avr::EnclaveIdentity, - }, - impl_bytes, runtime_api, -}; - -impl_bytes!(ContractId, 32, "A 256-bit contract identifier."); -impl_bytes!(PrivateKey, 32, "A private key."); -impl_bytes!(PublicKey, 32, "A public key."); -impl_bytes!(StateKey, 32, "A state key."); -impl_bytes!(MasterSecret, 32, "A 256 bit master secret."); - -/// Key manager initialization request. -#[derive(Clone, Serialize, Deserialize)] -pub struct InitRequest { - /// Checksum for validating replication. - #[serde(with = "serde_bytes")] - pub checksum: Vec, - /// Policy for queries/replication. - #[serde(with = "serde_bytes")] - pub policy: Vec, - /// True iff the enclave may generate a new master secret. - pub may_generate: bool, -} - -/// Key manager initialization response. -#[derive(Clone, Serialize, Deserialize)] -pub struct InitResponse { - /// True iff the key manager thinks it's running in a secure mode. - pub is_secure: bool, - /// Checksum for validating replication. - #[serde(with = "serde_bytes")] - pub checksum: Vec, - /// Checksum for identifying policy. - #[serde(with = "serde_bytes")] - pub policy_checksum: Vec, -} - -/// Context used for the init response signature. -pub const INIT_RESPONSE_CONTEXT: &'static [u8] = b"oasis-core/keymanager: init response"; - -/// Signed InitResponse. -#[derive(Clone, Serialize, Deserialize)] -pub struct SignedInitResponse { - /// InitResponse. - pub init_response: InitResponse, - /// Sign(init_response). - pub signature: Signature, -} - -/// Key manager replication request. -#[derive(Clone, Serialize, Deserialize)] -pub struct ReplicateRequest { - // Empty. -} - -/// Key manager replication response. -#[derive(Clone, Serialize, Deserialize)] -pub struct ReplicateResponse { - pub master_secret: MasterSecret, -} - -/// Request runtime/contract id tuple. -#[derive(Clone, Serialize, Deserialize)] -pub struct RequestIds { - /// Runtime ID. - pub runtime_id: RuntimeId, - /// Contract ID. - pub contract_id: ContractId, -} - -impl RequestIds { - pub fn new(runtime_id: RuntimeId, contract_id: ContractId) -> Self { - Self { - runtime_id, - contract_id, - } - } - - pub fn to_cache_key(&self) -> Vec { - let mut k = self.runtime_id.as_ref().to_vec(); - k.extend_from_slice(self.contract_id.as_ref()); - k - } -} - -/// Keys for a contract. -#[derive(Clone, Serialize, Deserialize)] -pub struct ContractKey { - /// Input key pair (pk, sk) - pub input_keypair: InputKeyPair, - /// State encryption key - pub state_key: StateKey, - /// Checksum of the key manager state. - #[serde(with = "serde_bytes")] - pub checksum: Vec, -} - -impl ContractKey { - /// Generate a new random key (for testing). - pub fn generate_mock() -> Self { - let mut rng = OsRng::new().unwrap(); - let sk = x25519_dalek::StaticSecret::new(&mut rng); - let pk = x25519_dalek::PublicKey::from(&sk); - - let mut state_key = StateKey::default(); - rng.fill(&mut state_key.0); - - ContractKey::new( - PublicKey(*pk.as_bytes()), - PrivateKey(sk.to_bytes()), - state_key, - vec![], - ) - } - - /// Create a set of `ContractKey`. - pub fn new(pk: PublicKey, sk: PrivateKey, k: StateKey, sum: Vec) -> Self { - Self { - input_keypair: InputKeyPair::new(pk, sk), - state_key: k, - checksum: sum, - } - } - - /// Create a set of `ContractKey` with only the public key. - pub fn from_public_key(k: PublicKey, sum: Vec) -> Self { - Self { - input_keypair: InputKeyPair::new(k, PrivateKey::default()), - state_key: StateKey::default(), - checksum: sum, - } - } -} - -#[derive(Clone, Serialize, Deserialize)] -pub struct InputKeyPair { - /// Pk - pk: PublicKey, - /// sk - sk: PrivateKey, -} - -impl InputKeyPair { - pub fn new(pk: PublicKey, sk: PrivateKey) -> Self { - Self { pk, sk } - } - - pub fn get_pk(&self) -> PublicKey { - self.pk - } - - pub fn get_sk(&self) -> PrivateKey { - self.sk - } -} - -/// Context used for the public key signature. -pub const PUBLIC_KEY_CONTEXT: [u8; 8] = *b"EkKmPubK"; - -/// Signed public key. -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct SignedPublicKey { - /// Public key. - pub key: PublicKey, - /// Checksum of the key manager state. - #[serde(with = "serde_bytes")] - pub checksum: Vec, - /// Sign(sk, (key || checksum)) from the key manager. - pub signature: Signature, -} - -/// Key manager error. -#[derive(Debug, Fail)] -pub enum KeyManagerError { - #[fail(display = "client session is not authenticated")] - NotAuthenticated, - #[fail(display = "client session authentication is invalid")] - InvalidAuthentication, - #[fail(display = "key manager is not initialized")] - NotInitialized, - #[fail(display = "key manager state corrupted")] - StateCorrupted, - #[fail(display = "key manager replication required")] - ReplicationRequired, - #[fail(display = "policy rollback")] - PolicyRollback, - #[fail(display = "policy alteration, without serial increment")] - PolicyChanged, - #[fail(display = "policy is malformed or invalid")] - PolicyInvalid, - #[fail(display = "policy failed signature verification")] - PolicyInvalidSignature, - #[fail(display = "policy has insufficient signatures")] - PolicyInsufficientSignatures, -} - -/// Key manager access control policy. -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct PolicySGX { - pub serial: u32, - pub id: RuntimeId, - pub enclaves: HashMap, -} - -/// Per enclave key manager access control policy. -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct EnclavePolicySGX { - pub may_query: HashMap>, - pub may_replicate: Vec, -} - -/// Signed key manager access control policy. -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct SignedPolicySGX { - pub policy: PolicySGX, - pub signatures: Vec, -} +use oasis_core_runtime::runtime_api; runtime_api! { pub fn get_or_create_keys(RequestIds) -> ContractKey; diff --git a/keymanager-runtime/api/src/lib.rs b/keymanager-runtime/api/src/lib.rs index 77c68c04190..37a9706c880 100644 --- a/keymanager-runtime/api/src/lib.rs +++ b/keymanager-runtime/api/src/lib.rs @@ -1,7 +1,7 @@ -//! Key manager API. extern crate base64; extern crate failure; extern crate lazy_static; +extern crate oasis_core_keymanager_api_common; extern crate oasis_core_runtime; extern crate rand; extern crate rustc_hex; @@ -10,77 +10,38 @@ extern crate serde_bytes; extern crate serde_derive; extern crate x25519_dalek; -use failure::Fallible; -use lazy_static::lazy_static; use std::collections::HashSet; -use oasis_core_runtime::common::{ - cbor, - crypto::signature::{PrivateKey as OasisPrivateKey, PublicKey as OasisPublicKey}, -}; +use oasis_core_runtime::common::crypto::signature::PrivateKey as OasisPrivateKey; #[macro_use] mod api; // Re-exports. pub use api::*; - -lazy_static! { - static ref MULTISIG_KEYS: HashSet = { - let mut set = HashSet::new(); - if option_env!("OASIS_UNSAFE_KM_POLICY_KEYS").is_some() { - for seed in [ - "ekiden key manager test multisig key 0", - "ekiden key manager test multisig key 1", - "ekiden key manager test multisig key 2", - ].iter() { - let private_key = OasisPrivateKey::from_test_seed( - seed.to_string(), - ); - set.insert(private_key.public_key()); - } - } - - // TODO: Populate with the production keys as well. - set - }; -} -const MULTISIG_THRESHOLD: usize = 9001; // TODO: Set this to a real value. - -const POLICY_SIGN_CONTEXT: &'static [u8] = b"oasis-core/keymanager: policy"; - -impl SignedPolicySGX { - /// Verify the signatures and return the PolicySGX, if the signatures are correct. - pub fn verify(&self) -> Fallible { - // Verify the signatures. - let untrusted_policy_raw = cbor::to_vec(&self.policy); - let mut signers: HashSet = HashSet::new(); - for sig in &self.signatures { - let public_key = match sig.public_key { - Some(public_key) => public_key, - None => return Err(KeyManagerError::PolicyInvalid.into()), - }; - - if !sig - .signature - .verify(&public_key, &POLICY_SIGN_CONTEXT, &untrusted_policy_raw) - .is_ok() - { - return Err(KeyManagerError::PolicyInvalidSignature.into()); +pub use oasis_core_keymanager_api_common::*; + +/// Initializes the set of trusted policy signers for this key manager. +pub fn init_trusted_policy_signers() { + set_trusted_policy_signers(TrustedPolicySigners { + signers: { + let mut set = HashSet::new(); + if option_env!("OASIS_UNSAFE_KM_POLICY_KEYS").is_some() { + for seed in [ + "ekiden key manager test multisig key 0", + "ekiden key manager test multisig key 1", + "ekiden key manager test multisig key 2", + ] + .iter() + { + let private_key = OasisPrivateKey::from_test_seed(seed.to_string()); + set.insert(private_key.public_key()); + } } - signers.insert(public_key); - } - - // Ensure that enough valid signatures from trusted signers are present. - let signers: HashSet<_> = MULTISIG_KEYS.intersection(&signers).collect(); - let multisig_threshold = match option_env!("OASIS_UNSAFE_KM_POLICY_KEYS") { - Some(_) => 2, - None => MULTISIG_THRESHOLD, - }; - if signers.len() < multisig_threshold { - return Err(KeyManagerError::PolicyInsufficientSignatures.into()); - } - Ok(self.policy.clone()) - } + // TODO: Populate with the production keys as well. + set + }, + threshold: 9001, // TODO: Set this to a real value. + }); } diff --git a/keymanager-runtime/src/main.rs b/keymanager-runtime/src/main.rs index f4d9e93ac6c..bf3b10e7479 100644 --- a/keymanager-runtime/src/main.rs +++ b/keymanager-runtime/src/main.rs @@ -1,22 +1,12 @@ extern crate failure; -extern crate io_context; extern crate lazy_static; -extern crate lru; extern crate oasis_core_keymanager_api; -extern crate oasis_core_keymanager_client; +extern crate oasis_core_keymanager_lib; extern crate oasis_core_runtime; -extern crate rand; -extern crate sp800_185; -extern crate tiny_keccak; -extern crate x25519_dalek; -extern crate zeroize; use std::sync::Arc; -mod context; -mod kdf; mod methods; -mod policy; use failure::Fallible; @@ -32,7 +22,7 @@ use oasis_core_runtime::{ version_from_cargo, Protocol, RpcDemux, RpcDispatcher, TxnDispatcher, }; -use self::{kdf::Kdf, policy::Policy}; +use oasis_core_keymanager_lib::{context, kdf::Kdf, policy::Policy}; /// Initialize the Kdf. fn init_kdf(req: &InitRequest, ctx: &mut RpcContext) -> Fallible { @@ -47,6 +37,9 @@ fn main() { _rpc_demux: &mut RpcDemux, rpc: &mut RpcDispatcher, _txn: &mut TxnDispatcher| { + // Initialize the set of trusted policy signers. + init_trusted_policy_signers(); + // Register RPC methods exposed via EnclaveRPC to remote clients. { use crate::methods::*; diff --git a/keymanager-runtime/src/methods.rs b/keymanager-runtime/src/methods.rs index 43001d46841..297411460d8 100644 --- a/keymanager-runtime/src/methods.rs +++ b/keymanager-runtime/src/methods.rs @@ -3,7 +3,7 @@ use failure::Fallible; use oasis_core_keymanager_api::*; use oasis_core_runtime::rpc::Context as RpcContext; -use crate::{kdf::Kdf, policy::Policy}; +use oasis_core_keymanager_lib::{kdf::Kdf, policy::Policy}; /// See `Kdf::get_or_create_keys`. pub fn get_or_create_keys(req: &RequestIds, ctx: &mut RpcContext) -> Fallible {