From ef0e2356c4fc0f4cf43bb09040d4b95739f5d1b5 Mon Sep 17 00:00:00 2001 From: Nick Santana Date: Tue, 11 Oct 2022 15:39:31 -0700 Subject: [PATCH] Add `PathInitializer` to `mc-sgx-dcap-ql` Add a `PathInitializer` struct to `mc-sgx-dcap-ql` to ensure that the necessary DCAP quote library paths are set prior to making quote library calls. As well as ensuring that the paths are only initialized once. --- Cargo.lock | 156 ++++++++++++++++- dcap/ql/Cargo.toml | 3 + dcap/ql/src/lib.rs | 21 ++- dcap/ql/src/quote3.rs | 39 ++--- dcap/ql/src/quote_enclave.rs | 315 +++++++++++++++++++++++++++++------ 5 files changed, 458 insertions(+), 76 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5cd384aa5..4481f49d2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -175,6 +175,19 @@ dependencies = [ "typenum", ] +[[package]] +name = "dashmap" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" +dependencies = [ + "cfg-if", + "hashbrown", + "lock_api", + "once_cell", + "parking_lot_core", +] + [[package]] name = "der" version = "0.5.1" @@ -264,9 +277,9 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[package]] name = "hashbrown" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "607c8a29735385251a339424dd462993c0fed8fa09d378f259377df08c126022" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hermit-abi" @@ -339,6 +352,16 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "292a948cd991e376cf75541fe5b97a1081d713c618b4f1b9500f8844e49eb565" +[[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "log" version = "0.4.17" @@ -426,12 +449,15 @@ dependencies = [ name = "mc-sgx-dcap-ql" version = "0.2.1-pre" dependencies = [ + "displaydoc", "mc-sgx-core-sys-types", "mc-sgx-core-types", "mc-sgx-dcap-ql-sys", "mc-sgx-dcap-ql-types", "mc-sgx-dcap-types", "mc-sgx-util", + "once_cell", + "serial_test", "tempfile", "yare", ] @@ -755,12 +781,41 @@ dependencies = [ "libm", ] +[[package]] +name = "once_cell" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" + [[package]] name = "os_str_bytes" version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa" +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + [[package]] name = "peeking_take_while" version = "0.1.2" @@ -804,6 +859,30 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.43" @@ -913,6 +992,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "serde" version = "1.0.145" @@ -933,6 +1018,30 @@ dependencies = [ "syn", ] +[[package]] +name = "serial_test" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92761393ee4dc3ff8f4af487bd58f4307c9329bbedea02cac0089ad9c411e153" +dependencies = [ + "dashmap", + "lazy_static", + "parking_lot", + "serial_test_derive", +] + +[[package]] +name = "serial_test_derive" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b6f5d1c3087fb119617cff2966fe3808a80e5eb59a8c1601d5994d66f4346a5" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "sha2" version = "0.10.6" @@ -1104,6 +1213,49 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + [[package]] name = "yare" version = "1.0.2" diff --git a/dcap/ql/Cargo.toml b/dcap/ql/Cargo.toml index cd9015d3d..f808608ea 100644 --- a/dcap/ql/Cargo.toml +++ b/dcap/ql/Cargo.toml @@ -13,12 +13,14 @@ categories = ["api-bindings", "hardware-support"] keywords = ["sgx"] [dependencies] +displaydoc = { version = "0.2.3", default-features = false } mc-sgx-core-sys-types = { path = "../../core/sys/types", version = "=0.2.1-pre" } mc-sgx-core-types = { path = "../../core/types", version = "=0.2.1-pre" } mc-sgx-dcap-ql-sys = { path = "sys", version = "=0.2.1-pre" } mc-sgx-dcap-ql-types = { path = "types", version = "=0.2.1-pre" } mc-sgx-dcap-types = { path = "../types", version = "=0.2.1-pre", features = ["alloc"] } mc-sgx-util = { path = "../../util", version = "=0.2.1-pre" } +once_cell = "1.15.0" [features] default = [] @@ -27,5 +29,6 @@ default = [] sim = [] [dev-dependencies] +serial_test = { version = "0.9.0", default-features = false } tempfile = "3.3.0" yare = "1.0.1" diff --git a/dcap/ql/src/lib.rs b/dcap/ql/src/lib.rs index 52ba77588..db42b3c92 100644 --- a/dcap/ql/src/lib.rs +++ b/dcap/ql/src/lib.rs @@ -8,5 +8,24 @@ extern crate alloc; mod quote3; mod quote_enclave; +use mc_sgx_dcap_types::Quote3Error; pub use quote3::TryFromReport; -pub use quote_enclave::{load_policy, set_path, QeTargetInfo}; +pub use quote_enclave::{load_policy, PathInitializer, QeTargetInfo}; + +/// Errors interacting with quote library functions +#[derive(Clone, Debug, displaydoc::Display, Eq, Hash, PartialEq, PartialOrd, Ord)] +#[non_exhaustive] +pub enum Error { + /// Paths have already been initialized + PathsInitialized, + /// Error from SGX quoting library function: {0} + Sgx(Quote3Error), + /// Failed ot convert a path to a string. Path {0} + PathStringConversion(String), +} + +impl From for Error { + fn from(src: Quote3Error) -> Self { + Self::Sgx(src) + } +} diff --git a/dcap/ql/src/quote3.rs b/dcap/ql/src/quote3.rs index aa38f95fa..80185c0da 100644 --- a/dcap/ql/src/quote3.rs +++ b/dcap/ql/src/quote3.rs @@ -5,17 +5,30 @@ //! This functionality requires HW SGX to work correctly otherwise all //! functionality will return errors. +use crate::Error; use mc_sgx_core_types::Report; -use mc_sgx_dcap_types::{Quote3, Quote3Error}; +use mc_sgx_dcap_types::Quote3; use mc_sgx_util::ResultInto; /// Create a Quote3 from a Report pub trait TryFromReport { /// Try to create a [`Quote3`] from the provided [`Report`] /// + /// Note: This will initialized the + /// [`PathInitializer`](crate::PathInitializer) to the defaults if the + /// [`PathInitializer`](crate::PathInitializer) has not been initialized + /// yet. Calling + /// [`PathInitializer::with_paths()`](crate::PathInitializer::with_paths) + /// after calling this function will result in an error. + /// /// # Arguments /// * `report` - The report to build the quote from - fn try_from_report(report: Report) -> Result>, Quote3Error> { + /// + /// # Errors + /// Will return an [`Error::Sgx`] if there is a failure from the SGX SDK + fn try_from_report(report: Report) -> Result>, Error> { + crate::PathInitializer::ensure_initialized()?; + let mut size = 0; unsafe { mc_sgx_dcap_ql_sys::sgx_qe_get_quote_size(&mut size) }.into_result()?; @@ -37,35 +50,17 @@ impl TryFromReport for Quote3> {} #[cfg(all(test, not(feature = "sim")))] mod test { use super::*; - use crate::{set_path, QeTargetInfo}; + use crate::QeTargetInfo; use mc_sgx_core_types::TargetInfo; - use mc_sgx_dcap_ql_types::PathKind::{ - IdEnclave, ProvisioningCertificateEnclave, QuotingEnclave, - }; #[test] fn get_quote() { - set_path( - ProvisioningCertificateEnclave, - "/usr/lib/x86_64-linux-gnu/libsgx_pce.signed.so.1", - ) - .unwrap(); - set_path( - QuotingEnclave, - "/usr/lib/x86_64-linux-gnu/libsgx_qe3.signed.so.1", - ) - .unwrap(); - set_path( - IdEnclave, - "/usr/lib/x86_64-linux-gnu/libsgx_id_enclave.signed.so.1", - ) - .unwrap(); // Target info must be gotten first in order to initialize sgx let _ = TargetInfo::for_quoting_enclave(); let report = Report::default(); assert_eq!( Quote3::try_from_report(report), - Err(Quote3Error::InvalidReport) + Err(Error::Sgx(Quote3Error::InvalidReport)) ); } } diff --git a/dcap/ql/src/quote_enclave.rs b/dcap/ql/src/quote_enclave.rs index f5515f8dd..a97048e08 100644 --- a/dcap/ql/src/quote_enclave.rs +++ b/dcap/ql/src/quote_enclave.rs @@ -8,17 +8,167 @@ //! has a mix up. It uses the *verification* description for `sgx_ql_set_path` //! and the "generation" description for `sgx_qv_set_path` +use crate::Error; +use core::result::Result as CoreResult; use mc_sgx_core_sys_types::sgx_target_info_t; use mc_sgx_core_types::TargetInfo; use mc_sgx_dcap_ql_types::PathKind; -use mc_sgx_dcap_types::{Quote3Error, RequestPolicy}; +use mc_sgx_dcap_types::RequestPolicy; use mc_sgx_util::ResultInto; +use once_cell::sync::OnceCell; use std::{ffi::CString, os::unix::ffi::OsStrExt, path::Path}; +/// A convenience type alias for a `Result` which contains an [`Error`]. +pub type Result = CoreResult; + +/// Initialization of the paths for the quoting enclaves and quote provider +/// library +/// +/// This can only be called once during process start up utilizing +/// [`PathInitializer::with_paths()`] or [`PathInitializer::try_default()`]. +/// If a consumer of this crate does not explicitly initialize the paths, then +/// they will be defaulted on the first call to an SGX function that needs the +/// paths set. +#[derive(Debug)] +pub struct PathInitializer; +static PATH_INITIALIZER: OnceCell = OnceCell::new(); + +impl PathInitializer { + /// Try to initialize the paths to the default for the system + /// + /// Currently the defaults assume the default DCAP install on an Ubuntu + /// machine. + /// + /// # Errors + /// * [`Error::PathsInitialized`] if the paths have been previously + /// initialized. + /// * [`Error::Sgx`] if any of the default paths don't exist on the system. + pub fn try_default() -> Result<()> { + Self::with_paths( + "/usr/lib/x86_64-linux-gnu/libsgx_qe3.signed.so.1", + "/usr/lib/x86_64-linux-gnu/libsgx_pce.signed.so.1", + None, + "/usr/lib/x86_64-linux-gnu/libsgx_id_enclave.signed.so.1", + ) + } + + /// Initialize the DCAP quoting library paths with provided values + /// + /// # Arguments + /// * `quoting_enclave` - The full file path to the quoting enclave + /// * `provisioning_certificate_enclave` - The full file path to the + /// provisioning certificate enclave + /// * `quote_provider_library` - The full file path to the quote provider + /// library. When this is `None` then no quote provider library will be + /// used limiting quote generation to local quote generation only. + /// * `id_enclave` - The full file path to the ID enclave. + /// + /// # Errors + /// * [`Error::PathsInitialized`] if the paths have been previously + /// initialized. + /// * [`Error::PathStringConversion`] if one of the paths cannot be + /// converted to a [`CString`] + /// * [`Error::Sgx`] if + /// * one of the paths does not point to a file + /// * one of the paths is longer than 259 (bytes) + /// * one of the paths contains a null (0) byte. + pub fn with_paths>( + quoting_enclave: P, + provisioning_certificate_enclave: P, + quote_provider_library: Option

, + id_enclave: P, + ) -> Result<()> { + let mut paths_set = false; + PATH_INITIALIZER.get_or_try_init(|| { + paths_set = true; + Self::set_paths( + quoting_enclave, + provisioning_certificate_enclave, + quote_provider_library, + id_enclave, + ) + })?; + match paths_set { + true => Ok(()), + false => Err(Error::PathsInitialized), + } + } + + /// Will ensure the paths have been initialized + /// + /// If the paths have not been initialized will initialize to the default. + /// + /// # Errors + /// Will return [`Error::Sgx`] if the paths have not been initialized and + /// the default paths don't exist. + /// + /// Will *not* return an error if the paths were previously initialized. + pub(crate) fn ensure_initialized() -> Result<()> { + match Self::try_default() { + Ok(_) | Err(Error::PathsInitialized) => Ok(()), + Err(e) => Err(e), + } + } + + fn set_paths>( + quoting_enclave: P, + provisioning_certificate_enclave: P, + quote_provider_library: Option

, + id_enclave: P, + ) -> Result { + Self::set_path(PathKind::QuotingEnclave, quoting_enclave)?; + Self::set_path( + PathKind::ProvisioningCertificateEnclave, + provisioning_certificate_enclave, + )?; + Self::set_path(PathKind::IdEnclave, id_enclave)?; + quote_provider_library.map_or(Ok(()), |path| { + Self::set_path(PathKind::QuoteProviderLibrary, path) + })?; + Ok(PathInitializer) + } + + /// Set path for QE(Quoting Enclave), PCE(Provisioning Certificate Enclave) + /// or QPL(Quote Provider Library) + /// + /// This allows one to override the path that will be searched for each + /// `path_kind`. When this isn't called then the local path and dlopen + /// search path will be utilized. + /// + /// # Arguments + /// * `path_kind` - Which path to set + /// * `path` - The path value to use. This is the full path to a file. + /// + /// # Errors + /// * [`Error::PathStringConversion`] if `path_kind` cannot be converted to + /// a [`CString`] + /// * [`Error::Sgx`] if + /// * `path` does not point to a file + /// * `path` is longer than 259 (bytes) + /// * `path` contains a null (0) byte. + fn set_path>(path_kind: PathKind, path: P) -> Result<()> { + let c_path = CString::new(path.as_ref().as_os_str().as_bytes()).map_err(|_| { + Error::PathStringConversion(path.as_ref().to_string_lossy().into_owned()) + })?; + unsafe { mc_sgx_dcap_ql_sys::sgx_ql_set_path(path_kind.into(), c_path.as_ptr()) } + .into_result()?; + Ok(()) + } +} + /// Target info for quoting enclave pub trait QeTargetInfo { /// The target info of the QE(Quoting Enclave) - fn for_quoting_enclave() -> Result { + /// + /// Note: This will initialized the [`PathInitializer`] to the + /// defaults if the [`PathInitializer`] has not been initialized yet. + /// Calling [`PathInitializer::with_paths()`] after calling this function + /// will result in an error. + /// + /// # Errors + /// Will return an error if there is a failure from the SGX SDK + fn for_quoting_enclave() -> Result { + PathInitializer::ensure_initialized()?; let mut info = sgx_target_info_t::default(); unsafe { mc_sgx_dcap_ql_sys::sgx_qe_get_target_info(&mut info) }.into_result()?; Ok(info.into()) @@ -27,33 +177,13 @@ pub trait QeTargetInfo { impl QeTargetInfo for TargetInfo {} -/// Set path for QE(Quoting Enclave), PCE(Provisioning Certificate Enclave) or -/// QPL(Quote Provider Library) -/// -/// This allows one to override the path that will be searched for each -/// `path_kind`. When this isn't called then the local path and dlopen search -/// path will be utilized. -/// -/// Returns [`Quote3Error`] when -/// * `path` does not point to a file -/// * `path` is longer than 259 (bytes) -/// * `path` contains a null (0) byte. -/// -/// # Arguments -/// * `path_type` - Which path to set -/// * `path` - The path value to use. This is the full path to a file. -pub fn set_path>(path_kind: PathKind, path: P) -> Result<(), Quote3Error> { - let c_path = CString::new(path.as_ref().as_os_str().as_bytes()) - .map_err(|_| Quote3Error::InvalidParameter)?; - unsafe { mc_sgx_dcap_ql_sys::sgx_ql_set_path(path_kind.into(), c_path.as_ptr()) }.into_result() -} - /// Set the load policy /// /// # Arguments /// * `policy` - The policy to use for loading quoting enclaves -pub fn load_policy(policy: RequestPolicy) -> Result<(), Quote3Error> { - unsafe { mc_sgx_dcap_ql_sys::sgx_qe_set_enclave_load_policy(policy.into()) }.into_result() +pub fn load_policy(policy: RequestPolicy) -> Result<()> { + unsafe { mc_sgx_dcap_ql_sys::sgx_qe_set_enclave_load_policy(policy.into()) }.into_result()?; + Ok(()) } #[cfg(test)] @@ -62,10 +192,36 @@ mod test { use mc_sgx_dcap_ql_types::PathKind::{ ProvisioningCertificateEnclave, QuoteProviderLibrary, QuotingEnclave, }; - use std::fs; + use serial_test::serial; + use std::{ffi::c_void, fs}; use tempfile::tempdir; use yare::parameterized; + /// Resets the [`PATH_INITIALIZER`] to being uninitialized. This is *not* + /// thread safe so tests that make use of this need to utilize the + /// `#[serial]` macro. + fn reset_path_initializer() { + // SAFETY: This is only performed in tests. While it may be undefined + // behavior to convert from const to mutable, IFF this fails the outcome + // would be isolated to test failures. + // See https://doc.rust-lang.org/nomicon/transmutes.html + // + // > Transmuting an & to &mut is always Undefined Behavior. + // + // In general don't do this if you don't have to, even in tests. It was + // done this way to ensure proper error handling when the paths were + // initialized more than once. With the no dedicated order to the tests + // and the need to call `PathInitializer::try_default()` in some SGX + // functions, there didn't appear to be an alternative to test the + // behavior reliably in an automated fashion. + unsafe { + let pointer = &PATH_INITIALIZER as *const _ as *const c_void; + let mutable: &mut OnceCell = + &mut *(pointer as *mut OnceCell); + let _ = mutable.take(); + } + } + #[parameterized( qe = { QuotingEnclave }, qpl = { QuoteProviderLibrary }, @@ -75,7 +231,7 @@ mod test { let dir = tempdir().unwrap(); let file_name = dir.path().join("fake.txt"); fs::write(&file_name, "stuff").unwrap(); - assert_eq!(set_path(path_kind, file_name), Ok(())); + assert_eq!(PathInitializer::set_path(path_kind, file_name), Ok(())); } #[test] @@ -83,13 +239,16 @@ mod test { let dir = tempdir().unwrap(); let file_name = dir.path().join("fake.txt"); fs::write(&file_name, "stuff").unwrap(); - assert_eq!(set_path(QuoteProviderLibrary, file_name), Ok(())); + assert_eq!( + PathInitializer::set_path(QuoteProviderLibrary, file_name), + Ok(()) + ); } #[test] fn path_as_directory_fails() { let dir = tempdir().unwrap(); - assert!(set_path(QuotingEnclave, dir.path()).is_err()); + assert!(PathInitializer::set_path(QuotingEnclave, dir.path()).is_err()); } #[test] @@ -98,7 +257,7 @@ mod test { let file_name = dir.path().join("fake\0.txt"); // fs::write() will fail to create the file with a null byte in the path // so we pass the path as non existent to `set_path`. - assert!(set_path(ProvisioningCertificateEnclave, file_name).is_err()); + assert!(PathInitializer::set_path(ProvisioningCertificateEnclave, file_name).is_err()); } #[test] @@ -112,7 +271,7 @@ mod test { let file_name = dir.path().join(long_name); fs::write(&file_name, "stuff").unwrap(); - assert!(set_path(QuoteProviderLibrary, file_name).is_ok()); + assert!(PathInitializer::set_path(QuoteProviderLibrary, file_name).is_ok()); } #[test] @@ -126,7 +285,7 @@ mod test { let file_name = dir.path().join(long_name); fs::write(&file_name, "stuff").unwrap(); - assert!(set_path(QuoteProviderLibrary, file_name).is_err()); + assert!(PathInitializer::set_path(QuoteProviderLibrary, file_name).is_err()); } #[parameterized( @@ -136,33 +295,87 @@ mod test { fn load_policy_succeeds(policy: RequestPolicy) { assert!(load_policy(policy).is_ok()); } + + #[test] + #[serial] + fn default_path_initializer_succeeds() { + reset_path_initializer(); + let result = PathInitializer::try_default(); + assert_eq!(result, Ok(())); + } + + #[test] + #[serial] + fn default_path_initializer_fails_when_already_initialized() { + reset_path_initializer(); + PathInitializer::try_default().unwrap(); + let result = PathInitializer::try_default(); + assert_eq!(result, Err(Error::PathsInitialized)); + } + + #[test] + #[serial] + fn with_paths_path_initializer_succeeds() { + let dir = tempdir().unwrap(); + let names = ["1", "2", "3", "4"] + .into_iter() + .map(|name| { + let file_name = dir.path().join(name); + fs::write(&file_name, name).unwrap(); + file_name + }) + .collect::>(); + + reset_path_initializer(); + let result = PathInitializer::with_paths(&names[0], &names[1], Some(&names[2]), &names[3]); + assert_eq!(result, Ok(())); + } + + #[test] + #[serial] + fn with_paths_after_default_fails() { + let dir = tempdir().unwrap(); + let names = ["1", "2", "3", "4"] + .into_iter() + .map(|name| { + let file_name = dir.path().join(name); + fs::write(&file_name, name).unwrap(); + file_name + }) + .collect::>(); + + reset_path_initializer(); + PathInitializer::try_default().unwrap(); + let result = PathInitializer::with_paths(&names[0], &names[1], Some(&names[2]), &names[3]); + assert_eq!(result, Err(Error::PathsInitialized)); + } + + #[test] + #[serial] + fn with_paths_more_than_once_fails() { + let dir = tempdir().unwrap(); + let names = ["a", "b", "c", "d"] + .into_iter() + .map(|name| { + let file_name = dir.path().join(name); + fs::write(&file_name, name).unwrap(); + file_name + }) + .collect::>(); + + reset_path_initializer(); + PathInitializer::with_paths(&names[0], &names[1], Some(&names[2]), &names[3]).unwrap(); + let result = PathInitializer::with_paths(&names[0], &names[1], Some(&names[2]), &names[3]); + assert_eq!(result, Err(Error::PathsInitialized)); + } } #[cfg(all(test, not(feature = "sim")))] mod hw_test { use super::*; - use crate::set_path; - use mc_sgx_dcap_ql_types::PathKind::{ - IdEnclave, ProvisioningCertificateEnclave, QuotingEnclave, - }; #[test] fn getting_target_info() { - set_path( - ProvisioningCertificateEnclave, - "/usr/lib/x86_64-linux-gnu/libsgx_pce.signed.so.1", - ) - .unwrap(); - set_path( - QuotingEnclave, - "/usr/lib/x86_64-linux-gnu/libsgx_qe3.signed.so.1", - ) - .unwrap(); - set_path( - IdEnclave, - "/usr/lib/x86_64-linux-gnu/libsgx_id_enclave.signed.so.1", - ) - .unwrap(); assert!(TargetInfo::for_quoting_enclave().is_ok()); } }