rewrote ioctl layer, updated scripts
This commit is contained in:
		
							parent
							
								
									365fb6499b
								
							
						
					
					
						commit
						924a443998
					
				
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -3,3 +3,4 @@ target | ||||
| Cargo.lock | ||||
| client_instance | ||||
| server_instance | ||||
| lib | ||||
|  | ||||
							
								
								
									
										11
									
								
								Cargo.toml
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										11
									
								
								Cargo.toml
									
									
									
									
									
								
							| @ -26,6 +26,9 @@ hyper = "1.4.1" | ||||
| hyper-util = "0.1.7" | ||||
| hyper-rustls = { version = "0.27", features = ["http2"] } | ||||
| prost = "0.13" | ||||
| #cfg-if = "1.0" | ||||
| base64 = "0.22" | ||||
| lazy_static = "1.5" | ||||
| 
 | ||||
| [dependencies.tonic] | ||||
| version = "0.12" | ||||
| @ -59,10 +62,10 @@ version = "0.11" | ||||
| version = "1" | ||||
| features = ["full"] | ||||
| 
 | ||||
| [dev-dependencies.cargo-husky] | ||||
| version = "1" | ||||
| default-features = false | ||||
| features = ["precommit-hook", "run-cargo-test", "run-cargo-clippy"] | ||||
| #[dev-dependencies.cargo-husky] | ||||
| #version = "1" | ||||
| #default-features = false | ||||
| #features = ["precommit-hook", "run-cargo-test", "run-cargo-clippy"] | ||||
| 
 | ||||
| [build-dependencies] | ||||
| tonic-build = "0.12" | ||||
|  | ||||
							
								
								
									
										80
									
								
								Occlum.json
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										80
									
								
								Occlum.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,80 @@ | ||||
| { | ||||
|     "resource_limits": { | ||||
|         "kernel_space_heap_size": "32MB", | ||||
|         "kernel_space_stack_size": "1MB", | ||||
|         "user_space_size": "300MB", | ||||
|         "max_num_of_threads": 32 | ||||
|     }, | ||||
|     "process": { | ||||
|         "default_stack_size": "4MB", | ||||
|         "default_heap_size": "32MB", | ||||
|         "default_mmap_size": "100MB" | ||||
|     }, | ||||
|     "entry_points": [ | ||||
|         "/bin" | ||||
|     ], | ||||
|     "env": { | ||||
|         "default": [ | ||||
|             "OCCLUM=yes" | ||||
|         ], | ||||
|         "untrusted": [ | ||||
|             "EXAMPLE" | ||||
|         ] | ||||
|     }, | ||||
|     "metadata": { | ||||
|         "product_id": 0, | ||||
|         "version_number": 0, | ||||
|         "debuggable": false, | ||||
|         "enable_kss": false, | ||||
|         "family_id": { | ||||
|             "high": "0x0", | ||||
|             "low": "0x0" | ||||
|         }, | ||||
|         "ext_prod_id": { | ||||
|             "high": "0x0", | ||||
|             "low": "0x0" | ||||
|         } | ||||
|     }, | ||||
|     "feature": { | ||||
|         "amx": 0, | ||||
|         "pkru": 0, | ||||
|         "enable_edmm": false, | ||||
|         "enable_posix_shm": false | ||||
|     }, | ||||
|     "mount": [ | ||||
|         { | ||||
|             "target": "/", | ||||
|             "type": "unionfs", | ||||
|             "options": { | ||||
|                 "layers": [ | ||||
|                     { | ||||
|                         "target": "/", | ||||
|                         "type": "sefs", | ||||
|                         "source": "./build/mount/__ROOT", | ||||
|                         "options": { | ||||
|                             "MAC": "" | ||||
|                         } | ||||
|                     }, | ||||
|                     { | ||||
|                         "target": "/", | ||||
|                         "type": "sefs", | ||||
|                         "source": "./run/mount/__ROOT" | ||||
|                     } | ||||
|                 ] | ||||
|             } | ||||
|         }, | ||||
|         { | ||||
|             "target": "/host", | ||||
|             "type": "hostfs", | ||||
|             "source": "." | ||||
|         }, | ||||
|         { | ||||
|             "target": "/proc", | ||||
|             "type": "procfs" | ||||
|         }, | ||||
|         { | ||||
|             "target": "/dev", | ||||
|             "type": "devfs" | ||||
|         } | ||||
|     ] | ||||
| } | ||||
							
								
								
									
										5
									
								
								build.rs
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										5
									
								
								build.rs
									
									
									
									
									
								
							| @ -1,4 +1,9 @@ | ||||
| fn main() { | ||||
|     // TODO: should be conditional on the target platform (musl vs glibc)
 | ||||
|     println!("cargo:rustc-link-search=/opt/occlum/toolchains/dcap_lib/musl"); | ||||
|     // Cargo will automatically know it must look for `libocclum_dcap.a`
 | ||||
|     println!("cargo:rustc-link-lib=occlum_dcap"); | ||||
| 
 | ||||
|     tonic_build::configure() | ||||
|         .build_server(true) | ||||
|         .compile(&["examples/echo.proto"], &["examples"]) | ||||
|  | ||||
| @ -3,16 +3,17 @@ set -e | ||||
| 
 | ||||
| SCRIPT=$0 | ||||
| EXAMPLE=$1 | ||||
| EXEC=$2 | ||||
| 
 | ||||
| if [ $# -eq 0 ] || [ "$EXAMPLE" != "https" ] && [ "$EXAMPLE" != "grpcs" ]; then | ||||
|     echo "usage: $SCRIPT https|grpcs" | ||||
|     echo "usage: $SCRIPT https|grpcs [--run]" | ||||
|     exit 1 | ||||
| fi | ||||
| 
 | ||||
| FEATURES=$(if [ "$EXAMPLE" == "https" ]; then echo "reqwest,occlum"; else echo "tonic,occlum"; fi) | ||||
| 
 | ||||
| occlum-cargo build --example mratls_"${EXAMPLE}"_client --features="$FEATURES" | ||||
| strip target/x86_64-unknown-linux-musl/debug/examples/mratls_"${EXAMPLE}"_client | ||||
| occlum-cargo build --release --example mratls_"${EXAMPLE}"_client --features="$FEATURES" | ||||
| strip target/x86_64-unknown-linux-musl/release/examples/mratls_"${EXAMPLE}"_client | ||||
| 
 | ||||
| cat > client.yaml <<EOF | ||||
| includes: | ||||
| @ -21,13 +22,17 @@ targets: | ||||
|   - target: /bin | ||||
|     copy: | ||||
|       - files: | ||||
|         - ../target/x86_64-unknown-linux-musl/debug/examples/mratls_${EXAMPLE}_client | ||||
|         - ../target/x86_64-unknown-linux-musl/release/examples/mratls_${EXAMPLE}_client | ||||
| EOF | ||||
| 
 | ||||
| rm -rf client_instance && mkdir client_instance && cd client_instance | ||||
| occlum init && rm -rf image | ||||
| cp ../Occlum.json ./ | ||||
| copy_bom -f ../client.yaml --root image --include-dir /opt/occlum/etc/template | ||||
| occlum build --sign-key ../examples/signing_key.pem --enable-edmm Y | ||||
| occlum package --debug client.tar.gz | ||||
| # TODO: "--enable-edmm Y" must be only for platforms that support SGX2 | ||||
| occlum build --sign-key ../examples/signing_key.pem | ||||
| occlum package client.tar.gz | ||||
| 
 | ||||
| occlum run /bin/mratls_${EXAMPLE}_client | ||||
| if [ "$EXEC" == "--run" ]; then | ||||
|     occlum run /bin/mratls_${EXAMPLE}_client | ||||
| fi | ||||
|  | ||||
| @ -3,16 +3,17 @@ set -e | ||||
| 
 | ||||
| SCRIPT=$0 | ||||
| EXAMPLE=$1 | ||||
| EXEC=$2 | ||||
| 
 | ||||
| if [ $# -eq 0 ] || [ "$EXAMPLE" != "https" ] && [ "$EXAMPLE" != "grpcs" ]; then | ||||
|     echo "usage: $SCRIPT https|grpcs" | ||||
|     echo "usage: $SCRIPT https|grpcs [--run]" | ||||
|     exit 1 | ||||
| fi | ||||
| 
 | ||||
| FEATURES=$(if [ "$EXAMPLE" == "https" ]; then echo "actix-web,occlum"; else echo "tonic,occlum"; fi) | ||||
| 
 | ||||
| occlum-cargo build --example mratls_"${EXAMPLE}"_server --features="$FEATURES" | ||||
| strip target/x86_64-unknown-linux-musl/debug/examples/mratls_"${EXAMPLE}"_server | ||||
| occlum-cargo build --release --example mratls_"${EXAMPLE}"_server --features="$FEATURES" | ||||
| strip target/x86_64-unknown-linux-musl/release/examples/mratls_"${EXAMPLE}"_server | ||||
| 
 | ||||
| cat > server.yaml <<EOF | ||||
| includes: | ||||
| @ -21,13 +22,17 @@ targets: | ||||
|   - target: /bin | ||||
|     copy: | ||||
|       - files: | ||||
|         - ../target/x86_64-unknown-linux-musl/debug/examples/mratls_${EXAMPLE}_server | ||||
|         - ../target/x86_64-unknown-linux-musl/release/examples/mratls_${EXAMPLE}_server | ||||
| EOF | ||||
| 
 | ||||
| rm -rf server_instance && mkdir server_instance && cd server_instance | ||||
| occlum init && rm -rf image | ||||
| cp ../Occlum.json ./ | ||||
| copy_bom -f ../server.yaml --root image --include-dir /opt/occlum/etc/template | ||||
| occlum build --sign-key ../examples/signing_key.pem --enable-edmm Y | ||||
| occlum package --debug server.tar.gz | ||||
| # TODO: "--enable-edmm Y" must be only for platforms that support SGX2 | ||||
| occlum build --sign-key ../examples/signing_key.pem | ||||
| occlum package server.tar.gz | ||||
| 
 | ||||
| occlum run /bin/mratls_${EXAMPLE}_server | ||||
| if [ "$EXEC" == "--run" ]; then | ||||
|     occlum run /bin/mratls_${EXAMPLE}_server | ||||
| fi | ||||
|  | ||||
| @ -6,7 +6,6 @@ use hyper::Uri; | ||||
| use hyper_util::{client::legacy::connect::HttpConnector, rt::TokioExecutor}; | ||||
| use occlum_ratls::prelude::*; | ||||
| use occlum_ratls::RaTlsConfigBuilder; | ||||
| use occlum_sgx::SGXMeasurement; | ||||
| use pb::{echo_client::EchoClient, EchoRequest}; | ||||
| use tokio_rustls::rustls::ClientConfig; | ||||
| 
 | ||||
| @ -18,9 +17,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { | ||||
|     let mut mrsigner = [0u8; 32]; | ||||
|     hex::decode_to_slice(mrsigner_hex, &mut mrsigner).expect("mrsigner decoding failed"); | ||||
| 
 | ||||
|     let config = RaTlsConfig::new().allow_instance_measurement( | ||||
|         InstanceMeasurement::new().with_mrsigners(vec![SGXMeasurement::new(mrsigner)]), | ||||
|     ); | ||||
|     let config = RaTlsConfig::new() | ||||
|         .allow_instance_measurement(InstanceMeasurement::new().with_mrsigners(vec![mrsigner])); | ||||
| 
 | ||||
|     let tls = ClientConfig::from_ratls_config(config) | ||||
|         .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("{}", e)))?; | ||||
|  | ||||
| @ -33,9 +33,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { | ||||
|     let mut mrsigner = [0u8; 32]; | ||||
|     hex::decode_to_slice(mrsigner_hex, &mut mrsigner).expect("mrsigner decoding failed"); | ||||
| 
 | ||||
|     let config = RaTlsConfig::new().allow_instance_measurement( | ||||
|         InstanceMeasurement::new().with_mrsigners(vec![SGXMeasurement::new(mrsigner)]), | ||||
|     ); | ||||
|     let config = RaTlsConfig::new() | ||||
|         .allow_instance_measurement(InstanceMeasurement::new().with_mrsigners(vec![mrsigner])); | ||||
| 
 | ||||
|     let mut tls = ServerConfig::from_ratls_config(config) | ||||
|         .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("{}", e)))?; | ||||
|  | ||||
| @ -9,11 +9,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { | ||||
|     let mut mrsigner = [0u8; 32]; | ||||
|     hex::decode_to_slice(mrsigner_hex, &mut mrsigner)?; | ||||
| 
 | ||||
|     let client = ClientBuilder::new() | ||||
|         .use_ratls(RaTlsConfig::new().allow_instance_measurement( | ||||
|             InstanceMeasurement::new().with_mrsigners(vec![SGXMeasurement::new(mrsigner)]), | ||||
|         )) | ||||
|         .build()?; | ||||
|     let client = | ||||
|         ClientBuilder::new() | ||||
|             .use_ratls(RaTlsConfig::new().allow_instance_measurement( | ||||
|                 InstanceMeasurement::new().with_mrsigners(vec![mrsigner]), | ||||
|             )) | ||||
|             .build()?; | ||||
|     let res = client.get("https://127.0.0.1:8000").send().await?; | ||||
|     let data = res.text().await?; | ||||
| 
 | ||||
|  | ||||
| @ -19,7 +19,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { | ||||
|         .bind_ratls( | ||||
|             SocketAddr::from(([127, 0, 0, 1], 8000)), | ||||
|             RaTlsConfig::new().allow_instance_measurement( | ||||
|                 InstanceMeasurement::new().with_mrsigners(vec![SGXMeasurement::new(mrsigner)]), | ||||
|                 InstanceMeasurement::new().with_mrsigners(vec![mrsigner]), | ||||
|             ), | ||||
|         ) | ||||
|         .unwrap() | ||||
|  | ||||
							
								
								
									
										1988
									
								
								src/bindings.rs
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										1988
									
								
								src/bindings.rs
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -1,13 +1,12 @@ | ||||
| use crate::{RaTlsConfigBuilder, RaTlsError}; | ||||
| 
 | ||||
| #[cfg(feature = "occlum")] | ||||
| use occlum_sgx::SGXQuote; | ||||
| use crate::quote::Quote; | ||||
| 
 | ||||
| // FIXME: this only suppresses the warnings
 | ||||
| #[allow(unused_imports)] | ||||
| pub use occlum_sgx::SGXMeasurement; | ||||
| use rustls::{ClientConfig, ServerConfig}; | ||||
| 
 | ||||
| pub type Measurement = [u8; 32]; | ||||
| 
 | ||||
| #[derive(Default, Debug)] | ||||
| pub struct RaTlsConfig { | ||||
|     #[cfg(feature = "occlum")] | ||||
| @ -17,8 +16,8 @@ pub struct RaTlsConfig { | ||||
| #[cfg(feature = "occlum")] | ||||
| #[derive(Default, Debug, Clone)] | ||||
| pub struct InstanceMeasurement { | ||||
|     pub(crate) mrsigners: Option<Vec<SGXMeasurement>>, | ||||
|     pub(crate) mrenclaves: Option<Vec<SGXMeasurement>>, | ||||
|     pub(crate) mrsigners: Option<Vec<Measurement>>, | ||||
|     pub(crate) mrenclaves: Option<Vec<Measurement>>, | ||||
|     pub(crate) product_ids: Option<Vec<u16>>, | ||||
|     pub(crate) versions: Option<Vec<u16>>, | ||||
| } | ||||
| @ -29,14 +28,14 @@ impl InstanceMeasurement { | ||||
|         Self::default() | ||||
|     } | ||||
| 
 | ||||
|     pub fn with_mrsigners(self, mrsigners: Vec<SGXMeasurement>) -> Self { | ||||
|     pub fn with_mrsigners(self, mrsigners: Vec<Measurement>) -> Self { | ||||
|         Self { | ||||
|             mrsigners: Some(mrsigners), | ||||
|             ..self | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn with_mrenclaves(self, mrenclaves: Vec<SGXMeasurement>) -> Self { | ||||
|     pub fn with_mrenclaves(self, mrenclaves: Vec<Measurement>) -> Self { | ||||
|         Self { | ||||
|             mrenclaves: Some(mrenclaves), | ||||
|             ..self | ||||
| @ -57,18 +56,18 @@ impl InstanceMeasurement { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub(crate) fn check_quote_measurements(&self, quote: &SGXQuote) -> bool { | ||||
|     pub(crate) fn check_quote_measurements(&self, quote: &Quote) -> bool { | ||||
|         let mut result = false; | ||||
|         if let Some(mrsigners) = &self.mrsigners { | ||||
|             result = true; | ||||
|             let value = quote.mrsigner(); | ||||
|             let value = quote.mrsigner().into(); | ||||
|             if !mrsigners.contains(&value) { | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|         if let Some(mrenclaves) = &self.mrenclaves { | ||||
|             result = true; | ||||
|             let value = quote.mrenclave(); | ||||
|             let value = quote.mrenclave().into(); | ||||
|             if !mrenclaves.contains(&value) { | ||||
|                 return false; | ||||
|             } | ||||
| @ -76,7 +75,7 @@ impl InstanceMeasurement { | ||||
| 
 | ||||
|         if let Some(product_ids) = &self.product_ids { | ||||
|             result = true; | ||||
|             let value = quote.product_id(); | ||||
|             let value = quote.product_id().into(); | ||||
|             if !product_ids.contains(&value) { | ||||
|                 return false; | ||||
|             } | ||||
| @ -84,7 +83,7 @@ impl InstanceMeasurement { | ||||
| 
 | ||||
|         if let Some(versions) = &self.versions { | ||||
|             result = true; | ||||
|             let value = quote.version(); | ||||
|             let value = quote.version().into(); | ||||
|             if !versions.contains(&value) { | ||||
|                 return false; | ||||
|             } | ||||
| @ -106,14 +105,14 @@ impl RaTlsConfig { | ||||
|     } | ||||
| 
 | ||||
|     #[cfg(feature = "occlum")] | ||||
|     pub(crate) fn is_allowed_quote(&self, quote: &SGXQuote) -> Result<(), RaTlsError> { | ||||
|     pub(crate) fn is_allowed_quote(&self, quote: &Quote) -> Result<(), RaTlsError> { | ||||
|         match self | ||||
|             .allowed_instances | ||||
|             .iter() | ||||
|             .any(|im| im.check_quote_measurements(quote)) | ||||
|         { | ||||
|             true => Ok(()), | ||||
|             false => Err(RaTlsError::QuoteVerifyError(format!( | ||||
|             false => Err(RaTlsError::QuoteError(format!( | ||||
|                 "{:?} is not allowed", | ||||
|                 quote | ||||
|             ))), | ||||
|  | ||||
| @ -3,7 +3,8 @@ use std::{error::Error, fmt::Display}; | ||||
| #[derive(Debug)] | ||||
| pub enum RaTlsError { | ||||
|     CertificateBuildError(String), | ||||
|     QuoteVerifyError(String), | ||||
|     QuoteError(String), | ||||
|     DcapError(String), | ||||
| } | ||||
| 
 | ||||
| impl Display for RaTlsError { | ||||
| @ -12,7 +13,8 @@ impl Display for RaTlsError { | ||||
|             RaTlsError::CertificateBuildError(ref message) => { | ||||
|                 write!(f, "CertificateBuildError: {}", message) | ||||
|             } | ||||
|             RaTlsError::QuoteVerifyError(ref message) => write!(f, "QuoteVerifyError: {}", message), | ||||
|             RaTlsError::QuoteError(ref message) => write!(f, "QuoteVerifyError: {}", message), | ||||
|             RaTlsError::DcapError(ref message) => write!(f, "DcapError: {}", message), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,13 +1,17 @@ | ||||
| mod racert; | ||||
| mod client; | ||||
| mod config; | ||||
| mod error; | ||||
| mod http; | ||||
| mod racert; | ||||
| mod server; | ||||
| #[cfg(feature = "occlum")] | ||||
| mod utils; | ||||
| 
 | ||||
| #[cfg(feature = "occlum")] | ||||
| mod bindings; | ||||
| pub mod prelude; | ||||
| #[cfg(feature = "occlum")] | ||||
| mod quote; | ||||
| //mod sscert;
 | ||||
| 
 | ||||
| pub use crate::config::RaTlsConfig; | ||||
|  | ||||
| @ -1,8 +1,7 @@ | ||||
| pub use crate::RaTlsConfig; | ||||
| pub use crate::SGXMeasurement; | ||||
| 
 | ||||
| #[cfg(feature = "occlum")] | ||||
| pub use crate::InstanceMeasurement; | ||||
| pub use crate::config::InstanceMeasurement; | ||||
| 
 | ||||
| #[cfg(feature = "reqwest")] | ||||
| pub use crate::reqwest::ReqwestUseRatls; | ||||
|  | ||||
							
								
								
									
										334
									
								
								src/quote.rs
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										334
									
								
								src/quote.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,334 @@ | ||||
| use crate::bindings::*; | ||||
| use crate::error::RaTlsError; | ||||
| use lazy_static::lazy_static; | ||||
| use log::{trace, warn}; | ||||
| use std::fmt::Debug; | ||||
| use std::ops::Deref; | ||||
| use std::sync::Mutex; | ||||
| use std::time::Instant; | ||||
| 
 | ||||
| pub struct Quote { | ||||
|     buf: Vec<u8>, | ||||
|     report_body: *const sgx_report_body_t, | ||||
| } | ||||
| 
 | ||||
| impl TryFrom<Vec<u8>> for Quote { | ||||
|     type Error = RaTlsError; | ||||
|     fn try_from(buf: Vec<u8>) -> Result<Self, Self::Error> { | ||||
|         let report_body_offset = size_of::<QuoteHeader>(); | ||||
|         let report_body_size = size_of::<sgx_report_body_t>(); | ||||
| 
 | ||||
|         if buf.len() < report_body_offset + report_body_size { | ||||
|             let minimal = report_body_offset + report_body_size; | ||||
|             let actual = buf.len(); | ||||
|             return Err(RaTlsError::QuoteError(format!( | ||||
|                 "Failed to parse DCAP quote, min {minimal}, act {actual}" | ||||
|             ))); | ||||
|         } | ||||
| 
 | ||||
|         let report_body = buf.as_slice()[report_body_offset..].as_ptr() as *const sgx_report_body_t; | ||||
| 
 | ||||
|         Ok(Self { buf, report_body }) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[repr(C)] | ||||
| struct QuoteHeader { | ||||
|     pub version: u16, | ||||
|     pub att_key_type: u16, | ||||
|     pub att_key_data_0: u32, | ||||
|     pub qe_svn: u16, | ||||
|     pub pce_svn: u16, | ||||
|     pub vendor_id: [u8; 16], | ||||
|     pub user_data: [u8; 20], | ||||
| } | ||||
| 
 | ||||
| impl TryFrom<&[u8]> for Quote { | ||||
|     type Error = RaTlsError; | ||||
| 
 | ||||
|     fn try_from(buf: &[u8]) -> Result<Self, Self::Error> { | ||||
|         buf.to_vec().try_into() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl TryFrom<ReportData> for Quote { | ||||
|     type Error = RaTlsError; | ||||
| 
 | ||||
|     fn try_from(value: ReportData) -> Result<Self, Self::Error> { | ||||
|         Self::from_report_data(value) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Deref for Quote { | ||||
|     type Target = [u8]; | ||||
| 
 | ||||
|     fn deref(&self) -> &Self::Target { | ||||
|         self.buf.as_ref() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Quote { | ||||
|     pub fn from_report_data(data: ReportData) -> Result<Self, RaTlsError> { | ||||
|         IOCTL_CLIENT | ||||
|             .lock() | ||||
|             .unwrap() | ||||
|             .generate_quote(data)? | ||||
|             .try_into() | ||||
|     } | ||||
| 
 | ||||
|     pub fn from_slice(slice: &[u8]) -> Result<Self, RaTlsError> { | ||||
|         slice.try_into() | ||||
|     } | ||||
| 
 | ||||
|     pub fn as_slice(&self) -> &[u8] { | ||||
|         self | ||||
|     } | ||||
| 
 | ||||
|     pub fn verify(&self) -> Result<VerifyResult, RaTlsError> { | ||||
|         IOCTL_CLIENT.lock().unwrap().verify_quote(self.buf.as_ref()) | ||||
|     } | ||||
| 
 | ||||
|     pub fn isv_family_id(&self) -> sgx_isvfamily_id_t { | ||||
|         unsafe { (*self.report_body).isv_family_id } | ||||
|     } | ||||
| 
 | ||||
|     pub fn isv_ext_prod_id(&self) -> sgx_isvext_prod_id_t { | ||||
|         unsafe { (*self.report_body).isv_ext_prod_id } | ||||
|     } | ||||
| 
 | ||||
|     pub fn config_id(&self) -> sgx_config_id_t { | ||||
|         unsafe { (*self.report_body).config_id } | ||||
|     } | ||||
| 
 | ||||
|     pub fn mrenclave(&self) -> sgx_measurement_t { | ||||
|         unsafe { (*self.report_body).mr_enclave } | ||||
|     } | ||||
| 
 | ||||
|     pub fn mrsigner(&self) -> sgx_measurement_t { | ||||
|         unsafe { (*self.report_body).mr_signer } | ||||
|     } | ||||
| 
 | ||||
|     pub fn product_id(&self) -> sgx_prod_id_t { | ||||
|         unsafe { (*self.report_body).isv_prod_id } | ||||
|     } | ||||
| 
 | ||||
|     pub fn version(&self) -> sgx_isv_svn_t { | ||||
|         unsafe { (*self.report_body).isv_svn } | ||||
|     } | ||||
| 
 | ||||
|     pub fn report_data(&self) -> ReportData { | ||||
|         unsafe { (*self.report_body).report_data.into() } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Debug for Quote { | ||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||
|         f.debug_struct("SGXQuote") | ||||
|             .field("mrenclave", &self.mrenclave()) | ||||
|             .field("mrsigner", &self.mrsigner()) | ||||
|             .field("report_body", &self.report_data()) | ||||
|             .field("product_id", &self.product_id()) | ||||
|             .field("version", &self.version()) | ||||
|             .field("family_id", &self.isv_family_id()) | ||||
|             .field("ext_prod_id", &self.isv_ext_prod_id()) | ||||
|             .field("config_id", &self.config_id()) | ||||
|             .finish() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| lazy_static! { | ||||
|     pub static ref IOCTL_CLIENT: Mutex<IoctlClient> = { | ||||
|         let client = IoctlClient::new(); | ||||
|         Mutex::new(client) | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| pub struct IoctlClient { | ||||
|     fd: HandleType, | ||||
|     quote_size: Option<u32>, | ||||
|     supplemental_size: Option<u32>, | ||||
| } | ||||
| 
 | ||||
| // Needed to numb the compiler
 | ||||
| unsafe impl Send for IoctlClient {} | ||||
| 
 | ||||
| impl IoctlClient { | ||||
|     fn new() -> Self { | ||||
|         Self { | ||||
|             fd: std::ptr::null_mut(), | ||||
|             quote_size: None, | ||||
|             supplemental_size: None, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn handle(&mut self) -> Result<HandleType, RaTlsError> { | ||||
|         if self.fd.is_null() { | ||||
|             let handle = unsafe { dcap_quote_open() }; | ||||
|             if self.fd.is_null() { | ||||
|                 return Err(RaTlsError::DcapError( | ||||
|                     "Failed to open DCAP quote device".to_string(), | ||||
|                 )); | ||||
|             } | ||||
|             self.fd = handle; | ||||
|         } | ||||
|         Ok(self.fd) | ||||
|     } | ||||
| 
 | ||||
|     fn get_quote_size(&mut self) -> Result<u32, RaTlsError> { | ||||
|         if self.quote_size.is_none() { | ||||
|             let size = unsafe { dcap_get_quote_size(self.fd) }; | ||||
|             trace!("DCAP quote size is {}", size); | ||||
|             self.quote_size = Some(size); | ||||
|         } | ||||
| 
 | ||||
|         Ok(*self.quote_size.as_ref().unwrap()) | ||||
|     } | ||||
| 
 | ||||
|     fn get_supplemental_data_size(&mut self) -> Result<u32, RaTlsError> { | ||||
|         if self.supplemental_size.is_none() { | ||||
|             let size = unsafe { dcap_get_supplemental_data_size(self.handle()?) }; | ||||
|             trace!("DCAP supplemental data size is {}", size); | ||||
|             self.quote_size = Some(size); | ||||
|         } | ||||
| 
 | ||||
|         Ok(*self.supplemental_size.as_ref().unwrap()) | ||||
|     } | ||||
| 
 | ||||
|     pub fn generate_quote(&mut self, report_data: ReportData) -> Result<Vec<u8>, RaTlsError> { | ||||
|         let instant = Instant::now(); | ||||
|         let quote_buf = self.generate_quote_inner(report_data)?; | ||||
|         trace!("Generated quote in {:?}ms", instant.elapsed().as_millis()); | ||||
|         Ok(quote_buf) | ||||
|     } | ||||
| 
 | ||||
|     fn generate_quote_inner(&mut self, report_data: ReportData) -> Result<Vec<u8>, RaTlsError> { | ||||
|         let quote_size = self.get_quote_size()?; | ||||
|         let mut quote_buf: Vec<u8> = vec![0; quote_size as usize]; | ||||
| 
 | ||||
|         let instant = Instant::now(); | ||||
|         let ret_code = unsafe { | ||||
|             dcap_generate_quote(self.handle()?, quote_buf.as_mut_ptr(), &report_data.into()) | ||||
|         }; | ||||
|         trace!("Generated quote in {:?}ms", instant.elapsed().as_millis()); | ||||
| 
 | ||||
|         if ret_code < 0 { | ||||
|             return Err(RaTlsError::DcapError( | ||||
|                 "Failed to generate DCAP quote".to_string(), | ||||
|             )); | ||||
|         } | ||||
| 
 | ||||
|         Ok(quote_buf) | ||||
|     } | ||||
| 
 | ||||
|     pub fn verify_quote(&mut self, quote_buf: &[u8]) -> Result<VerifyResult, RaTlsError> { | ||||
|         let instant = Instant::now(); | ||||
|         let result = self.verify_quote_inner(quote_buf)?; | ||||
|         trace!("Verified quote in {:?}ms", instant.elapsed().as_millis()); | ||||
| 
 | ||||
|         if result.is_negligible() { | ||||
|             if !result.is_ok() { | ||||
|                 warn!("DCAP quote verification returned: {:?}", result); | ||||
|             } | ||||
|             return Ok(result); | ||||
|         } | ||||
| 
 | ||||
|         Err(RaTlsError::QuoteError(format!( | ||||
|             "DCAP quote verification returned: {:?}", | ||||
|             result | ||||
|         ))) | ||||
|     } | ||||
| 
 | ||||
|     fn verify_quote_inner(&mut self, quote_buf: &[u8]) -> Result<VerifyResult, RaTlsError> { | ||||
|         let supplemental_data_size = self.get_supplemental_data_size()?; | ||||
| 
 | ||||
|         let mut status = 1; | ||||
|         let mut result = SGX_QL_QV_RESULT_UNSPECIFIED; | ||||
|         let mut suppl_buf: Vec<u8> = vec![0; supplemental_data_size as usize]; | ||||
| 
 | ||||
|         let ret_code = unsafe { | ||||
|             dcap_verify_quote( | ||||
|                 self.handle()?, | ||||
|                 quote_buf.as_ptr(), | ||||
|                 quote_buf.len() as u32, | ||||
|                 &mut status, | ||||
|                 &mut result, | ||||
|                 supplemental_data_size, | ||||
|                 suppl_buf.as_mut_ptr(), | ||||
|             ) | ||||
|         }; | ||||
| 
 | ||||
|         if ret_code < 0 { | ||||
|             return Err(RaTlsError::DcapError( | ||||
|                 "Failed to verify DCAP quote".to_string(), | ||||
|             )); | ||||
|         } | ||||
| 
 | ||||
|         Ok(result.into()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Drop for IoctlClient { | ||||
|     fn drop(&mut self) { | ||||
|         unsafe { | ||||
|             if !self.fd.is_null() { | ||||
|                 dcap_quote_close(self.fd); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| type HandleType = *mut ::std::os::raw::c_void; | ||||
| pub type ReportData = [u8; 64]; | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub enum VerifyResult { | ||||
|     Ok, | ||||
|     ConfigNeeded, | ||||
|     OutOfDate, | ||||
|     OutOfDateConfigNeeded, | ||||
|     InvalidSignature, | ||||
|     Revoked, | ||||
|     Unspecified, | ||||
|     SwHardeningNeeded, | ||||
|     ConfigAndSwHardeningNeeded, | ||||
| } | ||||
| 
 | ||||
| impl From<sgx_ql_qv_result_t> for VerifyResult { | ||||
|     fn from(result: sgx_ql_qv_result_t) -> Self { | ||||
|         match result { | ||||
|             SGX_QL_QV_RESULT_OK => VerifyResult::Ok, | ||||
|             SGX_QL_QV_RESULT_CONFIG_NEEDED => VerifyResult::ConfigNeeded, | ||||
|             SGX_QL_QV_RESULT_OUT_OF_DATE => VerifyResult::OutOfDate, | ||||
|             SGX_QL_QV_RESULT_OUT_OF_DATE_CONFIG_NEEDED => VerifyResult::OutOfDateConfigNeeded, | ||||
|             SGX_QL_QV_RESULT_INVALID_SIGNATURE => VerifyResult::InvalidSignature, | ||||
|             SGX_QL_QV_RESULT_REVOKED => VerifyResult::Revoked, | ||||
|             SGX_QL_QV_RESULT_SW_HARDENING_NEEDED => VerifyResult::SwHardeningNeeded, | ||||
|             SGX_QL_QV_RESULT_CONFIG_AND_SW_HARDENING_NEEDED => { | ||||
|                 VerifyResult::ConfigAndSwHardeningNeeded | ||||
|             } | ||||
|             //SGX_QL_QV_RESULT_UNSPECIFIED => QuoteVerifyResult::Unspecified,
 | ||||
|             _ => VerifyResult::Unspecified, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl VerifyResult { | ||||
|     pub fn is_ok(&self) -> bool { | ||||
|         match self { | ||||
|             VerifyResult::Ok => true, | ||||
|             _ => false, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn is_negligible(&self) -> bool { | ||||
|         match self { | ||||
|             VerifyResult::Ok => true, | ||||
|             VerifyResult::ConfigNeeded => true, | ||||
|             VerifyResult::OutOfDate => true, | ||||
|             VerifyResult::OutOfDateConfigNeeded => true, | ||||
|             VerifyResult::SwHardeningNeeded => true, | ||||
|             VerifyResult::ConfigAndSwHardeningNeeded => true, | ||||
|             _ => false, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -6,7 +6,9 @@ use crate::{error::RaTlsError, RaTlsConfig}; | ||||
| use log::error; | ||||
| 
 | ||||
| #[cfg(feature = "occlum")] | ||||
| use occlum_sgx::SGXQuote; | ||||
| use crate::quote::Quote; | ||||
| //#[cfg(feature = "occlum")]
 | ||||
| //use occlum_sgx::SGXQuote;
 | ||||
| use rcgen::{CertificateParams, CustomExtension, DistinguishedName, KeyPair}; | ||||
| use rustls::crypto::aws_lc_rs::sign::any_supported_type; | ||||
| use rustls::pki_types::{PrivateKeyDer, PrivatePkcs8KeyDer}; | ||||
| @ -77,7 +79,7 @@ impl RaTlsCertificateBuilder { | ||||
|     fn get_quote(&self, key_pair: &KeyPair) -> Result<Vec<u8>, Box<dyn Error>> { | ||||
|         let public_key = key_pair.public_key_raw().to_vec(); | ||||
|         let report_data = hash_sha512(public_key); | ||||
|         let quote = SGXQuote::from_report_data(&report_data)?; | ||||
|         let quote = Quote::from_report_data(report_data.into())?; | ||||
| 
 | ||||
|         Ok(quote.as_slice().to_vec()) | ||||
|     } | ||||
| @ -123,7 +125,7 @@ impl RaTlsCertificate for CertificateDer<'_> { | ||||
|         let report_oid = Oid::from(&REPORT_OID).unwrap(); | ||||
| 
 | ||||
|         if let Ok(Some(report)) = x509.get_extension_unique(&report_oid) { | ||||
|             let quote = SGXQuote::from_slice(report.value)?; | ||||
|             let quote = Quote::from_slice(report.value)?; | ||||
| 
 | ||||
|             // ECDSA quote verification using SGX DCAP driver
 | ||||
|             quote.verify()?; | ||||
| @ -134,7 +136,7 @@ impl RaTlsCertificate for CertificateDer<'_> { | ||||
|                 _ => return Err("Unexpected public key type".into()), | ||||
|             }; | ||||
| 
 | ||||
|             let report_data = &*quote.report_data(); | ||||
|             let report_data = quote.report_data(); | ||||
| 
 | ||||
|             if hash_sha512(public_key) != report_data { | ||||
|                 return Err("Invalid quote report data".into()); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user