| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License.. |
| |
| #![crate_name = "mra"] |
| #![crate_type = "staticlib"] |
| |
| #![cfg_attr(not(target_env = "sgx"), no_std)] |
| #![cfg_attr(target_env = "sgx", feature(rustc_private))] |
| |
| extern crate sgx_types; |
| extern crate sgx_tcrypto; |
| extern crate sgx_trts; |
| extern crate sgx_tse; |
| #[cfg(not(target_env = "sgx"))] |
| #[macro_use] |
| extern crate sgx_tstd as std; |
| extern crate sgx_rand; |
| |
| extern crate rustls; |
| extern crate webpki; |
| extern crate itertools; |
| extern crate base64; |
| extern crate httparse; |
| extern crate yasna; |
| extern crate bit_vec; |
| extern crate num_bigint; |
| extern crate serde_json; |
| extern crate chrono; |
| extern crate webpki_roots; |
| |
| use std::backtrace::{self, PrintFormat}; |
| use sgx_types::*; |
| use sgx_tse::*; |
| //use sgx_trts::trts::{rsgx_raw_is_outside_enclave, rsgx_lfence}; |
| use sgx_tcrypto::*; |
| use sgx_rand::*; |
| |
| use std::prelude::v1::*; |
| use std::sync::Arc; |
| use std::net::TcpStream; |
| use std::string::String; |
| use std::io; |
| use std::ptr; |
| use std::str; |
| use std::io::{Write, Read}; |
| use std::untrusted::fs; |
| use std::vec::Vec; |
| use itertools::Itertools; |
| |
| mod cert; |
| mod hex; |
| |
| pub const DEV_HOSTNAME:&'static str = "api.trustedservices.intel.com"; |
| pub const SIGRL_SUFFIX:&'static str = "/sgx/dev/attestation/v3/sigrl/"; |
| pub const REPORT_SUFFIX:&'static str = "/sgx/dev/attestation/v3/report"; |
| pub const CERTEXPIRYDAYS: i64 = 90i64; |
| |
| extern "C" { |
| pub fn ocall_sgx_init_quote ( ret_val : *mut sgx_status_t, |
| ret_ti : *mut sgx_target_info_t, |
| ret_gid : *mut sgx_epid_group_id_t) -> sgx_status_t; |
| pub fn ocall_get_ias_socket ( ret_val : *mut sgx_status_t, |
| ret_fd : *mut i32) -> sgx_status_t; |
| pub fn ocall_get_quote (ret_val : *mut sgx_status_t, |
| p_sigrl : *const u8, |
| sigrl_len : u32, |
| p_report : *const sgx_report_t, |
| quote_type : sgx_quote_sign_type_t, |
| p_spid : *const sgx_spid_t, |
| p_nonce : *const sgx_quote_nonce_t, |
| p_qe_report : *mut sgx_report_t, |
| p_quote : *mut u8, |
| maxlen : u32, |
| p_quote_len : *mut u32) -> sgx_status_t; |
| } |
| |
| |
| fn parse_response_attn_report(resp : &[u8]) -> (String, String, String){ |
| println!("parse_response_attn_report"); |
| let mut headers = [httparse::EMPTY_HEADER; 16]; |
| let mut respp = httparse::Response::new(&mut headers); |
| let result = respp.parse(resp); |
| println!("parse result {:?}", result); |
| |
| let msg : &'static str; |
| |
| match respp.code { |
| Some(200) => msg = "OK Operation Successful", |
| Some(401) => msg = "Unauthorized Failed to authenticate or authorize request.", |
| Some(404) => msg = "Not Found GID does not refer to a valid EPID group ID.", |
| Some(500) => msg = "Internal error occurred", |
| Some(503) => msg = "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. ", |
| _ => {println!("DBG:{}", respp.code.unwrap()); msg = "Unknown error occured"}, |
| } |
| |
| println!("{}", msg); |
| let mut len_num : u32 = 0; |
| |
| let mut sig = String::new(); |
| let mut cert = String::new(); |
| let mut attn_report = String::new(); |
| |
| for i in 0..respp.headers.len() { |
| let h = respp.headers[i]; |
| //println!("{} : {}", h.name, str::from_utf8(h.value).unwrap()); |
| match h.name{ |
| "Content-Length" => { |
| let len_str = String::from_utf8(h.value.to_vec()).unwrap(); |
| len_num = len_str.parse::<u32>().unwrap(); |
| println!("content length = {}", len_num); |
| } |
| "X-IASReport-Signature" => sig = str::from_utf8(h.value).unwrap().to_string(), |
| "X-IASReport-Signing-Certificate" => cert = str::from_utf8(h.value).unwrap().to_string(), |
| _ => (), |
| } |
| } |
| |
| // Remove %0A from cert, and only obtain the signing cert |
| cert = cert.replace("%0A", ""); |
| cert = cert::percent_decode(cert); |
| let v: Vec<&str> = cert.split("-----").collect(); |
| let sig_cert = v[2].to_string(); |
| |
| if len_num != 0 { |
| let header_len = result.unwrap().unwrap(); |
| let resp_body = &resp[header_len..]; |
| attn_report = str::from_utf8(resp_body).unwrap().to_string(); |
| println!("Attestation report: {}", attn_report); |
| } |
| |
| // len_num == 0 |
| (attn_report, sig, sig_cert) |
| } |
| |
| |
| fn parse_response_sigrl(resp : &[u8]) -> Vec<u8> { |
| println!("parse_response_sigrl"); |
| let mut headers = [httparse::EMPTY_HEADER; 16]; |
| let mut respp = httparse::Response::new(&mut headers); |
| let result = respp.parse(resp); |
| println!("parse result {:?}", result); |
| println!("parse response{:?}", respp); |
| |
| let msg : &'static str; |
| |
| match respp.code { |
| Some(200) => msg = "OK Operation Successful", |
| Some(401) => msg = "Unauthorized Failed to authenticate or authorize request.", |
| Some(404) => msg = "Not Found GID does not refer to a valid EPID group ID.", |
| Some(500) => msg = "Internal error occurred", |
| Some(503) => msg = "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. ", |
| _ => msg = "Unknown error occured", |
| } |
| |
| println!("{}", msg); |
| let mut len_num : u32 = 0; |
| |
| for i in 0..respp.headers.len() { |
| let h = respp.headers[i]; |
| if h.name == "content-length" { |
| let len_str = String::from_utf8(h.value.to_vec()).unwrap(); |
| len_num = len_str.parse::<u32>().unwrap(); |
| println!("content length = {}", len_num); |
| } |
| } |
| |
| if len_num != 0 { |
| let header_len = result.unwrap().unwrap(); |
| let resp_body = &resp[header_len..]; |
| println!("Base64-encoded SigRL: {:?}", resp_body); |
| |
| return base64::decode(str::from_utf8(resp_body).unwrap()).unwrap(); |
| } |
| |
| // len_num == 0 |
| Vec::new() |
| } |
| |
| pub fn make_ias_client_config() -> rustls::ClientConfig { |
| let mut config = rustls::ClientConfig::new(); |
| |
| config.root_store.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS); |
| |
| config |
| } |
| |
| |
| pub fn get_sigrl_from_intel(fd : c_int, gid : u32) -> Vec<u8> { |
| println!("get_sigrl_from_intel fd = {:?}", fd); |
| let config = make_ias_client_config(); |
| //let sigrl_arg = SigRLArg { group_id : gid }; |
| //let sigrl_req = sigrl_arg.to_httpreq(); |
| let ias_key = get_ias_api_key(); |
| |
| let req = format!("GET {}{:08x} HTTP/1.1\r\nHOST: {}\r\nOcp-Apim-Subscription-Key: {}\r\nConnection: Close\r\n\r\n", |
| SIGRL_SUFFIX, |
| gid, |
| DEV_HOSTNAME, |
| ias_key); |
| println!("{}", req); |
| |
| let dns_name = webpki::DNSNameRef::try_from_ascii_str(DEV_HOSTNAME).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(); |
| |
| println!("write complete"); |
| |
| match tls.read_to_end(&mut plaintext) { |
| Ok(_) => (), |
| Err(e) => { |
| println!("get_sigrl_from_intel tls.read_to_end: {:?}", e); |
| panic!("haha"); |
| } |
| } |
| println!("read_to_end complete"); |
| let resp_string = String::from_utf8(plaintext.clone()).unwrap(); |
| |
| println!("{}", resp_string); |
| |
| parse_response_sigrl(&plaintext) |
| } |
| |
| // TODO: support pse |
| pub fn get_report_from_intel(fd : c_int, quote : Vec<u8>) -> (String, String, String) { |
| println!("get_report_from_intel fd = {:?}", fd); |
| let config = make_ias_client_config(); |
| let encoded_quote = base64::encode("e[..]); |
| let encoded_json = format!("{{\"isvEnclaveQuote\":\"{}\"}}\r\n", encoded_quote); |
| |
| let ias_key = get_ias_api_key(); |
| |
| let req = format!("POST {} HTTP/1.1\r\nHOST: {}\r\nOcp-Apim-Subscription-Key:{}\r\nContent-Length:{}\r\nContent-Type: application/json\r\nConnection: close\r\n\r\n{}", |
| REPORT_SUFFIX, |
| DEV_HOSTNAME, |
| ias_key, |
| encoded_json.len(), |
| encoded_json); |
| println!("{}", req); |
| let dns_name = webpki::DNSNameRef::try_from_ascii_str(DEV_HOSTNAME).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(); |
| |
| println!("write complete"); |
| |
| tls.read_to_end(&mut plaintext).unwrap(); |
| println!("read_to_end complete"); |
| let resp_string = String::from_utf8(plaintext.clone()).unwrap(); |
| |
| println!("resp_string = {}", resp_string); |
| |
| let (attn_report, sig, cert) = parse_response_attn_report(&plaintext); |
| |
| (attn_report, sig, cert) |
| } |
| |
| fn as_u32_le(array: &[u8; 4]) -> u32 { |
| ((array[0] as u32) << 0) + |
| ((array[1] as u32) << 8) + |
| ((array[2] as u32) << 16) + |
| ((array[3] as u32) << 24) |
| } |
| |
| #[allow(const_err)] |
| pub fn create_attestation_report(pub_k: &sgx_ec256_public_t, sign_type: sgx_quote_sign_type_t) -> Result<(String, String, String), sgx_status_t> { |
| // Workflow: |
| // (1) ocall to get the target_info structure (ti) and epid group id (eg) |
| // (1.5) get sigrl |
| // (2) call sgx_create_report with ti+data, produce an sgx_report_t |
| // (3) ocall to sgx_get_quote to generate (*mut sgx-quote_t, uint32_t) |
| |
| // (1) get ti + eg |
| let mut ti : sgx_target_info_t = sgx_target_info_t::default(); |
| let mut eg : sgx_epid_group_id_t = sgx_epid_group_id_t::default(); |
| let mut rt : sgx_status_t = sgx_status_t::SGX_ERROR_UNEXPECTED; |
| |
| let res = unsafe { |
| ocall_sgx_init_quote(&mut rt as *mut sgx_status_t, |
| &mut ti as *mut sgx_target_info_t, |
| &mut eg as *mut sgx_epid_group_id_t) |
| }; |
| |
| println!("eg = {:?}", eg); |
| |
| if res != sgx_status_t::SGX_SUCCESS { |
| return Err(res); |
| } |
| |
| if rt != sgx_status_t::SGX_SUCCESS { |
| return Err(rt); |
| } |
| |
| let eg_num = as_u32_le(&eg); |
| |
| // (1.5) get sigrl |
| let mut ias_sock : i32 = 0; |
| |
| let res = unsafe { |
| ocall_get_ias_socket(&mut rt as *mut sgx_status_t, |
| &mut ias_sock as *mut i32) |
| }; |
| |
| if res != sgx_status_t::SGX_SUCCESS { |
| return Err(res); |
| } |
| |
| if rt != sgx_status_t::SGX_SUCCESS { |
| return Err(rt); |
| } |
| |
| //println!("Got ias_sock = {}", ias_sock); |
| |
| // Now sigrl_vec is the revocation list, a vec<u8> |
| let sigrl_vec : Vec<u8> = get_sigrl_from_intel(ias_sock, eg_num); |
| |
| // (2) Generate the report |
| // Fill ecc256 public key into report_data |
| let mut report_data: sgx_report_data_t = sgx_report_data_t::default(); |
| let mut pub_k_gx = pub_k.gx.clone(); |
| pub_k_gx.reverse(); |
| let mut pub_k_gy = pub_k.gy.clone(); |
| pub_k_gy.reverse(); |
| report_data.d[..32].clone_from_slice(&pub_k_gx); |
| report_data.d[32..].clone_from_slice(&pub_k_gy); |
| |
| let rep = match rsgx_create_report(&ti, &report_data) { |
| Ok(r) =>{ |
| println!("Report creation => success {:?}", r.body.mr_signer.m); |
| Some(r) |
| }, |
| Err(e) =>{ |
| println!("Report creation => failed {:?}", e); |
| None |
| }, |
| }; |
| |
| let mut quote_nonce = sgx_quote_nonce_t { rand : [0;16] }; |
| let mut os_rng = os::SgxRng::new().unwrap(); |
| os_rng.fill_bytes(&mut quote_nonce.rand); |
| println!("rand finished"); |
| let mut qe_report = sgx_report_t::default(); |
| const RET_QUOTE_BUF_LEN : u32 = 2048; |
| let mut return_quote_buf : [u8; RET_QUOTE_BUF_LEN as usize] = [0;RET_QUOTE_BUF_LEN as usize]; |
| let mut quote_len : u32 = 0; |
| |
| // (3) Generate the quote |
| // Args: |
| // 1. sigrl: ptr + len |
| // 2. report: ptr 432bytes |
| // 3. linkable: u32, unlinkable=0, linkable=1 |
| // 4. spid: sgx_spid_t ptr 16bytes |
| // 5. sgx_quote_nonce_t ptr 16bytes |
| // 6. p_sig_rl + sigrl size ( same to sigrl) |
| // 7. [out]p_qe_report need further check |
| // 8. [out]p_quote |
| // 9. quote_size |
| let (p_sigrl, sigrl_len) = |
| if sigrl_vec.len() == 0 { |
| (ptr::null(), 0) |
| } else { |
| (sigrl_vec.as_ptr(), sigrl_vec.len() as u32) |
| }; |
| let p_report = (&rep.unwrap()) as * const sgx_report_t; |
| let quote_type = sign_type; |
| |
| let spid : sgx_spid_t = load_spid("spid.txt"); |
| |
| let p_spid = &spid as *const sgx_spid_t; |
| let p_nonce = "e_nonce as * const sgx_quote_nonce_t; |
| let p_qe_report = &mut qe_report as *mut sgx_report_t; |
| let p_quote = return_quote_buf.as_mut_ptr(); |
| let maxlen = RET_QUOTE_BUF_LEN; |
| let p_quote_len = &mut quote_len as *mut u32; |
| |
| let result = unsafe { |
| ocall_get_quote(&mut rt as *mut sgx_status_t, |
| p_sigrl, |
| sigrl_len, |
| p_report, |
| quote_type, |
| p_spid, |
| p_nonce, |
| p_qe_report, |
| p_quote, |
| maxlen, |
| p_quote_len) |
| }; |
| |
| if result != sgx_status_t::SGX_SUCCESS { |
| return Err(result); |
| } |
| |
| if rt != sgx_status_t::SGX_SUCCESS { |
| println!("ocall_get_quote returned {}", rt); |
| return Err(rt); |
| } |
| |
| // Added 09-28-2018 |
| // Perform a check on qe_report to verify if the qe_report is valid |
| match rsgx_verify_report(&qe_report) { |
| Ok(()) => println!("rsgx_verify_report passed!"), |
| Err(x) => { |
| println!("rsgx_verify_report failed with {:?}", x); |
| return Err(x); |
| }, |
| } |
| |
| // Check if the qe_report is produced on the same platform |
| if ti.mr_enclave.m != qe_report.body.mr_enclave.m || |
| ti.attributes.flags != qe_report.body.attributes.flags || |
| ti.attributes.xfrm != qe_report.body.attributes.xfrm { |
| println!("qe_report does not match current target_info!"); |
| return Err(sgx_status_t::SGX_ERROR_UNEXPECTED); |
| } |
| |
| println!("qe_report check passed"); |
| |
| // Debug |
| // for i in 0..quote_len { |
| // print!("{:02X}", unsafe {*p_quote.offset(i as isize)}); |
| // } |
| // println!(""); |
| |
| // Check qe_report to defend against replay attack |
| // The purpose of p_qe_report is for the ISV enclave to confirm the QUOTE |
| // it received is not modified by the untrusted SW stack, and not a replay. |
| // The implementation in QE is to generate a REPORT targeting the ISV |
| // enclave (target info from p_report) , with the lower 32Bytes in |
| // report.data = SHA256(p_nonce||p_quote). The ISV enclave can verify the |
| // p_qe_report and report.data to confirm the QUOTE has not be modified and |
| // is not a replay. It is optional. |
| |
| let mut rhs_vec : Vec<u8> = quote_nonce.rand.to_vec(); |
| rhs_vec.extend(&return_quote_buf[..quote_len as usize]); |
| let rhs_hash = rsgx_sha256_slice(&rhs_vec[..]).unwrap(); |
| let lhs_hash = &qe_report.body.report_data.d[..32]; |
| |
| println!("rhs hash = {:02X}", rhs_hash.iter().format("")); |
| println!("report hs= {:02X}", lhs_hash.iter().format("")); |
| |
| if rhs_hash != lhs_hash { |
| println!("Quote is tampered!"); |
| return Err(sgx_status_t::SGX_ERROR_UNEXPECTED); |
| } |
| |
| let quote_vec : Vec<u8> = return_quote_buf[..quote_len as usize].to_vec(); |
| let res = unsafe { |
| ocall_get_ias_socket(&mut rt as *mut sgx_status_t, |
| &mut ias_sock as *mut i32) |
| }; |
| |
| if res != sgx_status_t::SGX_SUCCESS { |
| return Err(res); |
| } |
| |
| if rt != sgx_status_t::SGX_SUCCESS { |
| return Err(rt); |
| } |
| |
| let (attn_report, sig, cert) = get_report_from_intel(ias_sock, quote_vec); |
| Ok((attn_report, sig, cert)) |
| } |
| |
| fn load_spid(filename: &str) -> sgx_spid_t { |
| let mut spidfile = fs::File::open(filename).expect("cannot open spid file"); |
| let mut contents = String::new(); |
| spidfile.read_to_string(&mut contents).expect("cannot read the spid file"); |
| |
| hex::decode_spid(&contents) |
| } |
| |
| fn get_ias_api_key() -> String { |
| let mut keyfile = fs::File::open("key.txt").expect("cannot open ias key file"); |
| let mut key = String::new(); |
| keyfile.read_to_string(&mut key).expect("cannot read the ias key file"); |
| |
| key.trim_end().to_owned() |
| } |
| |
| struct ClientAuth { |
| outdated_ok: bool, |
| } |
| |
| impl ClientAuth { |
| fn new(outdated_ok: bool) -> ClientAuth { |
| ClientAuth{ outdated_ok : outdated_ok } |
| } |
| } |
| |
| impl rustls::ClientCertVerifier for ClientAuth { |
| fn client_auth_root_subjects(&self, _sni: Option<&webpki::DNSName>) -> Option<rustls::DistinguishedNames> { |
| Some(rustls::DistinguishedNames::new()) |
| } |
| |
| fn verify_client_cert(&self, _certs: &[rustls::Certificate], _sni: Option<&webpki::DNSName>) |
| -> Result<rustls::ClientCertVerified, rustls::TLSError> { |
| println!("client cert: {:?}", _certs); |
| // This call will automatically verify cert is properly signed |
| match cert::verify_mra_cert(&_certs[0].0) { |
| Ok(()) => { |
| return Ok(rustls::ClientCertVerified::assertion()); |
| } |
| Err(sgx_status_t::SGX_ERROR_UPDATE_NEEDED) => { |
| if self.outdated_ok { |
| println!("outdated_ok is set, overriding outdated error"); |
| return Ok(rustls::ClientCertVerified::assertion()); |
| } else { |
| return Err(rustls::TLSError::WebPKIError(webpki::Error::ExtensionValueInvalid)); |
| } |
| } |
| Err(_) => { |
| return Err(rustls::TLSError::WebPKIError(webpki::Error::ExtensionValueInvalid)); |
| } |
| } |
| } |
| } |
| |
| struct ServerAuth { |
| outdated_ok: bool |
| } |
| |
| impl ServerAuth { |
| fn new(outdated_ok: bool) -> ServerAuth { |
| ServerAuth{ outdated_ok : outdated_ok } |
| } |
| } |
| |
| impl rustls::ServerCertVerifier for ServerAuth { |
| fn verify_server_cert(&self, |
| _roots: &rustls::RootCertStore, |
| _certs: &[rustls::Certificate], |
| _hostname: webpki::DNSNameRef, |
| _ocsp: &[u8]) -> Result<rustls::ServerCertVerified, rustls::TLSError> { |
| println!("server cert: {:?}", _certs); |
| // This call will automatically verify cert is properly signed |
| match cert::verify_mra_cert(&_certs[0].0) { |
| Ok(()) => { |
| return Ok(rustls::ServerCertVerified::assertion()); |
| } |
| Err(sgx_status_t::SGX_ERROR_UPDATE_NEEDED) => { |
| if self.outdated_ok { |
| println!("outdated_ok is set, overriding outdated error"); |
| return Ok(rustls::ServerCertVerified::assertion()); |
| } else { |
| return Err(rustls::TLSError::WebPKIError(webpki::Error::ExtensionValueInvalid)); |
| } |
| } |
| Err(_) => { |
| return Err(rustls::TLSError::WebPKIError(webpki::Error::ExtensionValueInvalid)); |
| } |
| } |
| } |
| } |
| |
| #[no_mangle] |
| pub extern "C" fn run_server(socket_fd : c_int, sign_type: sgx_quote_sign_type_t) -> sgx_status_t { |
| let _ = backtrace::enable_backtrace("enclave.signed.so", PrintFormat::Short); |
| |
| // Generate Keypair |
| let ecc_handle = SgxEccHandle::new(); |
| let _result = ecc_handle.open(); |
| let (prv_k, pub_k) = ecc_handle.create_key_pair().unwrap(); |
| |
| let (attn_report, sig, cert) = match create_attestation_report(&pub_k, sign_type) { |
| Ok(r) => r, |
| Err(e) => { |
| println!("Error in create_attestation_report: {:?}", e); |
| return e; |
| } |
| }; |
| |
| let payload = attn_report + "|" + &sig + "|" + &cert; |
| let (key_der, cert_der) = match cert::gen_ecc_cert(payload, &prv_k, &pub_k, &ecc_handle) { |
| Ok(r) => r, |
| Err(e) => { |
| println!("Error in gen_ecc_cert: {:?}", e); |
| return e; |
| } |
| }; |
| let _result = ecc_handle.close(); |
| |
| |
| let mut cfg = rustls::ServerConfig::new(Arc::new(ClientAuth::new(true))); |
| let mut certs = Vec::new(); |
| certs.push(rustls::Certificate(cert_der)); |
| let privkey = rustls::PrivateKey(key_der); |
| |
| cfg.set_single_cert_with_ocsp_and_sct(certs, privkey, vec![], vec![]).unwrap(); |
| |
| let mut sess = rustls::ServerSession::new(&Arc::new(cfg)); |
| let mut conn = TcpStream::new(socket_fd).unwrap(); |
| |
| let mut tls = rustls::Stream::new(&mut sess, &mut conn); |
| let mut plaintext = [0u8;1024]; //Vec::new(); |
| match tls.read(&mut plaintext) { |
| Ok(_) => println!("Client said: {}", str::from_utf8(&plaintext).unwrap()), |
| Err(e) => { |
| println!("Error in read_to_end: {:?}", e); |
| panic!(""); |
| } |
| }; |
| |
| tls.write("hello back".as_bytes()).unwrap(); |
| |
| sgx_status_t::SGX_SUCCESS |
| } |
| |
| |
| #[no_mangle] |
| pub extern "C" fn run_client(socket_fd : c_int, sign_type: sgx_quote_sign_type_t) -> sgx_status_t { |
| let _ = backtrace::enable_backtrace("enclave.signed.so", PrintFormat::Short); |
| |
| // Generate Keypair |
| let ecc_handle = SgxEccHandle::new(); |
| ecc_handle.open().unwrap(); |
| let (prv_k, pub_k) = ecc_handle.create_key_pair().unwrap(); |
| |
| let (attn_report, sig, cert) = match create_attestation_report(&pub_k, sign_type) { |
| Ok(r) => r, |
| Err(e) => { |
| println!("Error in create_attestation_report: {:?}", e); |
| return e; |
| } |
| }; |
| |
| let payload = attn_report + "|" + &sig + "|" + &cert; |
| |
| let (key_der, cert_der) = match cert::gen_ecc_cert(payload, &prv_k, &pub_k, &ecc_handle) { |
| Ok(r) => r, |
| Err(e) => { |
| println!("Error in gen_ecc_cert: {:?}", e); |
| return e; |
| } |
| }; |
| ecc_handle.close().unwrap(); |
| |
| |
| let mut cfg = rustls::ClientConfig::new(); |
| let mut certs = Vec::new(); |
| certs.push(rustls::Certificate(cert_der)); |
| let privkey = rustls::PrivateKey(key_der); |
| |
| cfg.set_single_client_cert(certs, privkey).unwrap(); |
| cfg.dangerous().set_certificate_verifier(Arc::new(ServerAuth::new(true))); |
| cfg.versions.clear(); |
| cfg.versions.push(rustls::ProtocolVersion::TLSv1_2); |
| |
| let dns_name = webpki::DNSNameRef::try_from_ascii_str("localhost").unwrap(); |
| let mut sess = rustls::ClientSession::new(&Arc::new(cfg), dns_name); |
| let mut conn = TcpStream::new(socket_fd).unwrap(); |
| |
| let mut tls = rustls::Stream::new(&mut sess, &mut conn); |
| |
| tls.write("hello".as_bytes()).unwrap(); |
| |
| let mut plaintext = Vec::new(); |
| match tls.read_to_end(&mut plaintext) { |
| Ok(_) => { |
| println!("Server replied: {}", str::from_utf8(&plaintext).unwrap()); |
| } |
| Err(ref err) if err.kind() == io::ErrorKind::ConnectionAborted => { |
| println!("EOF (tls)"); |
| } |
| Err(e) => println!("Error in read_to_end: {:?}", e), |
| } |
| |
| sgx_status_t::SGX_SUCCESS |
| } |