diff --git a/Cargo.lock b/Cargo.lock index 8e57bd1b2..1282d8312 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -30,6 +30,54 @@ dependencies = [ "yansi-term", ] +[[package]] +name = "anstream" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" + +[[package]] +name = "anstyle-parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" +dependencies = [ + "anstyle", + "windows-sys 0.48.0", +] + [[package]] name = "async-stream" version = "0.3.5" @@ -175,6 +223,46 @@ dependencies = [ "libloading", ] +[[package]] +name = "clap" +version = "4.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.16", +] + +[[package]] +name = "clap_lex" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" + [[package]] name = "cmake" version = "0.1.49" @@ -194,6 +282,12 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + [[package]] name = "core-foundation-sys" version = "0.8.3" @@ -408,6 +502,12 @@ version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -611,6 +711,7 @@ dependencies = [ "byteorder", "cc", "cfg-if", + "clap", "env_logger", "futures", "hex", @@ -1044,6 +1145,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "syn" version = "1.0.103" @@ -1220,6 +1327,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + [[package]] name = "version_check" version = "0.1.5" diff --git a/mbedtls/Cargo.toml b/mbedtls/Cargo.toml index ffa49466c..7c8fabedc 100644 --- a/mbedtls/Cargo.toml +++ b/mbedtls/Cargo.toml @@ -15,18 +15,22 @@ environment.""" readme = "../README.md" repository = "https://github.com/fortanix/rust-mbedtls" documentation = "https://docs.rs/mbedtls/" -keywords = ["MbedTLS","mbed","TLS","SSL","cryptography"] +keywords = ["MbedTLS", "mbed", "TLS", "SSL", "cryptography"] [dependencies] bitflags = "1" serde = { version = "1.0.7", default-features = false, features = ["alloc"] } serde_derive = "1.0.7" byteorder = { version = "1.0.0", default-features = false } -yasna = { version = "0.2", optional = true, features = ["num-bigint", "bit-vec"] } +yasna = { version = "0.2", optional = true, features = [ + "num-bigint", + "bit-vec", +] } num-bigint = { version = "0.2", optional = true } bit-vec = { version = "0.5", optional = true } cfg-if = "1.0.0" tokio = { version = "1.16.1", optional = true } +clap = { version = "4.4", features = ["derive"] } [target.x86_64-fortanix-unknown-sgx.dependencies] rs-libc = "0.2.4" @@ -62,7 +66,13 @@ cc = "1.0" [features] # Features are documented in the README default = ["std", "aesni", "time", "padlock"] -std = ["byteorder/std", "mbedtls-sys-auto/std", "serde/std", "yasna", "mbedtls-platform-support/std"] +std = [ + "byteorder/std", + "mbedtls-sys-auto/std", + "serde/std", + "yasna", + "mbedtls-platform-support/std", +] debug = ["mbedtls-sys-auto/debug"] no_std_deps = ["mbedtls-platform-support/spin", "serde/alloc"] force_aesni_support = ["mbedtls-platform-support/force_aesni_support", "aesni"] diff --git a/mbedtls/build.rs b/mbedtls/build.rs index b334a6c28..fa69b8632 100644 --- a/mbedtls/build.rs +++ b/mbedtls/build.rs @@ -23,6 +23,12 @@ fn get_compilation_metadata_hash() -> String { } fn main() { + println!("cargo:rustc-link-lib=dylib=ra_tls_attest"); + println!("cargo:rustc-link-lib=dylib=ra_tls_verify_dcap_gramine"); + println!("cargo:rustc-link-lib=dylib=ra_tls_verify_dcap"); + println!("cargo:rustc-link-lib=dylib=sgx_urts"); + println!("cargo:rustc-link-search=all=/home/ubuntu/rust-mbedtls/mbedtls/examples"); + let metadata_hash = get_compilation_metadata_hash(); println!("cargo:rustc-env=RUST_MBEDTLS_METADATA_HASH={}", metadata_hash); diff --git a/mbedtls/examples/client.rs b/mbedtls/examples/client.rs index f3087334d..9d1597f1a 100644 --- a/mbedtls/examples/client.rs +++ b/mbedtls/examples/client.rs @@ -6,9 +6,14 @@ * option. This file may not be copied, modified, or distributed except * according to those terms. */ -// needed to have common code for `mod support` in unit and integrations tests +#![feature(c_size_t)] + extern crate mbedtls; +use clap::Parser; +use core::ffi::{c_char, c_int, c_size_t, c_uchar, c_uint}; +use mbedtls::error::LoError::Asn1InvalidData; +use std::ffi::CStr; use std::io::{self, stdin, stdout, Write}; use std::net::TcpStream; use std::sync::Arc; @@ -16,7 +21,7 @@ use std::sync::Arc; use mbedtls::rng::CtrDrbg; use mbedtls::ssl::config::{Endpoint, Preset, Transport}; use mbedtls::ssl::{Config, Context}; -use mbedtls::x509::Certificate; +use mbedtls::x509::{Certificate, VerifyError}; use mbedtls::Result as TlsResult; #[path = "../tests/support/mod.rs"] @@ -24,32 +29,303 @@ mod support; use support::entropy::entropy_new; use support::keys; +/********************************** Beginning of the FFI section **********************************/ + +// FFI stuff for the functions defined in libra_tls_verify_dcap_gramine.so (if run in SGX enclave) +// and libra_tls_verify_dcap.so (if run outside of SGX enclave). +// See: https://github.com/gramineproject/gramine/blob/master/tools/sgx/ra-tls/ra_tls.h + +// FFI for `ra_tls_verify_callback_extended_der` function + +pub type RATLSAttestationScheme = c_uint; +pub const RA_TLS_ATTESTATION_SCHEME_T_RA_TLS_ATTESTATION_SCHEME_UNKNOWN: RATLSAttestationScheme = 0; +pub const RA_TLS_ATTESTATION_SCHEME_T_RA_TLS_ATTESTATION_SCHEME_EPID: RATLSAttestationScheme = 1; +pub const RA_TLS_ATTESTATION_SCHEME_T_RA_TLS_ATTESTATION_SCHEME_DCAP: RATLSAttestationScheme = 2; + +pub type RATLSErrLoc = c_uint; +pub const RA_TLS_ERR_LOC_T_AT_NONE: RATLSErrLoc = 0; +pub const RA_TLS_ERR_LOC_T_AT_INIT: RATLSErrLoc = 1; +pub const RA_TLS_ERR_LOC_T_AT_EXTRACT_QUOTE: RATLSErrLoc = 2; +pub const RA_TLS_ERR_LOC_T_AT_VERIFY_EXTERNAL: RATLSErrLoc = 3; +pub const RA_TLS_ERR_LOC_T_AT_VERIFY_ENCLAVE_ATTRS: RATLSErrLoc = 4; +pub const RA_TLS_ERR_LOC_T_AT_VERIFY_ENCLAVE_MEASUREMENTS: RATLSErrLoc = 5; + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct RATLSverifyCallbackResultsEPID { + pub ias_enclave_quote_status: [c_char; 128usize], +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct RATLSVerifyCallbackResultsDCAP { + pub func_verify_quote_result: c_int, + pub quote_verification_result: c_int, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct RATLSVerifyCallbackResultsMisc { + pub reserved: [c_char; 128usize], +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub union ra_tls_verify_callback_results_union { + pub epid: RATLSverifyCallbackResultsEPID, + pub dcap: RATLSVerifyCallbackResultsDCAP, + pub misc: RATLSVerifyCallbackResultsMisc, +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct RATLSVerifyCallbackResults { + pub attestation_scheme: RATLSAttestationScheme, + pub err_loc: RATLSErrLoc, /* the step at which RA-TLS failed with RA_TLS_ERR_LOC_T_AT_VERIFY_ENCLAVE_ATTRS */ + pub __bindgen_anon_1: ra_tls_verify_callback_results_union, +} + +extern "C" { + /// Generic verification callback for EPID-based (IAS) or ECDSA-based (DCAP) quote verification + /// (DER format) with additional information. + /// + /// * `der_crt` - Self-signed RA-TLS certificate with SGX quote embedded in DER format. + /// * `der_crt_size` - Size of the RA-TLS certificate. + /// * `results` - (Optional) Verification callback results for retrieving additional + /// verification results from RA-TLS. + /// + /// Returns 0 on success, specific mbedTLS error code (negative int) otherwise. This function + /// must be called from a non-mbedTLS verification callback, e.g., from a user-defined OpenSSL + /// callback for SSL_CTX_set_cert_verify_callback(). All parameters required for the SGX quote, + /// IAS attestation report verification, and/or DCAP quote verification must be passed in the + /// corresponding RA-TLS environment variables. + /// + /// Originally defined as: int ra_tls_verify_callback_extended_der(uint8_t* der_crt, size_t + /// der_crt_size, struct ra_tls_verify_callback_results* results); + /// + /// See: + /// https://raw.githubusercontent.com/gramineproject/gramine/master/tools/sgx/ra-tls/ra_tls.h + pub fn ra_tls_verify_callback_extended_der( + der_crt: *mut c_uchar, + der_crt_size: c_size_t, + results: *mut RATLSVerifyCallbackResults, + ) -> c_int; +} + +// FFI for `ra_tls_set_measurement_callback` function + +pub type VerifyMeasurementsCallback = Option< + unsafe extern "C" fn( + mrenclave: *const c_char, + mrsigner: *const c_char, + isv_prod_id: *const c_char, + isv_svn: *const c_char, + ) -> c_int, +>; + +extern "C" { + /// Callback for user-specific verification of measurements in SGX quote. + /// + /// * `f_cb` - Callback for user-specific verification; RA-TLS passes pointers to MRENCLAVE, + /// MRSIGNER, ISV_PROD_ID, ISV_SVN measurements in SGX quote. Use NULL to revert to + /// default behavior of RA-TLS. + /// + /// Returns 0 on success, specific error code (negative int) otherwise. + /// + /// If this callback is registered before RA-TLS session, then RA-TLS verification will invoke + /// this callback to allow for user-specific checks on SGX measurements reported in the SGX + /// quote. If no callback is registered (or registered as NULL), then RA-TLS defaults to + /// verifying SGX measurements against `RA_TLS_*` environment variables (if any). + pub fn ra_tls_set_measurement_callback(f_cb: VerifyMeasurementsCallback); +} + +fn are_equal_u8_array_and_c_string(u8_array: &[u8], c_string_ptr: *const c_char) -> bool { + let c_str_from_ptr = unsafe { CStr::from_ptr(c_string_ptr) }; + + let arr_as_str = unsafe { + let len = u8_array + .iter() + .position(|&c| c == 0) + .unwrap_or(u8_array.len()); + std::str::from_utf8_unchecked(&u8_array[..len]) + }; + + c_str_from_ptr.to_bytes() == arr_as_str.as_bytes() +} + +static mut MRENCLAVE_ARR: [u8; 32] = [0; 32]; +static mut MRSIGNER_ARR: [u8; 32] = [0; 32]; +static mut ISV_PROD_ID_ARR: [u8; 2] = [0; 2]; +static mut ISV_SVN_ARR: [u8; 2] = [0; 2]; + +unsafe extern "C" fn measurement_verification_callback( + mrenclave: *const c_char, + mrsigner: *const c_char, + isv_prod_id: *const c_char, + isv_svn: *const c_char, +) -> c_int { + assert!(!mrenclave.is_null()); + assert!(!mrsigner.is_null()); + assert!(!isv_prod_id.is_null()); + assert!(!isv_svn.is_null()); + + let pairs = [(&MRENCLAVE_ARR, mrenclave), (&MRSIGNER_ARR, mrsigner)]; + + for &(arr, c_str_ptr) in &pairs { + if are_equal_u8_array_and_c_string(arr, c_str_ptr) == false { + return -1; + } + } + + let pairs2 = [(&ISV_PROD_ID_ARR, isv_prod_id), (&ISV_SVN_ARR, isv_svn)]; + + for &(arr, c_str_ptr) in &pairs2 { + if are_equal_u8_array_and_c_string(arr, c_str_ptr) == false { + return -1; + } + } + + 0 +} + +/************************************* End of the FFI section *************************************/ + +fn parse_hex(hex: &str, buffer: &mut [u8; 32]) -> Result<(), &'static str> { + if hex.len() != buffer.len() * 2 { + return Err("Hex string length does not match buffer size"); + } + + for i in 0..buffer.len() { + let hex_byte = &hex[i * 2..i * 2 + 2]; + + if !hex_byte.chars().all(|c| c.is_ascii_hexdigit()) { + return Err("Invalid hexadecimal character detected"); + } + + if let Ok(parsed_byte) = u8::from_str_radix(hex_byte, 16) { + buffer[i] = parsed_byte; + } else { + return Err("Failed to parse hexadecimal byte"); + } + } + + Ok(()) +} + fn result_main(addr: &str) -> TlsResult<()> { let entropy = Arc::new(entropy_new()); - let rng = Arc::new(CtrDrbg::new(entropy, None)?); - let cert = Arc::new(Certificate::from_pem_multiple(keys::ROOT_CA_CERT.as_bytes())?); + let rng: Arc = Arc::new(CtrDrbg::new(entropy, None)?); + let cert = Arc::new(Certificate::from_pem_multiple( + keys::ROOT_CA_CERT.as_bytes(), + )?); + + let verify_callback = move |crt: &Certificate, depth: i32, verify_flags: &mut VerifyError| { + if depth != 0 { + println!("Depth should be 0 but is {}", depth); + // the cert chain in RA-TLS consists of single self-signed cert, so we expect depth 0 */ + return Err(Asn1InvalidData.into()); // MBEDTLS_ERR_X509_INVALID_FORMAT + } + if *verify_flags != VerifyError::empty() { + /* mbedTLS sets flags to signal that the cert is not to be trusted (e.g., it is not + * correctly signed by a trusted CA; since RA-TLS uses self-signed certs, we don't care + * what mbedTLS thinks and ignore internal cert verification logic of mbedTLS */ + *verify_flags = VerifyError::empty(); + } + let mut ratls_verify_results: RATLSVerifyCallbackResults = unsafe { std::mem::zeroed() }; + let mut der_data: Vec = crt.as_der().to_vec(); + println!("DER data: {:?}", der_data); // prints the same DER that was generated by the server + let der_ptr = der_data.as_mut_ptr(); + let der_len = der_data.len(); + unsafe { + let ret = ra_tls_verify_callback_extended_der( + der_ptr, + der_len, + &mut ratls_verify_results as *mut RATLSVerifyCallbackResults, + ); + println!("debug_info: {:?}", ratls_verify_results.err_loc); + if ret != 0 { + println!("ra_tls_verify_callback_extended_der returned {}", ret); + return Err(Asn1InvalidData.into()); + } + } + + Ok(()) + }; + let mut config = Config::new(Endpoint::Client, Transport::Stream, Preset::Default); config.set_rng(rng); - config.set_ca_list(cert, None); + // https://github.com/fortanix/rust-mbedtls/blob/52476eed8af2824cc331acbd5ec84151a836291a/mbedtls/tests/ssl_conf_verify.rs#L53C25-L54C49 + config.set_verify_callback(verify_callback); + config.set_ca_list(cert, None); // TODO needed? let mut ctx = Context::new(Arc::new(config)); let conn = TcpStream::connect(addr).unwrap(); - ctx.establish(conn, None)?; + ctx.establish(conn, None)?; // TODO it is failing here (callback failure) let mut line = String::new(); stdin().read_line(&mut line).unwrap(); ctx.write_all(line.as_bytes()).unwrap(); io::copy(&mut ctx, &mut stdout()).unwrap(); + Ok(()) } +#[derive(Parser)] +struct Cli { + address: String, + mrenclave: String, + mrsigner: String, + isv_prod_id: u16, + isv_svn: u16, +} + +// Run with: +// export RA_TLS_ALLOW_DEBUG_ENCLAVE_INSECURE=1 +// export RA_TLS_ALLOW_HW_CONFIG_NEEDED=1 +// export RA_TLS_ALLOW_OUTDATED_TCB_INSECURE=1 +// export RA_TLS_ALLOW_SW_HARDENING_NEEDED=1 +// RUST_BACKTRACE=1 ./client 127.0.0.1:8080 3ed8e65a2635898edfd1cf746256f0483005ca8aaab259c2f93066c537816f7a 669b80648c2d9c97f32263fa1961f95f83818682d6359758221f0e7acb9584c0 0 0 +// +// See the details: +// https://gramine.readthedocs.io/en/stable/attestation.html +// +// TODO - throws: +// ra_tls_verify_callback: Quote: verification failed with error OUT_OF_DATE_CONFIG_NEEDED +// ra_tls_verify_callback_extended_der returned -9984 +// +// Related to the above -9984 error: +// https://github.com/gramineproject/gramine/discussions/1139 +// https://github.com/gramineproject/gramine/discussions/1494#discussioncomment-6776238 +// +// For reference, see how SSL connection is implemented in mbedtls tests directory: +// https://github.com/fortanix/rust-mbedtls/blob/52476eed8af2824cc331acbd5ec84151a836291a/mbedtls/tests/ssl_conf_verify.rs#L19 fn main() { - let mut args = std::env::args(); - args.next(); - result_main( - &args - .next() - .expect("supply destination in command-line argument"), - ) - .unwrap(); + let args = Cli::parse(); + + // Convert arguments to the format expected by FFI + + unsafe { + match parse_hex(&args.mrenclave, &mut MRENCLAVE_ARR) { + Ok(_) => println!( + "Mrenclave hex string parsed successfully: {:?}", + MRENCLAVE_ARR + ), + Err(err) => println!("Error: {}", err), + } + match parse_hex(&args.mrsigner, &mut MRSIGNER_ARR) { + Ok(_) => println!( + "Mrsigner hex string parsed successfully: {:?}", + MRSIGNER_ARR + ), + Err(err) => println!("Error: {}", err), + } + ISV_PROD_ID_ARR.copy_from_slice(&args.isv_prod_id.to_le_bytes()); + ISV_SVN_ARR.copy_from_slice(&args.isv_svn.to_le_bytes()); + } + + unsafe { + ra_tls_set_measurement_callback(Some(measurement_verification_callback)); + } + + result_main(&args.address).unwrap(); } diff --git a/mbedtls/examples/libra_tls_attest.so b/mbedtls/examples/libra_tls_attest.so new file mode 100755 index 000000000..5ecc5cf80 Binary files /dev/null and b/mbedtls/examples/libra_tls_attest.so differ diff --git a/mbedtls/examples/libra_tls_verify_dcap.so b/mbedtls/examples/libra_tls_verify_dcap.so new file mode 100755 index 000000000..a1e7fd70e Binary files /dev/null and b/mbedtls/examples/libra_tls_verify_dcap.so differ diff --git a/mbedtls/examples/libra_tls_verify_dcap_gramine.so b/mbedtls/examples/libra_tls_verify_dcap_gramine.so new file mode 100755 index 000000000..24964e1aa Binary files /dev/null and b/mbedtls/examples/libra_tls_verify_dcap_gramine.so differ diff --git a/mbedtls/examples/libsgx_urts.so b/mbedtls/examples/libsgx_urts.so new file mode 100644 index 000000000..3be7471d7 Binary files /dev/null and b/mbedtls/examples/libsgx_urts.so differ diff --git a/mbedtls/examples/server-sgx.manifest.template b/mbedtls/examples/server-sgx.manifest.template new file mode 100644 index 000000000..462e0a477 --- /dev/null +++ b/mbedtls/examples/server-sgx.manifest.template @@ -0,0 +1,45 @@ +# RA-TLS manifest file example + +loader.entrypoint = "file:{{ gramine.libos }}" +libos.entrypoint = "/server-sgx" +loader.log_level = "{{ log_level }}" +loader.env.LD_LIBRARY_PATH = "/lib:{{ arch_libdir }}:/usr{{ arch_libdir }}" +loader.insecure__use_cmdline_argv = true + +sys.enable_sigterm_injection = true + +fs.mounts = [ + { path = "/lib", uri = "file:{{ gramine.runtimedir() }}" }, + { path = "{{ arch_libdir }}", uri = "file:{{ arch_libdir }}" }, + { path = "/usr{{ arch_libdir }}", uri = "file:/usr{{ arch_libdir }}" }, + { path = "/usr/lib/ssl/certs/", uri = "file:/usr/lib/ssl/certs/" }, + { path = "/tmp", uri = "file:/tmp" }, + { path = "/etc", uri = "file:/etc" }, +] + +sgx.debug = false +sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} + +sgx.remote_attestation = "dcap" + +sgx.trusted_files = [ + "file:{{ gramine.libos }}", + "file:server-sgx", + "file:{{ gramine.runtimedir() }}/", + "file:{{ arch_libdir }}/", + "file:/usr{{ arch_libdir }}/", + "file:{{ arch_libdir }}/libgcc_s.so.1", + "file:{{ arch_libdir }}/libssl.so.3", + "file:{{ arch_libdir }}/libcrypto.so.3", + "file:/usr/lib/ssl/certs/", +] + +sgx.allowed_files = [ + "file:/etc/nsswitch.conf", + "file:/etc/ethers", + "file:/etc/hosts", + "file:/etc/group", + "file:/etc/passwd", + "file:/etc/gai.conf", + "file:/tmp", +] diff --git a/mbedtls/examples/server-sgx.rs b/mbedtls/examples/server-sgx.rs new file mode 100644 index 000000000..62d91578b --- /dev/null +++ b/mbedtls/examples/server-sgx.rs @@ -0,0 +1,177 @@ +/* Copyright (c) Fortanix, Inc. + * + * Licensed under the GNU General Public License, version 2 or the Apache License, Version + * 2.0 , at your + * option. This file may not be copied, modified, or distributed except + * according to those terms. */ + +#![feature(c_size_t)] + +// needed to have common code for `mod support` in unit and integrations tests +extern crate mbedtls; + +use std::fs::File; +use std::io::prelude::*; +use std::io::{BufRead, BufReader, Write}; +use std::net::{TcpListener, TcpStream}; +use std::sync::Arc; + +use mbedtls::alloc::List as MbedtlsList; +use mbedtls::pk::Pk; +use mbedtls::rng::CtrDrbg; +use mbedtls::ssl::config::{Endpoint, Preset, Transport}; +use mbedtls::ssl::{Config, Context}; +use mbedtls::x509::Certificate; +use mbedtls::Result as TlsResult; + +#[path = "../tests/support/mod.rs"] +mod support; +use support::entropy::entropy_new; +use support::keys; +use support::rand::test_rng; + +use core::ffi::{c_int, c_size_t, c_uchar}; + +// Define functions exported from Gramine's libra_tls_attest.so (RA-TLS) +// #[link(name = "ra_tls_attest")] +extern "C" { + fn ra_tls_create_key_and_crt_der( + der_key: *mut *mut c_uchar, + der_key_size: *mut c_size_t, + der_crt: *mut *mut c_uchar, + der_crt_size: *mut c_size_t, + ) -> c_int; +} + +fn listen Result<(), E>>(mut handle_client: F) -> Result<(), E> { + let sock = TcpListener::bind("127.0.0.1:8080").unwrap(); + for conn in sock.incoming().map(Result::unwrap) { + println!("Connection from {}", conn.peer_addr().unwrap()); + handle_client(conn)?; + } + + Ok(()) +} + +fn result_main() -> TlsResult<()> { + // TODO + // + // https://gramine.readthedocs.io/en/latest/devel/debugging.html?highlight=meson#debugging-gramine-with-gdb + // meson setup build-debug/ --werror -Ddirect=enabled -Ddcap=enabled -Dsgx=enabled + // ninja -C build-debug/ + // cargo build --example server-sgx --verbose + // ubuntu@VM-0-6-ubuntu:~/rust-mbedtls/target/debug/examples$ gramine-manifest -Dlog_level=error -Darch_libdir=/lib/x86_64-linux-gnu/ ./server-sgx.manifest.template ./server-sgx.manifest + // ubuntu@VM-0-6-ubuntu:~/rust-mbedtls/target/debug/examples$ gramine-sgx-sign --manifest ./server-sgx.manifest --output ./server-sgx.manifest.sgx + // ubuntu@VM-0-6-ubuntu:~/rust-mbedtls/target/debug/examples$ sudo gramine-sgx ./server-sgx + // ubuntu@VM-0-6-ubuntu:~/gramine$ nm -D ./build-debug/tools/sgx/ra-tls/libra_tls_attest.so + // ubuntu@VM-0-6-ubuntu:~/rust-mbedtls/target/debug/examples$ gramine-sgx-sigstruct-view ./server-sgx.sig + // ubuntu@VM-0-6-ubuntu:~/rust-mbedtls/target/debug/examples$ nm -D /home/ubuntu/rust-mbedtls/mbedtls/examples/libra_tls_attest.so + // https://github.com/gramineproject/gramine/blob/master/CI-Examples/ra-tls-mbedtls/src/server.c + // https://stackoverflow.com/questions/40602708/linking-rust-application-with-a-dynamic-library-not-in-the-runtime-linker-search + + // assert /dev/attestation/attestation_type == "dcap" + + if let Ok(mut attestation_type_file) = File::open("/dev/attestation/attestation_type") { + let mut attestation_type = String::new(); + if let Ok(_) = attestation_type_file.read_to_string(&mut attestation_type) { + println!("Detected attestation type: {}", attestation_type.trim()); + } + assert_eq!(attestation_type, "dcap"); + } + + // Seeding the random number generator: + // 4. ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char*)pers, strlen(pers)); + + let entropy = entropy_new(); + let rng = Arc::new(CtrDrbg::new(Arc::new(entropy), None)?); + + // Creating the RA-TLS server cert and key: + // 5. ret = (*ra_tls_create_key_and_crt_der_f)(&der_key, &der_key_size, &der_crt, &der_crt_size); + + let mut der_key: *mut c_uchar = std::ptr::null_mut(); + let der_key_ptr: *mut *mut c_uchar = &mut der_key; + let mut der_key_size: c_size_t = 0; + let mut der_crt: *mut c_uchar = std::ptr::null_mut(); + let der_crt_ptr: *mut *mut c_uchar = &mut der_crt; + let mut der_crt_size: c_size_t = 0; + + // throws MBEDTLS_ERR_X509_FILE_IO_ERROR (-10496) + let result = unsafe { + ra_tls_create_key_and_crt_der( + der_key_ptr, + &mut der_key_size, + der_crt_ptr, + &mut der_crt_size, + ) + }; + + if result != 0 { + panic!( + "Failed to obtain key and certificate data (error code: {})", + result + ); + } + + println!("Successfully obtained key and certificate data."); + + // Convert the raw pointers and sizes to slices + let der_key_slice = unsafe { std::slice::from_raw_parts(der_key, der_key_size as usize) }; + let der_crt_slice = unsafe { std::slice::from_raw_parts(der_crt, der_crt_size as usize) }; + + // Print or use the key and certificate data as needed + println!("DER Key: {:?}", der_key_slice); + println!("DER Certificate: {:?}", der_crt_slice); + + // Ensure to free the allocated memory in the C function + // unsafe { + // libc::free(der_key_ptr as *mut c_void); + // libc::free(der_crt_ptr as *mut c_void); + // } + + // 6. ret = mbedtls_x509_crt_parse(&srvcert, (unsigned char*)der_crt, der_crt_size); + let cert = Certificate::from_der(der_crt_slice)?; // generate using libra_tls_attest.so instead (ra_tls_create_key_and_crt_der function) + // cert.extensions_raw().unwrap() + println!("raz dwa {}", hex::encode(cert.extensions_raw().unwrap())); + // 7. ret = mbedtls_pk_parse_key(&pkey, (unsigned char*)der_key, der_key_size, /*pwd=*/NULL, 0, mbedtls_ctr_drbg_random, &ctr_drbg); + + let key = Pk::from_private_key(&mut test_rng(), der_key_slice, None)?; + + // Bind on https://localhost:4433/: + // 8. ret = mbedtls_net_bind(&listen_fd, NULL, "4433", MBEDTLS_NET_PROTO_TCP); + // Setting up the SSL data: + // 9. ret = mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); + // 10. mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg); + // 11. mbedtls_ssl_conf_dbg(&conf, my_debug, stdout); + // 12. ret = mbedtls_ssl_conf_own_cert(&conf, &srvcert, &pkey); + // 13. ret = mbedtls_ssl_setup(&ssl, &conf); + + let mut config = Config::new(Endpoint::Server, Transport::Stream, Preset::Default); + config.set_rng(rng); + let mut cert_list = MbedtlsList::::new(); + cert_list.push(cert); + let arc_cert_list = Arc::new(cert_list); + config.push_cert(arc_cert_list, key.into())?; + + let rc_config = Arc::new(config); + + // Waiting for a remote connection: + // 14. ret = mbedtls_net_accept(&listen_fd, &client_fd, NULL, 0, NULL); + // 15. mbedtls_ssl_set_bio(&ssl, &client_fd, mbedtls_net_send, mbedtls_net_recv, NULL); + + listen(move |conn| { + let mut ctx = Context::new(rc_config.clone()); + ctx.establish(conn, None)?; + let mut session = BufReader::new(ctx); + let mut line = Vec::new(); + session.read_until(b'\n', &mut line).unwrap(); + let s = String::from_utf8(line.clone()).expect("Found invalid UTF-8"); + println!("result: {}", s); + session.get_mut().write_all(&line).unwrap(); + Ok(()) + }) +} + +fn main() { + result_main().unwrap(); +}