Skip to content

Commit

Permalink
pruntime: Don't change cpu_svn while handover key
Browse files Browse the repository at this point in the history
  • Loading branch information
kvinwang committed Sep 18, 2023
1 parent b916fca commit dbff650
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 54 deletions.
2 changes: 1 addition & 1 deletion crates/phactory/api/proto
Submodule proto updated 1 files
+4 −2 pruntime_rpc.proto
20 changes: 17 additions & 3 deletions crates/phactory/pal/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
//! Platform abstraction layer for Trusted Execution Environments

use core::time::Duration;
use std::fmt::Debug;
use std::path::Path;
use core::time::Duration;

use phala_types::AttestationProvider;

Expand All @@ -11,12 +11,26 @@ pub use phactory_api::prpc::MemoryUsage;
pub trait ErrorType: Debug + Into<anyhow::Error> {}
impl<T: Debug + Into<anyhow::Error>> ErrorType for T {}

pub struct UnsealedData {
pub data: Vec<u8>,
pub svn: Vec<u8>,
}

pub trait Sealing {
type SealError: ErrorType;
type UnsealError: ErrorType;

fn seal_data(&self, path: impl AsRef<Path>, data: &[u8]) -> Result<(), Self::SealError>;
fn unseal_data(&self, path: impl AsRef<Path>) -> Result<Option<Vec<u8>>, Self::UnsealError>;
fn current_svn(&self) -> Result<Vec<u8>, Self::SealError>;
fn seal_data(
&self,
path: impl AsRef<Path>,
data: &[u8],
svn: Option<&[u8]>,
) -> Result<(), Self::SealError>;
fn unseal_data(
&self,
path: impl AsRef<Path>,
) -> Result<Option<UnsealedData>, Self::UnsealError>;
}

pub trait RA {
Expand Down
31 changes: 24 additions & 7 deletions crates/phactory/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,14 +338,21 @@ impl<Platform: pal::Platform> Phactory<Platform> {
predefined_identity_key: Option<sr25519::Pair>,
) -> Result<PersistentRuntimeData> {
let data = if let Some(identity_sk) = predefined_identity_key {
self.save_runtime_data(genesis_block_hash, para_id, identity_sk, false, true)?
self.save_runtime_data(genesis_block_hash, para_id, identity_sk, false, true, None)?
} else {
match Self::load_runtime_data(&self.platform, &self.args.sealing_path) {
Ok(data) => data,
Err(Error::PersistentRuntimeNotFound) => {
warn!("Persistent data not found.");
let identity_sk = new_sr25519_key();
self.save_runtime_data(genesis_block_hash, para_id, identity_sk, true, false)?
self.save_runtime_data(
genesis_block_hash,
para_id,
identity_sk,
true,
false,
None,
)?
}
Err(err) => return Err(anyhow!("Failed to load persistent data: {}", err)),
}
Expand Down Expand Up @@ -375,6 +382,7 @@ impl<Platform: pal::Platform> Phactory<Platform> {
sr25519_sk: sr25519::Pair,
trusted_sk: bool,
dev_mode: bool,
svn: Option<&[u8]>,
) -> Result<PersistentRuntimeData> {
// Put in PresistentRuntimeData
let sk = sr25519_sk.dump_secret_key();
Expand All @@ -392,7 +400,7 @@ impl<Platform: pal::Platform> Phactory<Platform> {
info!("Length of encoded slice: {}", encoded_vec.len());
let filepath = PathBuf::from(&self.args.sealing_path).join(RUNTIME_SEALED_DATA_FILE);
self.platform
.seal_data(filepath, &encoded_vec)
.seal_data(filepath, &encoded_vec, svn)
.map_err(Into::into)
.context("Failed to seal runtime data")?;
info!("Persistent Runtime Data V2 saved");
Expand All @@ -401,22 +409,31 @@ impl<Platform: pal::Platform> Phactory<Platform> {
}

/// Loads the persistent runtime data from the sealing path
fn persistent_runtime_data(&self) -> Result<PersistentRuntimeData, Error> {
Self::load_runtime_data(&self.platform, &self.args.sealing_path)
fn load_persistent_runtime_data_with_svn(
&self,
) -> Result<(PersistentRuntimeData, Vec<u8>), Error> {
Self::load_runtime_data_with_svn(&self.platform, &self.args.sealing_path)
}

fn load_runtime_data(
platform: &Platform,
sealing_path: &str,
) -> Result<PersistentRuntimeData, Error> {
Self::load_runtime_data_with_svn(platform, sealing_path).map(|(data, _)| data)
}

fn load_runtime_data_with_svn(
platform: &Platform,
sealing_path: &str,
) -> Result<(PersistentRuntimeData, Vec<u8>), Error> {
let filepath = PathBuf::from(sealing_path).join(RUNTIME_SEALED_DATA_FILE);
let data = platform
let pal::UnsealedData { data, svn } = platform
.unseal_data(filepath)
.map_err(Into::into)?
.ok_or(Error::PersistentRuntimeNotFound)?;
let data: RuntimeDataSeal = Decode::decode(&mut &data[..]).map_err(Error::DecodeError)?;
match data {
RuntimeDataSeal::V1(data) => Ok(data),
RuntimeDataSeal::V1(data) => Ok((data, svn)),
}
}

Expand Down
71 changes: 51 additions & 20 deletions crates/phactory/src/prpc_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ use phala_pallets::utils::attestation::{validate as validate_attestation_report,
use phala_types::contract::contract_id_preimage;
use phala_types::{
contract, messaging::EncryptedKey, wrap_content_to_sign, AttestationReport,
ChallengeHandlerInfo, EncryptedWorkerKey, HandoverChallenge, SignedContentType,
VersionedWorkerEndpoints, WorkerEndpointPayload, WorkerPublicKey, WorkerRegistrationInfoV2,
ChallengeHandlerInfo, EncryptedWorkerKeyV0, EncryptedWorkerKeyV1, HandoverChallenge,
SignedContentType, VersionedWorkerEndpoints, WorkerEndpointPayload, WorkerPublicKey,
WorkerRegistrationInfoV2,
};
use sp_application_crypto::UncheckedFrom;
use tracing::{error, info};
Expand Down Expand Up @@ -1637,7 +1638,9 @@ impl<Platform: pal::Platform + Serialize + DeserializeOwned> PhactoryApi for Rpc
// Share the key with attestation
let ecdh_pubkey = challenge_handler.ecdh_pubkey;
let iv = crate::generate_random_iv();
let runtime_data = phactory.persistent_runtime_data().map_err(from_display)?;
let (runtime_data, svn) = phactory
.load_persistent_runtime_data_with_svn()
.map_err(from_display)?;
let (my_identity_key, _) = runtime_data.decode_keys();
let (ecdh_pubkey, encrypted_key) = key_share::encrypt_secret_to(
&my_identity_key,
Expand All @@ -1652,21 +1655,22 @@ impl<Platform: pal::Platform + Serialize + DeserializeOwned> PhactoryApi for Rpc
encrypted_key,
iv,
};
let runtime_state = phactory.runtime_state()?;
let genesis_block_hash = runtime_state.genesis_block_hash;
let encrypted_worker_key = EncryptedWorkerKey {
let genesis_block_hash = runtime_data.genesis_block_hash;
let encrypted_worker_key = EncryptedWorkerKeyV1 {
genesis_block_hash,
para_id: runtime_state.para_id,
para_id: runtime_data.para_id,
dev_mode,
encrypted_key,
svn,
};

let worker_key_hash = sp_core::hashing::blake2_256(&encrypted_worker_key.encode());
let encoded_worker_key = encrypted_worker_key.encode();
let payload_hash = sp_core::hashing::blake2_256(&encoded_worker_key);
let attestation = if !dev_mode && in_sgx {
Some(create_attestation_report_on(
&phactory.platform,
attestation_provider,
&worker_key_hash,
&payload_hash,
phactory.args.ra_timeout,
phactory.args.ra_max_retries,
)?)
Expand All @@ -1675,10 +1679,11 @@ impl<Platform: pal::Platform + Serialize + DeserializeOwned> PhactoryApi for Rpc
None
};

Ok(pb::HandoverWorkerKey::new(
encrypted_worker_key,
Ok(pb::HandoverWorkerKey {
attestation,
))
encoded_worker_key_v0: None,
encoded_worker_key_v1: Some(encoded_worker_key),
})
}

// WorkerKey Handover Client
Expand Down Expand Up @@ -1741,12 +1746,37 @@ impl<Platform: pal::Platform + Serialize + DeserializeOwned> PhactoryApi for Rpc

async fn handover_receive(&mut self, request: pb::HandoverWorkerKey) -> RpcResult<()> {
let mut phactory = self.lock_phactory(false, true)?;
let encrypted_worker_key = request.decode_worker_key().map_err(from_display)?;

let dev_mode = encrypted_worker_key.dev_mode;
let received_key;
let payload_hash;
match (
&request.encoded_worker_key_v0,
&request.encoded_worker_key_v1,
) {
(None, None) => return Err(from_display("No worker key found")),
(Some(_), Some(_)) => return Err(from_display("Both v0 and v1 worker key found")),
(Some(encoded), None) => {
payload_hash = sp_core::hashing::blake2_256(encoded);
let v0 = EncryptedWorkerKeyV0::decode(&mut &encoded[..])
.map_err(|_| from_display("Decode worker key failed"))?;
received_key = EncryptedWorkerKeyV1 {
genesis_block_hash: v0.genesis_block_hash,
para_id: v0.para_id,
dev_mode: v0.dev_mode,
encrypted_key: v0.encrypted_key,
// If the version of the key is v0, it must from pRuntime v2.0 or v2.1, which never load the
// keys with a different svn. Thus, we can safely set the svn to current svn.
svn: phactory.platform.current_svn().map_err(from_debug)?,
};
}
(None, Some(encoded)) => {
payload_hash = sp_core::hashing::blake2_256(encoded);
received_key = EncryptedWorkerKeyV1::decode(&mut &encoded[..])
.map_err(|_| from_display("Decode worker key failed"))?;
}
}
let dev_mode = received_key.dev_mode;
// verify RA report
if !dev_mode {
let worker_key_hash = sp_core::hashing::blake2_256(&encrypted_worker_key.encode());
let raw_attestation = request
.attestation
.ok_or_else(|| from_display("Server attestation not found"))?;
Expand All @@ -1755,7 +1785,7 @@ impl<Platform: pal::Platform + Serialize + DeserializeOwned> PhactoryApi for Rpc
.map_err(|_| from_display("Decode server attestation failed"))?;
validate_attestation_report(
attn_to_validate,
&worker_key_hash,
&payload_hash,
now(),
false,
vec![],
Expand All @@ -1766,7 +1796,7 @@ impl<Platform: pal::Platform + Serialize + DeserializeOwned> PhactoryApi for Rpc
info!("Skip server RA report check for dev mode key");
}

let encrypted_key = encrypted_worker_key.encrypted_key;
let encrypted_key = received_key.encrypted_key;
let my_ecdh_key = phactory
.handover_ecdh_key
.as_ref()
Expand All @@ -1782,11 +1812,12 @@ impl<Platform: pal::Platform + Serialize + DeserializeOwned> PhactoryApi for Rpc
// only seal if the key is successfully updated
phactory
.save_runtime_data(
encrypted_worker_key.genesis_block_hash,
encrypted_worker_key.para_id,
received_key.genesis_block_hash,
received_key.para_id,
sr25519::Pair::restore_from_secret_key(&secret),
false, // we are not sure whether this key is injected
dev_mode,
Some(&received_key.svn),
)
.map_err(from_display)?;

Expand Down
8 changes: 4 additions & 4 deletions crates/phactory/src/system/master_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use sp_core::sr25519;

use phala_crypto::sr25519::{Signature, Signing, Sr25519SecretKey};

use crate::pal::Sealing;
use crate::pal::{Sealing, UnsealedData};

/// Master key filepath
pub const MASTER_KEY_FILE: &str = "master_key.seal";
Expand Down Expand Up @@ -66,7 +66,7 @@ pub fn seal(
info!("Seal master key to {}", filepath.as_path().display());
// TODO.shelven: seal with identity key so the newly handovered pRuntime do not need to do an extra sync to get master
// key
sys.seal_data(filepath, &data.encode())
sys.seal_data(filepath, &data.encode(), None)
.expect("Seal master key failed");
}

Expand All @@ -84,7 +84,7 @@ pub fn try_unseal(
) -> Vec<RotatedMasterKey> {
let filepath = master_key_file_path(&sealing_path);
info!("Unseal master key from {}", filepath.as_path().display());
let sealed_data = match sys
let UnsealedData { data, .. } = match sys
.unseal_data(&filepath)
.expect("Unseal master key failed")
{
Expand All @@ -96,7 +96,7 @@ pub fn try_unseal(
};

let versioned_data =
MasterKeySeal::decode(&mut &sealed_data[..]).expect("Failed to decode sealed master key");
MasterKeySeal::decode(&mut &data[..]).expect("Failed to decode sealed master key");

#[allow(clippy::infallible_destructuring_match)]
let secrets = match versioned_data {
Expand Down
11 changes: 10 additions & 1 deletion crates/phala-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -530,13 +530,22 @@ pub struct ChallengeHandlerInfo<BlockNumber> {
}

#[derive(Encode, Decode, Debug, Clone, PartialEq, Eq, TypeInfo)]
pub struct EncryptedWorkerKey {
pub struct EncryptedWorkerKeyV0 {
pub genesis_block_hash: H256,
pub para_id: u32,
pub dev_mode: bool,
pub encrypted_key: messaging::EncryptedKey,
}

#[derive(Encode, Decode, Debug, Clone, PartialEq, Eq, TypeInfo)]
pub struct EncryptedWorkerKeyV1 {
pub genesis_block_hash: H256,
pub para_id: u32,
pub dev_mode: bool,
pub encrypted_key: messaging::EncryptedKey,
pub svn: Vec<u8>,
}

#[derive(Encode, Decode, Debug, Clone, PartialEq, Eq, TypeInfo)]
pub struct WorkerRegistrationInfo<AccountId> {
pub version: u32,
Expand Down
Loading

0 comments on commit dbff650

Please sign in to comment.