blob: 494d6f625d72f698b41a7c6e621289b4f91e9445 [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.
//! This module provides types used to verify attestation reports.
use crate::report::AttestationReport;
use std::vec::Vec;
use log::{debug, error};
use teaclave_types::EnclaveAttr;
/// User defined verification function to further verify the attestation report.
pub type AttestationReportVerificationFn = fn(&AttestationReport) -> bool;
/// Type used to verify attestation reports (this can be set as a certificate
/// verifier in `rustls::ClientConfig`).
#[derive(Clone)]
pub struct AttestationReportVerifier {
/// Valid enclave attributes (only enclaves with attributes in this vector
/// will be accepted).
pub accepted_enclave_attrs: Vec<EnclaveAttr>,
/// Root certificate of the attestation service provider (e.g., IAS).
pub root_ca: Vec<u8>,
/// User defined function to verify the attestation report.
pub verifier: AttestationReportVerificationFn,
}
/// Checks if he quote's status is not `UnknownBadStatus`
pub fn universal_quote_verifier(report: &AttestationReport) -> bool {
debug!("report.sgx_quote_status: {:?}", report.sgx_quote_status);
report.sgx_quote_status != crate::report::SgxQuoteStatus::UnknownBadStatus
}
impl AttestationReportVerifier {
pub fn new(
accepted_enclave_attrs: Vec<EnclaveAttr>,
root_ca: &[u8],
verifier: AttestationReportVerificationFn,
) -> Self {
Self {
accepted_enclave_attrs,
root_ca: root_ca.to_vec(),
verifier,
}
}
/// Verify whether the `MR_SIGNER` and `MR_ENCLAVE` in the attestation report is
/// accepted by us, which are defined in `accepted_enclave_attrs`.
fn verify_measures(&self, attestation_report: &AttestationReport) -> bool {
debug!("verify measures");
let this_mr_signer = attestation_report
.sgx_quote_body
.isv_enclave_report
.mr_signer;
let this_mr_enclave = attestation_report
.sgx_quote_body
.isv_enclave_report
.mr_enclave;
self.accepted_enclave_attrs.iter().any(|a| {
a.measurement.mr_signer == this_mr_signer && a.measurement.mr_enclave == this_mr_enclave
})
}
/// Verify TLS certificate.
fn verify_cert(&self, cert_der: &[u8]) -> bool {
debug!("verify cert");
if cfg!(sgx_sim) {
return true;
}
let report = match AttestationReport::from_cert(&cert_der, &self.root_ca) {
Ok(report) => report,
Err(e) => {
error!("cert verification error {:?}", e);
return false;
}
};
// Enclave measures are not tested in test mode since we have
// a dedicated test enclave not known to production enclaves
if cfg!(test_mode) {
return (self.verifier)(&report);
}
self.verify_measures(&report) && (self.verifier)(&report)
}
}
impl rustls::ServerCertVerifier for AttestationReportVerifier {
fn verify_server_cert(
&self,
_roots: &rustls::RootCertStore,
certs: &[rustls::Certificate],
_hostname: webpki::DNSNameRef,
_ocsp: &[u8],
) -> std::result::Result<rustls::ServerCertVerified, rustls::TLSError> {
// This call automatically verifies certificate signature
debug!("verify server cert");
if certs.len() != 1 {
return Err(rustls::TLSError::NoCertificatesPresented);
}
if self.verify_cert(&certs[0].0) {
Ok(rustls::ServerCertVerified::assertion())
} else {
Err(rustls::TLSError::WebPKIError(
webpki::Error::ExtensionValueInvalid,
))
}
}
}
impl rustls::ClientCertVerifier for AttestationReportVerifier {
fn offer_client_auth(&self) -> bool {
// If test_mode is on, then disable TLS client authentication.
!cfg!(test_mode)
}
fn client_auth_root_subjects(&self) -> rustls::DistinguishedNames {
rustls::DistinguishedNames::new()
}
fn verify_client_cert(
&self,
certs: &[rustls::Certificate],
) -> std::result::Result<rustls::ClientCertVerified, rustls::TLSError> {
// This call automatically verifies certificate signature
debug!("verify client cert");
if certs.len() != 1 {
return Err(rustls::TLSError::NoCertificatesPresented);
}
if self.verify_cert(&certs[0].0) {
Ok(rustls::ClientCertVerified::assertion())
} else {
Err(rustls::TLSError::WebPKIError(
webpki::Error::ExtensionValueInvalid,
))
}
}
}