blob: 9558146461916ec36fb288535bff31cb179c94a2 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
use anyhow::{anyhow, bail, Result};
use log::debug;
use std::prelude::v1::*;
use std::sync::{Arc, SgxRwLock as RwLock};
use std::time::SystemTime;
use std::untrusted::time::SystemTimeEx;
use teaclave_attestation::report::AttestationReport;
use teaclave_attestation::verifier::AttestationReportVerifier;
use teaclave_attestation::AttestedTlsConfig;
use teaclave_types::EnclaveAttr;
#[derive(Clone)]
pub struct SgxTrustedTlsServerConfig {
server_config: rustls::ServerConfig,
attested_tls_config: Option<Arc<RwLock<AttestedTlsConfig>>>,
time: std::time::SystemTime,
validity: std::time::Duration,
}
impl Default for SgxTrustedTlsServerConfig {
fn default() -> Self {
let client_cert_verifier = rustls::NoClientAuth::new();
let server_config = rustls::ServerConfig::new(client_cert_verifier);
let time = SystemTime::now();
let validity = std::time::Duration::from_secs(u64::max_value());
Self {
server_config,
attested_tls_config: None,
time,
validity,
}
}
}
impl SgxTrustedTlsServerConfig {
pub fn new() -> Self {
Self::default()
}
pub fn server_cert(mut self, cert: &[u8], key_der: &[u8]) -> Result<Self> {
let cert_chain = vec![rustls::Certificate(cert.to_vec())];
let key_der = rustls::PrivateKey(key_der.to_vec());
self.server_config.set_single_cert(cert_chain, key_der)?;
Ok(Self { ..self })
}
pub fn from_attested_tls_config(
attested_tls_config: Arc<RwLock<AttestedTlsConfig>>,
) -> Result<Self> {
let lock = attested_tls_config.clone();
let tls_config = lock.read().map_err(|_| anyhow!("lock error"))?;
let mut config = Self::new().server_cert(&tls_config.cert, &tls_config.private_key)?;
config.attested_tls_config = Some(attested_tls_config);
config.time = tls_config.time;
config.validity = tls_config.validity;
Ok(config)
}
pub fn attestation_report_verifier(
mut self,
accepted_enclave_attrs: Vec<EnclaveAttr>,
root_ca: &[u8],
verifier: fn(&AttestationReport) -> bool,
) -> Result<Self> {
let verifier = Arc::new(AttestationReportVerifier::new(
accepted_enclave_attrs,
root_ca,
verifier,
));
self.server_config.set_client_certificate_verifier(verifier);
Ok(Self { ..self })
}
pub fn server_config(&self) -> Arc<rustls::ServerConfig> {
Arc::new(self.server_config.clone())
}
pub fn need_refresh(&self) -> bool {
let current_time = SystemTime::now();
let elapsed_time = current_time
.duration_since(self.time)
.unwrap_or(self.validity);
debug!(
"current_time: {:?}, self.time: {:?}, elapsed time: {:?}, self.validity: {:?}",
current_time, self.time, elapsed_time, self.validity
);
elapsed_time >= self.validity
}
pub fn refresh_server_config(&mut self) -> Result<()> {
let lock = match &self.attested_tls_config {
Some(config) => config,
None => bail!("Attestation TLS Config is not set"),
};
let attested_tls_config = lock.read().map_err(|_| anyhow!("lock error"))?;
let cert_chain = vec![rustls::Certificate(attested_tls_config.cert.to_vec())];
let key_der = rustls::PrivateKey(attested_tls_config.private_key.to_vec());
let mut new_server_config = self.server_config.clone();
new_server_config.set_single_cert(cert_chain, key_der)?;
self.server_config = new_server_config;
self.time = attested_tls_config.time;
self.validity = attested_tls_config.validity;
Ok(())
}
}
pub struct SgxTrustedTlsClientConfig {
pub client_config: rustls::ClientConfig,
pub attested_tls_config: Option<Arc<RwLock<AttestedTlsConfig>>>,
pub validity: std::time::Duration,
}
struct NoServerAuth;
impl NoServerAuth {
// Allow new_ret_no_self, make it consistent with rustls definition of
// `NoClientAuth::new()`.
#[allow(clippy::new_ret_no_self)]
pub fn new() -> Arc<dyn rustls::ServerCertVerifier> {
Arc::new(NoServerAuth)
}
}
impl rustls::ServerCertVerifier for NoServerAuth {
fn verify_server_cert(
&self,
_roots: &rustls::RootCertStore,
_certs: &[rustls::Certificate],
_hostname: webpki::DNSNameRef<'_>,
_ocsp: &[u8],
) -> Result<rustls::ServerCertVerified, rustls::TLSError> {
Ok(rustls::ServerCertVerified::assertion())
}
}
impl Default for SgxTrustedTlsClientConfig {
fn default() -> Self {
let mut client_config = rustls::ClientConfig::new();
client_config
.dangerous()
.set_certificate_verifier(NoServerAuth::new());
client_config.versions.clear();
client_config
.versions
.push(rustls::ProtocolVersion::TLSv1_2);
Self {
client_config,
attested_tls_config: None,
validity: std::time::Duration::default(),
}
}
}
impl SgxTrustedTlsClientConfig {
pub fn new() -> Self {
Self::default()
}
pub fn attestation_report_verifier(
mut self,
accepted_enclave_attrs: Vec<EnclaveAttr>,
root_ca: &[u8],
verifier: fn(&AttestationReport) -> bool,
) -> Self {
let verifier = Arc::new(AttestationReportVerifier::new(
accepted_enclave_attrs,
root_ca,
verifier,
));
self.client_config
.dangerous()
.set_certificate_verifier(verifier);
Self { ..self }
}
pub fn client_cert(mut self, cert: &[u8], key_der: &[u8]) -> Self {
let cert_chain = vec![rustls::Certificate(cert.to_vec())];
let key_der = rustls::PrivateKey(key_der.to_vec());
self.client_config
.set_single_client_cert(cert_chain, key_der);
Self { ..self }
}
pub fn from_attested_tls_config(
attested_tls_config: Arc<RwLock<AttestedTlsConfig>>,
) -> Result<Self> {
let lock = attested_tls_config.clone();
let tls_config = lock.read().map_err(|_| anyhow!("lock error"))?;
let mut config = Self::new().client_cert(&tls_config.cert, &tls_config.private_key);
config.attested_tls_config = Some(attested_tls_config);
Ok(config)
}
}