diff --git a/.drone.yml b/.drone.yml index 6281f65b3..2d14348c6 100644 --- a/.drone.yml +++ b/.drone.yml @@ -59,7 +59,7 @@ steps: commands: - export CARGO_HOME=$PWD/drone/cargo - export CARGO_TARGET_DIR=$PWD/drone/target - - export PATH=$CARGO_HOME/bin:$PATH + - export PATH=$CARGO_HOME/bin:$CARGO_TARGET_DIR/debug:$PATH - export PYTHON_VENV_DIR=$PWD/drone/venv - export CRYPTO_CHAIN_ENABLE_SANITY_CHECKS=1 - LD_LIBRARY_PATH=/opt/intel/sgx-aesm-service/aesm /opt/intel/sgx-aesm-service/aesm/aesm_service --no-daemon & @@ -134,6 +134,6 @@ trigger: --- kind: signature -hmac: a14adf1ecbabfbdef92b2e94155e60a89ac84f16d6eb56f3ce5ca63329c0c400 +hmac: 6805b3eb9f8dc619bbca037606e8cd92f6f29105c586f87e4bba3887cb32165d ... diff --git a/chain-tx-enclave-next/enclave-ra/ra-client/src/verifier.rs b/chain-tx-enclave-next/enclave-ra/ra-client/src/verifier.rs index 3e33ceeb2..c8aad16af 100644 --- a/chain-tx-enclave-next/enclave-ra/ra-client/src/verifier.rs +++ b/chain-tx-enclave-next/enclave-ra/ra-client/src/verifier.rs @@ -101,6 +101,7 @@ impl EnclaveCertVerifier { not_after, } = certificate.tbs_certificate.validity; let now_sec = now.timestamp(); + if now_sec < not_before.to_timespec().sec { return Err(EnclaveCertVerifierError::CertificateNotBegin); } diff --git a/chain-tx-enclave-next/mls/Cargo.toml b/chain-tx-enclave-next/mls/Cargo.toml index 357a34ddf..8b3f811d3 100644 --- a/chain-tx-enclave-next/mls/Cargo.toml +++ b/chain-tx-enclave-next/mls/Cargo.toml @@ -17,6 +17,7 @@ secrecy = "0.6.0" hpke = "0.1.3" aead = "0.2.0" rand = "0.7" +chrono="0.4.11" ra-client = { path = "../enclave-ra/ra-client" } subtle = "2.2.3" diff --git a/chain-tx-enclave-next/mls/src/main.rs b/chain-tx-enclave-next/mls/src/main.rs index 66fb5af90..351f713d2 100644 --- a/chain-tx-enclave-next/mls/src/main.rs +++ b/chain-tx-enclave-next/mls/src/main.rs @@ -1,5 +1,6 @@ #[cfg(target_env = "sgx")] use std::io::{self, Write}; +pub type Timespec = u64; #[cfg(target_env = "sgx")] fn main() -> io::Result<()> { @@ -9,15 +10,25 @@ fn main() -> io::Result<()> { use rs_libc::alloc::*; use rustls::internal::msgs::codec::Codec; - let kp = OwnedKeyPackage::new( - EnclaveRaContext::new(&EnclaveRaConfig { - sp_addr: "0.0.0.0:8989".to_owned(), - certificate_validity_secs: 86400, - }) - .unwrap(), - ) - .unwrap(); - io::stdout().write_all(&kp.keypackage.get_encoding()) + let config = EnclaveRaContext::new(&EnclaveRaConfig { + sp_addr: "0.0.0.0:8989".to_owned(), + certificate_validity_secs: 86400, + }); + if config.is_err() { + eprintln!("cannot connect ra-sp-server, run ra-sp-server beforehand e.g.) ra-sp-server --quote-type Unlinkable --ias-key $IAS_API_KEY --spid $SPID") + } + let kp = OwnedKeyPackage::new(config.unwrap()).unwrap(); + + let now = chrono::Utc::now().timestamp() as u64; + let verication_result = kp + .keypackage + .verify(&*ra_client::ENCLAVE_CERT_VERIFIER, now); + if let Err(value) = verication_result { + eprintln!("verification_fail {}", value); + io::stdout().write_all("-1".as_bytes()) + } else { + io::stdout().write_all(&kp.keypackage.get_encoding()) + } } #[cfg(not(target_env = "sgx"))] diff --git a/client-cli/src/command/transaction_command.rs b/client-cli/src/command/transaction_command.rs index 20a91f6e5..c3c2e50e8 100644 --- a/client-cli/src/command/transaction_command.rs +++ b/client-cli/src/command/transaction_command.rs @@ -18,10 +18,7 @@ use chain_core::tx::data::attribute::TxAttributes; use chain_core::tx::data::input::TxoPointer; use chain_core::tx::data::output::TxOut; use chain_core::tx::TxAux; -use client_common::{ - gen_keypackage, verify_keypackage, Error, ErrorKind, PublicKey, Result, ResultExt, SecKey, - Transaction, -}; +use client_common::{Error, ErrorKind, PublicKey, Result, ResultExt, SecKey, Transaction}; use client_core::transaction_builder::SignedTransferTransaction; use client_core::types::{BalanceChange, TransactionPending}; use client_core::WalletClient; @@ -232,15 +229,6 @@ pub enum TransactionCommand { )] file: PathBuf, }, - GenKeypackage { - #[structopt( - name = "Path to mls enclave", - short = "p", - long = "path", - help = "Path to mls enclave" - )] - path: String, - }, } impl TransactionCommand { @@ -328,11 +316,6 @@ impl TransactionCommand { success(hex::encode(tx_id).as_str()); Ok(()) } - TransactionCommand::GenKeypackage { path } => { - let blob = gen_keypackage(&path)?; - success(&base64::encode(&blob)); - Ok(()) - } } } } @@ -1055,11 +1038,8 @@ fn ask_node_metadata() -> Result { ask("please enter base64 encoded keypackage:"); match base64::decode(&text().chain(|| (ErrorKind::IoError, "Unable to read keypackage"))?) { Ok(kp) => { - if let Err(err) = verify_keypackage(&kp) { - println!("invalid keypackage: {}", err); - } else { - break kp; - } + /* TODO : use dev-utils to verify*/ + break kp; } Err(err) => { println!("invalid base64: {}", err); diff --git a/client-common/Cargo.toml b/client-common/Cargo.toml index 30b7049ce..ec04a62c7 100644 --- a/client-common/Cargo.toml +++ b/client-common/Cargo.toml @@ -7,8 +7,7 @@ edition = "2018" [dependencies] chain-core = { path = "../chain-core" } chain-tx-filter = { path = "../chain-tx-filter" } -mls = { path = "../chain-tx-enclave-next/mls" } -ra-client = { path = "../chain-tx-enclave-next/enclave-ra/ra-client" } + aes = "0.3" aes-gcm-siv = "0.4" diff --git a/client-common/src/keypackage.rs b/client-common/src/keypackage.rs index a12bc65b3..c550efaf4 100644 --- a/client-common/src/keypackage.rs +++ b/client-common/src/keypackage.rs @@ -18,12 +18,17 @@ pub fn gen_keypackage(sgxs_path: &str) -> Result> { .output() .map_err(|err| Error::new(ErrorKind::RunEnclaveError, err.to_string()))?; if !output.status.success() { + let check_ra_sp_server="run ra-sp-server beforehand e.g.) ./ra-sp-server --quote-type Unlinkable --ias-key $IAS_API_KEY --spid $SPID"; + let check_mls = + "check mls path is correct e.g.) mls.sgxs, mls.sig <- two files are necessary"; return Err(Error::new( ErrorKind::RunEnclaveError, format!( - "enclave runner return error code: {:?}, stderr: {}", + "enclave runner return error code: {:?}, stderr: {}\n{}\n{}", output.status.code(), - String::from_utf8_lossy(&output.stderr) + String::from_utf8_lossy(&output.stderr), + check_ra_sp_server, + check_mls, ), )); } diff --git a/client-common/src/lib.rs b/client-common/src/lib.rs index 1a6c74c64..565bfb4d9 100644 --- a/client-common/src/lib.rs +++ b/client-common/src/lib.rs @@ -4,7 +4,6 @@ mod transaction; pub mod error; pub mod key; -pub mod keypackage; pub mod multi_sig_address; pub mod seckey; pub mod storage; @@ -15,8 +14,6 @@ pub use error::{Error, ErrorKind, Result, ResultExt}; #[doc(inline)] pub use key::{PrivateKey, PrivateKeyAction, PublicKey}; #[doc(inline)] -pub use keypackage::{gen_keypackage, verify_keypackage}; -#[doc(inline)] pub use multi_sig_address::MultiSigAddress; #[doc(inline)] pub use seckey::SecKey; diff --git a/client-rpc/src/rpc/staking_rpc.rs b/client-rpc/src/rpc/staking_rpc.rs index 21ca10a5c..2daaa9cfb 100644 --- a/client-rpc/src/rpc/staking_rpc.rs +++ b/client-rpc/src/rpc/staking_rpc.rs @@ -15,10 +15,7 @@ use chain_core::tx::data::address::ExtendedAddr; use chain_core::tx::data::attribute::TxAttributes; use chain_core::tx::data::input::TxoPointer; use chain_core::tx::data::output::TxOut; -use client_common::{ - gen_keypackage, verify_keypackage, Error, ErrorKind, PublicKey, Result as CommonResult, - ResultExt, Transaction, -}; +use client_common::{Error, ErrorKind, PublicKey, Result as CommonResult, ResultExt, Transaction}; use client_core::wallet::WalletRequest; use client_core::{MultiSigWalletClient, WalletClient}; use client_network::NetworkOpsClient; @@ -73,9 +70,6 @@ pub trait StakingRpc: Send + Sync { staking_address: String, keypackage: String, ) -> Result; - - #[rpc(name = "staking_genKeyPackage")] - fn gen_keypackage(&self, path: String) -> Result; } pub struct StakingRpcImpl @@ -443,11 +437,6 @@ where Ok(hex::encode(transaction.tx_id())) } - - fn gen_keypackage(&self, path: String) -> Result { - let keypackage = gen_keypackage(&path).map_err(to_rpc_error)?; - Ok(base64::encode(&keypackage)) - } } fn get_node_metadata( @@ -479,9 +468,6 @@ fn get_node_metadata( .err_kind(ErrorKind::InvalidInput, || "invalid base64") .map_err(to_rpc_error)?; - #[cfg(not(feature = "mock-enclave"))] - verify_keypackage(&keypackage).map_err(to_rpc_error)?; - Ok(CouncilNode { name: validator_name.to_string(), security_contact: None, diff --git a/dev-utils/Cargo.toml b/dev-utils/Cargo.toml index 765afb7b3..571aba6b4 100644 --- a/dev-utils/Cargo.toml +++ b/dev-utils/Cargo.toml @@ -24,6 +24,8 @@ secstr = "0.4.0" parity-scale-codec = { version = "1.3" } secp256k1zkp = { git = "https://github.com/crypto-com/rust-secp256k1-zkp.git", rev = "f8759809f6e3fed793b37166f7cd91c57cdb2eab", features = ["recovery", "endomorphism"] } base64 = "0.11" +mls = { path = "../chain-tx-enclave-next/mls" } +ra-client = { path = "../chain-tx-enclave-next/enclave-ra/ra-client" } [features] mock-enclave = ["chain-abci/mock-enclave"] diff --git a/dev-utils/src/commands.rs b/dev-utils/src/commands.rs index b811101ec..b2e641c5b 100644 --- a/dev-utils/src/commands.rs +++ b/dev-utils/src/commands.rs @@ -1,6 +1,7 @@ mod genesis_command; mod genesis_dev_config; mod init_command; +mod keypackage_command; mod run_command; mod stop_command; mod test_vector_command; @@ -8,6 +9,7 @@ mod test_vector_command; pub use self::genesis_command::GenesisCommand; pub use self::genesis_dev_config::{GenesisDevConfig, InitialFeePolicy}; pub use self::init_command::InitCommand; +pub use self::keypackage_command::KeypackageCommand; pub use self::run_command::RunCommand; pub use self::stop_command::StopCommand; pub use self::test_vector_command::TestVectorCommand; diff --git a/dev-utils/src/commands/genesis_command.rs b/dev-utils/src/commands/genesis_command.rs index 42b33cce3..9c3de3ef5 100644 --- a/dev-utils/src/commands/genesis_command.rs +++ b/dev-utils/src/commands/genesis_command.rs @@ -23,7 +23,6 @@ use client_common::{ErrorKind, Result, ResultExt}; use crate::commands::genesis_dev_config::GenesisDevConfig; use client_core::wallet::syncer::compute_genesis_hash; - #[derive(Debug, StructOpt)] pub enum GenesisCommand { #[structopt(name = "generate", about = "Generate new genesis.json")] diff --git a/dev-utils/src/commands/init_command.rs b/dev-utils/src/commands/init_command.rs index c8a483ea0..18df8baf3 100644 --- a/dev-utils/src/commands/init_command.rs +++ b/dev-utils/src/commands/init_command.rs @@ -8,12 +8,13 @@ use quest::{password, success}; use secstr::SecUtf8; use serde_json::json; +use crate::verify_keypackage; use chain_core::init::{address::RedeemAddress, coin::Coin, config::InitConfig}; use chain_core::state::account::ConfidentialInit; use chain_core::state::tendermint::{TendermintValidator, TendermintValidatorPubKey}; use client_common::storage::SledStorage; use client_common::tendermint::types::Time; -use client_common::{verify_keypackage, Error, ErrorKind, Result, ResultExt}; +use client_common::{Error, ErrorKind, Result, ResultExt}; use client_core::types::WalletKind; use client_core::wallet::{DefaultWalletClient, WalletClient}; diff --git a/dev-utils/src/commands/keypackage_command.rs b/dev-utils/src/commands/keypackage_command.rs new file mode 100644 index 000000000..cab3692b7 --- /dev/null +++ b/dev-utils/src/commands/keypackage_command.rs @@ -0,0 +1,55 @@ +use crate::{gen_keypackage, verify_keypackage}; +use client_common::{ErrorKind, Result, ResultExt}; +use structopt::StructOpt; +#[derive(Debug, StructOpt)] +pub enum KeypackageCommand { + #[structopt(name = "generate", about = "Generate key-package")] + GenKeypackage { + #[structopt( + name = "Path to mls enclave", + short = "p", + long = "path", + help = "Path to mls enclave (e.g. mls.sgxs)" + )] + path: String, + #[structopt( + name = "Path to key-package", + short = "o", + long = "output", + help = "Path to key-package (e.g. key.txt)" + )] + output: String, + }, + #[structopt(name = "verify", about = "Verify key-package")] + VerifyKeypackage { + #[structopt( + name = "Path to base64 encoded keypackage", + short = "p", + long = "path", + help = "Path to keypackage enclave which is base64 encoded" + )] + path: String, + }, +} + +impl KeypackageCommand { + pub fn execute(&self) -> Result<()> { + match self { + KeypackageCommand::GenKeypackage { path, output } => { + let blob = gen_keypackage(&path)?; + let encoded = base64::encode(&blob); + std::fs::write(&output, &encoded) + .chain(|| (ErrorKind::IoError, "Cannot write encoded key-package"))?; + Ok(()) + } + KeypackageCommand::VerifyKeypackage { path } => { + let contents = std::fs::read_to_string(&path) + .chain(|| (ErrorKind::IoError, "Unable to read keypackage"))?; + let kp = base64::decode(&contents) + .chain(|| (ErrorKind::IoError, "Unable to parse keypackage"))?; + verify_keypackage(&kp)?; + Ok(()) + } + } + } +} diff --git a/dev-utils/src/dev_utils.rs b/dev-utils/src/dev_utils.rs index 4a80eaafa..2fa23cacf 100644 --- a/dev-utils/src/dev_utils.rs +++ b/dev-utils/src/dev_utils.rs @@ -2,7 +2,9 @@ use structopt::StructOpt; use client_common::Result; -use crate::commands::{GenesisCommand, InitCommand, RunCommand, StopCommand, TestVectorCommand}; +use crate::commands::{ + GenesisCommand, InitCommand, KeypackageCommand, RunCommand, StopCommand, TestVectorCommand, +}; const NETWORKS: [&str; 3] = ["devnet", "testnet", "mainnet"]; /// Enum used to specify subcommands under dev-utils @@ -60,6 +62,13 @@ pub enum DevUtils { )] seed: String, }, + + /// Used for working with tendermint's genesis.json + #[structopt(name = "keypackage", about = "Commands for keypackage")] + Keypackage { + #[structopt(subcommand)] + keypackage_command: KeypackageCommand, + }, } impl DevUtils { @@ -82,6 +91,7 @@ impl DevUtils { let test_vectors_command = TestVectorCommand::new(network.clone(), seed.clone()); test_vectors_command.execute() } + DevUtils::Keypackage { keypackage_command } => keypackage_command.execute(), } } } diff --git a/dev-utils/src/keypackage.rs b/dev-utils/src/keypackage.rs new file mode 100644 index 000000000..d23d0e496 --- /dev/null +++ b/dev-utils/src/keypackage.rs @@ -0,0 +1,50 @@ +//! gen keypackage in the client +use std::convert::TryInto; +use std::process; + +use chain_core::common::Timespec; +use chrono::offset::Utc; +use mls::{Codec, KeyPackage}; +use ra_client::ENCLAVE_CERT_VERIFIER; + +use client_common::{Error, ErrorKind, Result, ResultExt}; + +/// gen keypackage by running mls enclave +pub fn gen_keypackage(sgxs_path: &str) -> Result> { + let output = process::Command::new("ftxsgx-runner") + .arg(sgxs_path) + .arg("--signature") + .arg("coresident") + .output() + .map_err(|err| Error::new(ErrorKind::RunEnclaveError, err.to_string()))?; + if !output.status.success() { + let check_ra_sp_server="run ra-sp-server beforehand e.g.) ./ra-sp-server --quote-type Unlinkable --ias-key $IAS_API_KEY --spid $SPID"; + let check_mls = + "check mls path is correct e.g.) mls.sgxs, mls.sig <- two files are necessary"; + return Err(Error::new( + ErrorKind::RunEnclaveError, + format!( + "enclave runner return error code: {:?}, stderr: {}\n{}\n{}", + output.status.code(), + String::from_utf8_lossy(&output.stderr), + check_ra_sp_server, + check_mls, + ), + )); + } + Ok(output.stdout) +} + +/// verify serialized keypackage blob against current time +pub fn verify_keypackage(keypackage: &[u8]) -> Result<()> { + let now: Timespec = Utc::now() + .timestamp() + .try_into() + .expect("reversed time flow"); + let keypackage = KeyPackage::read_bytes(keypackage) + .err_kind(ErrorKind::InvalidInput, || "keypackage decode fail")?; + keypackage + .verify(&*ENCLAVE_CERT_VERIFIER, now) + .err_kind(ErrorKind::InvalidInput, || "keypackage verify fail")?; + Ok(()) +} diff --git a/dev-utils/src/main.rs b/dev-utils/src/main.rs index e8c30ca1e..5d833ffce 100644 --- a/dev-utils/src/main.rs +++ b/dev-utils/src/main.rs @@ -1,11 +1,13 @@ mod commands; mod dev_utils; +mod keypackage; use structopt::StructOpt; use client_common::Result; use self::dev_utils::DevUtils; +pub use keypackage::{gen_keypackage, verify_keypackage}; fn main() { if let Err(err) = execute() { diff --git a/integration-tests/bot/chainrpc.py b/integration-tests/bot/chainrpc.py index 5a0b79a71..9b5e3e361 100755 --- a/integration-tests/bot/chainrpc.py +++ b/integration-tests/bot/chainrpc.py @@ -5,6 +5,9 @@ import base64 import binascii import json +import subprocess +import tempfile + from jsonrpcclient import request from decouple import config @@ -270,7 +273,10 @@ def gen_keypackage(self, path=MLS_ENCLAVE_PATH): if self.client.mock_mode: return '' else: - return self.client.call('staking_genKeyPackage', path) + temp = tempfile.NamedTemporaryFile() + subprocess.run(["dev-utils", "keypackage", "generate","--path", path, "--output", temp.name]) + value= temp.read().decode('utf-8') + return value class MultiSig: