From 87ed65a1a3196361a518387fe742ed9a8069337d Mon Sep 17 00:00:00 2001 From: Reuven Podmazo Date: Mon, 13 Jul 2020 20:41:04 +0300 Subject: [PATCH 1/4] errors in new node authentication now show readable messages --- .../packages/enclave-ffi-types/src/lib.rs | 4 +- .../packages/enclave-ffi-types/src/types.rs | 22 ++++++++++ cosmwasm/packages/sgx-vm/src/attestation.rs | 20 +++++---- cosmwasm/packages/sgx-vm/src/seed.rs | 4 +- cosmwasm/packages/wasmi-runtime/Enclave.edl | 2 +- .../wasmi-runtime/src/registration/cert.rs | 5 +-- .../wasmi-runtime/src/registration/onchain.rs | 28 ++++++------ go-cosmwasm/src/error/rust.rs | 13 ++++++ go-cosmwasm/src/lib.rs | 43 ++++++++++--------- 9 files changed, 89 insertions(+), 52 deletions(-) diff --git a/cosmwasm/packages/enclave-ffi-types/src/lib.rs b/cosmwasm/packages/enclave-ffi-types/src/lib.rs index d2a494a16..fb1ad90a1 100644 --- a/cosmwasm/packages/enclave-ffi-types/src/lib.rs +++ b/cosmwasm/packages/enclave-ffi-types/src/lib.rs @@ -4,8 +4,8 @@ mod types; pub use types::{ - Ctx, EnclaveBuffer, EnclaveError, HandleResult, InitResult, OcallReturn, QueryResult, - UntrustedVmError, UserSpaceBuffer, + Ctx, EnclaveBuffer, EnclaveError, HandleResult, InitResult, NodeAuthResult, OcallReturn, + QueryResult, UntrustedVmError, UserSpaceBuffer, }; pub const ENCRYPTED_SEED_SIZE: usize = 48; diff --git a/cosmwasm/packages/enclave-ffi-types/src/types.rs b/cosmwasm/packages/enclave-ffi-types/src/types.rs index 30559ea08..e846a6828 100644 --- a/cosmwasm/packages/enclave-ffi-types/src/types.rs +++ b/cosmwasm/packages/enclave-ffi-types/src/types.rs @@ -92,6 +92,28 @@ pub enum EnclaveError { Unknown, } +/// This type represents the possible error conditions that can be encountered in the +/// enclave while authenticating a new node in the network. +/// cbindgen:prefix-with-name +#[repr(C)] +#[derive(Debug, Display, PartialEq, Eq)] +pub enum NodeAuthResult { + Success, + #[display(fmt = "Enclave received invalid inputs")] + InvalidInput, + #[display(fmt = "The provided certificate was invalid")] + InvalidCert, + #[display(fmt = "Writing to file system from the enclave failed")] + CantWriteToStorage, + #[display(fmt = "The public key in the certificate appears to be malformed")] + MalformedPublicKey, + #[display(fmt = "Encrypting the seed failed")] + SeedEncryptionFailed, + EnclaveFailure, + #[display(fmt = "Enclave panicked :( please file a bug report!")] + Panic, +} + /// This type holds a pointer to a VmError that is boxed on the untrusted side // `VmError` is the standard error type for the `cosmwasm-sgx-vm` layer. // During an ocall, we call into the original implementation of `db_read`, `db_write`, and `db_remove`. diff --git a/cosmwasm/packages/sgx-vm/src/attestation.rs b/cosmwasm/packages/sgx-vm/src/attestation.rs index 68531220c..481396a5a 100644 --- a/cosmwasm/packages/sgx-vm/src/attestation.rs +++ b/cosmwasm/packages/sgx-vm/src/attestation.rs @@ -7,7 +7,7 @@ use log::*; use sgx_types::*; use sgx_types::{sgx_status_t, SgxResult}; -use enclave_ffi_types::ENCRYPTED_SEED_SIZE; +use enclave_ffi_types::{NodeAuthResult, ENCRYPTED_SEED_SIZE}; use crate::enclave::get_enclave; @@ -18,7 +18,7 @@ extern "C" { ) -> sgx_status_t; pub fn ecall_authenticate_new_node( eid: sgx_enclave_id_t, - retval: *mut sgx_status_t, + retval: *mut NodeAuthResult, cert: *const u8, cert_len: u32, seed: &mut [u8; ENCRYPTED_SEED_SIZE], @@ -122,7 +122,7 @@ pub extern "C" fn ocall_get_update_info( unsafe { sgx_report_attestation_status(platform_blob, enclave_trusted, update_info) } } -pub fn create_attestation_report_u() -> SgxResult { +pub fn create_attestation_report_u() -> SgxResult<()> { info!("Hello from just before initializing - create_attestation_report_u"); let enclave = get_enclave()?; info!("Hello from just after initializing - create_attestation_report_u"); @@ -140,17 +140,19 @@ pub fn create_attestation_report_u() -> SgxResult { return Err(retval); } - Ok(sgx_status_t::SGX_SUCCESS) + Ok(()) } -pub fn untrusted_get_encrypted_seed(cert: &[u8]) -> SgxResult<[u8; ENCRYPTED_SEED_SIZE]> { +pub fn untrusted_get_encrypted_seed( + cert: &[u8], +) -> SgxResult> { info!("Hello from just before initializing - untrusted_get_encrypted_seed"); let enclave = get_enclave()?; info!("Hello from just after initializing - untrusted_get_encrypted_seed"); info!("Entered produce report"); let eid = enclave.geteid(); - let mut retval = sgx_status_t::SGX_SUCCESS; + let mut retval = NodeAuthResult::Success; let mut seed = [0u8; ENCRYPTED_SEED_SIZE]; let status = unsafe { ecall_authenticate_new_node( @@ -166,8 +168,8 @@ pub fn untrusted_get_encrypted_seed(cert: &[u8]) -> SgxResult<[u8; ENCRYPTED_SEE return Err(status); } - if retval != sgx_status_t::SGX_SUCCESS { - return Err(retval); + if retval != NodeAuthResult::Success { + return Ok(Err(retval)); } if seed.is_empty() { @@ -175,7 +177,7 @@ pub fn untrusted_get_encrypted_seed(cert: &[u8]) -> SgxResult<[u8; ENCRYPTED_SEE return Err(sgx_status_t::SGX_ERROR_UNEXPECTED); } - Ok(seed) + Ok(Ok(seed)) } #[cfg(test)] diff --git a/cosmwasm/packages/sgx-vm/src/seed.rs b/cosmwasm/packages/sgx-vm/src/seed.rs index e20b4048e..4f8392225 100644 --- a/cosmwasm/packages/sgx-vm/src/seed.rs +++ b/cosmwasm/packages/sgx-vm/src/seed.rs @@ -27,7 +27,7 @@ extern "C" { ) -> sgx_status_t; } -pub fn untrusted_init_node(master_cert: &[u8], encrypted_seed: &[u8]) -> SgxResult { +pub fn untrusted_init_node(master_cert: &[u8], encrypted_seed: &[u8]) -> SgxResult<()> { info!("Hello from just before initializing - init_node"); let enclave = get_enclave()?; info!("Hello from just after initializing - init_node"); @@ -54,7 +54,7 @@ pub fn untrusted_init_node(master_cert: &[u8], encrypted_seed: &[u8]) -> SgxResu return Err(ret); } - Ok(sgx_status_t::SGX_SUCCESS) + Ok(()) } pub fn untrusted_key_gen() -> SgxResult<[u8; 32]> { diff --git a/cosmwasm/packages/wasmi-runtime/Enclave.edl b/cosmwasm/packages/wasmi-runtime/Enclave.edl index 5a8323674..56999e681 100644 --- a/cosmwasm/packages/wasmi-runtime/Enclave.edl +++ b/cosmwasm/packages/wasmi-runtime/Enclave.edl @@ -29,7 +29,7 @@ enclave { public sgx_status_t ecall_get_attestation_report(); - public sgx_status_t ecall_authenticate_new_node( + public NodeAuthResult ecall_authenticate_new_node( [in, count=cert_len] const uint8_t* cert, uintptr_t cert_len, [out, count=48] uint8_t* seed diff --git a/cosmwasm/packages/wasmi-runtime/src/registration/cert.rs b/cosmwasm/packages/wasmi-runtime/src/registration/cert.rs index 6922118db..ac8ab7b23 100644 --- a/cosmwasm/packages/wasmi-runtime/src/registration/cert.rs +++ b/cosmwasm/packages/wasmi-runtime/src/registration/cert.rs @@ -300,10 +300,7 @@ pub fn verify_ra_cert(cert_der: &[u8]) -> SgxResult> { // 2. Verify quote status (mandatory field) - match verify_quote_status(report.sgx_quote_status) { - Ok(_) => (), - Err(e) => return Err(e), - } + verify_quote_status(report.sgx_quote_status)?; // verify certificate match SIGNING_METHOD { diff --git a/cosmwasm/packages/wasmi-runtime/src/registration/onchain.rs b/cosmwasm/packages/wasmi-runtime/src/registration/onchain.rs index 3c44bd8fa..e9cdd6417 100644 --- a/cosmwasm/packages/wasmi-runtime/src/registration/onchain.rs +++ b/cosmwasm/packages/wasmi-runtime/src/registration/onchain.rs @@ -2,9 +2,10 @@ /// These functions run on-chain and must be deterministic across all nodes /// use log::*; -use sgx_types::{sgx_status_t, SgxResult}; use std::panic; +use enclave_ffi_types::NodeAuthResult; + use crate::consts::ENCRYPTED_SEED_SIZE; use crate::crypto::PUBLIC_KEY_SIZE; use crate::storage::write_to_untrusted; @@ -32,24 +33,22 @@ pub unsafe extern "C" fn ecall_authenticate_new_node( cert: *const u8, cert_len: u32, seed: &mut [u8; ENCRYPTED_SEED_SIZE], -) -> sgx_status_t { +) -> NodeAuthResult { if let Err(_e) = validate_mut_ptr(seed.as_mut_ptr(), seed.len()) { - return sgx_status_t::SGX_ERROR_UNEXPECTED; + return NodeAuthResult::InvalidInput; } - if let Err(_e) = validate_const_ptr(cert, cert_len as usize) { - return sgx_status_t::SGX_ERROR_UNEXPECTED; + return NodeAuthResult::InvalidInput; } let cert_slice = std::slice::from_raw_parts(cert, cert_len as usize); - let result = panic::catch_unwind(|| -> SgxResult> { + let result = panic::catch_unwind(|| -> Result, NodeAuthResult> { // verify certificate, and return the public key in the extra data of the report let pk = verify_ra_cert(cert_slice).map_err(|verification_status| { error!("Error in validating certificate: {:?}", verification_status); - if let Err(write_status) = write_to_untrusted(cert_slice, "failed_cert.der") { - write_status - } else { - verification_status + match write_to_untrusted(cert_slice, "failed_cert.der") { + Err(_) => NodeAuthResult::CantWriteToStorage, + Ok(_) => NodeAuthResult::InvalidCert, } })?; @@ -59,7 +58,7 @@ pub unsafe extern "C" fn ecall_authenticate_new_node( "Got public key from certificate with the wrong size: {:?}", pk.len() ); - return Err(sgx_status_t::SGX_ERROR_UNEXPECTED); + return Err(NodeAuthResult::MalformedPublicKey); } let mut target_public_key: [u8; 32] = [0u8; 32]; @@ -69,7 +68,8 @@ pub unsafe extern "C" fn ecall_authenticate_new_node( &target_public_key.to_vec() ); - let res: Vec = encrypt_seed(target_public_key)?; + let res: Vec = + encrypt_seed(target_public_key).map_err(|_| NodeAuthResult::SeedEncryptionFailed)?; Ok(res) }); @@ -78,12 +78,12 @@ pub unsafe extern "C" fn ecall_authenticate_new_node( match res { Ok(res) => { seed.copy_from_slice(&res); - sgx_status_t::SGX_SUCCESS + NodeAuthResult::Success } Err(e) => e, } } else { error!("Enclave call ecall_authenticate_new_node panic!"); - sgx_status_t::SGX_ERROR_UNEXPECTED + NodeAuthResult::Panic } } diff --git a/go-cosmwasm/src/error/rust.rs b/go-cosmwasm/src/error/rust.rs index fbb0b7f7d..46e02e6b0 100644 --- a/go-cosmwasm/src/error/rust.rs +++ b/go-cosmwasm/src/error/rust.rs @@ -35,6 +35,12 @@ pub enum Error { #[cfg(feature = "backtraces")] backtrace: snafu::Backtrace, }, + #[snafu(display("Error calling the enclave: {}", msg))] + EnclaveErr { + msg: String, + #[cfg(feature = "backtraces")] + backtrace: snafu::Backtrace, + }, } impl Error { @@ -60,6 +66,13 @@ impl Error { .build() } + pub fn enclave_err(msg: S) -> Self { + EnclaveErr { + msg: msg.to_string(), + } + .build() + } + pub fn out_of_gas() -> Self { OutOfGas {}.build() } diff --git a/go-cosmwasm/src/lib.rs b/go-cosmwasm/src/lib.rs index 18365ad7c..357d816da 100644 --- a/go-cosmwasm/src/lib.rs +++ b/go-cosmwasm/src/lib.rs @@ -29,7 +29,6 @@ use cosmwasm_sgx_vm::{ }; use ctor::ctor; -use log; use log::*; #[ctor] @@ -54,24 +53,30 @@ pub extern "C" fn get_encrypted_seed(cert: Buffer, err: Option<&mut Buffer>) -> info!("Hello from get_encrypted_seed"); let cert_slice = match unsafe { cert.read() } { None => { - set_error(Error::vm_err("Attestation Certificate is empty"), err); + set_error(Error::empty_arg("attestation_cert"), err); return Buffer::default(); } Some(r) => r, }; info!("Hello from right before untrusted_get_encrypted_seed"); - let result = match untrusted_get_encrypted_seed(cert_slice) { + match untrusted_get_encrypted_seed(cert_slice) { Err(e) => { - error!("Error :("); - set_error(Error::vm_err(e.to_string()), err); - return Buffer::default(); + // An error happened in the SGX sdk. + error!("SGX error :( {}", e); + set_error(Error::enclave_err(e.to_string()), err); + Buffer::default() } - Ok(r) => { + Ok(Err(e)) => { + // An error was returned from the enclave. + error!("Enclave error :( {}", e); + set_error(Error::enclave_err(e.to_string()), err); + Buffer::default() + } + Ok(Ok(seed)) => { clear_error(); - Buffer::from_vec(r.to_vec()) + Buffer::from_vec(seed.to_vec()) } - }; - return result; + } } #[no_mangle] @@ -80,7 +85,7 @@ pub extern "C" fn init_bootstrap(err: Option<&mut Buffer>) -> Buffer { match untrusted_init_bootstrap() { Err(e) => { error!("Error :("); - set_error(Error::vm_err(e.to_string()), err); + set_error(Error::enclave_err(e.to_string()), err); Buffer::default() } Ok(r) => { @@ -98,37 +103,35 @@ pub extern "C" fn init_node( ) -> bool { let pk_slice = match unsafe { master_cert.read() } { None => { - set_error(Error::vm_err("Public key is empty"), err); + set_error(Error::empty_arg("master_cert"), err); return false; } Some(r) => r, }; let encrypted_seed_slice = match unsafe { encrypted_seed.read() } { None => { - set_error(Error::vm_err("Encrypted seed is empty"), err); + set_error(Error::empty_arg("encrypted_seed"), err); return false; } Some(r) => r, }; - let result = match untrusted_init_node(pk_slice, encrypted_seed_slice) { + match untrusted_init_node(pk_slice, encrypted_seed_slice) { Ok(_) => { clear_error(); true } Err(e) => { - set_error(Error::vm_err(e.to_string()), err); + set_error(Error::enclave_err(e.to_string()), err); false } - }; - - result + } } #[no_mangle] pub extern "C" fn create_attestation_report(err: Option<&mut Buffer>) -> bool { if let Err(status) = create_attestation_report_u() { - set_error(Error::vm_err(status.to_string()), err); + set_error(Error::enclave_err(status.to_string()), err); return false; } clear_error(); @@ -470,7 +473,7 @@ pub extern "C" fn key_gen(err: Option<&mut Buffer>) -> Buffer { match untrusted_key_gen() { Err(e) => { error!("Error :("); - set_error(Error::vm_err(e.to_string()), err); + set_error(Error::enclave_err(e.to_string()), err); Buffer::default() } Ok(r) => { From 05787bae238375af0e95662e3006ba56451f9590 Mon Sep 17 00:00:00 2001 From: Reuven Podmazo Date: Mon, 13 Jul 2020 21:20:08 +0300 Subject: [PATCH 2/4] added missing declaration in cbindgen.toml --- cosmwasm/packages/enclave-ffi-types/cbindgen.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/cosmwasm/packages/enclave-ffi-types/cbindgen.toml b/cosmwasm/packages/enclave-ffi-types/cbindgen.toml index 3d424415f..2b45b887d 100644 --- a/cosmwasm/packages/enclave-ffi-types/cbindgen.toml +++ b/cosmwasm/packages/enclave-ffi-types/cbindgen.toml @@ -32,6 +32,7 @@ style = "both" include = [ "UserSpaceBuffer", "EnclaveBuffer", + "NodeAuthResult", "Ctx", "InitResult", "HandleResult", From 2b401713558b96b1e560ca51492bc6cdf89c82e3 Mon Sep 17 00:00:00 2001 From: Reuven Podmazo Date: Wed, 15 Jul 2020 13:08:48 +0300 Subject: [PATCH 3/4] removed unused variant (EnclaveFailure) from NodeAuthResult --- cosmwasm/packages/enclave-ffi-types/src/types.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/cosmwasm/packages/enclave-ffi-types/src/types.rs b/cosmwasm/packages/enclave-ffi-types/src/types.rs index e846a6828..10f18d5cb 100644 --- a/cosmwasm/packages/enclave-ffi-types/src/types.rs +++ b/cosmwasm/packages/enclave-ffi-types/src/types.rs @@ -109,7 +109,6 @@ pub enum NodeAuthResult { MalformedPublicKey, #[display(fmt = "Encrypting the seed failed")] SeedEncryptionFailed, - EnclaveFailure, #[display(fmt = "Enclave panicked :( please file a bug report!")] Panic, } From 9d73d5a74c4114c127304dac297f598893742076 Mon Sep 17 00:00:00 2001 From: Reuven Podmazo Date: Wed, 15 Jul 2020 13:49:19 +0300 Subject: [PATCH 4/4] renamed go_cosmwasm::Error:EnclaveError to GoCwEnclaveError --- go-cosmwasm/src/error/rust.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/go-cosmwasm/src/error/rust.rs b/go-cosmwasm/src/error/rust.rs index 46e02e6b0..090997c28 100644 --- a/go-cosmwasm/src/error/rust.rs +++ b/go-cosmwasm/src/error/rust.rs @@ -35,8 +35,8 @@ pub enum Error { #[cfg(feature = "backtraces")] backtrace: snafu::Backtrace, }, - #[snafu(display("Error calling the enclave: {}", msg))] - EnclaveErr { + #[snafu(display("{}", msg))] + GoCwEnclaveError { msg: String, #[cfg(feature = "backtraces")] backtrace: snafu::Backtrace, @@ -67,7 +67,7 @@ impl Error { } pub fn enclave_err(msg: S) -> Self { - EnclaveErr { + GoCwEnclaveError { msg: msg.to_string(), } .build()