Add Teaclave SGX Tool (#379)

diff --git a/.drone.yml b/.drone.yml
index 968da46..3cdd28f 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -36,6 +36,8 @@
     path: /var/run/aesmd/aesm.socket
   commands:
   - . /root/.cargo/env
+  - (cd release/tool && ./teaclave_sgx_tool status)
+  - (cd release/tool && ./teaclave_sgx_tool attestation --key $AS_KEY --spid $AS_SPID)
   - cd build && make run-tests
 
 volumes:
diff --git a/README.md b/README.md
index 09fa0d4..4c00db3 100644
--- a/README.md
+++ b/README.md
@@ -72,6 +72,7 @@
 - [Teaclave Worker](worker)
 - [Test Harness and Test Cases](tests)
 - [Third-Party Dependency Vendoring](third_party)
+- [Tool](tool)
 - [Types](types)
 
 ### API Docs
diff --git a/attestation/src/key.rs b/attestation/src/key.rs
index 87acf3f..a506b37 100644
--- a/attestation/src/key.rs
+++ b/attestation/src/key.rs
@@ -30,14 +30,14 @@
 
 /// NistP256KeyPair stores a pair of ECDSA (private, public) key based on the
 /// NIST P-256 curve (a.k.a secp256r1).
-pub(crate) struct NistP256KeyPair {
+pub struct NistP256KeyPair {
     prv_k: sgx_ec256_private_t,
     pub_k: sgx_ec256_public_t,
 }
 
 impl NistP256KeyPair {
     /// Generate a ECDSA key pair.
-    pub(crate) fn new() -> Result<Self> {
+    pub fn new() -> Result<Self> {
         let ecc_handle = SgxEccHandle::new();
         ecc_handle.open()?;
         let (prv_k, pub_k) = ecc_handle.create_key_pair()?;
@@ -45,7 +45,7 @@
         Ok(Self { prv_k, pub_k })
     }
 
-    pub(crate) fn pub_k(&self) -> sgx_ec256_public_t {
+    pub fn pub_k(&self) -> sgx_ec256_public_t {
         self.pub_k
     }
 
diff --git a/attestation/src/lib.rs b/attestation/src/lib.rs
index 5fc7685..11e5bd7 100644
--- a/attestation/src/lib.rs
+++ b/attestation/src/lib.rs
@@ -137,7 +137,7 @@
 /// using EPID or Data Center Attestation
 /// Service (platform dependent) using ECDSA.
 #[derive(Default, Serialize, Deserialize)]
-pub(crate) struct EndorsedAttestationReport {
+pub struct EndorsedAttestationReport {
     /// Attestation report generated by the hardware
     pub report: Vec<u8>,
     /// Singature of the report
@@ -163,7 +163,7 @@
 cfg_if::cfg_if! {
     if #[cfg(feature = "mesalock_sgx")]  {
         mod service;
-        mod key;
+        pub mod key;
         mod platform;
         mod attestation;
         pub use attestation::RemoteAttestation;
diff --git a/attestation/src/report.rs b/attestation/src/report.rs
index 7d334e7..5b8d758 100644
--- a/attestation/src/report.rs
+++ b/attestation/src/report.rs
@@ -342,7 +342,7 @@
 
 impl SgxQuote {
     /// Parse from bytes to `SgxQuote`.
-    fn parse_from<'a>(bytes: &'a [u8]) -> Result<Self> {
+    pub fn parse_from<'a>(bytes: &'a [u8]) -> Result<Self> {
         let mut pos: usize = 0;
         let mut take = |n: usize| -> Result<&'a [u8]> {
             if n > 0 && bytes.len() >= pos + n {
diff --git a/attestation/src/service.rs b/attestation/src/service.rs
index 3117c03..34173ca 100644
--- a/attestation/src/service.rs
+++ b/attestation/src/service.rs
@@ -71,7 +71,7 @@
 }
 
 impl EndorsedAttestationReport {
-    pub(crate) fn new(
+    pub fn new(
         att_service_cfg: &AttestationServiceConfig,
         pub_k: sgx_types::sgx_ec256_public_t,
     ) -> anyhow::Result<Self> {
diff --git a/binder/src/proto.rs b/binder/src/proto.rs
index 95e103a..b3e7fa7 100644
--- a/binder/src/proto.rs
+++ b/binder/src/proto.rs
@@ -24,6 +24,7 @@
     InitEnclave,
     FinalizeEnclave,
     RunTest,
+    Raw,
     Unimplemented,
 }
 
@@ -35,6 +36,7 @@
             0x0000_1001 => ECallCommand::InitEnclave,
             0x0000_1002 => ECallCommand::FinalizeEnclave,
             0x0000_1003 => ECallCommand::RunTest,
+            0x0000_1004 => ECallCommand::Raw,
             _ => ECallCommand::Unimplemented,
         }
     }
@@ -48,6 +50,7 @@
             ECallCommand::InitEnclave => 0x0000_1001,
             ECallCommand::FinalizeEnclave => 0x0000_1002,
             ECallCommand::RunTest => 0x0000_1003,
+            ECallCommand::Raw => 0x0000_1004,
             ECallCommand::Unimplemented => 0xffff_ffff,
         }
     }
@@ -92,3 +95,21 @@
 
 #[derive(Serialize, Deserialize, Debug)]
 pub struct RunTestOutput;
+
+#[derive(Default, Serialize, Deserialize, Debug)]
+pub struct RawJsonInput {
+    pub json: String,
+}
+
+impl RawJsonInput {
+    pub fn new(json: impl ToString) -> Self {
+        Self {
+            json: json.to_string(),
+        }
+    }
+}
+
+#[derive(Default, Serialize, Deserialize, Debug)]
+pub struct RawJsonOutput {
+    pub json: String,
+}
diff --git a/cmake/TeaclaveGenVars.cmake b/cmake/TeaclaveGenVars.cmake
index 006af9a..6e6894c 100644
--- a/cmake/TeaclaveGenVars.cmake
+++ b/cmake/TeaclaveGenVars.cmake
@@ -7,6 +7,7 @@
 set(TEACLAVE_EXAMPLE_INSTALL_DIR ${TEACLAVE_INSTALL_DIR}/examples)
 set(TEACLAVE_BIN_INSTALL_DIR ${TEACLAVE_INSTALL_DIR}/bin)
 set(TEACLAVE_CLI_INSTALL_DIR ${TEACLAVE_INSTALL_DIR}/cli)
+set(TEACLAVE_TOOL_INSTALL_DIR ${TEACLAVE_INSTALL_DIR}/tool)
 set(TEACLAVE_DCAP_INSTALL_DIR ${TEACLAVE_INSTALL_DIR}/dcap)
 set(TEACLAVE_LIB_INSTALL_DIR ${TEACLAVE_INSTALL_DIR}/lib)
 set(TEACLAVE_DOC_INSTALL_DIR ${TEACLAVE_INSTALL_DIR}/docs)
@@ -102,6 +103,7 @@
     TEACLAVE_EXAMPLE_INSTALL_DIR=${TEACLAVE_EXAMPLE_INSTALL_DIR}
     TEACLAVE_BIN_INSTALL_DIR=${TEACLAVE_BIN_INSTALL_DIR}
     TEACLAVE_CLI_INSTALL_DIR=${TEACLAVE_CLI_INSTALL_DIR}
+    TEACLAVE_TOOL_INSTALL_DIR=${TEACLAVE_TOOL_INSTALL_DIR}
     TEACLAVE_DCAP_INSTALL_DIR=${TEACLAVE_DCAP_INSTALL_DIR}
     TEACLAVE_LIB_INSTALL_DIR=${TEACLAVE_LIB_INSTALL_DIR}
     TEACLAVE_DOC_INSTALL_DIR=${TEACLAVE_DOC_INSTALL_DIR}
diff --git a/cmake/TeaclaveUtils.cmake b/cmake/TeaclaveUtils.cmake
index 85b5bfc..2ada262 100644
--- a/cmake/TeaclaveUtils.cmake
+++ b/cmake/TeaclaveUtils.cmake
@@ -186,6 +186,10 @@
     set(_enclave_info "${TEACLAVE_OUT_DIR}/${pkg_name}_info.toml")
   endif()
 
+  if(pkg_name_no_enclave MATCHES "_tool$")
+    set(_enclave_info "/dev/null")
+  endif()
+
   add_custom_target(
     ${_target_name} ALL
     COMMAND
diff --git a/cmake/scripts/parse_cargo_packages.py b/cmake/scripts/parse_cargo_packages.py
index 46399a5..6d77327 100644
--- a/cmake/scripts/parse_cargo_packages.py
+++ b/cmake/scripts/parse_cargo_packages.py
@@ -63,6 +63,8 @@
         return 'examples'
     elif pkg_path.startswith('tests/'):
         return 'tests'
+    elif pkg_path.startswith('tool/'):
+        return 'tool'
     elif pkg_path == 'cli':
         return 'cli'
     elif pkg_path == 'dcap':
diff --git a/cmake/scripts/prep.sh b/cmake/scripts/prep.sh
index a7fca71..ec85f7b 100755
--- a/cmake/scripts/prep.sh
+++ b/cmake/scripts/prep.sh
@@ -5,7 +5,8 @@
 "SGX_EDGER8R" "TEACLAVE_EDL_DIR" "SGX_SDK" "RUST_SGX_SDK" "CMAKE_C_COMPILER"
 "CMAKE_AR" "SGX_UNTRUSTED_CFLAGS" "SGX_TRUSTED_CFLAGS" "MT_SCRIPT_DIR"
 "TEACLAVE_SERVICE_INSTALL_DIR" "TEACLAVE_EXAMPLE_INSTALL_DIR" "TEACLAVE_BIN_INSTALL_DIR"
-"TEACLAVE_CLI_INSTALL_DIR" "TEACLAVE_DCAP_INSTALL_DIR" "TEACLAVE_LIB_INSTALL_DIR" "TEACLAVE_TEST_INSTALL_DIR"
+"TEACLAVE_CLI_INSTALL_DIR" "TEACLAVE_TOOL_INSTALL_DIR" "TEACLAVE_DCAP_INSTALL_DIR"
+"TEACLAVE_LIB_INSTALL_DIR" "TEACLAVE_TEST_INSTALL_DIR"
 "TEACLAVE_AUDITORS_DIR" "TEACLAVE_EXAMPLE_AUDITORS_DIR" "DCAP" "TEACLAVE_SYMLINKS"
 "TEACLAVE_PROJECT_ROOT"
 )
@@ -16,7 +17,7 @@
 
 ${MT_SCRIPT_DIR}/setup_cmake_tomls.py ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR}
 mkdir -p ${TEACLAVE_OUT_DIR} ${TEACLAVE_TARGET_DIR} ${TEACLAVE_SERVICE_INSTALL_DIR} \
-      ${TEACLAVE_EXAMPLE_INSTALL_DIR} ${TEACLAVE_CLI_INSTALL_DIR} \
+      ${TEACLAVE_EXAMPLE_INSTALL_DIR} ${TEACLAVE_CLI_INSTALL_DIR} ${TEACLAVE_TOOL_INSTALL_DIR} \
       ${TEACLAVE_BIN_INSTALL_DIR} ${TEACLAVE_LIB_INSTALL_DIR} \
     ${TEACLAVE_TEST_INSTALL_DIR} ${TEACLAVE_AUDITORS_DIR} ${TEACLAVE_EXAMPLE_AUDITORS_DIR}
 if [ -n "$DCAP" ]; then
diff --git a/cmake/tomls/Cargo.sgx_trusted_lib.toml b/cmake/tomls/Cargo.sgx_trusted_lib.toml
index 959603e..24d0b67 100644
--- a/cmake/tomls/Cargo.sgx_trusted_lib.toml
+++ b/cmake/tomls/Cargo.sgx_trusted_lib.toml
@@ -11,6 +11,7 @@
   "tests/unit/enclave",
   "tests/functional/enclave",
   "tests/integration/enclave",
+  "tool/enclave",
 ]
 
 exclude = [
diff --git a/cmake/tomls/Cargo.sgx_untrusted_app.toml b/cmake/tomls/Cargo.sgx_untrusted_app.toml
index 21fe9b3..1ef34f3 100644
--- a/cmake/tomls/Cargo.sgx_untrusted_app.toml
+++ b/cmake/tomls/Cargo.sgx_untrusted_app.toml
@@ -11,6 +11,7 @@
   "tests/unit/app",
   "tests/functional/app",
   "tests/integration/app",
+  "tool/app",
 ]
 
 exclude = [
diff --git a/third_party/crates-io b/third_party/crates-io
index dd10153..eb25981 160000
--- a/third_party/crates-io
+++ b/third_party/crates-io
@@ -1 +1 @@
-Subproject commit dd10153ccb910b83d095bc290300a95a35a260c4
+Subproject commit eb259811db1316ec63d9dd01cda3d87e3b860ca0
diff --git a/tool/README.md b/tool/README.md
new file mode 100644
index 0000000..329cfd8
--- /dev/null
+++ b/tool/README.md
@@ -0,0 +1,54 @@
+# Teaclave SGX Tool
+
+This tool is to dump some SGX related information, e.g., hardware and software
+information, remote attestation report. This can help to diagnose some issues
+which may caused by the platform settings.
+
+## Hardware/Software Status
+
+To dump the SGX related hardware and software information, you can use this
+command:
+
+```
+$ ./teaclave_sgx_tool status
+Vendor: GenuineIntel
+CPU Model: Intel(R) Core(TM) i9-9900K CPU @ 3.60GHz
+SGX:
+  Has SGX: true
+  Has SGX1: true
+  Has SGX2: false
+  Supports ENCLV instruction leaves EINCVIRTCHILD, EDECVIRTCHILD, and ESETCONTEXT: false
+  Supports ENCLS instruction leaves ETRACKC, ERDINFO, ELDBC, and ELDUC: false
+  Bit vector of supported extended SGX features: 0x00000000
+  Maximum supported enclave size in non-64-bit mode: 2^31
+  Maximum supported enclave size in 64-bit mode: 2^36
+  Bits of SECS.ATTRIBUTES[127:0] set with ECREATE: 0x0000000000000036 (lower) 0x000000000000001F (upper)
+  EPC physical base: 0x00000000B0200000
+  EPC size: 0x0000000005D80000 (93M)
+  Supports flexible launch control: true
+
+...
+```
+
+## Remote Attestation Report
+
+Use the following command to dump remote attestation report and configure the
+platform accordingly:
+
+```
+$ ./teaclave_sgx_tool attestation --key {as_key} --spid {as_spid} --url {as_url} --algorithm {as_algorithm}
+Remote Attestation Report:
+{
+  "advisoryIDs": [
+    "INTEL-SA-00161",
+    "INTEL-SA-00320",
+    "INTEL-SA-00329",
+    "INTEL-SA-00220",
+    "INTEL-SA-00270",
+    "INTEL-SA-00293",
+    "INTEL-SA-00233"
+  ],
+  "advisoryURL": "https://security-center.intel.com",
+  ...
+}
+```
diff --git a/tool/app/Cargo.toml b/tool/app/Cargo.toml
new file mode 100644
index 0000000..a2b80bc
--- /dev/null
+++ b/tool/app/Cargo.toml
@@ -0,0 +1,22 @@
+[package]
+name = "teaclave_sgx_tool"
+version = "0.1.0"
+authors = ["Teaclave Contributors <dev@teaclave.apache.org>"]
+description = "Teaclave SGX Tool"
+license = "Apache-2.0"
+build = "build.rs"
+edition = "2018"
+
+[dependencies]
+log        = { version = "0.4.6", features = ["release_max_level_info"] }
+env_logger = { version = "0.7.1" }
+anyhow     = { version = "1.0.26" }
+serde            = { version = "1.0.92", features = ["derive"] }
+serde_json       = { version = "1.0.39" }
+raw-cpuid = "8.1.0"
+structopt = "0.3"
+
+teaclave_binder            = { path = "../../binder", features = ["app"] }
+teaclave_types             = { path = "../../types" }
+
+sgx_types = { version = "1.1.2" }
diff --git a/tool/app/build.rs b/tool/app/build.rs
new file mode 100644
index 0000000..dff52fd
--- /dev/null
+++ b/tool/app/build.rs
@@ -0,0 +1,54 @@
+// 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 std::env;
+use std::path::PathBuf;
+
+fn choose_sgx_dylib(is_sim: bool) {
+    if is_sim {
+        println!("cargo:rustc-link-lib=dylib=sgx_urts_sim");
+        println!("cargo:rustc-link-lib=dylib=sgx_uae_service_sim");
+    } else {
+        println!("cargo:rustc-link-lib=dylib=sgx_urts");
+        println!("cargo:rustc-link-lib=dylib=sgx_uae_service");
+    }
+}
+
+fn main() {
+    let sdk_dir = env::var("SGX_SDK").unwrap_or("/opt/intel/sgxsdk".into());
+    println!("cargo:rustc-link-search=native={}/lib64", sdk_dir);
+
+    let out_path = env::var_os("ENCLAVE_OUT_DIR").unwrap_or("out".into());
+    let out_dir = &PathBuf::from(out_path);
+
+    println!("cargo:rustc-link-search=native={}", out_dir.display());
+    if let Ok(edl_dir) = env::var("TEACLAVE_EDL_DIR") {
+        println!("cargo:rerun-if-changed={}/Enclave_common.edl", edl_dir);
+    }
+    println!("cargo:rustc-link-lib=static=Enclave_common_u");
+
+    let is_sim = match env::var("SGX_MODE") {
+        Ok(ref v) if v == "SW" => true,
+        Ok(ref v) if v == "HW" => false,
+        Err(env::VarError::NotPresent) => false,
+        _ => {
+            panic!("Stop build process, wrong SGX_MODE env provided.");
+        }
+    };
+
+    choose_sgx_dylib(is_sim);
+}
diff --git a/tool/app/src/main.rs b/tool/app/src/main.rs
new file mode 100644
index 0000000..8b20963
--- /dev/null
+++ b/tool/app/src/main.rs
@@ -0,0 +1,201 @@
+// 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::Result;
+use log::error;
+use std::process;
+use structopt::StructOpt;
+use teaclave_binder::proto::{ECallCommand, RawJsonInput, RawJsonOutput};
+use teaclave_binder::TeeBinder;
+use teaclave_types::TeeServiceResult;
+
+fn attestation(opt: &AttestationOpt) -> anyhow::Result<()> {
+    env_logger::init();
+    let tee = TeeBinder::new(env!("CARGO_PKG_NAME"))?;
+    run(&tee, opt)?;
+    tee.finalize();
+
+    Ok(())
+}
+
+fn start_enclave_unit_test_driver(tee: &TeeBinder, opt: &AttestationOpt) -> anyhow::Result<()> {
+    let cmd = ECallCommand::Raw;
+    let json = serde_json::to_string(opt)?;
+    let input = RawJsonInput::new(json);
+    match tee.invoke::<RawJsonInput, TeeServiceResult<RawJsonOutput>>(cmd, input) {
+        Err(e) => error!("{:?}", e),
+        Ok(Err(e)) => error!("{:?}", e),
+        _ => (),
+    }
+
+    Ok(())
+}
+
+fn run(tee: &TeeBinder, opt: &AttestationOpt) -> anyhow::Result<()> {
+    start_enclave_unit_test_driver(tee, opt)?;
+
+    Ok(())
+}
+
+#[derive(Debug, StructOpt)]
+#[structopt(name = "teaclave_sgx_tool", about = "Teaclave SGX tool.")]
+struct Opt {
+    #[structopt(subcommand)]
+    command: Command,
+}
+
+#[derive(Debug, StructOpt, serde::Serialize)]
+struct AttestationOpt {
+    /// Attestation algorithm, supported algorithms are "sgx_epid" for IAS
+    /// attestation and "sgx_ecdsa" for DCAP attestation.
+    #[structopt(long, default_value = "sgx_epid")]
+    algorithm: String,
+
+    /// URL of attestation service.
+    #[structopt(long, default_value = "https://api.trustedservices.intel.com:443")]
+    url: String,
+
+    /// API key for attestation service.
+    #[structopt(long, default_value = "00000000000000000000000000000000")]
+    key: String,
+
+    /// SPID for attestation service.
+    #[structopt(long, default_value = "00000000000000000000000000000000")]
+    spid: String,
+}
+
+#[derive(Debug, StructOpt)]
+enum Command {
+    /// Dump current hardware and software information related with Intel SGX
+    #[structopt(name = "status")]
+    Status,
+    /// Dump remote attestationation report
+    #[structopt(name = "attestation")]
+    Attestation(AttestationOpt),
+}
+
+fn status() {
+    let cpuid = raw_cpuid::CpuId::new();
+    println!(
+        "Vendor: {}",
+        cpuid
+            .get_vendor_info()
+            .as_ref()
+            .map_or_else(|| "unknown", |vf| vf.as_string(),)
+    );
+
+    println!(
+        "CPU Model: {}",
+        cpuid.get_extended_function_info().as_ref().map_or_else(
+            || "n/a",
+            |extfuninfo| extfuninfo.processor_brand_string().unwrap_or("unreadable"),
+        )
+    );
+
+    println!("SGX: ");
+
+    println!(
+        "  Has SGX: {}",
+        cpuid
+            .get_extended_feature_info()
+            .as_ref()
+            .map_or_else(|| "n/a".to_string(), |ext| ext.has_sgx().to_string(),)
+    );
+
+    let sgx_info = cpuid.get_sgx_info();
+    match sgx_info {
+        Some(sgx_info) => {
+            println!("  Has SGX1: {}", sgx_info.has_sgx1());
+            println!("  Has SGX2: {}", sgx_info.has_sgx2());
+            println!("  Supports ENCLV instruction leaves EINCVIRTCHILD, EDECVIRTCHILD, and ESETCONTEXT: {}", sgx_info.has_enclv_leaves_einvirtchild_edecvirtchild_esetcontext());
+            println!(
+                "  Supports ENCLS instruction leaves ETRACKC, ERDINFO, ELDBC, and ELDUC: {}",
+                sgx_info.has_encls_leaves_etrackc_erdinfo_eldbc_elduc()
+            );
+            println!(
+                "  Bit vector of supported extended SGX features: {:#010X}",
+                sgx_info.miscselect()
+            );
+            println!(
+                "  Maximum supported enclave size in non-64-bit mode: 2^{}",
+                sgx_info.max_enclave_size_non_64bit()
+            );
+            println!(
+                "  Maximum supported enclave size in 64-bit mode: 2^{}",
+                sgx_info.max_enclave_size_64bit()
+            );
+            println!("  Bits of SECS.ATTRIBUTES[127:0] set with ECREATE: {:#018X} (lower) {:#018X} (upper)", sgx_info.secs_attributes().0, sgx_info.secs_attributes().1);
+            for i in sgx_info.iter() {
+                match i {
+                    raw_cpuid::SgxSectionInfo::Epc(epc) => {
+                        println!("  EPC physical base: {:#018X}", epc.physical_base());
+                        println!(
+                            "  EPC size: {:#018X} ({}M)",
+                            epc.size(),
+                            epc.size() / 1024 / 1024
+                        );
+                    }
+                }
+            }
+        }
+        None => println!("  Intel SGX: n/a"),
+    }
+
+    println!(
+        "  Supports flexible launch control: {}",
+        cpuid
+            .get_extended_feature_info()
+            .as_ref()
+            .map_or_else(|| "n/a".to_string(), |ext| ext.has_sgx_lc().to_string(),)
+    );
+
+    println!(
+        "  SGX device: /dev/sgx {}, /dev/isgx {}",
+        std::path::Path::new("/dev/sgx").exists(),
+        std::path::Path::new("/dev/isgx").exists()
+    );
+    println!(
+        "  AESM service: {}",
+        std::path::Path::new("/var/run/aesmd/aesm.socket").exists()
+    );
+
+    println!("\nKernel module (isgx):");
+    if process::Command::new("modinfo")
+        .arg("isgx")
+        .status()
+        .is_err()
+    {
+        println!("failed to execute modinfo isgx");
+    }
+    println!("\nKernel module (sgx):");
+    if process::Command::new("modinfo")
+        .arg("sgx")
+        .status()
+        .is_err()
+    {
+        println!("failed to execute modinfo sgx");
+    }
+}
+
+fn main() -> Result<()> {
+    let args = Opt::from_args();
+    match args.command {
+        Command::Status => status(),
+        Command::Attestation(opt) => attestation(&opt)?,
+    };
+    Ok(())
+}
diff --git a/tool/enclave/Cargo.toml b/tool/enclave/Cargo.toml
new file mode 100644
index 0000000..3c780c2
--- /dev/null
+++ b/tool/enclave/Cargo.toml
@@ -0,0 +1,39 @@
+[package]
+name = "teaclave_sgx_tool_enclave"
+version = "0.1.0"
+authors = ["Teaclave Contributors <dev@teaclave.apache.org>"]
+description = "Teaclave SGX Tool"
+license = "Apache-2.0"
+edition = "2018"
+
+[lib]
+name = "teaclave_sgx_tool_enclave"
+crate-type = ["staticlib"]
+
+[features]
+default = []
+mesalock_sgx = [
+  "sgx_tstd",
+  "teaclave_attestation/mesalock_sgx",
+  "teaclave_binder/mesalock_sgx",
+  "teaclave_types/mesalock_sgx",
+  "teaclave_service_enclave_utils/mesalock_sgx",
+]
+cov = ["teaclave_service_enclave_utils/cov"]
+
+[dependencies]
+log         = { version = "0.4.6", features = ["release_max_level_info"] }
+anyhow      = { version = "1.0.26" }
+serde       = { version = "1.0.92" }
+serde_json       = { version = "1.0.39" }
+base64           = { version = "0.10.1" }
+thiserror   = { version = "1.0.9" }
+
+
+teaclave_attestation           = { path = "../../attestation" }
+teaclave_binder                = { path = "../../binder" }
+teaclave_service_enclave_utils = { path = "../../services/utils/service_enclave_utils" }
+teaclave_types                 = { path = "../../types" }
+
+sgx_tstd  = { version = "1.1.2", features = ["net", "thread", "backtrace"], optional = true }
+sgx_types = { version = "1.1.2" }
diff --git a/tool/enclave/Enclave.config.xml b/tool/enclave/Enclave.config.xml
new file mode 100644
index 0000000..2c4cfca
--- /dev/null
+++ b/tool/enclave/Enclave.config.xml
@@ -0,0 +1,12 @@
+<!-- Please refer to User's Guide for the explanation of each field -->
+<EnclaveConfiguration>
+  <ProdID>0</ProdID>
+  <ISVSVN>0</ISVSVN>
+  <StackMaxSize>0x200000</StackMaxSize>
+  <HeapMaxSize>0x8000000</HeapMaxSize>
+  <TCSNum>22</TCSNum>
+  <TCSPolicy>0</TCSPolicy>
+  <DisableDebug>0</DisableDebug>
+  <MiscSelect>0</MiscSelect>
+  <MiscMask>0xFFFFFFFF</MiscMask>
+</EnclaveConfiguration>
diff --git a/tool/enclave/src/lib.rs b/tool/enclave/src/lib.rs
new file mode 100644
index 0000000..0bf1c67
--- /dev/null
+++ b/tool/enclave/src/lib.rs
@@ -0,0 +1,97 @@
+// 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.
+
+#![cfg_attr(feature = "mesalock_sgx", no_std)]
+#[cfg(feature = "mesalock_sgx")]
+#[macro_use]
+extern crate sgx_tstd as std;
+
+use std::prelude::v1::*;
+
+use serde_json::Value;
+use teaclave_attestation::report::SgxQuote;
+use teaclave_attestation::EndorsedAttestationReport;
+use teaclave_attestation::{key, AttestationConfig};
+use teaclave_binder::proto::{
+    ECallCommand, FinalizeEnclaveInput, FinalizeEnclaveOutput, InitEnclaveInput, InitEnclaveOutput,
+    RawJsonInput, RawJsonOutput,
+};
+use teaclave_binder::{handle_ecall, register_ecall_handler};
+use teaclave_service_enclave_utils::ServiceEnclave;
+use teaclave_types::TeeServiceError;
+use teaclave_types::{self, TeeServiceResult};
+
+fn attestation(raw_json_input: &RawJsonInput) -> anyhow::Result<()> {
+    let v: serde_json::Value = serde_json::from_str(&raw_json_input.json)?;
+    let attestation_config = AttestationConfig::new(
+        v["algorithm"].as_str().unwrap(),
+        v["url"].as_str().unwrap(),
+        v["key"].as_str().unwrap(),
+        v["spid"].as_str().unwrap(),
+    )?;
+    let key_pair = key::NistP256KeyPair::new()?;
+    let report = match *attestation_config {
+        AttestationConfig::NoAttestation => EndorsedAttestationReport::default(),
+        AttestationConfig::WithAttestation(ref config) => {
+            EndorsedAttestationReport::new(config, key_pair.pub_k())?
+        }
+    };
+    let attn_report: Value = serde_json::from_slice(&report.report)?;
+    let sgx_quote_body = {
+        let quote_encoded = attn_report["isvEnclaveQuoteBody"]
+            .as_str()
+            .ok_or_else(|| anyhow::anyhow!("report error"))?;
+        let quote_raw = base64::decode(&quote_encoded.as_bytes())?;
+        SgxQuote::parse_from(quote_raw.as_slice())?
+    };
+    println!("Remote Attestation Report:");
+    println!("{}", serde_json::to_string_pretty(&attn_report)?);
+    println!("");
+    println!("ISV Enclave Quote Body:");
+    println!("{:?}", sgx_quote_body);
+    Ok(())
+}
+
+#[handle_ecall]
+fn handle_run_test(input: &RawJsonInput) -> TeeServiceResult<RawJsonOutput> {
+    match attestation(input) {
+        Ok(_) => Ok(RawJsonOutput::default()),
+        Err(e) => {
+            log::error!("Failed to start the service: {}", e);
+            Err(TeeServiceError::ServiceError)
+        }
+    }
+}
+
+#[handle_ecall]
+fn handle_init_enclave(_: &InitEnclaveInput) -> TeeServiceResult<InitEnclaveOutput> {
+    ServiceEnclave::init(env!("CARGO_PKG_NAME"))?;
+    Ok(InitEnclaveOutput)
+}
+
+#[handle_ecall]
+fn handle_finalize_enclave(_: &FinalizeEnclaveInput) -> TeeServiceResult<FinalizeEnclaveOutput> {
+    ServiceEnclave::finalize()?;
+    Ok(FinalizeEnclaveOutput)
+}
+
+register_ecall_handler!(
+    type ECallCommand,
+    (ECallCommand::Raw, RawJsonInput, RawJsonOutput),
+    (ECallCommand::InitEnclave, InitEnclaveInput, InitEnclaveOutput),
+    (ECallCommand::FinalizeEnclave, FinalizeEnclaveInput, FinalizeEnclaveOutput),
+);