diff --git a/sdk-tools/src/lib.rs b/sdk-tools/src/lib.rs index 6c83b0b23..0cd6b0816 100644 --- a/sdk-tools/src/lib.rs +++ b/sdk-tools/src/lib.rs @@ -3,5 +3,7 @@ #![doc = include_str!("../README.md")] #![deny(missing_docs, missing_debug_implementations, unsafe_code)] mod edger8r; +mod sign; pub use crate::edger8r::Edger8r; +pub use crate::sign::SgxSign; diff --git a/sdk-tools/src/sign.rs b/sdk-tools/src/sign.rs new file mode 100644 index 000000000..8775518d4 --- /dev/null +++ b/sdk-tools/src/sign.rs @@ -0,0 +1,284 @@ +// Copyright (c) 2023 The MobileCoin Foundation + +//! Builder wrapper around SgxSign. + +use std::{ + path::{Path, PathBuf}, + process::Command, +}; + +/// Wrapper for the enclave signing tool (sgx_sign). +/// +/// The enclave signing tool ships as part of the IntelĀ® Software Guard +/// Extensions SDK. Signing an enclave is a process that involves producing a +/// signature structure that contains enclave properties such as the enclave +/// measurement. Once an enclave is signed in such structure, the modifications +/// to the enclave file (such as code, data, signature, and so on) can be +/// detected. The signing tool also evaluates the enclave image for potential +/// errors and warns you about potential security hazards. +/// +/// See [Enclave Signing Tool Documentation](https://download.01.org/intel-sgx/sgx-linux/2.18/docs/Intel_SGX_Developer_Reference_Linux_2.18_Open_Source.pdf#%5B%7B%22num%22%3A85%2C%22gen%22%3A0%7D%2C%7B%22name%22%3A%22XYZ%22%7D%2C94.5%2C206.25%2C0%5D) +/// for more details. + +#[derive(Clone, Debug)] +pub struct SgxSign { + /// The path to the sgx_sign executable. + sgx_sign_path: PathBuf, + /// Whether to ignore the presence of relocations in the enclave shared + /// object. + ignore_relocation_error: bool, + /// Whether to ignore .init sections in the enclave. + ignore_init_section_error: bool, + /// Whether to re-sign a previously signed enclave (default: false) + resign: bool, +} + +impl Default for SgxSign { + /// Create a new SGX signing utility from the current environment. + fn default() -> Self { + let bin_dir = mc_sgx_core_build::sgx_bin_x64_dir(); + + SgxSign::from(bin_dir.join("sgx_sign")) + } +} + +impl SgxSign { + /// Relocations are generally forbidden in the enclave shared object, this + /// tells the `sgx_sign` utility to ignore those errors. + #[must_use] + pub fn allow_relocations(mut self, allow: bool) -> Self { + self.ignore_relocation_error = allow; + self + } + + /// Whether or not to allow .init sections in the enclave. + #[must_use] + pub fn allow_init_sections(mut self, allow: bool) -> Self { + self.ignore_init_section_error = allow; + self + } + + /// Whether to re-sign a previously signed enclave (default: false) + #[must_use] + pub fn allow_resign(mut self, allow: bool) -> Self { + self.resign = allow; + self + } + + /// Generate the command to sign the given enclave object with the given + /// private key and write the resulting enclave to the given path. Note + /// that online signatures are inherently insecure. + pub fn sign( + &mut self, + unsigned_enclave: impl AsRef<Path>, + config_file: impl AsRef<Path>, + private_key: impl AsRef<Path>, + output_enclave: impl AsRef<Path>, + ) -> Command { + let mut cmd = Command::new(&self.sgx_sign_path); + cmd.arg("sign") + .arg("-enclave") + .arg(unsigned_enclave.as_ref()) + .arg("-config") + .arg(config_file.as_ref()) + .arg("-key") + .arg(private_key.as_ref()) + .arg("-out") + .arg(output_enclave.as_ref()); + + if self.ignore_relocation_error { + cmd.arg("-ignore-rel-error"); + } + + if self.ignore_init_section_error { + cmd.arg("-ignore-init-sec-error"); + } + + if self.resign { + cmd.arg("-resign"); + } + + cmd + } + + /// Generate the command to create the data required for offline signing, + /// and write it to the given output data path. + pub fn gendata( + &mut self, + unsigned_enclave: impl AsRef<Path>, + config_file: impl AsRef<Path>, + output_datafile: impl AsRef<Path>, + ) -> Command { + let mut cmd = Command::new(&self.sgx_sign_path); + cmd.arg("gendata") + .arg("-enclave") + .arg(unsigned_enclave.as_ref()) + .arg("-config") + .arg(config_file.as_ref()) + .arg("-out") + .arg(output_datafile.as_ref()); + + if self.ignore_relocation_error { + cmd.arg("-ignore-rel-error"); + } + + if self.ignore_init_section_error { + cmd.arg("-ignore-init-sec-error"); + } + + if self.resign { + cmd.arg("-resign"); + } + + cmd + } + + /// Combine an unsigned enclave and signature into the output enclave, after + /// checking the signature. + pub fn catsig( + &mut self, + unsigned_enclave: impl AsRef<Path>, + config_file: impl AsRef<Path>, + public_key_pem: impl AsRef<Path>, + enclave_signing_material: impl AsRef<Path>, + signature: impl AsRef<Path>, + output_enclave: impl AsRef<Path>, + ) -> Command { + let mut cmd = Command::new(&self.sgx_sign_path); + cmd.arg("catsig") + .arg("-enclave") + .arg(unsigned_enclave.as_ref()) + .arg("-config") + .arg(config_file.as_ref()) + .arg("-key") + .arg(public_key_pem.as_ref()) + .arg("-unsigned") + .arg(enclave_signing_material.as_ref()) + .arg("-sig") + .arg(signature.as_ref()) + .arg("-out") + .arg(output_enclave.as_ref()); + + if self.ignore_relocation_error { + cmd.arg("-ignore-rel-error"); + } + + if self.ignore_init_section_error { + cmd.arg("-ignore-init-sec-error"); + } + + cmd + } + + /// Examine a signed enclave file and dump the data + pub fn dump( + &mut self, + signed_enclave: impl AsRef<Path>, + css_file_path: impl AsRef<Path>, + dump_file_path: impl AsRef<Path>, + ) -> Command { + let mut cmd = Command::new(&self.sgx_sign_path); + cmd.arg("dump") + .arg("-enclave") + .arg(signed_enclave.as_ref()) + .arg("-dumpfile") + .arg(dump_file_path.as_ref()) + .arg("-cssfile") + .arg(css_file_path.as_ref()); + + if self.ignore_relocation_error { + cmd.arg("-ignore-rel-error"); + } + + if self.ignore_init_section_error { + cmd.arg("-ignore-init-sec-error"); + } + + if self.resign { + cmd.arg("-resign"); + } + + cmd + } +} + +/// Construct a new SgxSign utility around the given executable path +impl From<PathBuf> for SgxSign { + fn from(sgx_sign_path: PathBuf) -> Self { + Self { + sgx_sign_path, + ignore_relocation_error: false, + ignore_init_section_error: false, + resign: false, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn generate_sign_command() { + let cmd = format!( + "{:?}", + SgxSign::default().sign( + "path_to_unsigned_enclave/file", + "path_to_config/file", + "path_to_private_key/file", + "path_to_output_enclave/file", + ) + ); + let expected_cmd = "\"/opt/intel/sgxsdk/bin/x64/sgx_sign\" \"sign\" \"-enclave\" \"path_to_unsigned_enclave/file\" \"-config\" \"path_to_config/file\" \"-key\" \"path_to_private_key/file\" \"-out\" \"path_to_output_enclave/file\""; + + assert_eq!(expected_cmd, cmd); + } + + #[test] + fn generate_gendata_command() { + let cmd = format!( + "{:?}", + SgxSign::default().gendata( + "path_to_unsigned_enclave/file", + "path_to_config/file", + "path_to_output_data/file", + ) + ); + let expected_cmd = "\"/opt/intel/sgxsdk/bin/x64/sgx_sign\" \"gendata\" \"-enclave\" \"path_to_unsigned_enclave/file\" \"-config\" \"path_to_config/file\" \"-out\" \"path_to_output_data/file\""; + + assert_eq!(expected_cmd, cmd); + } + + #[test] + fn generate_catsig_command() { + let cmd = format!( + "{:?}", + SgxSign::default().catsig( + "path_to_unsigned_enclave/file", + "path_to_config/file", + "path_to_public_key_pem/file", + "path_to_enclave_signing_material/file", + "path_to_signature/file", + "path_to_output_enclave/file", + ) + ); + let expected_cmd = "\"/opt/intel/sgxsdk/bin/x64/sgx_sign\" \"catsig\" \"-enclave\" \"path_to_unsigned_enclave/file\" \"-config\" \"path_to_config/file\" \"-key\" \"path_to_public_key_pem/file\" \"-unsigned\" \"path_to_enclave_signing_material/file\" \"-sig\" \"path_to_signature/file\" \"-out\" \"path_to_output_enclave/file\""; + + assert_eq!(expected_cmd, cmd); + } + + #[test] + fn generate_dump_command() { + let cmd = format!( + "{:?}", + SgxSign::default().dump( + "path_to_signed_enclave/file", + "path_to_css/file", + "path_to_dump/file", + ) + ); + let expected_cmd = "\"/opt/intel/sgxsdk/bin/x64/sgx_sign\" \"dump\" \"-enclave\" \"path_to_signed_enclave/file\" \"-dumpfile\" \"path_to_dump/file\" \"-cssfile\" \"path_to_css/file\""; + + assert_eq!(expected_cmd, cmd); + } +}