diff --git a/Makefile b/Makefile index 3113fb8e8..ec62db89c 100644 --- a/Makefile +++ b/Makefile @@ -254,7 +254,7 @@ build-testnet-bootstrap: --build-arg SECRET_NODE_TYPE=BOOTSTRAP \ --build-arg CGO_LDFLAGS=${DOCKER_CGO_LDFLAGS} \ -f deployment/dockerfiles/Dockerfile \ - -t ghcr.io/scrtlabs/secret-network-bootstrap-testnet:v$(VERSION) \ + -t ghcr.io/scrtlabs/testnet:${DOCKER_TAG} \ --target release-image . build-testnet: @@ -268,7 +268,7 @@ build-testnet: --build-arg SECRET_NODE_TYPE=NODE \ --build-arg CGO_LDFLAGS=${DOCKER_CGO_LDFLAGS} \ -f deployment/dockerfiles/Dockerfile \ - -t ghcr.io/scrtlabs/secret-network-node-testnet:v$(VERSION) \ + -t ghcr.io/scrtlabs/testnet:${DOCKER_TAG} \ --target release-image . DOCKER_BUILDKIT=1 docker build --build-arg BUILDKIT_INLINE_CACHE=1 \ --secret id=API_KEY,src=api_key.txt \ @@ -277,7 +277,7 @@ build-testnet: --build-arg SGX_MODE=HW \ --build-arg CGO_LDFLAGS=${DOCKER_CGO_LDFLAGS} \ --build-arg DB_BACKEND=${DB_BACKEND} \ - --cache-from ghcr.io/scrtlabs/secret-network-node-testnet:v$(VERSION) \ + --cache-from ghcr.io/scrtlabs/testnet:${DOCKER_TAG} \ -f deployment/dockerfiles/Dockerfile \ -t deb_build \ --target build-deb . diff --git a/cosmwasm/enclaves/execute/src/registration/attestation.rs b/cosmwasm/enclaves/execute/src/registration/attestation.rs index b0001742a..37a61b2da 100644 --- a/cosmwasm/enclaves/execute/src/registration/attestation.rs +++ b/cosmwasm/enclaves/execute/src/registration/attestation.rs @@ -46,8 +46,9 @@ use enclave_crypto::consts::SigningMethod; #[cfg(all(feature = "SGX_MODE_HW"))] use enclave_crypto::consts::{ - CONSENSUS_SEED_SEALING_PATH, DEFAULT_SGX_SECRET_PATH, NODE_ENCRYPTED_SEED_KEY_FILE, - NODE_EXCHANGE_KEY_FILE, REGISTRATION_KEY_SEALING_PATH, + CURRENT_CONSENSUS_SEED_SEALING_PATH, DEFAULT_SGX_SECRET_PATH, + GENESIS_CONSENSUS_SEED_SEALING_PATH, NODE_ENCRYPTED_SEED_KEY_CURRENT_FILE, + NODE_ENCRYPTED_SEED_KEY_GENESIS_FILE, NODE_EXCHANGE_KEY_FILE, REGISTRATION_KEY_SEALING_PATH, }; #[cfg(all(feature = "SGX_MODE_HW"))] use std::sgxfs::remove as SgxFsRemove; @@ -92,6 +93,7 @@ pub fn create_attestation_certificate( kp: &KeyPair, _sign_type: sgx_quote_sign_type_t, _api_key: &[u8], + _challenge: Option<[u8; 4]>, ) -> Result<(Vec, Vec), sgx_status_t> { // init sgx ecc let ecc_handle = SgxEccHandle::new(); @@ -115,6 +117,7 @@ pub fn create_attestation_certificate( kp: &KeyPair, sign_type: sgx_quote_sign_type_t, api_key: &[u8], + challenge: Option<&[u8]>, ) -> Result<(Vec, Vec), sgx_status_t> { // extract private key from KeyPair let ecc_handle = SgxEccHandle::new(); @@ -124,13 +127,14 @@ pub fn create_attestation_certificate( let (prv_k, pub_k) = ecc_handle.create_key_pair().unwrap(); // call create_report using the secp256k1 public key, and __not__ the P256 one - let signed_report = match create_attestation_report(&kp.get_pubkey(), sign_type, api_key) { - Ok(r) => r, - Err(e) => { - error!("Error creating attestation report"); - return Err(e); - } - }; + let signed_report = + match create_attestation_report(&kp.get_pubkey(), sign_type, api_key, challenge) { + Ok(r) => r, + Err(e) => { + error!("Error creating attestation report"); + return Err(e); + } + }; let payload: String = serde_json::to_string(&signed_report).map_err(|_| { error!("Error serializing report. May be malformed, or badly encoded"); @@ -148,11 +152,17 @@ pub fn create_attestation_certificate( pub fn validate_report(cert: &[u8], _override_verify: Option) { let _ = verify_ra_cert(cert, None).map_err(|e| { info!("Error validating created certificate: {:?}", e); - let _ = SgxFsRemove(CONSENSUS_SEED_SEALING_PATH.as_str()); + let _ = SgxFsRemove(GENESIS_CONSENSUS_SEED_SEALING_PATH.as_str()); + let _ = SgxFsRemove(CURRENT_CONSENSUS_SEED_SEALING_PATH.as_str()); let _ = SgxFsRemove(REGISTRATION_KEY_SEALING_PATH.as_str()); let _ = SgxFsRemove( std::path::Path::new(DEFAULT_SGX_SECRET_PATH) - .join(NODE_ENCRYPTED_SEED_KEY_FILE) + .join(NODE_ENCRYPTED_SEED_KEY_GENESIS_FILE) + .as_path(), + ); + let _ = SgxFsRemove( + std::path::Path::new(DEFAULT_SGX_SECRET_PATH) + .join(NODE_ENCRYPTED_SEED_KEY_CURRENT_FILE) .as_path(), ); let _ = SgxFsRemove( @@ -175,6 +185,7 @@ pub fn create_attestation_report( pub_k: &[u8; 32], sign_type: sgx_quote_sign_type_t, api_key_file: &[u8], + challenge: Option<&[u8]>, ) -> Result { // Workflow: // (1) ocall to get the target_info structure (ti) and epid group id (eg) @@ -231,6 +242,9 @@ pub fn create_attestation_report( let mut report_data: sgx_report_data_t = sgx_report_data_t::default(); report_data.d[..32].copy_from_slice(pub_k); + if let Some(c) = challenge { + report_data.d[32..36].copy_from_slice(c); + } let rep = match rsgx_create_report(&ti, &report_data) { Ok(r) => { diff --git a/cosmwasm/enclaves/execute/src/registration/offchain.rs b/cosmwasm/enclaves/execute/src/registration/offchain.rs index 173c47d0d..0d6bf7dfb 100644 --- a/cosmwasm/enclaves/execute/src/registration/offchain.rs +++ b/cosmwasm/enclaves/execute/src/registration/offchain.rs @@ -6,20 +6,33 @@ use log::*; #[cfg(feature = "SGX_MODE_HW")] use sgx_types::{sgx_platform_info_t, sgx_update_info_bit_t}; use sgx_types::{sgx_status_t, SgxResult}; +use std::any::Any; use std::slice; -#[cfg(feature = "SGX_MODE_HW")] -use enclave_ffi_types::NodeAuthResult; - use enclave_crypto::consts::{ SigningMethod, ATTESTATION_CERT_PATH, ENCRYPTED_SEED_SIZE, IO_CERTIFICATE_SAVE_PATH, SEED_EXCH_CERTIFICATE_SAVE_PATH, SIGNATURE_TYPE, }; -use enclave_crypto::{KeyPair, Keychain, KEY_MANAGER, PUBLIC_KEY_SIZE}; +use enclave_crypto::{ + key_manager, CryptoError, KeyPair, Keychain, Seed, KEY_MANAGER, PUBLIC_KEY_SIZE, +}; +#[cfg(feature = "SGX_MODE_HW")] +use enclave_ffi_types::NodeAuthResult; use enclave_utils::pointers::validate_mut_slice; use enclave_utils::storage::write_to_untrusted; use enclave_utils::{validate_const_ptr, validate_mut_ptr}; +use sgx_types::c_int; +use std::net::SocketAddr; +use std::os::unix::io::IntoRawFd; +use std::{ + io::{BufReader, ErrorKind, Read, Write}, + net::TcpStream, + str, + string::String, + sync::Arc, +}; + #[cfg(feature = "SGX_MODE_HW")] use crate::registration::report::AttestationReport; @@ -171,8 +184,12 @@ pub unsafe extern "C" fn ecall_init_node( } // this validates the cert and handles the "what if it fails" inside as well - let res = - create_attestation_certificate(&temp_key_result.unwrap(), SIGNATURE_TYPE, api_key_slice); + let res = create_attestation_certificate( + &temp_key_result.as_ref().unwrap(), + SIGNATURE_TYPE, + api_key_slice, + None, + ); if res.is_err() { error!("Error starting node, might not be updated",); return sgx_status_t::SGX_ERROR_UNEXPECTED; @@ -226,8 +243,14 @@ pub unsafe extern "C" fn ecall_init_node( Err(status) => return status, }; - let new_consensus_seed = match key_manager.get_next_consensus_seed_from_service(0, genesis_seed) - { + trace!("HERE {}", line!()); + let new_consensus_seed = match get_next_consensus_seed_from_service( + &mut key_manager, + 0, + genesis_seed, + api_key_slice, + KEY_MANAGER.get_registration_key().unwrap(), + ) { Ok(s) => s, Err(e) => { error!("Consensus seed failure: {}", e as u64); @@ -282,7 +305,7 @@ pub unsafe extern "C" fn ecall_get_attestation_report( &kp.get_pubkey().to_vec() ); let (_private_key_der, cert) = - match create_attestation_certificate(&kp, SIGNATURE_TYPE, api_key_slice) { + match create_attestation_certificate(&kp, SIGNATURE_TYPE, api_key_slice, None) { Err(e) => { warn!("Error in create_attestation_certificate: {:?}", e); return e; @@ -332,7 +355,7 @@ pub unsafe extern "C" fn ecall_key_gen( } pub fn attest_from_key(kp: &KeyPair, save_path: &str, api_key: &[u8]) -> SgxResult<()> { - let (_, cert) = match create_attestation_certificate(kp, SIGNATURE_TYPE, api_key) { + let (_, cert) = match create_attestation_certificate(kp, SIGNATURE_TYPE, api_key, None) { Err(e) => { error!("Error in create_attestation_certificate: {:?}", e); return Err(e); @@ -347,6 +370,351 @@ pub fn attest_from_key(kp: &KeyPair, save_path: &str, api_key: &[u8]) -> SgxResu Ok(()) } +fn create_socket_to_service(host_name: &str) -> Result { + use std::net::ToSocketAddrs; + + let mut addr: Option = None; + + let addrs = (host_name, 3000).to_socket_addrs().map_err(|err| { + trace!("Error while trying to convert to socket addrs {:?}", err); + CryptoError::SocketCreationError + })?; + + for a in addrs { + if let SocketAddr::V4(_) = a { + addr = Some(a); + } + } + + if addr.is_none() { + trace!("Failed to resolve the IPv4 address of the service"); + return Err(CryptoError::IPv4LookupError); + } + + let sock = TcpStream::connect(&addr.unwrap()).map_err(|err| { + trace!( + "Error while trying to connect to service with addr: {:?}, err: {:?}", + addr, + err + ); + CryptoError::SocketCreationError + })?; + + return Ok(sock.into_raw_fd()); +} + +fn make_client_config() -> rustls::ClientConfig { + let mut config = rustls::ClientConfig::new(); + + pub const SSS_CA: &[u8] = include_bytes!("sss_ca.pem"); + let mut pem_reader = BufReader::new(SSS_CA); + + let mut root_store = rustls::RootCertStore::empty(); + root_store + .add_pem_file(&mut pem_reader) + .expect("Failed to add PEM"); + + config.root_store = root_store; + + config +} + +fn get_body_from_response(resp: &[u8]) -> Result { + trace!("get_body_from_response"); + let mut headers = [httparse::EMPTY_HEADER; 16]; + let mut respp = httparse::Response::new(&mut headers); + let result = respp.parse(resp); + trace!("parse result {:?}", result); + + match respp.code { + Some(200) => info!("Response okay"), + Some(401) => { + error!("Unauthorized Failed to authenticate or authorize request."); + return Err(CryptoError::BadResponse); + } + Some(404) => { + error!("Not Found"); + return Err(CryptoError::BadResponse); + } + Some(500) => { + error!("Internal error occurred in SSS server"); + return Err(CryptoError::BadResponse); + } + Some(503) => { + error!( + "Service is currently not able to process the request (due to + a temporary overloading or maintenance). This is a + temporary state – the same request can be repeated after + some time. " + ); + return Err(CryptoError::BadResponse); + } + _ => { + error!( + "response from SSS server :{} - unknown error or response code", + respp.code.unwrap() + ); + return Err(CryptoError::BadResponse); + } + } + + let mut len_num: u32 = 0; + trace!( + "LIORRRR headers {:?} {}", + respp.headers, + respp.headers.len() + ); + + for i in 0..respp.headers.len() { + let h = respp.headers[i]; + //println!("{} : {}", h.name, str::from_utf8(h.value).unwrap()); + match h.name.to_lowercase().as_str() { + "content-length" => { + let len_str = String::from_utf8(h.value.to_vec()).unwrap(); + len_num = len_str.parse::().unwrap(); + trace!("content length = {}", len_num); + } + _ => (), + } + } + + let mut body = "".to_string(); + if len_num != 0 { + let header_len = result.unwrap().unwrap(); + let resp_body = &resp[header_len..]; + body = str::from_utf8(resp_body).unwrap().to_string(); + } + + Ok(body) +} + +fn get_challenge_from_service( + fd: c_int, + host_name: &str, + api_key: &[u8], + kp: KeyPair, +) -> Result, CryptoError> { + pub const CHALLENGE_ENDPOINT: &str = "/authenticate"; + trace!("HERE {}", line!()); + let (_, cert) = match create_attestation_certificate(&kp, SIGNATURE_TYPE, api_key, None) { + Err(_) => { + trace!("Failed to get certificate from intel for seed service"); + return Err(CryptoError::IntelCommunicationError); + } + Ok(res) => res, + }; + + let serialized_cert = base64::encode(cert); + + trace!("HERE {}", line!()); + let req = format!("GET {} HTTP/1.1\r\nHOST: {}\r\nContent-Length:{}\r\nContent-Type: application/json\r\nConnection: close\r\n\r\n{}", + CHALLENGE_ENDPOINT, + host_name, + serialized_cert.len(), + serialized_cert); + + trace!("{}", req); + let config = make_client_config(); + let dns_name = webpki::DNSNameRef::try_from_ascii_str(host_name).unwrap(); + let mut sess = rustls::ClientSession::new(&Arc::new(config), dns_name); + let mut sock = TcpStream::new(fd).map_err(|err| { + trace!("Error while trying to create TcpStream {:?}", err); + CryptoError::SocketCreationError + })?; + let mut tls = rustls::Stream::new(&mut sess, &mut sock); + + let _result = tls.write(req.as_bytes()); + let mut plaintext = Vec::new(); + + info!("write complete"); + + match tls.read_to_end(&mut plaintext) { + Ok(_) => {} + Err(e) => { + if e.kind() != ErrorKind::ConnectionAborted { + trace!("Error while reading https response {:?}", e); + return Err(CryptoError::SSSCommunicationError); + } + } + } + + info!("read_to_end complete"); + + let challenge = base64::decode(get_body_from_response(&plaintext)?).map_err(|err| { + trace!("https response wasn't base64 {:?}", err); + CryptoError::SSSCommunicationError + })?; + + info!("LIORRR challenge {:?}", challenge); + + Ok(challenge) +} + +fn get_seed_from_service( + fd: c_int, + host_name: &str, + api_key: &[u8], + kp: KeyPair, + id: u16, + challenge: Vec, +) -> Result, CryptoError> { + pub const SEED_ENDPOINT: &str = "/seed/"; + trace!("HERE {}", line!()); + let (_, cert) = match create_attestation_certificate( + &kp, + SIGNATURE_TYPE, + api_key, + Some(challenge.as_slice()), + ) { + Err(_) => { + trace!("Failed to get certificate from intel for seed service"); + return Err(CryptoError::IntelCommunicationError); + } + Ok(res) => res, + }; + + let serialized_cert = base64::encode(cert); + + trace!("HERE {}", line!()); + let req = format!("GET {} HTTP/1.1\r\nHOST: {}\r\nContent-Length:{}\r\nContent-Type: application/json\r\nConnection: close\r\n\r\n{}", + format!("{}{}", SEED_ENDPOINT, id), + host_name, + serialized_cert.len(), + serialized_cert); + + trace!("{}", req); + let config = make_client_config(); + let dns_name = webpki::DNSNameRef::try_from_ascii_str(host_name).unwrap(); + let mut sess = rustls::ClientSession::new(&Arc::new(config), dns_name); + let mut sock = TcpStream::new(fd).map_err(|err| { + trace!("Error while trying to create TcpStream {:?}", err); + CryptoError::SocketCreationError + })?; + let mut tls = rustls::Stream::new(&mut sess, &mut sock); + + let _result = tls.write(req.as_bytes()); + let mut plaintext = Vec::new(); + + info!("write complete"); + + match tls.read_to_end(&mut plaintext) { + Ok(_) => {} + Err(e) => { + if e.kind() != ErrorKind::ConnectionAborted { + trace!("Error while reading https response {:?}", e); + return Err(CryptoError::SSSCommunicationError); + } + } + } + + info!("read_to_end complete"); + + let seed = base64::decode(get_body_from_response(&plaintext)?).map_err(|err| { + trace!("https response wasn't base64 {:?}", err); + CryptoError::SSSCommunicationError + })?; + + info!("LIORRR seed {:?}", seed); + + Ok(seed) +} + +fn try_get_consensus_seed_from_service( + id: u16, + api_key: &[u8], + kp: KeyPair, +) -> Result { + #[cfg(feature = "production")] + pub const SEED_SERVICE_DNS: &'static str = "sss.scrtlabs.com"; + #[cfg(not(feature = "production"))] + pub const SEED_SERVICE_DNS: &'static str = "sssd.scrtlabs.com"; + + trace!("HERE {}", line!()); + let mut socket = create_socket_to_service(SEED_SERVICE_DNS)?; + trace!("HERE {}", line!()); + let challenge = get_challenge_from_service(socket, SEED_SERVICE_DNS, api_key, kp)?; + socket = create_socket_to_service(SEED_SERVICE_DNS)?; + get_seed_from_service(socket, SEED_SERVICE_DNS, api_key, kp, id, challenge)?; + let s: [u8; 32] = [ + 0, id as u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, + ]; + let mut seed = Seed::default(); + seed.as_mut().copy_from_slice(&s); + Ok(seed) +} + +// Retreiving consensus seed from SingularitySeedService +// id - The desired seed id +// retries - The amount of times to retry upon failure. 0 means infinite +fn get_next_consensus_seed_from_service( + key_manager: &mut Keychain, + retries: u8, + genesis_seed: Seed, + api_key: &[u8], + kp: KeyPair, +) -> Result { + let mut opt_seed: Result = Err(CryptoError::DecryptionError); + + match retries { + 0 => { + trace!("Looping consensus seed lookup forever"); + loop { + if let Ok(seed) = try_get_consensus_seed_from_service( + key_manager.get_consensus_seed_id(), + api_key, + kp, + ) { + opt_seed = Ok(seed); + break; + } + } + } + _ => { + for try_id in 1..retries + 1 { + trace!("Looping consensus seed lookup {}/{}", try_id, retries); + match try_get_consensus_seed_from_service( + key_manager.get_consensus_seed_id(), + api_key, + kp, + ) { + Ok(seed) => { + opt_seed = Ok(seed); + break; + } + Err(e) => opt_seed = Err(e), + } + } + } + }; + + if let Err(e) = opt_seed { + return Err(e); + } + + let mut seed = opt_seed?; + trace!( + "LIORRR Genesis seed is {:?} service seed is {:?}", + genesis_seed.as_slice(), + seed.as_slice() + ); + + // XOR the seed with the genesis seed + let mut seed_vec = seed.as_mut().to_vec(); + seed_vec + .iter_mut() + .zip(genesis_seed.as_slice().to_vec().iter()) + .for_each(|(x1, x2)| *x1 ^= *x2); + + seed.as_mut().copy_from_slice(seed_vec.as_slice()); + + trace!("LIORRR New seed is {:?}", seed.as_slice()); + + trace!("Successfully fetched consensus seed from service"); + key_manager.inc_consensus_seed_id(); + Ok(seed) +} + #[cfg(not(feature = "SGX_MODE_HW"))] fn print_local_report_info(_cert: &[u8]) {} diff --git a/cosmwasm/enclaves/execute/src/registration/sss_ca.pem b/cosmwasm/enclaves/execute/src/registration/sss_ca.pem new file mode 100644 index 000000000..bab26e836 --- /dev/null +++ b/cosmwasm/enclaves/execute/src/registration/sss_ca.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDuTCCAqGgAwIBAgIURkvISRNEOxvXLqCooLVnoJJneWwwDQYJKoZIhvcNAQEL +BQAwbDELMAkGA1UEBhMCSUwxEzARBgNVBAgMClNvbWUtU3RhdGUxEjAQBgNVBAoM +CVNDUlQgTGFiczESMBAGA1UEAwwJU0NSVCBMYWJzMSAwHgYJKoZIhvcNAQkBFhFp +bmZvQHNjcnRsYWJzLmNvbTAeFw0yMjExMjkwOTI1NDdaFw0yNzExMjgwOTI1NDda +MGwxCzAJBgNVBAYTAklMMRMwEQYDVQQIDApTb21lLVN0YXRlMRIwEAYDVQQKDAlT +Q1JUIExhYnMxEjAQBgNVBAMMCVNDUlQgTGFiczEgMB4GCSqGSIb3DQEJARYRaW5m +b0BzY3J0bGFicy5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDl +AsDE6qlElROsVhmmSOjFJ1Xn6zt1mE/H25lY0L9gotGTFfMzIEk1/IZw+Z5CMj4m +O4sFamlxbVNjFNnjBTv7m43Z15Y8RRzGvqSbeLhXLM5lT1krWiNQnDrHZHqjlqMf +qAb1EERZIOqK002lzhqmNDO6zd4VuHHP1Tt7dviVLDX2l9JvOuL0Ug3cE2Sfm97I +5AcQDCcenffwPLNbG0211kKtA9K5pm/Br6Hkvo0t0kUZY/xrl3EUl2W0rQOaoH+E ++bb0wdhH/ITAOvoHB5DZg3NTYrRojUN5U4I42ysJ6feaTxZIDhMIwWoR5PgsCclJ +oGwB+1230snPdZAT2IRVAgMBAAGjUzBRMB0GA1UdDgQWBBRJFJk7uO63CvXmr/an +JZee2MerIzAfBgNVHSMEGDAWgBRJFJk7uO63CvXmr/anJZee2MerIzAPBgNVHRMB +Af8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBEpR0/42aNhQOfncrQeSvDs2nV +lpbon47O/S9g1lPclERfVzcdo0GHOEckabfZG/NcPu2gjiWretZS5l2ogpxcLYyX +8o3im7cQxyvE/ezAZ8V1bXRiSY7/TIA8kOuXCLQOvsIhDA9uy0FgYtugVubt4tW4 +9ep2QRTrVgLjXI1ILTtl3hOYeLY337tBVGQOrw9sQRwv1pISRQmvr3ne0VTTixDX +qlYcYVjz3AHmFT706svlT7dA6QR5qeWuJANKQzaPM4tiQZ8ciSrOmJ5nvQpBa6Ri +4Z0l+5efsO3q3hr0XJSiGyof2eQA8EdU4GUohyvZ4Rudf38G+vflgrVHYik+ +-----END CERTIFICATE----- diff --git a/cosmwasm/enclaves/shared/crypto/src/errors.rs b/cosmwasm/enclaves/shared/crypto/src/errors.rs index 617404390..1bd9dc263 100644 --- a/cosmwasm/enclaves/shared/crypto/src/errors.rs +++ b/cosmwasm/enclaves/shared/crypto/src/errors.rs @@ -28,6 +28,9 @@ pub enum CryptoError { VerificationError = 11, SocketCreationError = 12, IPv4LookupError = 13, + IntelCommunicationError = 14, + SSSCommunicationError = 15, + BadResponse = 16, } #[derive(Debug, Display)] diff --git a/cosmwasm/enclaves/shared/crypto/src/key_manager.rs b/cosmwasm/enclaves/shared/crypto/src/key_manager.rs index 3957479d1..6eef176c3 100644 --- a/cosmwasm/enclaves/shared/crypto/src/key_manager.rs +++ b/cosmwasm/enclaves/shared/crypto/src/key_manager.rs @@ -5,16 +5,6 @@ use crate::{AESKey, KeyPair, Seed}; use enclave_ffi_types::EnclaveError; use lazy_static::lazy_static; use log::*; -use sgx_types::c_int; -use std::net::SocketAddr; -use std::os::unix::io::IntoRawFd; -use std::{ - io::{Read, Write}, - net::TcpStream, - str, - string::String, - sync::Arc, -}; // For phase 1 of the seed rotation, all consensus secrets come in two parts: // 1. The genesis seed generated on 15 September 2020 @@ -70,7 +60,7 @@ impl Keychain { let registration_key = Self::unseal_registration_key(); let mut x = Keychain { - consensus_seed_id: 1, + consensus_seed_id: CONSENSUS_SEED_VERSION, consensus_seed, registration_key, consensus_state_ikm: None, @@ -127,6 +117,14 @@ impl Keychain { }) } + pub fn get_consensus_seed_id(&self) -> u16 { + self.consensus_seed_id + } + + pub fn inc_consensus_seed_id(&mut self) -> () { + self.consensus_seed_id += 1; + } + pub fn get_consensus_seed(&self) -> Result, CryptoError> { self.consensus_seed.ok_or_else(|| { error!("Error accessing consensus_seed (does not exist, or was not initialized)"); @@ -376,157 +374,6 @@ impl Keychain { Ok(()) } - - pub fn make_client_config() -> rustls::ClientConfig { - let mut config = rustls::ClientConfig::new(); - - config - .root_store - .add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS); - - config - } - - fn create_socket_to_service(host_name: &str) -> Result { - use std::net::ToSocketAddrs; - - let mut addr: Option = None; - - let addrs = (host_name, 3000).to_socket_addrs().map_err(|err| { - trace!("Error while trying to convert to socket addrs {:?}", err); - CryptoError::SocketCreationError - })?; - - for a in addrs { - if let SocketAddr::V4(_) = a { - addr = Some(a); - } - } - - if addr.is_none() { - trace!("Failed to resolve the IPv4 address of the service"); - return Err(CryptoError::IPv4LookupError); - } - - let sock = TcpStream::connect(&addr.unwrap()).map_err(|err| { - trace!( - "Error while trying to connect to service with addr: {:?}, err: {:?}", - addr, - err - ); - CryptoError::SocketCreationError - })?; - - return Ok(sock.into_raw_fd()); - } - - fn get_challange_from_service(fd: c_int, host_name: &str) -> Result, CryptoError> { - pub const CHALLANGE_ENDPOINT: &str = "/authenticate"; - - let req = format!("GET {} HTTP/1.1\r\nHOST: {}\r\nContent-Length:{}\r\nContent-Type: application/json\r\nConnection: close\r\n\r\n{}", - CHALLANGE_ENDPOINT, - host_name, - encoded_json.len(), - encoded_json); - - trace!("{}", req); - let config = Keychain::make_client_config(); - let dns_name = webpki::DNSNameRef::try_from_ascii_str(host_name).unwrap(); - let mut sess = rustls::ClientSession::new(&Arc::new(config), dns_name); - let mut sock = TcpStream::new(fd).unwrap(); - let mut tls = rustls::Stream::new(&mut sess, &mut sock); - - let _result = tls.write(req.as_bytes()); - let mut plaintext = Vec::new(); - - info!("write complete"); - - tls.read_to_end(&mut plaintext).unwrap(); - info!("read_to_end complete"); - let resp_string = String::from_utf8(plaintext.clone()).unwrap(); - info!("resp string {}", resp_string); - - Ok(plaintext) - } - - fn try_get_consensus_seed_from_service(id: u16) -> Result { - #[cfg(feature = "production")] - pub const SEED_SERVICE_DNS: &'static str = "sss.scrtlabs.com"; - #[cfg(not(feature = "production"))] - pub const SEED_SERVICE_DNS: &'static str = "sssd.scrtlabs.com"; - let socket = Keychain::create_socket_to_service(SEED_SERVICE_DNS)?; - Keychain::get_challange_from_service(socket, SEED_SERVICE_DNS); - let s: [u8; 32] = [ - 0, id as u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - ]; - let mut seed = Seed::default(); - seed.as_mut().copy_from_slice(&s); - Ok(seed) - } - - // Retreiving consensus seed from SingularitySeedService - // id - The desired seed id - // retries - The amount of times to retry upon failure. 0 means infinite - pub fn get_next_consensus_seed_from_service( - &mut self, - retries: u8, - genesis_seed: Seed, - ) -> Result { - let mut opt_seed: Result = Err(CryptoError::DecryptionError); - - match retries { - 0 => { - trace!("Looping consensus seed lookup forever"); - loop { - if let Ok(seed) = - Keychain::try_get_consensus_seed_from_service(self.consensus_seed_id) - { - opt_seed = Ok(seed); - break; - } - } - } - _ => { - for try_id in 1..retries + 1 { - trace!("Looping consensus seed lookup {}/{}", try_id, retries); - match Keychain::try_get_consensus_seed_from_service(self.consensus_seed_id) { - Ok(seed) => { - opt_seed = Ok(seed); - break; - } - Err(e) => opt_seed = Err(e), - } - } - } - }; - - if let Err(e) = opt_seed { - return Err(e); - } - - let mut seed = opt_seed?; - trace!( - "LIORRR Genesis seed is {:?} service seed is {:?}", - genesis_seed.as_slice(), - seed.as_slice() - ); - - // XOR the seed with the genesis seed - let mut seed_vec = seed.as_mut().to_vec(); - seed_vec - .iter_mut() - .zip(genesis_seed.as_slice().to_vec().iter()) - .for_each(|(x1, x2)| *x1 ^= *x2); - - seed.as_mut().copy_from_slice(seed_vec.as_slice()); - - trace!("LIORRR New seed is {:?}", seed.as_slice()); - - trace!("Successfully fetched consensus seed from service"); - self.consensus_seed_id += 1; - Ok(seed) - } } #[cfg(feature = "test")] diff --git a/docker-compose.yml b/docker-compose.yml index d0df11213..a77a23624 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,18 +3,28 @@ version: "3" services: + aesm: + image: fortanix/aesmd:2.13.103.1-1 + devices: + - /dev/sgx/enclave + - /dev/sgx/provision + volumes: + - /tmp/aesmd:/var/run/aesmd + stdin_open: true + tty: true + bootstrap: - image: ghcr.io/scrtlabs/localsecret:seed-test-1 + image: ghcr.io/scrtlabs/testnet:sbs-1 container_name: bootstrap - #depends_on: - #- aesm - #devices: - #- /dev/sgx/enclave - #- /dev/sgx/provision + depends_on: + - aesm + devices: + - /dev/sgx/enclave + - /dev/sgx/provision volumes: - # - /tmp/aesmd:/var/run/aesmd + - /tmp/aesmd:/var/run/aesmd - /tmp/secretd:/root/.secretd - # - /tmp/secretcli:/root/.secretcli + - /tmp/secretcli:/root/.secretcli stdin_open: true tty: true environment: @@ -30,16 +40,16 @@ services: - "5000:5000" node: - image: ghcr.io/scrtlabs/localsecret:seed-test-1 + image: ghcr.io/scrtlabs/testnet:s-1 depends_on: - bootstrap - #devices: - # - /dev/sgx/enclave - # - /dev/sgx/provision + devices: + - /dev/sgx/enclave + - /dev/sgx/provision volumes: - # - /tmp/aesmd:/var/run/aesmd + - /tmp/aesmd:/var/run/aesmd - /tmp/secretd:/tmp/.secretd - # - /tmp/secretcli:/root/.secretcli + - /tmp/secretcli:/root/.secretcli stdin_open: true tty: true environment: @@ -56,4 +66,4 @@ services: condition: on-failure delay: 10s max_attempts: 10 - window: 120s + window: 123s