diff --git a/Cargo.toml b/Cargo.toml index 03a4c76..312fce2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,31 +1,28 @@ +# Copyright (c) 2024 DeTEE, LLC. +# All rights reserved. + [package] name = "occlum-ratls" -version = "0.4.5" +version = "0.1.0" edition = "2021" -authors = ["Ivan Chirkin "] -description = "Lib for remote attestation between occlum instances" +authors = ["Valentyn Faychuk ", "Ivan Chirkin "] +description = "Remote attestation for Intel SGX" license = "MIT OR Apache-2.0" -repository = "https://github.com/aggregion/occlum-ratls" keywords = ["occlum", "rustls", "ratls"] - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +# Inspired by https://github.com/aggregion/occlum-ratls [dependencies] -x509-parser = "0.15.0" -#rustls = { version = "0.21", features = [ -rustls = { version = "0.20.9", features = [ - "dangerous_configuration", - "logging" -] } -log = "0.4.17" -rcgen = "0.12.1" -occlum-sgx = "^0.1.12" -ring = "0.17.8" +rustls = "0.23" +x509-parser = "0.16" +occlum-sgx = "0.1" # get/verify quote +ring = "0.17" # hash256 +rcgen = "0.13" +log = "0.4" hex = "0.4" [dependencies.actix-web] -version = "4.3.1" -features = ["rustls-0_20"] +version = "4.3" +features = ["rustls-0_23"] optional = true [dependencies.actix-http] @@ -38,13 +35,13 @@ version = "2" optional = true [dependencies.reqwest] -version = "=0.11.10" +version = "0.12" default-features = false features = ["__rustls"] optional = true [dev-dependencies.env_logger] -version = "0.10.0" +version = "0.11" [dev-dependencies.tokio] version = "1" diff --git a/src/client.rs b/src/client.rs index aabfda4..f5c5b43 100644 --- a/src/client.rs +++ b/src/client.rs @@ -4,40 +4,76 @@ use crate::{ racert::{CertificateBuilder, RaTlsCertificate, RaTlsCertificateBuilder}, RaTlsConfig, RaTlsConfigBuilder, RaTlsError, }; +use rustls::client::danger::HandshakeSignatureValid; +use rustls::crypto::{aws_lc_rs, verify_tls12_signature, verify_tls13_signature, CryptoProvider}; +use rustls::pki_types::{CertificateDer, ServerName, UnixTime}; use rustls::{ - client::{ResolvesClientCert, ServerCertVerified, ServerCertVerifier}, + client::{danger::ServerCertVerified, danger::ServerCertVerifier, ResolvesClientCert}, sign::CertifiedKey, - ClientConfig, + ClientConfig, DigitallySignedStruct, Error, SignatureScheme, }; +#[derive(Debug)] pub struct RaTlsServerCertVerifier { config: RaTlsConfig, + provider: CryptoProvider, } impl RaTlsServerCertVerifier { pub fn new(config: RaTlsConfig) -> Self { - Self { config } + Self { + config, + provider: aws_lc_rs::default_provider(), // FIPS certified provider + } } } impl ServerCertVerifier for RaTlsServerCertVerifier { fn verify_server_cert( &self, - end_entity: &rustls::Certificate, - _intermediates: &[rustls::Certificate], - _server_name: &rustls::ServerName, - _scts: &mut dyn Iterator, + end_entity: &CertificateDer, + _intermediates: &[CertificateDer], + _server_name: &ServerName, _ocsp_response: &[u8], - _now: std::time::SystemTime, - ) -> Result { + _now: UnixTime, + ) -> Result { end_entity .verify_quote(&self.config) - .map_err(|e| rustls::Error::General(e.to_string()))?; + .map_err(|e| Error::General(e.to_string()))?; Ok(ServerCertVerified::assertion()) } + + // TLS 1.2 signature verification from the AWS libcrypto + fn verify_tls12_signature( + &self, + message: &[u8], + cert: &CertificateDer<'_>, + dss: &DigitallySignedStruct, + ) -> Result { + let supported_schemes = self.provider.signature_verification_algorithms; + verify_tls12_signature(message, cert, dss, &supported_schemes) + } + + // TLS 1.3 signature verification from the AWS libcrypto + fn verify_tls13_signature( + &self, + message: &[u8], + cert: &CertificateDer<'_>, + dss: &DigitallySignedStruct, + ) -> Result { + let supported_schemes = self.provider.signature_verification_algorithms; + verify_tls13_signature(message, cert, dss, &supported_schemes) + } + + fn supported_verify_schemes(&self) -> Vec { + self.provider + .signature_verification_algorithms + .supported_schemes() + } } +#[derive(Debug)] pub struct RaTlsClientCertResolver { cert: Arc, } @@ -67,7 +103,7 @@ impl ResolvesClientCert for RaTlsClientCertResolver { impl RaTlsConfigBuilder for ClientConfig { fn from_ratls_config(config: RaTlsConfig) -> Result { Ok(Self::builder() - .with_safe_defaults() + .dangerous() .with_custom_certificate_verifier(Arc::new(RaTlsServerCertVerifier::new(config))) .with_client_cert_resolver(Arc::new(RaTlsClientCertResolver::new()?))) } diff --git a/src/config.rs b/src/config.rs index 2e1075e..e4f8e89 100644 --- a/src/config.rs +++ b/src/config.rs @@ -3,17 +3,19 @@ use crate::{RaTlsConfigBuilder, RaTlsError}; #[cfg(feature = "occlum")] use occlum_sgx::SGXQuote; +// FIXME: this only suppresses the warnings +#[allow(unused_imports)] pub use occlum_sgx::SGXMeasurement; use rustls::{ClientConfig, ServerConfig}; -#[derive(Default)] +#[derive(Default, Debug)] pub struct RaTlsConfig { #[cfg(feature = "occlum")] pub(crate) allowed_instances: Vec, } #[cfg(feature = "occlum")] -#[derive(Default, Clone)] +#[derive(Default, Debug, Clone)] pub struct InstanceMeasurement { pub(crate) mrsigners: Option>, pub(crate) mrenclaves: Option>, diff --git a/src/http/actix_web.rs b/src/http/actix_web.rs index 9401b11..f783ddf 100644 --- a/src/http/actix_web.rs +++ b/src/http/actix_web.rs @@ -40,9 +40,8 @@ where addr: A, config: RaTlsConfig, ) -> Result { - let config = ServerConfig::from_ratls_config(config).map_err(|e| - std::io::Error::new(std::io::ErrorKind::Other, format!("{}", e)) - )?; - self.bind_rustls(addr, config) + let config = ServerConfig::from_ratls_config(config) + .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("{}", e)))?; + self.bind_rustls_0_23(addr, config) } } diff --git a/src/racert.rs b/src/racert.rs index d3a2023..625a5be 100644 --- a/src/racert.rs +++ b/src/racert.rs @@ -7,14 +7,10 @@ use log::error; #[cfg(feature = "occlum")] use occlum_sgx::SGXQuote; -use rustls::{ - sign::{any_supported_type, CertifiedKey}, - Certificate, PrivateKey, -}; - -use rcgen::{ - Certificate as GenCertificate, CertificateParams, CustomExtension, DistinguishedName, KeyPair, -}; +use rcgen::{CertificateParams, CustomExtension, DistinguishedName, KeyPair}; +use rustls::crypto::aws_lc_rs::sign::any_supported_type; +use rustls::pki_types::{PrivateKeyDer, PrivatePkcs8KeyDer}; +use rustls::{pki_types::CertificateDer, sign::CertifiedKey}; #[cfg(feature = "occlum")] use x509_parser::{nom::Parser, oid_registry::Oid, prelude::X509CertificateParser, public_key}; @@ -55,27 +51,21 @@ impl RaTlsCertificateBuilder { fn build_internal(&self) -> Result> { let mut distinguished_name = DistinguishedName::new(); - distinguished_name.push(rcgen::DnType::CommonName, self.common_name.clone()); - distinguished_name.push(rcgen::DnType::CountryName, "US"); + distinguished_name.push(rcgen::DnType::CountryName, "EU"); distinguished_name.push(rcgen::DnType::OrganizationName, "DeTEE"); - let mut params = CertificateParams::default(); - let key_pair = KeyPair::generate(params.alg)?; - + let key_pair = KeyPair::generate()?; let quote = self.get_quote(&key_pair)?; - params.key_pair = Some(key_pair); + let mut params = CertificateParams::default(); params.distinguished_name = distinguished_name; - params.custom_extensions = vec![CustomExtension::from_oid_content(&REPORT_OID, quote)]; + let crt = params.self_signed(&key_pair)?; - let crt = GenCertificate::from_params(params)?; - - Ok(RaTlsCertifiedKey { - cert_der: crt.serialize_der()?, - key_der: crt.serialize_private_key_der(), - }) + let cert_der = crt.der().to_vec(); + let key_der = key_pair.serialize_der(); + Ok(RaTlsCertifiedKey { cert_der, key_der }) } #[cfg(not(feature = "occlum"))] @@ -95,17 +85,23 @@ impl RaTlsCertificateBuilder { impl CertificateBuilder for RaTlsCertificateBuilder { fn build(&self) -> Result { - self.build_internal() - .map(|k| { - let sign_key = any_supported_type(&PrivateKey(k.key_der)).unwrap(); + let cert_key = self.build_internal().map_err(|e| { + let err = RaTlsError::CertificateBuildError(e.to_string()); + error!("{}", err); + err + })?; - CertifiedKey::new(vec![Certificate(k.cert_der)], sign_key) - }) - .map_err(|e| { - let err = RaTlsError::CertificateBuildError(e.to_string()); - error!("{}", err); - err - }) + let private_key_der = PrivateKeyDer::from(PrivatePkcs8KeyDer::from(cert_key.key_der)); + let signing_key = any_supported_type(&private_key_der).map_err(|e| { + let err = RaTlsError::CertificateBuildError(e.to_string()); + error!("{}", err); + err + })?; + + Ok(CertifiedKey::new( + vec![CertificateDer::from(cert_key.cert_der)], + signing_key, + )) } } @@ -113,7 +109,7 @@ pub trait RaTlsCertificate { fn verify_quote(&self, config: &RaTlsConfig) -> Result<(), Box>; } -impl RaTlsCertificate for rustls::Certificate { +impl RaTlsCertificate for CertificateDer<'_> { #[cfg(not(feature = "occlum"))] fn verify_quote(&self, _: &RaTlsConfig) -> Result<(), Box> { Ok(()) @@ -151,4 +147,4 @@ impl RaTlsCertificate for rustls::Certificate { Err("Not found quote extension".into()) } } -} \ No newline at end of file +} diff --git a/src/server.rs b/src/server.rs index 03a370c..d6a5f54 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,41 +1,81 @@ -use rustls::{server::{ClientCertVerified, ClientCertVerifier, ResolvesServerCert}, sign::CertifiedKey, Certificate, Error, ServerConfig, DistinguishedNames}; -use std::{sync::Arc, time::SystemTime}; - use crate::{ racert::{CertificateBuilder, RaTlsCertificate, RaTlsCertificateBuilder}, RaTlsConfig, RaTlsConfigBuilder, RaTlsError, }; +use rustls::client::danger::HandshakeSignatureValid; +use rustls::crypto::{aws_lc_rs, verify_tls12_signature, verify_tls13_signature, CryptoProvider}; +use rustls::pki_types::{CertificateDer, UnixTime}; +use rustls::{ + server::{danger::ClientCertVerified, danger::ClientCertVerifier, ResolvesServerCert}, + sign::CertifiedKey, + DigitallySignedStruct, DistinguishedName, Error, ServerConfig, SignatureScheme, +}; +use std::sync::Arc; +#[derive(Debug)] pub struct RaTlsClientCertVerifier { config: RaTlsConfig, + provider: CryptoProvider, } impl RaTlsClientCertVerifier { pub fn new(config: RaTlsConfig) -> Self { - Self { config } + Self { + config, + provider: aws_lc_rs::default_provider(), // FIPS certified provider + } } } impl ClientCertVerifier for RaTlsClientCertVerifier { + fn root_hint_subjects(&self) -> &[DistinguishedName] { + &[] // TODO: check if any names are needed + } + fn verify_client_cert( &self, - end_entity: &Certificate, - _intermediates: &[Certificate], - _now: SystemTime, + end_entity: &CertificateDer, + _intermediates: &[CertificateDer], + _now: UnixTime, ) -> Result { end_entity.verify_quote(&self.config).map_err(|e| { - println!("{:?}", e); - rustls::Error::General(e.to_string()) + log::log!(log::Level::Error, "{}", e); + Error::General(e.to_string()) })?; Ok(ClientCertVerified::assertion()) } - fn client_auth_root_subjects(&self) -> Option { - Some(DistinguishedNames::new()) + // TLS 1.2 signature verification from the AWS libcrypto + fn verify_tls12_signature( + &self, + message: &[u8], + cert: &CertificateDer<'_>, + dss: &DigitallySignedStruct, + ) -> Result { + let supported_schemes = self.provider.signature_verification_algorithms; + verify_tls12_signature(message, cert, dss, &supported_schemes) + } + + // TLS 1.3 signature verification from the AWS libcrypto + fn verify_tls13_signature( + &self, + message: &[u8], + cert: &CertificateDer<'_>, + dss: &DigitallySignedStruct, + ) -> Result { + let supported_schemes = self.provider.signature_verification_algorithms; + verify_tls13_signature(message, cert, dss, &supported_schemes) + } + + fn supported_verify_schemes(&self) -> Vec { + self.provider + .signature_verification_algorithms + .supported_schemes() } } +#[derive(Debug)] pub struct RaTlsServerCertResolver { cert: Arc, } @@ -49,10 +89,7 @@ impl RaTlsServerCertResolver { } impl ResolvesServerCert for RaTlsServerCertResolver { - fn resolve( - &self, - _client_hello: rustls::server::ClientHello, - ) -> Option> { + fn resolve(&self, _client_hello: rustls::server::ClientHello) -> Option> { Some(self.cert.clone()) } } @@ -60,7 +97,6 @@ impl ResolvesServerCert for RaTlsServerCertResolver { impl RaTlsConfigBuilder for ServerConfig { fn from_ratls_config(config: RaTlsConfig) -> Result { Ok(Self::builder() - .with_safe_defaults() .with_client_cert_verifier(Arc::new(RaTlsClientCertVerifier::new(config))) .with_cert_resolver(Arc::new(RaTlsServerCertResolver::new()?))) } diff --git a/src/sscert.rs b/src/sscert.rs index 03a370c..f5138f6 100644 --- a/src/sscert.rs +++ b/src/sscert.rs @@ -1,67 +1,67 @@ -use rustls::{server::{ClientCertVerified, ClientCertVerifier, ResolvesServerCert}, sign::CertifiedKey, Certificate, Error, ServerConfig, DistinguishedNames}; -use std::{sync::Arc, time::SystemTime}; - -use crate::{ - racert::{CertificateBuilder, RaTlsCertificate, RaTlsCertificateBuilder}, - RaTlsConfig, RaTlsConfigBuilder, RaTlsError, -}; - -pub struct RaTlsClientCertVerifier { - config: RaTlsConfig, -} - -impl RaTlsClientCertVerifier { - pub fn new(config: RaTlsConfig) -> Self { - Self { config } - } -} - -impl ClientCertVerifier for RaTlsClientCertVerifier { - fn verify_client_cert( - &self, - end_entity: &Certificate, - _intermediates: &[Certificate], - _now: SystemTime, - ) -> Result { - end_entity.verify_quote(&self.config).map_err(|e| { - println!("{:?}", e); - rustls::Error::General(e.to_string()) - })?; - - Ok(ClientCertVerified::assertion()) - } - - fn client_auth_root_subjects(&self) -> Option { - Some(DistinguishedNames::new()) - } -} - -pub struct RaTlsServerCertResolver { - cert: Arc, -} - -impl RaTlsServerCertResolver { - pub fn new() -> Result { - let builder = RaTlsCertificateBuilder::new().with_common_name("Client".to_string()); - let cert = builder.build().map(Arc::new)?; - Ok(Self { cert }) - } -} - -impl ResolvesServerCert for RaTlsServerCertResolver { - fn resolve( - &self, - _client_hello: rustls::server::ClientHello, - ) -> Option> { - Some(self.cert.clone()) - } -} - -impl RaTlsConfigBuilder for ServerConfig { - fn from_ratls_config(config: RaTlsConfig) -> Result { - Ok(Self::builder() - .with_safe_defaults() - .with_client_cert_verifier(Arc::new(RaTlsClientCertVerifier::new(config))) - .with_cert_resolver(Arc::new(RaTlsServerCertResolver::new()?))) - } -} +// use rustls::{server::{ClientCertVerified, ClientCertVerifier, ResolvesServerCert}, sign::CertifiedKey, Certificate, Error, ServerConfig, DistinguishedNames}; +// use std::{sync::Arc, time::SystemTime}; +// +// use crate::{ +// racert::{CertificateBuilder, RaTlsCertificate, RaTlsCertificateBuilder}, +// RaTlsConfig, RaTlsConfigBuilder, RaTlsError, +// }; +// +// pub struct RaTlsClientCertVerifier { +// config: RaTlsConfig, +// } +// +// impl RaTlsClientCertVerifier { +// pub fn new(config: RaTlsConfig) -> Self { +// Self { config } +// } +// } +// +// impl ClientCertVerifier for RaTlsClientCertVerifier { +// fn verify_client_cert( +// &self, +// end_entity: &Certificate, +// _intermediates: &[Certificate], +// _now: SystemTime, +// ) -> Result { +// end_entity.verify_quote(&self.config).map_err(|e| { +// println!("{:?}", e); +// rustls::Error::General(e.to_string()) +// })?; +// +// Ok(ClientCertVerified::assertion()) +// } +// +// fn client_auth_root_subjects(&self) -> Option { +// Some(DistinguishedNames::new()) +// } +// } +// +// pub struct RaTlsServerCertResolver { +// cert: Arc, +// } +// +// impl RaTlsServerCertResolver { +// pub fn new() -> Result { +// let builder = RaTlsCertificateBuilder::new().with_common_name("Client".to_string()); +// let cert = builder.build().map(Arc::new)?; +// Ok(Self { cert }) +// } +// } +// +// impl ResolvesServerCert for RaTlsServerCertResolver { +// fn resolve( +// &self, +// _client_hello: rustls::server::ClientHello, +// ) -> Option> { +// Some(self.cert.clone()) +// } +// } +// +// impl RaTlsConfigBuilder for ServerConfig { +// fn from_ratls_config(config: RaTlsConfig) -> Result { +// Ok(Self::builder() +// .with_safe_defaults() +// .with_client_cert_verifier(Arc::new(RaTlsClientCertVerifier::new(config))) +// .with_cert_resolver(Arc::new(RaTlsServerCertResolver::new()?))) +// } +// } diff --git a/src/utils.rs b/src/utils.rs index 241e8a9..240b882 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,5 +1,6 @@ use ring::digest::{Context, SHA512}; +// TODO: make sure this function is correct pub fn hash_sha512(input: Vec) -> [u8; 64] { let mut context = Context::new(&SHA512); context.update(input.as_ref());