This is an automated email from the ASF dual-hosted git repository.

mssun pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/incubator-teaclave.git


The following commit(s) were added to refs/heads/develop by this push:
     new 88fecf1  [attestation] Support DCAP
88fecf1 is described below

commit 88fecf12db0c0c691a8f9fb258ba8fce7e1eadc8
Author: Pei Wang <[email protected]>
AuthorDate: Thu Feb 6 16:42:31 2020 -0800

    [attestation] Support DCAP
---
 .drone.yml                                         |  30 ++-
 attestation/Cargo.toml                             |   1 +
 attestation/src/attestation.rs                     |   5 +-
 attestation/src/ias.rs                             | 194 --------------------
 attestation/src/lib.rs                             |  53 ++++--
 attestation/src/platform.rs                        |  32 +++-
 attestation/src/report.rs                          |  18 +-
 attestation/src/service.rs                         | 187 +++++++++++++++++++
 attestation/src/verifier.rs                        |   2 +-
 binder/Cargo.toml                                  |   1 +
 binder/Enclave.edl                                 |   2 +-
 binder/src/ocall.rs                                |  14 +-
 cmake/scripts/test.sh                              |   4 +-
 config/build.config.toml                           |   4 +-
 config/config_gen/main.rs                          |   8 +-
 config/config_gen/templates/config.j2              |   6 +-
 config/runtime.config.toml                         |   6 +
 config/src/runtime.rs                              |  51 ++++--
 dcap/Cargo.toml                                    |  28 +++
 dcap/Rocket.toml                                   |   7 +
 dcap/src/main.rs                                   | 202 +++++++++++++++++++++
 keys/README.md                                     |   6 +
 keys/dcap_root_ca_cert.der                         | Bin 0 -> 1403 bytes
 keys/dcap_root_ca_cert.pem                         |  32 ++++
 keys/dcap_server_cert.pem                          |  30 +++
 keys/dcap_server_key.der                           | Bin 0 -> 2350 bytes
 keys/dcap_server_key.pem                           |  52 ++++++
 services/access_control/enclave/src/lib.rs         |  10 +-
 services/authentication/enclave/src/lib.rs         |  16 +-
 services/execution/enclave/src/lib.rs              |  10 +-
 services/frontend/enclave/src/lib.rs               |  12 +-
 services/management/enclave/src/lib.rs             |  12 +-
 services/storage/enclave/src/lib.rs                |  10 +-
 tests/fixtures/runtime.config.toml                 |   8 +-
 .../enclave/src/teaclave_access_control_service.rs |   2 +-
 .../enclave/src/teaclave_authentication_service.rs |   4 +-
 .../enclave/src/teaclave_management_service.rs     |   2 +-
 .../app/src/teaclave_config_tests.rs               |  31 ++--
 third_party/crates-io                              |   2 +-
 39 files changed, 773 insertions(+), 321 deletions(-)

diff --git a/.drone.yml b/.drone.yml
index 9c9142d..fbf0495 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -21,9 +21,11 @@ steps:
 - name: test
   image: teaclave/teaclave-build-ubuntu-1804:0.1.0
   environment:
-    IAS_KEY:
+    AS_ALGO: sgx_epid
+    AS_URL: https://api.trustedservices.intel.com:443
+    AS_KEY:
       from_secret: V5_KEY
-    IAS_SPID:
+    AS_SPID:
       from_secret: V5_SPID
   privileged: true
   volumes:
@@ -72,9 +74,11 @@ steps:
   image: teaclave/teaclave-build-ubuntu-1804:0.1.0
   privileged: true
   environment:
-    IAS_KEY:
+    AS_ALGO: sgx_epid
+    AS_URL: https://api.trustedservices.intel.com:443
+    AS_KEY:
       from_secret: V5_KEY
-    IAS_SPID:
+    AS_SPID:
       from_secret: V5_SPID
   volumes:
   - name: isgx
@@ -183,9 +187,11 @@ steps:
 - name: test
   image: teaclave/teaclave-build-ubuntu-1604:0.1.0
   environment:
-    IAS_KEY:
+    AS_ALGO: sgx_epid
+    AS_URL: https://api.trustedservices.intel.com:443
+    AS_KEY:
       from_secret: V5_KEY
-    IAS_SPID:
+    AS_SPID:
       from_secret: V5_SPID
   privileged: true
   volumes:
@@ -234,9 +240,11 @@ steps:
   image: teaclave/teaclave-build-ubuntu-1604:0.1.0
   privileged: true
   environment:
-    IAS_KEY:
+    AS_ALGO: sgx_epid
+    AS_URL: https://api.trustedservices.intel.com:443
+    AS_KEY:
       from_secret: V5_KEY
-    IAS_SPID:
+    AS_SPID:
       from_secret: V5_SPID
   volumes:
   - name: isgx
@@ -372,9 +380,11 @@ node:
 # - name: test
 #   image: teaclave/teaclave-build-ubuntu-1804:0.1.0
 #   environment:
-#     IAS_KEY:
+#     AS_ALGO: sgx_epid
+#     AS_URL: https://api.trustedservices.intel.com:443
+#     AS_KEY:
 #       from_secret: V5_KEY
-#     IAS_SPID:
+#     AS_SPID:
 #       from_secret: V5_SPID
 #   privileged: true
 #   volumes:
diff --git a/attestation/Cargo.toml b/attestation/Cargo.toml
index b924346..fd7c57b 100644
--- a/attestation/Cargo.toml
+++ b/attestation/Cargo.toml
@@ -33,6 +33,7 @@ thiserror        = { version = "1.0.9" }
 uuid             = { version = "0.7.4", features = ["v4"] }
 webpki           = { version = "0.21.0" }
 webpki-roots     = { version = "0.17.0" }
+url              = { version = "2.1.1" }
 yasna            = { version = "0.3.0", features = ["bit-vec", "num-bigint", 
"chrono"] }
 
 teaclave_types  = { path = "../types" }
diff --git a/attestation/src/attestation.rs b/attestation/src/attestation.rs
index 3c79e3e..193ede0 100644
--- a/attestation/src/attestation.rs
+++ b/attestation/src/attestation.rs
@@ -20,10 +20,9 @@ impl RemoteAttestation {
         let key_pair = key::Secp256k1KeyPair::new()?;
         let report = match att_config {
             AttestationConfig::NoAttestation => 
EndorsedAttestationReport::default(),
-            AttestationConfig::SgxIas(config) => {
-                EndorsedAttestationReport::from_ias(key_pair.pub_k, 
&config.api_key, &config.spid)?
+            AttestationConfig::WithAttestation(config) => {
+                EndorsedAttestationReport::new(&config, key_pair.pub_k)?
             }
-            AttestationConfig::SgxDcap(_) => unimplemented!(),
         };
 
         let cert_extension = serde_json::to_vec(&report)?;
diff --git a/attestation/src/ias.rs b/attestation/src/ias.rs
deleted file mode 100644
index 28e90b8..0000000
--- a/attestation/src/ias.rs
+++ /dev/null
@@ -1,194 +0,0 @@
-// 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 crate::AttestationError;
-use crate::EndorsedAttestationReport;
-use anyhow::Error;
-use anyhow::Result;
-use anyhow::{anyhow, bail};
-use log::{debug, trace};
-use percent_encoding;
-use sgx_types::*;
-use std::collections::HashMap;
-use std::io::{Read, Write};
-use std::net::TcpStream;
-use std::os::unix::io::FromRawFd;
-use std::prelude::v1::*;
-use std::sync::Arc;
-
-extern "C" {
-    fn ocall_sgx_get_ias_socket(p_retval: *mut i32) -> sgx_status_t;
-}
-
-impl EndorsedAttestationReport {
-    pub(crate) fn from_ias(
-        pub_k: sgx_types::sgx_ec256_public_t,
-        ias_key: &str,
-        ias_spid: &sgx_spid_t,
-    ) -> anyhow::Result<Self> {
-        use crate::platform;
-        let mut ias_client = IasClient::new(ias_key);
-        let (mut ak_id, qe_target_info) = platform::init_sgx_quote()?;
-
-        // For IAS-based attestation, we need to fill our SPID (obtained from 
Intel)
-        // into the attestation key id.
-        const SPID_OFFSET: usize = std::mem::size_of::<sgx_ql_att_key_id_t>();
-        ak_id.att_key_id[SPID_OFFSET..(SPID_OFFSET + ias_spid.id.len())]
-            .clone_from_slice(&ias_spid.id);
-
-        let sgx_report = platform::create_sgx_isv_enclave_report(pub_k, 
qe_target_info)?;
-        let quote = platform::get_sgx_quote(&ak_id, sgx_report)?;
-        let ias_report = ias_client.get_report(&quote)?;
-        Ok(ias_report)
-    }
-}
-
-struct IasClient {
-    ias_key: String,
-    ias_hostname: &'static str,
-}
-
-impl IasClient {
-    fn new(ias_key: &str) -> Self {
-        #[cfg(production)]
-        let ias_hostname = "as.sgx.trustedservices.intel.com";
-        #[cfg(not(production))]
-        let ias_hostname = "api.trustedservices.intel.com";
-
-        Self {
-            ias_key: ias_key.to_owned(),
-            ias_hostname,
-        }
-    }
-
-    fn new_tls_stream(&self) -> 
Result<rustls::StreamOwned<rustls::ClientSession, TcpStream>> {
-        let dns_name = 
webpki::DNSNameRef::try_from_ascii_str(self.ias_hostname)?;
-        let mut config = rustls::ClientConfig::new();
-        config
-            .root_store
-            .add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
-        let client = rustls::ClientSession::new(&Arc::new(config), dns_name);
-        let fd = get_ias_socket()?;
-        let socket = unsafe { TcpStream::from_raw_fd(fd) };
-        let stream = rustls::StreamOwned::new(client, socket);
-
-        Ok(stream)
-    }
-
-    fn get_report(&mut self, quote: &[u8]) -> 
Result<EndorsedAttestationReport> {
-        debug!("get_report");
-        let report_uri = "/sgx/dev/attestation/v3/report";
-        let encoded_quote = base64::encode(quote);
-        let encoded_json = format!("{{\"isvEnclaveQuote\":\"{}\"}}\r\n", 
encoded_quote);
-
-        let request = format!(
-            "POST {} HTTP/1.1\r\n\
-             HOST: {}\r\n\
-             Ocp-Apim-Subscription-Key: {}\r\n\
-             Connection: Close\r\n\
-             Content-Length: {}\r\n\
-             Content-Type: application/json\r\n\r\n\
-             {}",
-            report_uri,
-            self.ias_hostname,
-            self.ias_key,
-            encoded_json.len(),
-            encoded_json
-        );
-        trace!("{}", request);
-
-        let mut stream = self.new_tls_stream()?;
-        stream.write_all(request.as_bytes())?;
-        let mut response = Vec::new();
-        stream.read_to_end(&mut response)?;
-
-        trace!("{}", String::from_utf8_lossy(&response));
-
-        let mut headers = [httparse::EMPTY_HEADER; 16];
-        let mut http_response = httparse::Response::new(&mut headers);
-        debug!("http_response.parse");
-        let header_len = match http_response
-            .parse(&response)
-            .map_err(|_| 
Error::new(AttestationError::AttestationServiceError))?
-        {
-            httparse::Status::Complete(s) => s,
-            _ => bail!(AttestationError::AttestationServiceError),
-        };
-
-        let header_map = parse_headers(&http_response);
-
-        debug!("get_content_length");
-        if !header_map.contains_key("Content-Length")
-            || header_map
-                .get("Content-Length")
-                .unwrap()
-                .parse::<u32>()
-                .unwrap_or(0)
-                == 0
-        {
-            bail!(AttestationError::AttestationServiceError);
-        }
-
-        debug!("get_signature");
-        let signature = header_map
-            .get("X-IASReport-Signature")
-            .ok_or_else(|| 
Error::new(AttestationError::AttestationServiceError))?;
-        let signature = base64::decode(signature)?;
-        debug!("get_signing_cert");
-        let signing_cert = {
-            let cert_str = header_map
-                .get("X-IASReport-Signing-Certificate")
-                .ok_or_else(|| 
Error::new(AttestationError::AttestationServiceError))?;
-            let decoded_cert = 
percent_encoding::percent_decode_str(cert_str).decode_utf8()?;
-            let certs = rustls::internal::pemfile::certs(&mut 
decoded_cert.as_bytes())
-                .map_err(|_| anyhow!("pemfile error"))?;
-            certs[0].0.clone()
-        };
-
-        let report = response[header_len..].to_vec();
-        Ok(EndorsedAttestationReport {
-            report,
-            signature,
-            signing_cert,
-        })
-    }
-}
-
-fn parse_headers(resp: &httparse::Response) -> HashMap<String, String> {
-    debug!("parse_headers");
-    let mut header_map = HashMap::new();
-    for h in resp.headers.iter() {
-        header_map.insert(
-            h.name.to_owned(),
-            String::from_utf8_lossy(h.value).into_owned(),
-        );
-    }
-
-    header_map
-}
-
-fn get_ias_socket() -> Result<c_int> {
-    debug!("get_ias_socket");
-    let mut fd: c_int = -1;
-    let res = unsafe { ocall_sgx_get_ias_socket(&mut fd as _) };
-
-    if res != sgx_status_t::SGX_SUCCESS || fd < 0 {
-        bail!(AttestationError::OCallError)
-    } else {
-        Ok(fd)
-    }
-}
diff --git a/attestation/src/lib.rs b/attestation/src/lib.rs
index 1c5acdf..4952d62 100644
--- a/attestation/src/lib.rs
+++ b/attestation/src/lib.rs
@@ -37,32 +37,49 @@ pub enum AttestationError {
 
 pub enum AttestationConfig {
     NoAttestation,
-    SgxIas(IasConfig),
-    SgxDcap(DcapConfig), // not supported yet
+    WithAttestation(AttestationServiceConfig),
 }
 
-pub struct IasConfig {
-    pub api_key: String,
-    pub spid: sgx_types::sgx_spid_t,
+pub(crate) enum AttestationAlgorithm {
+    SgxEpid,
+    SgxEcdsa,
+}
+
+pub struct AttestationServiceConfig {
+    algo: AttestationAlgorithm,
+    as_url: url::Url,
+    api_key: String,
+    spid: sgx_types::sgx_spid_t,
 }
 
 pub struct DcapConfig {}
 
 impl AttestationConfig {
-    pub fn ias(ias_key: &str, ias_spid: &str) -> Self {
+    pub fn new(algorithm: &str, url: &str, api_key: &str, spid_str: &str) -> 
Self {
         if cfg!(sgx_sim) {
-            Self::NoAttestation
-        } else {
-            use core::convert::TryFrom;
-
-            let mut spid = sgx_types::sgx_spid_t::default();
-            let hex = hex::decode(ias_spid).expect("Illegal SPID provided");
-            spid.id = <[u8; 16]>::try_from(hex.as_slice()).expect("Illegal 
SPID provided");
-            Self::SgxIas(IasConfig {
-                api_key: ias_key.to_string(),
-                spid,
-            })
+            return Self::NoAttestation;
         }
+
+        use core::convert::TryFrom;
+
+        let mut spid = sgx_types::sgx_spid_t::default();
+        let hex = hex::decode(spid_str).expect("Illegal SPID provided");
+        spid.id = <[u8; 16]>::try_from(hex.as_slice()).expect("Illegal SPID 
provided");
+
+        let algo = match algorithm {
+            "sgx_epid" => AttestationAlgorithm::SgxEpid,
+            "sgx_ecdsa" => AttestationAlgorithm::SgxEcdsa,
+            _ => panic!("Unsupported remote attestation algorithm"),
+        };
+
+        let att_service_cfg = AttestationServiceConfig {
+            algo,
+            as_url: url::Url::parse(url).unwrap(),
+            api_key: api_key.to_string(),
+            spid,
+        };
+
+        Self::WithAttestation(att_service_cfg)
     }
 }
 
@@ -86,7 +103,7 @@ pub mod verifier;
 
 cfg_if::cfg_if! {
     if #[cfg(feature = "mesalock_sgx")]  {
-        mod ias;
+        mod service;
         mod key;
         mod platform;
         mod attestation;
diff --git a/attestation/src/platform.rs b/attestation/src/platform.rs
index 9290396..07c8b5d 100644
--- a/attestation/src/platform.rs
+++ b/attestation/src/platform.rs
@@ -32,6 +32,14 @@ extern "C" {
         p_quote: *mut u8,
         quote_size: u32,
     ) -> sgx_status_t;
+
+    fn ocall_sgx_get_remote_socket(
+        p_retval: *mut i32,
+        p_url: *const u8,
+        len: usize,
+    ) -> sgx_status_t;
+
+    fn sgx_self_target(p_target_info: *mut sgx_target_info_t) -> sgx_status_t;
 }
 
 pub(crate) fn init_sgx_quote() -> Result<(sgx_att_key_id_t, 
sgx_target_info_t)> {
@@ -92,6 +100,15 @@ pub(crate) fn get_sgx_quote(ak_id: &sgx_att_key_id_t, 
report: sgx_report_t) -> R
     rng.fill_bytes(&mut quote_nonce.rand);
     qe_report_info.nonce = quote_nonce;
 
+    debug!("sgx_self_target");
+    // Provide the target information of ourselves so that we can verify the 
QE report
+    // returned with the quote
+    let res = unsafe { sgx_self_target(&mut 
qe_report_info.app_enclave_target_info as _) };
+
+    if res != sgx_status_t::SGX_SUCCESS {
+        bail!(AttestationError::PlatformError);
+    }
+
     let mut quote = vec![0; quote_len as usize];
 
     debug!("ocall_sgx_get_quote");
@@ -113,7 +130,7 @@ pub(crate) fn get_sgx_quote(ak_id: &sgx_att_key_id_t, 
report: sgx_report_t) -> R
     debug!("rsgx_verify_report");
     let qe_report = qe_report_info.qe_report;
     // Perform a check on qe_report to verify if the qe_report is valid.
-    rsgx_verify_report(&qe_report).unwrap(); //map_err(|_| 
Error::new(AttestationError::PlatformError)).expect("verify report failed");
+    rsgx_verify_report(&qe_report).map_err(|_| 
Error::new(AttestationError::PlatformError))?;
 
     // Check qe_report to defend against replay attack. The purpose of
     // p_qe_report is for the ISV enclave to confirm the QUOTE it received
@@ -136,3 +153,16 @@ pub(crate) fn get_sgx_quote(ak_id: &sgx_att_key_id_t, 
report: sgx_report_t) -> R
 
     Ok(quote)
 }
+
+pub(crate) fn get_attestation_service_socket(url: &str) -> Result<c_int> {
+    debug!("get_attestation_service_socket");
+    let mut fd: c_int = -1;
+    let res =
+        unsafe { ocall_sgx_get_remote_socket(&mut fd as _, 
url.as_bytes().as_ptr(), url.len()) };
+
+    if res != sgx_status_t::SGX_SUCCESS || fd < 0 {
+        bail!(AttestationError::OCallError)
+    } else {
+        Ok(fd)
+    }
+}
diff --git a/attestation/src/report.rs b/attestation/src/report.rs
index b6c7dc3..731de0c 100644
--- a/attestation/src/report.rs
+++ b/attestation/src/report.rs
@@ -155,8 +155,11 @@ pub enum SgxEcdsaQuoteAkType {
 #[derive(PartialEq, Debug)]
 pub enum SgxQuoteStatus {
     OK,
-    GroupOutOfDate,
+    AttestationKeyRevoked,
+    TcbOutOfDate,
     ConfigurationNeeded,
+    TcbOutOfDateAndConfigurationNeeded,
+    SignatureInvalid,
     UnknownBadStatus,
 }
 
@@ -164,8 +167,13 @@ impl From<&str> for SgxQuoteStatus {
     fn from(status: &str) -> Self {
         match status {
             "OK" => SgxQuoteStatus::OK,
-            "GROUP_OUT_OF_DATE" => SgxQuoteStatus::GroupOutOfDate,
+            "KEY_REVOKED" => SgxQuoteStatus::AttestationKeyRevoked,
+            "GROUP_OUT_OF_DATE" | "TCB_OUT_OF_DATE" => 
SgxQuoteStatus::TcbOutOfDate,
             "CONFIGURATION_NEEDED" => SgxQuoteStatus::ConfigurationNeeded,
+            "OUT_OF_DATE_CONFIGURATION_NEEDED" => {
+                SgxQuoteStatus::TcbOutOfDateAndConfigurationNeeded
+            }
+            "SIGNATURE_INVALID" => SgxQuoteStatus::SignatureInvalid,
             _ => SgxQuoteStatus::UnknownBadStatus,
         }
     }
@@ -264,7 +272,7 @@ pub struct AttestationReport {
 }
 
 impl AttestationReport {
-    pub fn from_cert(cert: &[u8], ias_report_ca_cert: &[u8]) -> Result<Self> {
+    pub fn from_cert(cert: &[u8], report_ca_cert: &[u8]) -> Result<Self> {
         // Before we reach here, Webpki already verifed the cert is properly 
signed
         use super::cert::*;
 
@@ -285,7 +293,7 @@ impl AttestationReport {
 
         let mut root_store = rustls::RootCertStore::empty();
         root_store
-            .add(&rustls::Certificate(ias_report_ca_cert.to_vec()))
+            .add(&rustls::Certificate(report_ca_cert.to_vec()))
             .expect("Failed to add CA");
 
         let trust_anchors: Vec<webpki::TrustAnchor> = root_store
@@ -294,7 +302,7 @@ impl AttestationReport {
             .map(|cert| cert.to_trust_anchor())
             .collect();
 
-        let chain: Vec<&[u8]> = vec![ias_report_ca_cert];
+        let chain: Vec<&[u8]> = vec![report_ca_cert];
 
         let time = webpki::Time::try_from(SystemTime::now())
             .map_err(|_| anyhow!("Cannot convert time."))?;
diff --git a/attestation/src/service.rs b/attestation/src/service.rs
new file mode 100644
index 0000000..8b8a634
--- /dev/null
+++ b/attestation/src/service.rs
@@ -0,0 +1,187 @@
+// 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 crate::platform;
+use crate::AttestationAlgorithm;
+use crate::AttestationError;
+use crate::AttestationServiceConfig;
+use crate::EndorsedAttestationReport;
+use anyhow::Error;
+use anyhow::Result;
+use anyhow::{anyhow, bail};
+use log::{debug, trace};
+use percent_encoding;
+use sgx_types::*;
+use std::collections::HashMap;
+use std::io::{Read, Write};
+use std::net::TcpStream;
+use std::os::unix::io::FromRawFd;
+use std::prelude::v1::*;
+use std::sync::Arc;
+
+impl EndorsedAttestationReport {
+    pub(crate) fn new(
+        att_service_cfg: &AttestationServiceConfig,
+        pub_k: sgx_types::sgx_ec256_public_t,
+    ) -> anyhow::Result<Self> {
+        let (mut ak_id, qe_target_info) = platform::init_sgx_quote()?;
+
+        // For IAS-based attestation, we need to fill our SPID (obtained from 
Intel)
+        // into the attestation key id. For DCAP-based attestation, SPID 
should be 0
+        const SPID_OFFSET: usize = std::mem::size_of::<sgx_ql_att_key_id_t>();
+        ak_id.att_key_id[SPID_OFFSET..(SPID_OFFSET + 
att_service_cfg.spid.id.len())]
+            .clone_from_slice(&att_service_cfg.spid.id);
+
+        let sgx_report = platform::create_sgx_isv_enclave_report(pub_k, 
qe_target_info)?;
+        let quote = platform::get_sgx_quote(&ak_id, sgx_report)?;
+        let as_report = get_report(
+            &att_service_cfg.algo,
+            &att_service_cfg.as_url,
+            &att_service_cfg.api_key,
+            &quote,
+        )?;
+
+        Ok(as_report)
+    }
+}
+
+fn new_tls_stream(url: &url::Url) -> 
Result<rustls::StreamOwned<rustls::ClientSession, TcpStream>> {
+    let dns_name = 
webpki::DNSNameRef::try_from_ascii_str(url.host_str().unwrap())?;
+    let mut config = rustls::ClientConfig::new();
+    config
+        .root_store
+        .add(&rustls::Certificate(
+            include_bytes!("../../keys/dcap_root_ca_cert.der").to_vec(),
+        ))
+        .unwrap();
+    config
+        .root_store
+        .add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
+    let client = rustls::ClientSession::new(&Arc::new(config), dns_name);
+    let fd = platform::get_attestation_service_socket(&url.to_string())?;
+    let socket = unsafe { TcpStream::from_raw_fd(fd) };
+    let stream = rustls::StreamOwned::new(client, socket);
+
+    Ok(stream)
+}
+
+fn get_report(
+    algo: &AttestationAlgorithm,
+    url: &url::Url,
+    api_key: &str,
+    quote: &[u8],
+) -> Result<EndorsedAttestationReport> {
+    debug!("get_report");
+    let report_uri = "/sgx/dev/attestation/v3/report";
+    let encoded_quote = base64::encode(quote);
+    let encoded_json = format!("{{\"isvEnclaveQuote\":\"{}\"}}\r\n", 
encoded_quote);
+
+    let request = format!(
+        "POST {} HTTP/1.1\r\n\
+         HOST: {}\r\n\
+         Ocp-Apim-Subscription-Key: {}\r\n\
+         Connection: Close\r\n\
+         Content-Length: {}\r\n\
+         Content-Type: application/json\r\n\r\n\
+         {}",
+        report_uri,
+        url.host_str().unwrap(),
+        api_key,
+        encoded_json.len(),
+        encoded_json
+    );
+    trace!("{}", request);
+
+    let mut stream = new_tls_stream(url)?;
+    stream.write_all(request.as_bytes())?;
+    let mut response = Vec::new();
+    stream.read_to_end(&mut response)?;
+
+    trace!("{}", String::from_utf8_lossy(&response));
+
+    let mut headers = [httparse::EMPTY_HEADER; 16];
+    let mut http_response = httparse::Response::new(&mut headers);
+
+    debug!("http_response.parse");
+    let header_len = match http_response
+        .parse(&response)
+        .map_err(|_| Error::new(AttestationError::AttestationServiceError))?
+    {
+        httparse::Status::Complete(s) => s,
+        _ => bail!(AttestationError::AttestationServiceError),
+    };
+
+    let header_map = parse_headers(&http_response);
+
+    debug!("get_content_length");
+    if !header_map.contains_key("Content-Length")
+        || header_map
+            .get("Content-Length")
+            .unwrap()
+            .parse::<u32>()
+            .unwrap_or(0)
+            == 0
+    {
+        bail!(AttestationError::AttestationServiceError);
+    }
+
+    debug!("get_signature");
+    let signature_header = match algo {
+        AttestationAlgorithm::SgxEpid => "X-IASReport-Signature",
+        AttestationAlgorithm::SgxEcdsa => "X-DCAPReport-Signature",
+    };
+    let signature = header_map
+        .get(signature_header)
+        .ok_or_else(|| Error::new(AttestationError::AttestationServiceError))?;
+    let signature = base64::decode(signature)?;
+
+    debug!("get_signing_cert");
+    let signing_cert_header = match algo {
+        AttestationAlgorithm::SgxEpid => "X-IASReport-Signing-Certificate",
+        AttestationAlgorithm::SgxEcdsa => "X-DCAPReport-Signing-Certificate",
+    };
+    let signing_cert = {
+        let cert_str = header_map
+            .get(signing_cert_header)
+            .ok_or_else(|| 
Error::new(AttestationError::AttestationServiceError))?;
+        let decoded_cert = 
percent_encoding::percent_decode_str(cert_str).decode_utf8()?;
+        let certs = rustls::internal::pemfile::certs(&mut 
decoded_cert.as_bytes())
+            .map_err(|_| anyhow!("pemfile error"))?;
+        certs[0].0.clone()
+    };
+
+    debug!("return_report");
+    let report = response[header_len..].to_vec();
+    Ok(EndorsedAttestationReport {
+        report,
+        signature,
+        signing_cert,
+    })
+}
+
+fn parse_headers(resp: &httparse::Response) -> HashMap<String, String> {
+    debug!("parse_headers");
+    let mut header_map = HashMap::new();
+    for h in resp.headers.iter() {
+        header_map.insert(
+            h.name.to_owned(),
+            String::from_utf8_lossy(h.value).into_owned(),
+        );
+    }
+
+    header_map
+}
diff --git a/attestation/src/verifier.rs b/attestation/src/verifier.rs
index 8cfac14..4648762 100644
--- a/attestation/src/verifier.rs
+++ b/attestation/src/verifier.rs
@@ -69,7 +69,7 @@ impl AttestationReportVerifier {
         let report = match AttestationReport::from_cert(&cert_der, 
&self.root_ca) {
             Ok(report) => report,
             Err(e) => {
-                error!("{:?}", e);
+                error!("cert verification error {:?}", e);
                 return false;
             }
         };
diff --git a/binder/Cargo.toml b/binder/Cargo.toml
index 6dee9db..aa98157 100644
--- a/binder/Cargo.toml
+++ b/binder/Cargo.toml
@@ -23,6 +23,7 @@ log          = { version = "0.4.6" }
 serde        = { version = "1.0.92", features = ["derive"] }
 serde_json   = { version = "1.0.39" }
 thiserror    = { version = "1.0.9" }
+url          = { version = "2.1.1" }
 
 teaclave_types = { path = "../types" }
 teaclave_config = { path = "../config" }
diff --git a/binder/Enclave.edl b/binder/Enclave.edl
index 371821a..550e99f 100644
--- a/binder/Enclave.edl
+++ b/binder/Enclave.edl
@@ -40,7 +40,7 @@ enclave {
 
     include "sgx_quote.h"
     untrusted {
-        int ocall_sgx_get_ias_socket();
+        int ocall_sgx_get_remote_socket([in, size=len] const uint8_t *url, 
size_t len);
 
         sgx_status_t ocall_sgx_init_quote([out] sgx_att_key_id_t *p_att_key_id,
                                           [out] sgx_target_info_t 
*p_target_info);
diff --git a/binder/src/ocall.rs b/binder/src/ocall.rs
index b8785e8..067db7d 100644
--- a/binder/src/ocall.rs
+++ b/binder/src/ocall.rs
@@ -47,9 +47,17 @@ extern "C" {
 }
 
 #[no_mangle]
-pub extern "C" fn ocall_sgx_get_ias_socket() -> i32 {
-    let ias_addr = "api.trustedservices.intel.com:443";
-    match TcpStream::connect(ias_addr) {
+pub extern "C" fn ocall_sgx_get_remote_socket(url: *const u8, len: usize) -> 
i32 {
+    let bytes = unsafe { std::slice::from_raw_parts(url, len) };
+    let url = url::Url::parse(std::str::from_utf8(&bytes).unwrap()).unwrap();
+    match TcpStream::connect(
+        &*url
+            .socket_addrs(|| match url.scheme() {
+                "https" => Some(443),
+                _ => None,
+            })
+            .unwrap(),
+    ) {
         Ok(socket) => socket.into_raw_fd(),
         Err(_) => -1,
     }
diff --git a/cmake/scripts/test.sh b/cmake/scripts/test.sh
index 81b30ea..831b553 100755
--- a/cmake/scripts/test.sh
+++ b/cmake/scripts/test.sh
@@ -9,8 +9,8 @@ fi
 
 source ${SGX_SDK}/environment
 if [ "${SGX_MODE}" = "HW" ]; then
-       if [ -z ${IAS_SPID} ] || [ -z ${IAS_KEY} ] ; then
-        echo "Please set IAS_SPID and IAS_KEY environment variables."
+       if [ -z ${AS_ALGO} ] || [ -z ${AS_URL} ] || [ -z ${AS_SPID} ] || [ -z 
${AS_KEY} ] ; then
+        echo "Please set AS_ALGO, AS_URL, AS_SPID and AS_KEY environment 
variables."
         exit 1;
     fi
 fi
diff --git a/config/build.config.toml b/config/build.config.toml
index e13d77c..29bdeb6 100644
--- a/config/build.config.toml
+++ b/config/build.config.toml
@@ -1,7 +1,9 @@
 # Teaclave Build Config
 
 # Intel Attestation Service root CA certificate to verify attestation report
-ias_root_ca_cert = { path = "../keys/ias_root_ca_cert.pem" }
+as_root_ca_cert = { path = "../keys/ias_root_ca_cert.pem" }
+# For DCAP, use the following cert
+#as_root_ca_cert = { path = "../keys/dcap_root_ca_cert.pem" }
 
 # Auditors' public keys to verify their endorsement signatures
 auditor_public_keys = [
diff --git a/config/config_gen/main.rs b/config/config_gen/main.rs
index 45c99f5..361102e 100644
--- a/config/config_gen/main.rs
+++ b/config/config_gen/main.rs
@@ -11,7 +11,7 @@ use structopt::StructOpt;
 
 #[derive(Serialize, Deserialize)]
 struct BuildConfigToml {
-    ias_root_ca_cert: ConfigSource,
+    as_root_ca_cert: ConfigSource,
     auditor_public_keys: Vec<ConfigSource>,
     rpc_max_message_size: u32,
     inbound: Inbound,
@@ -50,7 +50,7 @@ fn display_config_source(config: &ConfigSource) -> String {
 #[derive(Template)]
 #[template(path = "config.j2")]
 struct ConfigTemplate {
-    ias_root_ca_cert: String,
+    as_root_ca_cert: String,
     auditor_public_keys: Vec<String>,
     rpc_max_message_size: u32,
     inbound: Inbound,
@@ -60,7 +60,7 @@ fn generate_build_config(toml: &Path, out: &Path) {
     let contents = fs::read_to_string(toml).expect("Something went wrong 
reading the file");
     let config: BuildConfigToml = toml::from_str(&contents).expect("Failed to 
parse the config.");
 
-    let ias_root_ca_cert = display_config_source(&config.ias_root_ca_cert);
+    let as_root_ca_cert = display_config_source(&config.as_root_ca_cert);
 
     let mut auditor_public_keys: Vec<String> = vec![];
     for key in &config.auditor_public_keys {
@@ -68,7 +68,7 @@ fn generate_build_config(toml: &Path, out: &Path) {
         auditor_public_keys.push(auditor_pulic_key);
     }
     let config_template = ConfigTemplate {
-        ias_root_ca_cert,
+        as_root_ca_cert,
         auditor_public_keys,
         rpc_max_message_size: config.rpc_max_message_size,
         inbound: config.inbound,
diff --git a/config/config_gen/templates/config.j2 
b/config/config_gen/templates/config.j2
index 6dd4f26..bb6e1ec 100644
--- a/config/config_gen/templates/config.j2
+++ b/config/config_gen/templates/config.j2
@@ -1,6 +1,6 @@
 #[derive(Debug)]
 pub struct BuildConfig {
-    pub ias_root_ca_cert: &'static [u8],
+    pub as_root_ca_cert: &'static [u8],
     pub auditor_public_keys: &'static [&'static [u8]; {{ 
auditor_public_keys.len() }}],
     pub rpc_max_message_size: u64,
     pub inbound: Inbounds,
@@ -14,8 +14,8 @@ pub struct Inbounds {
     pub storage: &'static [&'static str; {{ inbound.storage.len() }}],
 }
 
-pub const BUILD_CONFIG: BuildConfig = BuildConfig {
-    ias_root_ca_cert: &{{ ias_root_ca_cert }},
+pub static BUILD_CONFIG: BuildConfig = BuildConfig {
+    as_root_ca_cert: &{{ as_root_ca_cert }},
     auditor_public_keys: &[
         {%- for k in auditor_public_keys %}
         &{{ k }},
diff --git a/config/runtime.config.toml b/config/runtime.config.toml
index 1f3a9f5..0f7cb53 100644
--- a/config/runtime.config.toml
+++ b/config/runtime.config.toml
@@ -22,3 +22,9 @@ auditor_signatures = [
     { path = "auditors/optimus_prime/optimus_prime.sign.sha256" },
     { path = "auditors/albus_dumbledore/albus_dumbledore.sign.sha256" },
 ]
+
+[attestation]
+algorithm = "sgx_epid"
+url = "https://api.trustedservices.intel.com:443";
+key = "00000000000000000000000000000000"
+spid = "00000000000000000000000000000000"
diff --git a/config/src/runtime.rs b/config/src/runtime.rs
index 8c6ba6c..f057038 100644
--- a/config/src/runtime.rs
+++ b/config/src/runtime.rs
@@ -20,7 +20,7 @@ pub struct RuntimeConfig {
     pub api_endpoints: ApiEndpointsConfig,
     pub internal_endpoints: InternalEndpointsConfig,
     pub audit: AuditConfig,
-    pub ias: Option<IasConfig>,
+    pub attestation: AttestationServiceConfig,
 }
 
 #[derive(Debug, Serialize, Deserialize)]
@@ -61,9 +61,11 @@ pub struct AuditConfig {
 }
 
 #[derive(Debug, Serialize, Deserialize)]
-pub struct IasConfig {
-    pub ias_spid: String,
-    pub ias_key: String,
+pub struct AttestationServiceConfig {
+    pub algorithm: String,
+    pub url: String,
+    pub key: String,
+    pub spid: String,
 }
 
 impl RuntimeConfig {
@@ -92,17 +94,21 @@ impl RuntimeConfig {
         }
         config.audit.auditor_signatures_bytes = Some(signatures);
 
-        if env::var("IAS_SPID").is_ok() && env::var("IAS_KEY").is_ok() {
-            let ias_spid = env::var("IAS_SPID").unwrap();
-            let ias_key = env::var("IAS_KEY").unwrap();
-            config.ias = Some(IasConfig { ias_spid, ias_key });
-        }
-
-        if cfg!(sgx_sim) && config.ias.is_none() {
-            config.ias = Some(IasConfig {
-                ias_spid: "SGX_SIMULATION_MODE_IAS_SPID_123".to_string(),
-                ias_key: "SGX_SIMULATION_MODE_IAS_KEY_1234".to_string(),
-            });
+        if env::var("AS_ALGO").is_ok()
+            && env::var("AS_URL").is_ok()
+            && env::var("AS_SPID").is_ok()
+            && env::var("AS_KEY").is_ok()
+        {
+            let algorithm = env::var("AS_ALGO").unwrap();
+            let url = env::var("AS_URL").unwrap();
+            let spid = env::var("AS_SPID").unwrap();
+            let key = env::var("AS_KEY").unwrap();
+            config.attestation = AttestationServiceConfig {
+                algorithm,
+                url,
+                key,
+                spid,
+            };
         }
 
         validate_config(&config)?;
@@ -112,11 +118,16 @@ impl RuntimeConfig {
 }
 
 fn validate_config(config: &RuntimeConfig) -> Result<()> {
-    if config.ias.is_none()
-        || config.ias.as_ref().unwrap().ias_spid.len() != 32
-        || config.ias.as_ref().unwrap().ias_key.len() != 32
-    {
-        bail!("Cannot find IAS SPID/key or format error");
+    match config.attestation.algorithm.as_str() {
+        "sgx_epid" | "sgx_ecdsa" => (),
+        _ => bail!(
+            "Invalid attestation algorithm {}",
+            config.attestation.algorithm
+        ),
+    }
+
+    if config.attestation.spid.len() != 32 || config.attestation.key.len() != 
32 {
+        bail!("Cannot find Attestation Service SPID/key or format error");
     }
 
     Ok(())
diff --git a/dcap/Cargo.toml b/dcap/Cargo.toml
new file mode 100644
index 0000000..1556ad5
--- /dev/null
+++ b/dcap/Cargo.toml
@@ -0,0 +1,28 @@
+[package]
+name = "teaclave_dcap_ref_as"
+version = "0.1.0"
+authors = ["Teaclave Contributors <[email protected]>"]
+description = "Teaclave DCAP Attestation Service (Reference Implementation)"
+license = "Apache-2.0"
+edition = "2018"
+
+[features]
+default = []
+
+[dependencies]
+base64           = { version = "0.10.1" }
+hex              = { version = "0.4.0" }
+serde            = { version = "1.0.92", features = ["derive"] }
+serde_json       = { version = "1.0.39" }
+rocket           = { git = "https://github.com/SergioBenitez/Rocket";, features 
= ["tls"] }
+libc             = { version = "*" }
+rand             = { version = "0.7.3" }
+ring             = { version = "*" }
+untrusted        = { version = "*" }
+uuid             = { version = "*", features = ["v4"] }
+chrono           = { version = "*" }
+lazy_static      = { version = "*" }
+percent-encoding = { version = "2.1.0" }
+
+sgx_types        = { git = 
"https://github.com/apache/incubator-teaclave-sgx-sdk"; }
+sgx_ucrypto      = { git = 
"https://github.com/apache/incubator-teaclave-sgx-sdk"; }
diff --git a/dcap/Rocket.toml b/dcap/Rocket.toml
new file mode 100644
index 0000000..ddc7237
--- /dev/null
+++ b/dcap/Rocket.toml
@@ -0,0 +1,7 @@
+[global]
+port = 8080
+
+# The certificate is self-signed. DO NOT use in production.
+[global.tls]
+certs = "../keys/dcap_server_cert.pem"
+key = "../keys/dcap_server_key.pem"
diff --git a/dcap/src/main.rs b/dcap/src/main.rs
new file mode 100644
index 0000000..cd855fe
--- /dev/null
+++ b/dcap/src/main.rs
@@ -0,0 +1,202 @@
+#![feature(proc_macro_hygiene, decl_macro)]
+
+#[macro_use]
+extern crate rocket;
+#[macro_use]
+extern crate lazy_static;
+extern crate chrono;
+extern crate libc;
+extern crate rand;
+extern crate ring;
+extern crate serde_json;
+extern crate sgx_types;
+extern crate sgx_ucrypto;
+extern crate untrusted;
+extern crate uuid;
+
+use chrono::prelude::*;
+use rand::{RngCore, SeedableRng};
+use ring::signature;
+use rocket::{http, response};
+use sgx_types::*;
+
+const REPORT_SIGNING_CERT: &'static str = 
include_str!("../../keys/dcap_server_cert.pem");
+
+#[link(name = "dcap_quoteverify")]
+#[link(name = "sgx_dcap_ql")]
+#[link(name = "sgx_urts")]
+extern "C" {
+    #[allow(improper_ctypes)]
+    fn sgx_qv_verify_quote(
+        p_quote: *const u8,
+        quote_size: u32,
+        p_quote_collateral: *const sgx_ql_qve_collateral_t,
+        expiration_check_date: time_t,
+        p_collateral_expiration_status: *mut u32,
+        p_quote_verification_result: *mut sgx_ql_qv_result_t,
+        p_qve_report_info: *mut sgx_ql_qe_report_info_t,
+        supplemental_data_size: u32,
+        p_supplemental_data: *mut u8,
+    ) -> sgx_quote3_error_t;
+}
+
+lazy_static! {
+    static ref SIGNER: signature::RsaKeyPair =
+        
signature::RsaKeyPair::from_der(include_bytes!("../../keys/dcap_server_key.der")).unwrap();
+}
+
+enum QuoteVerificationResponse {
+    BadRequest,
+    InternalError,
+    AcceptedRequest(QuoteVerificationResult),
+}
+
+struct QuoteVerificationResult {
+    pub quote_status: sgx_ql_qv_result_t,
+    pub isv_enclave_quote: String,
+}
+
+impl QuoteVerificationResponse {
+    fn accept(quote_status: sgx_ql_qv_result_t, isv_enclave_quote: String) -> 
Self {
+        Self::AcceptedRequest(QuoteVerificationResult {
+            quote_status,
+            isv_enclave_quote,
+        })
+    }
+}
+
+fn to_report(rst: &sgx_ql_qv_result_t) -> &'static str {
+    use sgx_ql_qv_result_t::*;
+    match rst {
+        SGX_QL_QV_RESULT_OK => "OK",
+        SGX_QL_QV_RESULT_CONFIG_NEEDED => "CONFIGURATION_NEEDED",
+        SGX_QL_QV_RESULT_OUT_OF_DATE => "OUT_OF_DATE",
+        SGX_QL_QV_RESULT_OUT_OF_DATE_CONFIG_NEEDED => 
"OUT_OF_DATE_CONFIGURATION_NEEDED",
+        SGX_QL_QV_RESULT_INVALID_SIGNATURE => "SIGNATURE_INVALID",
+        SGX_QL_QV_RESULT_REVOKED => "KEY_REVOKED",
+        _ => panic!(),
+    }
+}
+
+impl QuoteVerificationResult {
+    pub fn to_json(self) -> String {
+        serde_json::json!({
+            "id": uuid::Uuid::new_v4().to_simple().to_string(),
+            "timestamp": Utc::now().format("%Y-%m-%dT%H:%M:%S%.f").to_string(),
+            "isvEnclaveQuoteStatus": to_report(&self.quote_status),
+            "isvEnclaveQuoteBody": self.isv_enclave_quote,
+        })
+        .to_string()
+    }
+}
+
+impl<'r> response::Responder<'r> for QuoteVerificationResponse {
+    fn respond_to(self, _: &rocket::Request) -> response::Result<'r> {
+        match self {
+            Self::BadRequest => 
response::Result::Err(http::Status::BadRequest),
+            Self::InternalError => 
response::Result::Err(http::Status::InternalServerError),
+            Self::AcceptedRequest(qvr) => {
+                let payload = qvr.to_json();
+                let mut signature = vec![0; SIGNER.public_modulus_len()];
+                let rng = ring::rand::SystemRandom::new();
+                SIGNER
+                    .sign(
+                        &signature::RSA_PKCS1_SHA256,
+                        &rng,
+                        payload.as_bytes(),
+                        &mut signature,
+                    )
+                    .unwrap();
+                response::Response::build()
+                    .header(http::ContentType::JSON)
+                    .header(http::hyper::header::Connection::close())
+                    .raw_header(
+                        "X-DCAPReport-Signing-Certificate",
+                        percent_encoding::utf8_percent_encode(
+                            REPORT_SIGNING_CERT,
+                            percent_encoding::NON_ALPHANUMERIC,
+                        ),
+                    )
+                    .raw_header("X-DCAPReport-Signature", 
base64::encode(&signature))
+                    .sized_body(std::io::Cursor::new(payload))
+                    .ok()
+            }
+        }
+    }
+}
+
+#[post(
+    "/sgx/dev/attestation/v3/report",
+    format = "application/json",
+    data = "<request>"
+)]
+fn verify_quote(request: String) -> QuoteVerificationResponse {
+    let v = match serde_json::from_str::<serde_json::Value>(&request) {
+        Ok(v) => v,
+        Err(_) => return QuoteVerificationResponse::BadRequest,
+    };
+
+    if let serde_json::Value::String(base64_quote) = &v["isvEnclaveQuote"] {
+        let quote = match base64::decode(&base64_quote) {
+            Ok(v) => v,
+            Err(_) => return QuoteVerificationResponse::BadRequest,
+        };
+        let mut collateral_exp_status = 0u32;
+        let mut quote_verification_result = 
sgx_ql_qv_result_t::SGX_QL_QV_RESULT_UNSPECIFIED;
+        let mut qve_report_info = sgx_ql_qe_report_info_t::default();
+
+        let mut nonce = sgx_quote_nonce_t::default();
+        let mut rng = rand::rngs::StdRng::from_entropy();
+        rng.fill_bytes(&mut nonce.rand);
+        qve_report_info.nonce = nonce;
+        let mut expiration_check_date: time_t = 0;
+
+        if sgx_quote3_error_t::SGX_QL_SUCCESS
+            != unsafe {
+                sgx_qv_verify_quote(
+                    quote.as_ptr(),
+                    quote.len() as _,
+                    std::ptr::null() as _,
+                    libc::time(&mut expiration_check_date),
+                    &mut collateral_exp_status as _,
+                    &mut quote_verification_result as _,
+                    &mut qve_report_info as _,
+                    0,
+                    std::ptr::null_mut(),
+                )
+            }
+        {
+            eprintln!("sgx_qv_verify_quote fialed");
+            return QuoteVerificationResponse::BadRequest;
+        };
+
+        let sha256 = sgx_ucrypto::SgxShaHandle::new();
+        sha256.init().unwrap();
+        sha256.update_msg(&nonce.rand).unwrap();
+        sha256.update_slice(&quote.as_slice()).unwrap();
+        sha256.update_msg(&expiration_check_date).unwrap();
+        sha256.update_msg(&collateral_exp_status).unwrap();
+        sha256
+            .update_msg(&(quote_verification_result as u32))
+            .unwrap();
+
+        // This check isn't quote necessary if we are verifying the nonce in
+        // an untrusted environment
+        if sha256.get_hash().unwrap() != 
qve_report_info.qe_report.body.report_data.d[..32]
+            || [0u8; 32] != qve_report_info.qe_report.body.report_data.d[32..]
+        {
+            // Something wrong with out SW stack, probably compromised
+            return QuoteVerificationResponse::InternalError;
+        }
+
+        // strip off signature data; client won't need this
+        let quote_body = base64::encode(&quote[..432]);
+        QuoteVerificationResponse::accept(quote_verification_result, 
quote_body)
+    } else {
+        QuoteVerificationResponse::BadRequest
+    }
+}
+
+fn main() {
+    rocket::ignite().mount("/", routes![verify_quote]).launch();
+}
diff --git a/keys/README.md b/keys/README.md
index e967463..03c4050 100644
--- a/keys/README.md
+++ b/keys/README.md
@@ -7,5 +7,11 @@ Note that these are only for demonstration. *DO NOT use them 
in production.*
 - `ias_root_ca_cert.pem`: attestation report root CA certificate for Intel SGX
   Attestation Service, obtained from the
   [service 
website](https://api.portal.trustedservices.intel.com/EPID-attestation)
+- `dcap_root_ca_cert.pem` and `dcap_root_ca_cert.der`: Root CA certificate (in 
PEM
+  and DER formats, respectively) used for conntecting to the reference DCAP
+  attestation server and verifying ECDSA attestation reports. Examples. Should
+  NOT be used in production.
+- `dcap_server_cert.pem` and `dcap_server_key.pem`: DCAP attestation server
+  end-entity certificate and private key. Certificate is signed by DCAP root 
CA.
 - `auditors`: contains auditors' keys to sign the *enclave info* for mutual
   attestation
diff --git a/keys/dcap_root_ca_cert.der b/keys/dcap_root_ca_cert.der
new file mode 100644
index 0000000..29686e4
Binary files /dev/null and b/keys/dcap_root_ca_cert.der differ
diff --git a/keys/dcap_root_ca_cert.pem b/keys/dcap_root_ca_cert.pem
new file mode 100644
index 0000000..4746925
--- /dev/null
+++ b/keys/dcap_root_ca_cert.pem
@@ -0,0 +1,32 @@
+-----BEGIN CERTIFICATE-----
+MIIFdzCCA1+gAwIBAgIUYGJXlZ8CxlRx7P6C+oiRsZAf47UwDQYJKoZIhvcNAQEL
+BQAwSzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRQwEgYDVQQKDAtUZWFjbGF2
+ZSBDQTEZMBcGA1UEAwwQVGVhY2xhdmUgUm9vdCBDQTAeFw0yMDAyMDUxOTA5MjFa
+Fw0zMDAyMDIxOTA5MjFaMEsxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEUMBIG
+A1UECgwLVGVhY2xhdmUgQ0ExGTAXBgNVBAMMEFRlYWNsYXZlIFJvb3QgQ0EwggIi
+MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCpwW+USb44VPeN1zW0DuVv/k7j
+FWbzxx60E3laiPk9K/EQp8L/Ma0mdPWb6O5MkY/DgeLp7UFmgTnBsTNERqAwqZrQ
+drcyyBb3akLEDuiCQWF6B+jZ8PEoSUvLPW+5QeKHvB0KHVon2Z4qNgVnVWTUk26Z
+BUvQjuJHK8GSZx9sS7Aip4s8jkqwWtio7UmRAeOOR5DFj3xZ87BzpWXi/5jD9RLx
+ScnjfR7oM3bnwpQBWyaaBiFUuxB0hZX2HoD1cvjiNshka+XtASquf9WQVj1KgBX/
+J3gUz2UYgYKO5Tr5fdtpuOs/Kbk4FBV10uCzqbSm4tR8aehpIlcADguPPgOIMkrb
+yWEtidEP5CdVETda6HnUnylOtp0Qb+EgPqzJtGlvjOmTvfAKVDTTO9w0K/NVXEMl
+xbaWm0XJgwBM5t4lh8OXw7WmPvCyKYpGfa6lw0CX4S6haMmL2OWYBwcfLSTUntii
+ENRuiBwgTPOvq+9WYMLO+NZ+ILg/j6cvbDB+7mYdsYTmF49KxvpianBRZCk5D/8Y
+/7Ty/NKJKHG0qNfwcPJcsqndiy8nzlFT31hqdDewBqgpgqqXjTJ/Zgv7iTUJ0ZN4
+T+3bo2hkoXw/nsQp+vu5wk1ErQI0G9DlolJGHNpsgYg6dkNpVgO7FEW9cNp4dZoc
+03JgOTfh6fkMD/DMbQIDAQABo1MwUTAdBgNVHQ4EFgQU761M4yztQfbaV8FFK7re
+wSRuJOAwHwYDVR0jBBgwFoAU761M4yztQfbaV8FFK7rewSRuJOAwDwYDVR0TAQH/
+BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAmsqK6jP3ETdkLFuVlE7HNFhQP3Sj
+LcRnrwcIX4X8Wa1Bfi81Cb6AEbE2LqX1tBd0wIeLv9AgEJr3zJLssCB/yxYhyD3i
+La6AP4lxGgckI7XWgwK7BHrDNsWzb5fdp+mn5GAJPzmIWpqIA8Us3UfC08cKhTgL
+lRp5h+u2JHjjLN83BY7poKD1hCf5lKd+a5nNHLTLkMrZOBWz3i7nho4M+9YTeIzm
+7mI/4UqJtUS/yEYw6SZlj3fVHqGHesGTW0ivPb7YLKslflRMnGlaYFK2w+beb3se
+x2L148z2aYBL846feFJ1d+Gvi3FY9W4MzLki+B/9X+aVcIv1OUhQ0v8ARw1gwAOP
+6ogYWzs1/fc3sYY/t4awZHcFDcv07UKDoCmzZ+7DHVwF76zgeYjrRq+YUO6fRpUL
+xRuFXYNylzUqyDCF4rUAB5GrtUvr+8qpHg20Eh5r/R77atOzlLFAlvMhT7TUw27C
+KzHS+OAtUSaRhZfFpDcyCBxTIcWc38K/7ZUKu6O82pudiHnJ2A5UXVqxSAzstJM4
+NEdrMdbIaMx9jiQ+/6JIyrAe1ve/BcFqpOLqEuF6vhBg9du5BdW0JaZDB0jeSFqQ
+Lok/lT48ASwddkUHrFjTst3wXRM1KbxbzSSOrvOPPg4eRhjJUqZgL0akxYZEgEg8
+7Y71NCmZxQdvPmI=
+-----END CERTIFICATE-----
diff --git a/keys/dcap_server_cert.pem b/keys/dcap_server_cert.pem
new file mode 100644
index 0000000..3e2dd1b
--- /dev/null
+++ b/keys/dcap_server_cert.pem
@@ -0,0 +1,30 @@
+-----BEGIN CERTIFICATE-----
+MIIFMjCCAxqgAwIBAgIUTZ2rgdpwr5Jzp18O0oRQeZmzqPIwDQYJKoZIhvcNAQEL
+BQAwSzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRQwEgYDVQQKDAtUZWFjbGF2
+ZSBDQTEZMBcGA1UEAwwQVGVhY2xhdmUgUm9vdCBDQTAeFw0yMDAyMDUxOTA5MjFa
+Fw0zMDAyMDIxOTA5MjFaMEExCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTERMA8G
+A1UECgwIVGVhY2xhdmUxEjAQBgNVBAMMCWxvY2FsaG9zdDCCAiIwDQYJKoZIhvcN
+AQEBBQADggIPADCCAgoCggIBAPAZYo90Tf5QoWxieUdUsKZ0lq3Xe0ssWfdkr/mS
+SrvpOqF0ei22+v9KCq0uPcqHOCJZWGTktGIL6nKZ+aTz/bhFXCokbKFDvXpQmUve
+0kzY7FCYu2mVl4h29BjH2OU2SIHEyAkbA3veczVgcCGQE9e0l+/NcC/C13xASw64
+1W59DUgBgXxSDnV3FytZ/Qqjs8sfC29RpqCfBdDQ/zZYB7bKQnjDmfiSKHBs8KSi
+5DhLw4WUArZcSEFa4FA9bdCHxWqjPVHSW0OidmCwPpOtRZB/agSyXUxYLNiEjmA4
+gGKGmFC0FsYhApfFcW6NsPqwhwalPxeIouSd7lXIsaOUEOT8VI6KCiOUeV+41w4U
+5bd7HT34Re24nyATcx5tZAN1wSKgLX2ZMI9CCeBeuQ6zVGfW4oXhjxDEotHVjpN1
+WFKKXh9b0c0npcDB1tR7j62g7FobMp9JAdaHhnh3LCfH2s8fBsLNoWa5H12GYjjz
+WSCVq8RBPztvotgKVHi00+1brKNmm1xZL5pv1u1wz7v7E0kERG+mty8bRFJmWtjQ
+YIRdk9C1iA0OYiUvHIkULwXVQjWoiSrihLJRhILyjxyu8aHjMCpMPPlGd3qouFsP
+0TmHMxMxZ0+ElugCOf07GDTKC7gpK5oX5tizvb2J1/jC/2QtCWXx+R4Z7liblMTH
+ziMvAgMBAAGjGDAWMBQGA1UdEQQNMAuCCWxvY2FsaG9zdDANBgkqhkiG9w0BAQsF
+AAOCAgEAS8ulPzQIiMsDOM3bpamQ+fs5nshNEbu/Mrh1So8ni9ovIObpCRm7yzfA
+1QebgRR/wIaKDTgfNj0NERwlvk6KiEJhO1jLgyu1FwrYucs06AlLywoptFuFGVhM
+I/jXYcKhtp287zF+9CE/W6g4YkpwQ73Hw/ptMoLUSVRI/dV1EkM8s9wJ6Z9ai67I
+4WjbM+oTmPv9R1eVQ97tKeDQ/SAaP93UzalXjEPQyffP523ETUvf2lpb2Vs4AzXV
+lscmpOQEQ9S5ghlarFLdCmLYWkAosuJFDXpV5eC2seaCUGWlQ5StgFxBRtWKelY7
+ejQcl30O4nNyv3GLAzD/RyYFPV/fYze7KP/EZJ8F9iDrb1nvnYi7Gphlpwg3MvAW
+JzyiVfEinYz+gDSc6DtATC0lVjh+3bP/kozTGd7KRP6axA9bvA8+sE/IOuys1oNz
+Z8VyMgbZkDI/gwlbUKSDszxdny/F7Pwt5SNxuH13+2pkgIfVDUiEnaNwAXdsdQB1
+aiHkrkfChBVXIdJClUPy8VbnPEezEGqP3+jA1RJ5706sIAWengOA02tBNv/UGAUx
+a5SGFbkbKvltQ982LGzOqN40j+Y0r33eEF0qK7Sb6hslHDLoXu3DvEG+Om0/5Rpl
+QYn3J9vgAUTd6w+6oZZGLfqfRXqq86kXzbhNY73f3EFhy4jqyW0=
+-----END CERTIFICATE-----
diff --git a/keys/dcap_server_key.der b/keys/dcap_server_key.der
new file mode 100644
index 0000000..fe7e5b2
Binary files /dev/null and b/keys/dcap_server_key.der differ
diff --git a/keys/dcap_server_key.pem b/keys/dcap_server_key.pem
new file mode 100644
index 0000000..bd6406b
--- /dev/null
+++ b/keys/dcap_server_key.pem
@@ -0,0 +1,52 @@
+-----BEGIN PRIVATE KEY-----
+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
+D3qfIvI350NSUfRmWAzKAAHZUEXCIebW
+-----END PRIVATE KEY-----
diff --git a/services/access_control/enclave/src/lib.rs 
b/services/access_control/enclave/src/lib.rs
index 5086106..294e93a 100644
--- a/services/access_control/enclave/src/lib.rs
+++ b/services/access_control/enclave/src/lib.rs
@@ -43,10 +43,12 @@ mod service;
 
 fn start_service(args: &StartServiceInput) -> anyhow::Result<()> {
     let listen_address = 
args.config.internal_endpoints.access_control.listen_address;
-    let ias_config = args.config.ias.as_ref().unwrap();
-    let attestation = 
RemoteAttestation::generate_and_endorse(&AttestationConfig::ias(
-        &ias_config.ias_key,
-        &ias_config.ias_spid,
+    let as_config = &args.config.attestation;
+    let attestation = 
RemoteAttestation::generate_and_endorse(&AttestationConfig::new(
+        &as_config.algorithm,
+        &as_config.url,
+        &as_config.key,
+        &as_config.spid,
     ))
     .unwrap();
     let config = SgxTrustedTlsServerConfig::new_without_verifier(
diff --git a/services/authentication/enclave/src/lib.rs 
b/services/authentication/enclave/src/lib.rs
index d958fb7..b2b337b 100644
--- a/services/authentication/enclave/src/lib.rs
+++ b/services/authentication/enclave/src/lib.rs
@@ -64,7 +64,7 @@ fn start_internal_endpoint(
             accepted_enclave_attrs,
             &attestation.cert,
             &attestation.private_key,
-            BUILD_CONFIG.ias_root_ca_cert,
+            BUILD_CONFIG.as_root_ca_cert,
             verifier::universal_quote_verifier,
         )
         .unwrap()
@@ -139,10 +139,16 @@ fn start_service(args: &StartServiceInput) -> 
anyhow::Result<()> {
         .collect();
     let api_listen_address = 
args.config.api_endpoints.authentication.listen_address;
     let internal_listen_address = 
args.config.internal_endpoints.authentication.listen_address;
-    let ias_config = args.config.ias.as_ref().unwrap();
-    let attestation = Arc::new(RemoteAttestation::generate_and_endorse(
-        &AttestationConfig::ias(&ias_config.ias_key, &ias_config.ias_spid),
-    )?);
+    let as_config = &args.config.attestation;
+    let attestation = Arc::new(
+        RemoteAttestation::generate_and_endorse(&AttestationConfig::new(
+            &as_config.algorithm,
+            &as_config.url,
+            &as_config.key,
+            &as_config.spid,
+        ))
+        .unwrap(),
+    );
     let database = user_db::Database::open()?;
     let mut api_jwt_secret = vec![0; user_info::JWT_SECRET_LEN];
     let mut rng = rand::thread_rng();
diff --git a/services/execution/enclave/src/lib.rs 
b/services/execution/enclave/src/lib.rs
index c4545ba..6fd4be0 100644
--- a/services/execution/enclave/src/lib.rs
+++ b/services/execution/enclave/src/lib.rs
@@ -45,10 +45,12 @@ use teaclave_types::{TeeServiceError, TeeServiceResult};
 
 fn start_service(args: &StartServiceInput) -> anyhow::Result<()> {
     let listen_address = 
args.config.internal_endpoints.execution.listen_address;
-    let ias_config = args.config.ias.as_ref().unwrap();
-    let attestation = 
RemoteAttestation::generate_and_endorse(&AttestationConfig::ias(
-        &ias_config.ias_key,
-        &ias_config.ias_spid,
+    let as_config = &args.config.attestation;
+    let attestation = 
RemoteAttestation::generate_and_endorse(&AttestationConfig::new(
+        &as_config.algorithm,
+        &as_config.url,
+        &as_config.key,
+        &as_config.spid,
     ))
     .unwrap();
     let config = SgxTrustedTlsServerConfig::new_without_verifier(
diff --git a/services/frontend/enclave/src/lib.rs 
b/services/frontend/enclave/src/lib.rs
index 7ffd5a1..42cae0d 100644
--- a/services/frontend/enclave/src/lib.rs
+++ b/services/frontend/enclave/src/lib.rs
@@ -46,10 +46,12 @@ mod service;
 
 fn start_service(args: &StartServiceInput) -> anyhow::Result<()> {
     let listen_address = args.config.api_endpoints.frontend.listen_address;
-    let ias_config = args.config.ias.as_ref().unwrap();
-    let attestation = 
RemoteAttestation::generate_and_endorse(&AttestationConfig::ias(
-        &ias_config.ias_key,
-        &ias_config.ias_spid,
+    let as_config = &args.config.attestation;
+    let attestation = 
RemoteAttestation::generate_and_endorse(&AttestationConfig::new(
+        &as_config.algorithm,
+        &as_config.url,
+        &as_config.key,
+        &as_config.spid,
     ))
     .unwrap();
     let config = SgxTrustedTlsServerConfig::new_without_verifier(
@@ -73,7 +75,7 @@ fn start_service(args: &StartServiceInput) -> 
anyhow::Result<()> {
         .client_cert(&attestation.cert, &attestation.private_key)
         .attestation_report_verifier(
             vec![enclave_attr],
-            BUILD_CONFIG.ias_root_ca_cert,
+            BUILD_CONFIG.as_root_ca_cert,
             verifier::universal_quote_verifier,
         );
     let authentication_service_address = &args
diff --git a/services/management/enclave/src/lib.rs 
b/services/management/enclave/src/lib.rs
index 6c1320f..2fdb21a 100644
--- a/services/management/enclave/src/lib.rs
+++ b/services/management/enclave/src/lib.rs
@@ -46,10 +46,12 @@ mod service;
 
 fn start_service(args: &StartServiceInput) -> anyhow::Result<()> {
     let listen_address = 
args.config.internal_endpoints.management.listen_address;
-    let ias_config = args.config.ias.as_ref().unwrap();
-    let attestation = 
RemoteAttestation::generate_and_endorse(&AttestationConfig::ias(
-        &ias_config.ias_key,
-        &ias_config.ias_spid,
+    let as_config = &args.config.attestation;
+    let attestation = 
RemoteAttestation::generate_and_endorse(&AttestationConfig::new(
+        &as_config.algorithm,
+        &as_config.url,
+        &as_config.key,
+        &as_config.spid,
     ))
     .unwrap();
     let config = SgxTrustedTlsServerConfig::new_without_verifier(
@@ -74,7 +76,7 @@ fn start_service(args: &StartServiceInput) -> 
anyhow::Result<()> {
         .client_cert(&attestation.cert, &attestation.private_key)
         .attestation_report_verifier(
             vec![enclave_attr],
-            BUILD_CONFIG.ias_root_ca_cert,
+            BUILD_CONFIG.as_root_ca_cert,
             verifier::universal_quote_verifier,
         );
     let storage_service_address = 
&args.config.internal_endpoints.storage.advertised_address;
diff --git a/services/storage/enclave/src/lib.rs 
b/services/storage/enclave/src/lib.rs
index cb0417a..990bcf6 100644
--- a/services/storage/enclave/src/lib.rs
+++ b/services/storage/enclave/src/lib.rs
@@ -47,10 +47,12 @@ use std::thread;
 
 fn start_service(args: &StartServiceInput) -> anyhow::Result<()> {
     let listen_address = args.config.internal_endpoints.storage.listen_address;
-    let ias_config = args.config.ias.as_ref().unwrap();
-    let attestation = 
RemoteAttestation::generate_and_endorse(&AttestationConfig::ias(
-        &ias_config.ias_key,
-        &ias_config.ias_spid,
+    let as_config = &args.config.attestation;
+    let attestation = 
RemoteAttestation::generate_and_endorse(&AttestationConfig::new(
+        &as_config.algorithm,
+        &as_config.url,
+        &as_config.key,
+        &as_config.spid,
     ))
     .unwrap();
     let config = SgxTrustedTlsServerConfig::new_without_verifier(
diff --git a/tests/fixtures/runtime.config.toml 
b/tests/fixtures/runtime.config.toml
index 6eefb30..a25a453 100644
--- a/tests/fixtures/runtime.config.toml
+++ b/tests/fixtures/runtime.config.toml
@@ -17,6 +17,8 @@ auditor_signatures = [
     { path = "fixtures/auditors/albus_dumbledore.sign.sha256" },
 ]
 
-[ias]
-ias_key  = "ias_key_AAAABBBBCCCCDDDDEEEEFFFF"
-ias_spid = "ias_spid_AAAABBBBCCCCDDDDEEEEFFF"
+[attestation]
+algorithm = "sgx_epid"
+url = "api.trustedservices.intel.com:443"
+key  = "ias_key_AAAABBBBCCCCDDDDEEEEFFFF"
+spid = "ias_spid_AAAABBBBCCCCDDDDEEEEFFF"
diff --git 
a/tests/functional_tests/enclave/src/teaclave_access_control_service.rs 
b/tests/functional_tests/enclave/src/teaclave_access_control_service.rs
index c8ddfcd..67bf78d 100644
--- a/tests/functional_tests/enclave/src/teaclave_access_control_service.rs
+++ b/tests/functional_tests/enclave/src/teaclave_access_control_service.rs
@@ -32,7 +32,7 @@ fn get_client() -> TeaclaveAccessControlClient {
         .expect("access_control");
     let config = SgxTrustedTlsClientConfig::new().attestation_report_verifier(
         vec![enclave_attr],
-        BUILD_CONFIG.ias_root_ca_cert,
+        BUILD_CONFIG.as_root_ca_cert,
         verifier::universal_quote_verifier,
     );
 
diff --git 
a/tests/functional_tests/enclave/src/teaclave_authentication_service.rs 
b/tests/functional_tests/enclave/src/teaclave_authentication_service.rs
index 06bf5bd..53a72a1 100644
--- a/tests/functional_tests/enclave/src/teaclave_authentication_service.rs
+++ b/tests/functional_tests/enclave/src/teaclave_authentication_service.rs
@@ -30,7 +30,7 @@ fn get_api_client() -> TeaclaveAuthenticationApiClient {
         .expect("authentication");
     let config = SgxTrustedTlsClientConfig::new().attestation_report_verifier(
         vec![enclave_attr],
-        BUILD_CONFIG.ias_root_ca_cert,
+        BUILD_CONFIG.as_root_ca_cert,
         verifier::universal_quote_verifier,
     );
 
@@ -50,7 +50,7 @@ fn get_internal_client() -> 
TeaclaveAuthenticationInternalClient {
         .expect("authentication");
     let config = SgxTrustedTlsClientConfig::new().attestation_report_verifier(
         vec![enclave_attr],
-        BUILD_CONFIG.ias_root_ca_cert,
+        BUILD_CONFIG.as_root_ca_cert,
         verifier::universal_quote_verifier,
     );
 
diff --git a/tests/functional_tests/enclave/src/teaclave_management_service.rs 
b/tests/functional_tests/enclave/src/teaclave_management_service.rs
index 2b33c4f..a53663a 100644
--- a/tests/functional_tests/enclave/src/teaclave_management_service.rs
+++ b/tests/functional_tests/enclave/src/teaclave_management_service.rs
@@ -25,7 +25,7 @@ fn get_client() -> TeaclaveManagementClient {
         .expect("management");
     let config = SgxTrustedTlsClientConfig::new().attestation_report_verifier(
         vec![enclave_attr],
-        BUILD_CONFIG.ias_root_ca_cert,
+        BUILD_CONFIG.as_root_ca_cert,
         verifier::universal_quote_verifier,
     );
 
diff --git a/tests/integration_tests/app/src/teaclave_config_tests.rs 
b/tests/integration_tests/app/src/teaclave_config_tests.rs
index 40ebe32..a2086c0 100644
--- a/tests/integration_tests/app/src/teaclave_config_tests.rs
+++ b/tests/integration_tests/app/src/teaclave_config_tests.rs
@@ -6,8 +6,8 @@ pub fn run_tests() -> bool {
 }
 
 fn test_runtime_config() {
-    env::remove_var("IAS_KEY");
-    env::remove_var("IAS_SPID");
+    env::remove_var("AS_KEY");
+    env::remove_var("AS_SPID");
     let config =
         
teaclave_config::RuntimeConfig::from_toml("./fixtures/runtime.config.toml").unwrap();
     let authentication_config = config.api_endpoints.authentication;
@@ -25,14 +25,8 @@ fn test_runtime_config() {
         Some(vec!["frontend".to_string()])
     );
 
-    assert_eq!(
-        config.ias.as_ref().unwrap().ias_key,
-        "ias_key_AAAABBBBCCCCDDDDEEEEFFFF"
-    );
-    assert_eq!(
-        config.ias.as_ref().unwrap().ias_spid,
-        "ias_spid_AAAABBBBCCCCDDDDEEEEFFF"
-    );
+    assert_eq!(config.attestation.key, "ias_key_AAAABBBBCCCCDDDDEEEEFFFF");
+    assert_eq!(config.attestation.spid, "ias_spid_AAAABBBBCCCCDDDDEEEEFFF");
 
     assert_eq!(
         config.audit.auditor_signatures_bytes.as_ref().unwrap()[0],
@@ -41,16 +35,13 @@ fn test_runtime_config() {
 }
 
 fn test_runtime_config_with_env_vars() {
-    env::set_var("IAS_KEY", "12345678901234567890123456789012");
-    env::set_var("IAS_SPID", "90123456789012345678901234567890");
+    env::set_var("AS_URL", "xxx.yy.zz:8080");
+    env::set_var("AS_ALGO", "sgx_epid");
+    env::set_var("AS_KEY", "12345678901234567890123456789012");
+    env::set_var("AS_SPID", "90123456789012345678901234567890");
     let config =
         
teaclave_config::RuntimeConfig::from_toml("./fixtures/runtime.config.toml").unwrap();
-    assert_eq!(
-        config.ias.as_ref().unwrap().ias_key,
-        "12345678901234567890123456789012"
-    );
-    assert_eq!(
-        config.ias.as_ref().unwrap().ias_spid,
-        "90123456789012345678901234567890"
-    );
+    assert_eq!(config.attestation.url, "xxx.yy.zz:8080");
+    assert_eq!(config.attestation.key, "12345678901234567890123456789012");
+    assert_eq!(config.attestation.spid, "90123456789012345678901234567890");
 }
diff --git a/third_party/crates-io b/third_party/crates-io
index 86b46dd..21edfad 160000
--- a/third_party/crates-io
+++ b/third_party/crates-io
@@ -1 +1 @@
-Subproject commit 86b46ddd38ead079ad24fba2a48feb31892f303f
+Subproject commit 21edfadc861ee0b95eed696d31e75d952b4465e5


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to