diff --git a/.gitignore b/.gitignore index daede8e..dc3380c 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,17 @@ Cargo.lock *.so.* **/target +*.wasm + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/faq.html#why-do-binaries-have-cargolock-in-version-control-but-not-libraries +Cargo.lock +!*/app/Cargo.lock +!*/enclave/Cargo.lock +.Cargo.toml.swp + +# These are backup files generated by rustfmt +**/*.rs.bk #generated assembly third_party/ring/pregenerated @@ -24,5 +35,77 @@ bazel-out bazel-rust-sgx-sdk bazel-testlogs +# SGX Files +Enclave_u.c +Enclave_u.h +Enclave_t.c +Enclave_t.h +bin/ +lib/ + +# enigma-types +enigma-types.h + +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + #Node/NPM -node_modules/ \ No newline at end of file +node_modules/ + +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# CMake +cmake-build-debug/ +cmake-build-release/ + +# File-based project format +*.iws + +# IDEs +out/ +.idea/ +.vscode/ +**/*.iml + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +/target +**/*.rs.bk \ No newline at end of file diff --git a/enclave/enigma-types/Cargo.toml b/enclave/enigma-types/Cargo.toml new file mode 100644 index 0000000..64b95fd --- /dev/null +++ b/enclave/enigma-types/Cargo.toml @@ -0,0 +1,24 @@ +# I use package renaming to import 2 libraries with the same name but from different sources (1 for SGX and 1 for regular std) +# Then in the code you can rename them back (under a cfg condition) to the same name to use abstractly. + +[package] +name = "enigma-types" +version = "0.3.0" +authors = ["Elichai Turkel "] +edition = "2018" +categories = ["no-std"] + +[dependencies] +rustc-hex = { version = "2.0.1", default-features = false } +arrayvec = { version = "0.4.10", default-features = false } +serde_sgx = { package = "serde", git = "https://github.com/mesalock-linux/serde-sgx.git", rev = "sgx_1.0.9", optional = true } +serde_std = { package = "serde", version = "1.0", default-features = false, optional = true } + +[build-dependencies] +cbindgen = "0.8" + +[features] +default = ["serde_std/derive"] # This library is no_std with the default features. +std = ["serde_std/std", "serde_std/derive"] +alloc = ["serde_std/alloc", "serde_std/derive"] +sgx = ["serde_sgx", "serde_sgx/derive"] diff --git a/enclave/enigma-types/build.rs b/enclave/enigma-types/build.rs new file mode 100644 index 0000000..3bf73f8 --- /dev/null +++ b/enclave/enigma-types/build.rs @@ -0,0 +1,42 @@ +// client/build.rs + +use cbindgen::Language; +use std::{env, path::PathBuf}; + +fn main() { + let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); + let package_name = env::var("CARGO_PKG_NAME").unwrap(); + let output_file = target_dir().join(format!("{}.h", package_name)).display().to_string(); + + cbindgen::Builder::new() + .with_no_includes() + .with_sys_include("stdbool.h") + .with_language(Language::C) + .include_item("EnclaveReturn") + .include_item("ResultStatus") + .include_item("ExecuteResult") + .include_item("Hash256") + .include_item("StateKey") + .include_item("ContractAddress") + .include_item("MsgID") + .include_item("PubKey") + .include_item("RawPointer") + .with_crate(&crate_dir) + .generate() + .expect("Unable to generate bindings") + .write_to_file(&output_file); +} + +/// Find the location of the `target/` directory. Note that this may be +/// overridden by `cmake`, so we also need to check the `CARGO_TARGET_DIR` +/// variable. +fn target_dir() -> PathBuf { + let mut target = PathBuf::from(env::var("OUT_DIR").unwrap()); + target.pop(); + target.pop(); + target.pop(); + target.pop(); + target.pop(); + + target +} \ No newline at end of file diff --git a/enclave/enigma-types/src/hash.rs b/enclave/enigma-types/src/hash.rs new file mode 100644 index 0000000..cb56f36 --- /dev/null +++ b/enclave/enigma-types/src/hash.rs @@ -0,0 +1,106 @@ +//! # Hash Module +//! This module provides a struct meant for containing Hashes (Kecack256 or Sha256). + +use core::ops::{Deref, DerefMut}; +use rustc_hex::{FromHex, FromHexError}; +use arrayvec::ArrayVec; +use crate::serde::{Serialize, Deserialize}; + +/// This struct is basically a wrapper over `[u8; 32]`, and is meant to be returned from whatever hashing functions we use. +/// `#[repr(C)]` is a Rust feature which makes the struct be aligned just like C structs. +/// See [`Repr(C)`][https://doc.rust-lang.org/nomicon/other-reprs.html] +#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Default)] +#[serde(crate = "crate::serde")] +#[repr(C)] +pub struct Hash256([u8; 32]); + + +impl Hash256 { + /// This method exposes rust's built in [`copy_from_slice`][https://doc.rust-lang.org/std/primitive.slice.html#method.copy_from_slice] + /// Copies the elements from `src` into `self`. + /// + /// The length of `src` must be the same as `self`. + /// + /// # Panics + /// + /// This function will panic if the two slices have different lengths. + /// + /// This might not be needed since we implement `Deref` and `DerefMut` for the inner array. + pub fn copy_from_slice(&mut self, src: &[u8]) { + self.0.copy_from_slice(src) + } + + /// This function converts a hex string into `Hash256` type. + /// the hex must not contain `0x` (as is usually the case in hexs in rust) + /// if the hex length isn't 64 (which will be converted into the 32 bytes) it will return an error. + pub fn from_hex(hex: &str) -> Result { + if hex.len() != 64 { + return Err(FromHexError::InvalidHexLength); + } + let hex_vec: ArrayVec<[u8; 32]> = hex.from_hex()?; + let mut result = Self::default(); + result.copy_from_slice(&hex_vec); + Ok(result) + } + + /// Checks if the struct contains only zeroes or not. + pub fn is_zero(&self) -> bool { + self.0 == [0u8;32] + } +} + + +impl From<[u8; 32]> for Hash256 { + fn from(arr: [u8; 32]) -> Self { + Hash256(arr) + } +} + +impl Into<[u8; 32]> for Hash256 { + fn into(self) -> [u8; 32] { + self.0 + } +} + +impl Deref for Hash256 { + type Target = [u8; 32]; + + fn deref(&self) -> &[u8; 32] { + &self.0 + } +} + +impl DerefMut for Hash256 { + fn deref_mut(&mut self) -> &mut [u8; 32] { + &mut self.0 + } +} + +impl AsRef<[u8]> for Hash256 { + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + +impl AsMut<[u8]> for Hash256 { + fn as_mut(&mut self) -> &mut [u8] { + &mut self.0 + } +} + +#[cfg(test)] +mod test { + use super::Hash256; + #[test] + fn test_hex_succeed() { + let a = "0101010101010101010101010101010101010101010101010101010101010101"; + Hash256::from_hex(&a).unwrap(); + } + + #[should_panic] + #[test] + fn test_hex_long() { + let a = "02020202020202020202020202020202020202020202020202020202020202020202024444020202020202"; + Hash256::from_hex(&a).unwrap(); + } +} \ No newline at end of file diff --git a/enclave/enigma-types/src/lib.rs b/enclave/enigma-types/src/lib.rs new file mode 100644 index 0000000..99b9a31 --- /dev/null +++ b/enclave/enigma-types/src/lib.rs @@ -0,0 +1,37 @@ +#![cfg_attr(all(not(feature = "std"), not(test)), no_std)] +#![deny(unused_extern_crates, missing_docs, warnings)] +//! # Enigma Types +//! This library is meant to supply all the types that are specific to our protocol.
+//! Inside of this library I abstracted the std as `localstd` so that you can use it without knowing if it's `sgx_tstd` or regular std. +//! *But* Unlike other crates this isn't just abstracting 2 different std's, +//! but this crate is expected to work even without std at all(except some parts maybe). +//! +//! in the `build.rs` I use `cbindgen` to auto generate `enigma-types.h` header so it can be included into the edl. +//! that way we can pass rust structs through the SGX bridge(which is C) +//! +//! This crate is Rust 2018 Edition, +//! meaning there's no `extern crate` and `use` statements need to start with `crate`/`self`/`super`. + + +pub mod traits; +mod types; +mod hash; + +#[cfg(all(feature = "sgx", not(feature = "std")))] +use serde_sgx as serde; + +#[cfg(not(feature = "sgx"))] +use serde_std as serde; + +use crate::traits::SliceCPtr; +pub use crate::types::*; + +/// This is a bit safer wrapper of [`core::ptr::copy_nonoverlapping`] +/// it checks that the src len is at least as big as `count` otherwise it will panic. +/// *and* it uses [`SliceCPtr`](crate::traits::SliceCPtr) trait to pass a C compatible pointer. +pub unsafe fn write_ptr(src: &[T], dst: *mut T, count: usize) { + if src.len() > count { + unimplemented!() + } + core::ptr::copy_nonoverlapping(src.as_c_ptr(), dst, src.len()); +} diff --git a/enclave/enigma-types/src/traits.rs b/enclave/enigma-types/src/traits.rs new file mode 100644 index 0000000..c9f5b7d --- /dev/null +++ b/enclave/enigma-types/src/traits.rs @@ -0,0 +1,45 @@ +//! # Traits module +//! This module should provide low level traits that are required on both sides of the SGX. +//! right now it only contains the [`SliceCPtr`] trait which is used to *always* provide valid C pointers. + +static EMPTY: [u8; 1] = [0]; + +/// This trait provides an interface into `C` like pointers. +/// in Rust if you try to get a pointer to an empty vector you'll get: +/// 0x0000000000000001 OR 0x0000000000000000, although bear in mind this *isn't* officially defined. +/// this behavior is UB in C's `malloc`, passing an invalid pointer with size 0 to `malloc` is implementation defined. +/// in the case of Intel's + GCC what we observed is a Segmentation Fault. +/// this is why if the vec/slice is empty we use this trait to pass a pointer to a stack allocated static `[0]` array. +/// this will make the pointer valid, and when the len is zero +/// `malloc` won't allocate anything but also won't produce a SegFault +pub trait SliceCPtr { + /// The Target for the trait. + /// this trait can't be generic because it should only be implemented once per type + /// (See [Associated Types][https://doc.rust-lang.org/rust-by-example/generics/assoc_items/types.html]) + type Target; + /// This function is what will produce a valid C pointer to the target + /// even if the target is 0 sized (and rust will produce a C *invalid* pointer for it ) + fn as_c_ptr(&self) -> *const Self::Target; +} + +impl SliceCPtr for [T] { + type Target = T; + fn as_c_ptr(&self) -> *const Self::Target { + if self.is_empty() { + EMPTY.as_ptr() as *const _ + } else { + self.as_ptr() + } + } +} + +impl SliceCPtr for str { + type Target = u8; + fn as_c_ptr(&self) -> *const Self::Target { + if self.is_empty() { + EMPTY.as_ptr() as *const _ + } else { + self.as_ptr() + } + } +} diff --git a/enclave/enigma-types/src/types.rs b/enclave/enigma-types/src/types.rs new file mode 100644 index 0000000..08dc3c6 --- /dev/null +++ b/enclave/enigma-types/src/types.rs @@ -0,0 +1,258 @@ +//! # Types module +//! This module should provide low level types, enums and structures that are required on both sides of the SGX. +//! All enums and structures should have `#[repr(C)]` on them so they would be aligned just like in C +//! See [`Repr(C)`][https://doc.rust-lang.org/nomicon/other-reprs.html] +//! +//! Any new type here that should pass through the edl should be added into the [`build.rs]` file, +//! so it will put it into the auto generated C header. +//! +//! Note: Please use the right types even if they're only aliases right now, +//! this helps both for readability and if in the future we decide to change the alias. + +use core::{fmt, mem, ptr, default::Default}; + +pub use crate::hash::Hash256; +/// The size of the symmetric 256 bit key we use for encryption (in bytes). +pub const SYMMETRIC_KEY_SIZE: usize = 256 / 8; +/// symmetric key we use for encryption. +pub type SymmetricKey = [u8; SYMMETRIC_KEY_SIZE]; +/// StateKey is the key used for state encryption. +pub type StateKey = SymmetricKey; +/// DHKey is the key that results from the ECDH [`enigma_crypto::KeyPair::derive_key`](../replace_me) +pub type DhKey = SymmetricKey; +/// ContractAddress is the address of contracts in the Enigma Network. +pub type ContractAddress = Hash256; +/// PubKey is a public key that is used for ECDSA signing. +pub type PubKey = [u8; 64]; + + +/// This enum is used to return from an ecall/ocall to represent if the operation was a success and if not then what was the error. +/// The goal is to not reveal anything sensitive +/// `#[repr(C)]` is a Rust feature which makes the struct be aligned just like C structs. +/// See [`Repr(C)`][https://doc.rust-lang.org/nomicon/other-reprs.html] +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum EnclaveReturn { + /// Success, the function returned without any failure. + Success, + /// TaskFailure, the task(Deploy/Compute) has failed + TaskFailure, + /// KeysError, There's a key missing or failed to derive a key. + KeysError, + /// Failure in Encryption, couldn't decrypt the variable / failed to encrypt the results. + EncryptionError, + // TODO: I'm not sure this error is used anywhere. + /// SigningError, for some reason it failed on signing the results. + SigningError, + // TODO: Also don't think this is needed. + /// RecoveringError, Something failed in recovering the public key. + RecoveringError, + ///PermissionError, Received a permission error from an ocall, (i.e. opening the signing keys file or something like that) + PermissionError, + /// SgxError, Error that came from the SGX specific stuff (i.e DRAND, Sealing etc.) + SgxError, + /// StateError, an Error in the State. (i.e. failed applying delta, failed deserializing it etc.) + StateError, + /// OcallError, an error from an ocall. + OcallError, + /// OcallDBError, an error from the Database in the untrusted part, couldn't get/save something. + OcallDBError, + /// MessagingError, a message that received couldn't be processed (i.e. KM Message, User Key Exchange etc.) + MessagingError, + /// WorkerAuthError, Failed to authenticate the worker, this is specific to the KM node. + WorkerAuthError, + // TODO: should consider merging with a different error. + /// Missing StateKeys in the KM node. + KeyProvisionError, + /// Something went really wrong. + Other +} + + +/// This struct is basically some sort of a boolean that says if an operation was a success or a failure. +#[repr(C)] +#[derive(Debug, PartialEq)] +pub enum ResultStatus { + /// Ok = Success = 1. + Ok = 1, + /// Failure = Error = 0. + Failure = 0, +} + + +/// This struct is what returned from a Deploy/Compute ecall, it contains all the needed data. +#[repr(C)] +#[derive(Clone, Copy)] +pub struct ExecuteResult { + /// A pointer to the output of the execution using [`ocall_save_to_memory`](../replace_me) (on the untrusted stack) + pub output: *const u8, + /// A pointer to the resulting delta using [`ocall_save_to_memory`](../replace_me) (on the untrusted stack) + pub delta_ptr: *const u8, + /// The delta index number. + pub delta_index: u32, + /// A pointer to the Ethereum payload using [`ocall_save_to_memory`](../replace_me) (on the untrusted stack) + pub ethereum_payload_ptr: *const u8, + /// The ethereum address that the payload belongs to. + pub ethereum_address: [u8; 20], + /// A signature by the enclave on all of the results. + pub signature: [u8; 65], + /// The gas used by the execution. + pub used_gas: u64, +} + +/// This struct is a wrapper to a raw pointer. +/// when you pass a pointer through the SGX bridge(EDL) the SGX Edger8r will copy the data that it's pointing to +/// using `memalloc` and `memset` to the other side of the bridge, then it changes the pointer to point to the new data. +/// +/// So this struct is needed if you want to pass a pointer from one side to the other while the pointer still points to the right locaiton. +/// +/// Say you want to give the enclave a DB on the untrusted, so that the enclave can then pass that pointer to an ocall. +/// This will let you do it without the Edger8r messing with the pointer. +/// +/// And I tried to add a mutability bool to make it a little more safe by giving you a pointer based on the original mutability. +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub struct RawPointer { + ptr: *const u8, + _mut: bool +} + +impl RawPointer { + /// Creates a new RawPointer wrapper. + /// it will auto cast the reference into a raw pointer. + pub unsafe fn new(reference: &T) -> Self { + RawPointer { ptr: reference as *const T as *const u8, _mut: false } + } + + /// Creates a new mutable RawPointer wrapper. + /// This is needed if when you unwrap this you want a mutable pointer. + pub unsafe fn new_mut(reference: &mut T) -> Self { + RawPointer { ptr: reference as *mut T as *const u8, _mut: true } + } + + /// This will return the underlying const raw pointer. + pub fn get_ptr(&self) -> *const T { + self.ptr as *const T + } + + /// this will return a Result and if the RawPointer was created with `new_mut` + /// it Will return `Ok` with the underlying mut raw pointer. + /// if the struct was created with just `new` it will return `Err`. + pub fn get_mut_ptr(&self) -> Result<*mut T, &'static str> { + if !self._mut { + Err("This DoublePointer is not mutable") + } else { + Ok(self.ptr as *mut T) + } + } + + /// This will unsafely cast the underlying pointer back into a reference. + pub unsafe fn get_ref(&self) -> &T { + &*(self.ptr as *const T) + } + + /// This will unsafely cast the underlying pointer back into a mut pointer. + /// it will return a result and have the same rules as [`get_mut_ptr`] + /// + /// [`get_mut_ptr`]: #method.get_mut_ptr + pub unsafe fn get_mut_ref(&self) -> Result<&mut T, &'static str> { + if !self._mut { + Err("This DoublePointer is not mutable") + } else { + Ok(&mut *(self.ptr as *mut T) ) + } + } + + +} + +impl From for ResultStatus { + fn from(i: bool) -> Self { + if i { + ResultStatus::Ok + } else { + ResultStatus::Failure + } + } +} + +impl Default for ExecuteResult { + fn default() -> ExecuteResult { + ExecuteResult { + output: ptr::null(), + delta_ptr: ptr::null(), + ethereum_payload_ptr: ptr::null(), + .. unsafe { mem::zeroed() } + } + } +} + +impl fmt::Debug for ExecuteResult { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut debug_trait_builder = f.debug_struct("ExecuteResult"); + debug_trait_builder.field("output", &(self.output)); + debug_trait_builder.field("delta_ptr", &(self.delta_ptr)); + debug_trait_builder.field("delta_index", &(self.delta_index)); + debug_trait_builder.field("ethereum_payload_ptr", &(self.ethereum_payload_ptr)); + debug_trait_builder.field("ethereum_address", &(self.ethereum_address)); + debug_trait_builder.field("signature", &(&self.signature[..])); + debug_trait_builder.field("used_gas", &(self.used_gas)); + debug_trait_builder.finish() + } +} + +impl Default for EnclaveReturn { + fn default() -> EnclaveReturn { EnclaveReturn::Success } +} + +impl fmt::Display for EnclaveReturn { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::EnclaveReturn::*; + let p = match *self { + Success => "EnclaveReturn: Success", + TaskFailure => "EnclaveReturn: Task failure", + KeysError => "EnclaveReturn: KeysError", + EncryptionError => "EnclaveReturn: EncryptionError", + SigningError => "EnclaveReturn: SigningError", + RecoveringError => "EnclaveReturn: RecoveringError", + PermissionError => "EnclaveReturn: PermissionError", + SgxError => "EnclaveReturn: SgxError", + StateError => "EnclaveReturn: StateError", + OcallError => "EnclaveReturn: OcallError", + OcallDBError => "EnclaveReturn: OcallDBError", + MessagingError => "EnclaveReturn: MessagingError", + WorkerAuthError => "EnclaveReturn: WorkerAuthError", + KeyProvisionError => "EnclaveReturn: KeyProvisionError", + Other => "EnclaveReturn: Other", + }; + write!(f, "{}", p) + } +} + + +/// This trait will convert a Result into EnclaveReturn. +/// +/// I used this because there's a problem. +/// we want to convert [`enigma_tools_t::common::errors::EnclaveError`](../replace_me) into [`EnclaveReturn`] to return it back through the EDL. +/// *but* in this module we can't impl [`From`](core::convert::From) from `EnclaveError` to `EnclaveReturn` because this crate is `std` pure +/// so it doesn't have access to `enigma_tools_t`. +/// And we can't implement this as `Into for Result<(), EnclaveError>` in `enigma_tools_t` +/// because in rust you can't implement an imported trait(`From`/`Into`) on a type you imported (`Result`). +/// +/// So my solution was to declare a new trait, and to implement [`core::convert::From`] on whatever implements my trait through generics. +/// that way all we need is to implement `ResultToEnclaveReturn` on `EnclaveError` and it will auto generate a `From` impl for it. +/// +/// And if the Result is `Ok` it will return `EnclaveReturn::Success` and if `Err` it will convert using this trait. +pub trait ResultToEnclaveReturn { + /// Should return a EnclaveReturn while consuming self. + fn into_enclave_return(self) -> EnclaveReturn; +} + +impl From> for EnclaveReturn { + fn from(res: Result<(), T>) -> Self { + match res { + Ok(()) => EnclaveReturn::Success, + Err(e) => ResultToEnclaveReturn::into_enclave_return(e), + } + } +} diff --git a/enclave/rust-toolchain b/enclave/rust-toolchain new file mode 100644 index 0000000..7b9d999 --- /dev/null +++ b/enclave/rust-toolchain @@ -0,0 +1 @@ +nightly-2020-03-12 \ No newline at end of file diff --git a/enclave/safetrace/Makefile b/enclave/safetrace/Makefile new file mode 100644 index 0000000..0a96b90 --- /dev/null +++ b/enclave/safetrace/Makefile @@ -0,0 +1,192 @@ +# 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. + +######## SGX SDK Settings ######## + +# The directory where intel sgx is installed +SGX_SDK ?= $(HOME)/.sgxsdk/sgxsdk + +# The path to the incubator-teaclave-sgx-sdk code. +SGX_SDK_RUST ?= ../incubator-teaclave-sgx-sdk/ + + +SGX_MODE ?= HW +SGX_ARCH ?= x64 + +ifeq ($(shell getconf LONG_BIT), 32) + SGX_ARCH := x86 +else ifeq ($(findstring -m32, $(CXXFLAGS)), -m32) + SGX_ARCH := x86 +endif + +ifeq ($(SGX_ARCH), x86) + SGX_COMMON_CFLAGS := -m32 + SGX_LIBRARY_PATH := $(SGX_SDK)/lib + SGX_ENCLAVE_SIGNER := $(SGX_SDK)/bin/x86/sgx_sign + SGX_EDGER8R := $(SGX_SDK)/bin/x86/sgx_edger8r +else + SGX_COMMON_CFLAGS := -m64 + SGX_LIBRARY_PATH := $(SGX_SDK)/lib64 + SGX_ENCLAVE_SIGNER := $(SGX_SDK)/bin/x64/sgx_sign + SGX_EDGER8R := $(SGX_SDK)/bin/x64/sgx_edger8r +endif + +ifeq ($(SGX_DEBUG), 1) +ifeq ($(SGX_PRERELEASE), 1) +$(error Cannot set SGX_DEBUG and SGX_PRERELEASE at the same time!!) +endif +endif + + +ifeq ($(SGX_DEBUG), 1) + SGX_COMMON_CFLAGS += -O0 -g +else + SGX_COMMON_CFLAGS += -O2 +endif + +######## CUSTOM Settings ######## + +# Path of all libraries that are linked into enclave DLL +CUSTOM_LIBRARY_PATH := ./lib + +# Path to untrusted Rust binary and signed enclave DLL +CUSTOM_BIN_PATH := ./bin + +# Path to baidu EDL .h files +CUSTOM_EDL_PATH := $(SGX_SDK_RUST)/edl +CUSTOM_COMMON_PATH := $(SGX_SDK_RUST)/common + +######## EDL Settings ######## + +# Files generated by the Intel edgerator +Enclave_EDL_Files := enclave/Enclave_t.c enclave/Enclave_t.h app/Enclave_u.c app/Enclave_u.h + +######## APP Settings ######## + +App_Rust_Flags := --release +App_SRC_Files := $(shell find app/ -type f -name '*.rs') $(shell find app/ -type f -name 'Cargo.toml') + +# Include paths for untrusted EDL object +App_Include_Paths := -I ./app -I./include -I$(SGX_SDK)/include -I$(CUSTOM_EDL_PATH) -I./enclave + +# C compilation flags for untrusted EDL object +App_C_Flags := $(SGX_COMMON_CFLAGS) -fPIC -Wno-attributes $(App_Include_Paths) + +App_Rust_Path := ./app/target/release +App_Enclave_u_Object :=app/libEnclave_u.a +App_Name := safetrace-app + +######## Enclave Settings ######## + +ifneq ($(SGX_MODE), HW) + Trts_Library_Name := sgx_trts_sim + Service_Library_Name := sgx_tservice_sim +else + Trts_Library_Name := sgx_trts + Service_Library_Name := sgx_tservice +endif +Crypto_Library_Name := sgx_tcrypto +KeyExchange_Library_Name := sgx_tkey_exchange +ProtectedFs_Library_Name := sgx_tprotected_fs + +RustEnclave_C_Files := $(wildcard ./enclave/*.c) +RustEnclave_C_Objects := $(RustEnclave_C_Files:.c=.o) +RustEnclave_Include_Paths := -I$(CUSTOM_COMMON_PATH)/inc -I$(CUSTOM_EDL_PATH) -I$(SGX_SDK)/include -I$(SGX_SDK)/include/tlibc -I$(SGX_SDK)/include/stlport -I$(SGX_SDK)/include/epid -I ./enclave -I./include + +RustEnclave_Link_Libs := -L$(CUSTOM_LIBRARY_PATH) -lcompiler-rt-patch -lenclave +RustEnclave_Compile_Flags := $(SGX_COMMON_CFLAGS) -nostdinc -fvisibility=hidden -fpie -fstack-protector $(RustEnclave_Include_Paths) +RustEnclave_Link_Flags := $(SGX_COMMON_CFLAGS) -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles -L$(SGX_LIBRARY_PATH) \ + -Wl,--whole-archive -l$(Trts_Library_Name) -Wl,--no-whole-archive \ + -Wl,--start-group -lsgx_tstdc -l$(Service_Library_Name) -l$(Crypto_Library_Name) $(RustEnclave_Link_Libs) -Wl,--end-group \ + -Wl,-Bstatic -Wl,-Bsymbolic -Wl,--no-undefined \ + -Wl,-pie,-eenclave_entry -Wl,--export-dynamic \ + -Wl,--defsym,__ImageBase=0 \ + -Wl,--gc-sections \ + -Wl,--version-script=enclave/Enclave.lds + +RustEnclave_Name := enclave/enclave.so +Signed_RustEnclave_Name := bin/enclave.signed.so + +.PHONY: all +all: $(Signed_RustEnclave_Name) + +######## EDL Objects ######## + +$(Enclave_EDL_Files): $(SGX_EDGER8R) enclave/Enclave.edl + $(SGX_EDGER8R) --trusted enclave/Enclave.edl --search-path $(SGX_SDK)/include --search-path $(CUSTOM_EDL_PATH) --trusted-dir enclave + $(SGX_EDGER8R) --untrusted enclave/Enclave.edl --search-path $(SGX_SDK)/include --search-path $(CUSTOM_EDL_PATH) --untrusted-dir app + @echo "GEN => $(Enclave_EDL_Files)" + +######## App Objects ######## + +# Untrusted EDL object +app/Enclave_u.o: $(Enclave_EDL_Files) + @cd app && cargo build -p enigma-types $(App_Rust_Flags) + @$(CC) $(App_C_Flags) -c app/Enclave_u.c -o $@ + @echo "CC <= $<" + +# Untrusted EDL static library +$(App_Enclave_u_Object): app/Enclave_u.o + $(AR) rcsD $@ $^ + cp $(App_Enclave_u_Object) $(CUSTOM_LIBRARY_PATH) + +# Untrusted Rust binary. Cargo gets parameters through app/build.rs. +# The binary is copied to $(CUSTOM_BIN_PATH) +$(App_Name): $(App_Enclave_u_Object) $(App_SRC_Files) + @cd app && SGX_SDK_RUST=$(SGX_SDK_RUST) SGX_SDK=$(SGX_SDK) cargo build $(App_Rust_Flags) + @echo "Cargo => $@" + mkdir -p $(CUSTOM_BIN_PATH) + cp $(App_Rust_Path)/$(App_Name) $(CUSTOM_BIN_PATH)/$(App_name) + +######## Enclave Objects ######## + +# Trusted EDL object +enclave/Enclave_t.o: $(Enclave_EDL_Files) + @$(CC) $(RustEnclave_Compile_Flags) -c enclave/Enclave_t.c -o $@ + @echo "CC <= $<" + +# Enclave DLL +$(RustEnclave_Name): enclave compiler-rt $(App_Name) enclave/Enclave_t.o + cp ../incubator-teaclave-sgx-sdk/compiler-rt/libcompiler-rt-patch.a ./lib + @$(CXX) enclave/Enclave_t.o -o $@ $(RustEnclave_Link_Flags) + @echo "LINK => $@" + +# Signing of the enclave DLL with Intel signing tool. The signed DLL will be loaded on creation of enclave. +# Signing in the Makefile publicly is possible only in debug or prerelease modes. +$(Signed_RustEnclave_Name): $(RustEnclave_Name) + mkdir -p $(CUSTOM_BIN_PATH) + @$(SGX_ENCLAVE_SIGNER) sign -key enclave/Enclave_private.pem -enclave $(RustEnclave_Name) -out $@ -config enclave/Enclave.config.xml + @echo "SIGN => $@" + +.PHONY: enclave +# Invocation of Makefile in ./enclave, which builds trusted Rust static library and copies it to $(CUSTOM_LIBRARY_PATH) +enclave: + mkdir -p $(CUSTOM_LIBRARY_PATH) + $(MAKE) -C ./enclave/ CARGO_FLAGS=$(App_Rust_Flags) Rust_target_dir=$(Rust_target_dir) + +.PHONY: compiler-rt +# Building of libcompiler-rt-patch.a library, which contains various builtin functions for a variety of architectures +compiler-rt: + $(MAKE) -C $(SGX_SDK_RUST)/compiler-rt/ 2> /dev/null + +.PHONY: clean +clean: + @rm -f $(App_Name) $(RustEnclave_Name) $(Signed_RustEnclave_Name) enclave/*_t.* app/*_u.* lib/*.a + @rm -rf enclave/enigma-types.h app/enigma-types.h + @cd enclave && cargo clean && rm -f Cargo.lock + @cd app && cargo clean && rm -f Cargo.lock + diff --git a/enclave/safetrace/app/Cargo.toml b/enclave/safetrace/app/Cargo.toml new file mode 100644 index 0000000..7b1c1d2 --- /dev/null +++ b/enclave/safetrace/app/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "safetrace-app" +version = "1.0.0" +authors = ["The Teaclave Authors"] +build = "build.rs" + +[dependencies] +sgx_types = { git = "https://github.com/apache/teaclave-sgx-sdk.git" } +sgx_urts = { git = "https://github.com/apache/teaclave-sgx-sdk.git" } +enigma-types = { path = "../../enigma-types", features = ["std"] } + + +futures = { version = "0.1.25", default-features = false } +tokio-zmq = "0.9.0" +zmq = "0.9.0" +failure = "0.1.3" +serde = { version = "1.0", default-features = false, features=["serde_derive"] } +serde_json = "1.0" +serde_repr = "0.1" +rustc-hex = "1.0.0" # 2.0.1? +rmp-serde = "0.14.0" + + +[patch.'https://github.com/apache/teaclave-sgx-sdk.git'] +sgx_types = { path = "../../incubator-teaclave-sgx-sdk/sgx_types" } +sgx_urts = { path = "../../incubator-teaclave-sgx-sdk/sgx_urts" } diff --git a/enclave/safetrace/app/build.rs b/enclave/safetrace/app/build.rs new file mode 100644 index 0000000..8ec16f1 --- /dev/null +++ b/enclave/safetrace/app/build.rs @@ -0,0 +1,36 @@ +// 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; + +fn main () { + + let sdk_dir = env::var("SGX_SDK") + .unwrap_or_else(|_| "/opt/intel/sgxsdk".to_string()); + let is_sim = env::var("SGX_MODE") + .unwrap_or_else(|_| "HW".to_string()); + + println!("cargo:rustc-link-search=native=../lib"); + println!("cargo:rustc-link-lib=static=Enclave_u"); + + println!("cargo:rustc-link-search=native={}/lib64", sdk_dir); + match is_sim.as_ref() { + "SW" => println!("cargo:rustc-link-lib=dylib=sgx_urts_sim"), + "HW" => println!("cargo:rustc-link-lib=dylib=sgx_urts"), + _ => println!("cargo:rustc-link-lib=dylib=sgx_urts"), // Treat undefined as HW + } +} diff --git a/enclave/safetrace/app/src/common_u/errors.rs b/enclave/safetrace/app/src/common_u/errors.rs new file mode 100644 index 0000000..14e37b5 --- /dev/null +++ b/enclave/safetrace/app/src/common_u/errors.rs @@ -0,0 +1,86 @@ +#![allow(dead_code)] +use sgx_types::*; +use std::fmt; +use failure::Error; + +// error while requesting to produce a quote (registration) +#[derive(Fail, Debug)] +#[fail(display = "Error while producing a quote sgx_status = {}. info = ({})", status, message)] +pub struct ProduceQuoteErr { + pub status: sgx_status_t, + pub message: String, +} + +#[derive(Fail, Debug)] +#[fail(display = "Error while decoding the quote = ({})", message)] +pub struct QuoteErr { + pub message: String, +} + +// error while requesting the public signing key (the registration key) +#[derive(Fail, Debug)] +#[fail(display = "Error while retrieving the registration signing public key sgx_status = {}. info = ({})", status, message)] +pub struct GetRegisterKeyErr { + pub status: sgx_status_t, + pub message: String, +} + +// error while request attestation service +#[derive(Fail, Debug)] +#[fail(display = "Error while using the attestation service info = ({})", message)] +pub struct AttestationServiceErr { + pub message: String, +} + +#[derive(Fail, Debug)] +#[fail(display = "Error while parsing the p2p messages, command: {}, error: {}", cmd, msg)] +pub struct P2PErr { + pub cmd: String, + pub msg: String, +} + +#[derive(Fail, Debug)] +#[fail(display = "Error while trying to {}, Because: {}", command, kind)] +pub struct DBErr { + pub command: String, + pub kind: DBErrKind, +} + +/// This method is called by all functions removing data from the DB. checks if the error +/// is of DBErr type, is so, the error is a missing key error +/// (The only option for an error of that type in the delete methods) +/// which is considered as a success for this matter +pub fn is_db_err_type(e: Error) -> Result { + e.downcast::() +} + +#[derive(Debug)] +pub enum DBErrKind { + KeyExists(String), + CreateError, + FetchError, + MissingKey(String), + UpdateError, + MissingKeys, +} + +impl fmt::Display for DBErrKind { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let printable: String = match &*self { + DBErrKind::KeyExists(k) => format!("the key already exists for the following address: {:?}", &k), + DBErrKind::CreateError => "Failed to create the key".into(), + DBErrKind::FetchError => "Failed to fetch the data".into(), + DBErrKind::MissingKey(k) => format!("The following Key doesn't exist: {}", &k), + DBErrKind::UpdateError => "Failed to update the key".into(), + DBErrKind::MissingKeys => "No keys exist the DB".into(), + }; + write!(f, "{}", printable) + } +} + +#[derive(Fail, Debug)] +#[fail(display = "Error inside the Enclave = ({:?})", err)] +pub struct EnclaveFailError { + pub err: enigma_types::EnclaveReturn, + pub status: sgx_status_t, +} diff --git a/enclave/safetrace/app/src/common_u/mod.rs b/enclave/safetrace/app/src/common_u/mod.rs new file mode 100644 index 0000000..629e98f --- /dev/null +++ b/enclave/safetrace/app/src/common_u/mod.rs @@ -0,0 +1 @@ +pub mod errors; diff --git a/enclave/safetrace/app/src/keys_u.rs b/enclave/safetrace/app/src/keys_u.rs new file mode 100644 index 0000000..8059cf4 --- /dev/null +++ b/enclave/safetrace/app/src/keys_u.rs @@ -0,0 +1,32 @@ +use crate::common_u::errors::EnclaveFailError; +use enigma_types::{EnclaveReturn, PubKey}; +use failure::Error; +use sgx_types::{sgx_enclave_id_t, sgx_status_t}; +//use enigma_types::{EnclaveReturn, PubKey, RawPointer}; + +extern { + pub fn ecall_get_user_key( + eid: sgx_enclave_id_t, + retval: *mut EnclaveReturn, + sig: *mut [u8; 65usize], + pubkey: *mut [u8; 64usize], + serialized_ptr: *mut u64, + ) -> sgx_status_t; +} + + +pub fn get_user_key(eid: sgx_enclave_id_t, user_pubkey: &PubKey) -> Result<(Box<[u8]>, [u8; 65]), Error> { + let mut sig = [0u8; 65]; + let mut ret = EnclaveReturn::Success; + let mut serialized_ptr = 0u64; + + let status = unsafe { + ecall_get_user_key(eid, &mut ret as *mut EnclaveReturn, &mut sig, user_pubkey.as_ptr() as _, &mut serialized_ptr as *mut u64) + }; + if ret != EnclaveReturn::Success || status != sgx_status_t::SGX_SUCCESS { + return Err(EnclaveFailError { err: ret, status }.into()); + } + let box_ptr = serialized_ptr as *mut Box<[u8]>; + let part = unsafe { Box::from_raw(box_ptr) }; + Ok((*part, sig)) +} diff --git a/enclave/safetrace/app/src/lib.rs b/enclave/safetrace/app/src/lib.rs new file mode 100644 index 0000000..d98c0fb --- /dev/null +++ b/enclave/safetrace/app/src/lib.rs @@ -0,0 +1,19 @@ +pub extern crate sgx_types; +pub extern crate futures; +extern crate tokio_zmq; +extern crate zmq; +#[macro_use] +extern crate failure; +#[macro_use] +extern crate serde; +extern crate serde_repr; +pub extern crate serde_json; +extern crate rmp_serde; +extern crate rustc_hex as hex; +extern crate enigma_types; + + + +pub mod common_u; +pub mod networking; +pub mod keys_u; diff --git a/enclave/safetrace/app/src/main.rs b/enclave/safetrace/app/src/main.rs new file mode 100644 index 0000000..e611c2c --- /dev/null +++ b/enclave/safetrace/app/src/main.rs @@ -0,0 +1,80 @@ +// 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.. + +extern crate safetrace_app; + +extern crate sgx_types; +extern crate sgx_urts; + + +pub use safetrace_app::*; +use sgx_types::*; +use sgx_urts::SgxEnclave; + +use networking::{ipc_listener, IpcListener}; +use futures::Future; + + + +static ENCLAVE_FILE: &'static str = "enclave.signed.so"; + +extern { + fn say_something(eid: sgx_enclave_id_t, retval: *mut sgx_status_t, + some_string: *const u8, len: usize) -> sgx_status_t; +} + +fn init_enclave() -> SgxResult { + let mut launch_token: sgx_launch_token_t = [0; 1024]; + let mut launch_token_updated: i32 = 0; + // call sgx_create_enclave to initialize an enclave instance + // Debug Support: set 2nd parameter to 1 + let debug = 1; + let mut misc_attr = sgx_misc_attribute_t {secs_attr: sgx_attributes_t { flags:0, xfrm:0}, misc_select:0}; + SgxEnclave::create(ENCLAVE_FILE, + debug, + &mut launch_token, + &mut launch_token_updated, + &mut misc_attr) +} + +fn main() { + let enclave= match init_enclave() { + Ok(r) => { + println!("[+] Init Enclave Successfully {}!", r.geteid()); + r + }, + Err(x) => { + println!("[-] Init Enclave Failed {}!", x.as_str()); + return; + }, + }; + + let server = IpcListener::new(&format!("tcp://*:5552")); + + server + .run(move |multi| ipc_listener::handle_message(multi, &format!("SPID"), enclave.geteid(), 1)) + + //.run(move |multi| ipc_listener::handle_message(multi, &opt.spid, eid, opt.retries)) + // .run(|mul| { + // println!("{:?}", mul); + // mul + // }) + .wait() + .unwrap(); + + // enclave.destroy(); +} diff --git a/enclave/safetrace/app/src/networking/ipc_listener.rs b/enclave/safetrace/app/src/networking/ipc_listener.rs new file mode 100644 index 0000000..3a41468 --- /dev/null +++ b/enclave/safetrace/app/src/networking/ipc_listener.rs @@ -0,0 +1,105 @@ +use crate::networking::messages::*; +use sgx_types::sgx_enclave_id_t; +use futures::{Future, Stream}; +use std::sync::Arc; +use tokio_zmq::prelude::*; +use tokio_zmq::{Error, Multipart, Rep}; + +pub struct IpcListener { + _context: Arc, + rep_future: Box>, +} + +impl IpcListener { + pub fn new(conn_str: &str) -> Self { + let _context = Arc::new(zmq::Context::new()); + let rep_future = Rep::builder(_context.clone()).bind(conn_str).build(); + println!("Binded to socket: {}", conn_str); + IpcListener { _context, rep_future } + } + + pub fn run(self, f: F) -> impl Future + where F: FnMut(Multipart) -> Multipart { + self.rep_future.and_then(|rep| { + let (sink, stream) = rep.sink_stream(25).split(); + stream.map(f).forward(sink).map(|(_stream, _sink)| ()) + }) + } +} + +//pub fn handle_message(request: Multipart, spid: &str, eid: sgx_enclave_id_t, retries: u32) -> Multipart { +pub fn handle_message(request: Multipart, spid: &str, eid: sgx_enclave_id_t, retries: u32) -> Multipart { + let mut responses = Multipart::new(); + for msg in request { + let msg: IpcMessageRequest = msg.into(); + let id = msg.id.clone(); + let response_msg = match msg.request { + IpcRequest::GetEnclaveReport => handling::get_enclave_report(eid, spid, retries), + IpcRequest::NewTaskEncryptionKey { userPubKey } => handling::new_task_encryption_key(&userPubKey, eid), + IpcRequest::AddPersonalData { input } => handling::add_personal_data(input, eid), + IpcRequest::FindMatch { input } => handling::find_match(input, eid), + }; + let msg = IpcMessageResponse::from_response(response_msg.unwrap_or_error(), id); + responses.push_back(msg.into()); + } + responses +} + +pub(self) mod handling { + use crate::networking::messages::*; + use crate::keys_u; + use failure::Error; + use sgx_types::sgx_enclave_id_t; + use hex::{FromHex, ToHex}; + use std::str; + use rmp_serde::Deserializer; + use serde::Deserialize; + use serde_json::Value; + + + type ResponseResult = Result; + + // TODO + //pub fn get_enclave_report(eid: sgx_enclave_id_t, spid: &str, retries: u32) -> ResponseResult { + pub fn get_enclave_report(eid: sgx_enclave_id_t, spid: &str, retries: u32) -> ResponseResult { + let result = IpcResults::EnclaveReport { spid: spid.to_string() }; + Ok(IpcResponse::GetEnclaveReport { result }) + } + + // TODO + //#[logfn(TRACE)] + //pub fn new_task_encryption_key(_user_pubkey: &str, eid: sgx_enclave_id_t) -> ResponseResult { + pub fn new_task_encryption_key(_user_pubkey: &str, eid: sgx_enclave_id_t) -> ResponseResult { + let mut user_pubkey = [0u8; 64]; + user_pubkey.clone_from_slice(&_user_pubkey.from_hex().unwrap()); + + let (msg, sig) = keys_u::get_user_key(eid, &user_pubkey)?; + + let mut des = Deserializer::new(&msg[..]); + let res: Value = Deserialize::deserialize(&mut des).unwrap(); + let pubkey = serde_json::from_value::>(res["pubkey"].clone())?; + + let result = IpcResults::DHKey {dh_key: pubkey.to_hex(), sig: sig.to_hex() }; + //let result = IpcResults::DHKey {dh_key: _user_pubkey.to_string(), sig: _user_pubkey.to_string()}; + + Ok(IpcResponse::NewTaskEncryptionKey { result }) + } + + // TODO + //#[logfn(DEBUG)] + // pub fn compute_task(db: &mut DB, input: IpcTask, eid: sgx_enclave_id_t) -> ResponseResult { + pub fn add_personal_data( input: IpcInput, eid: sgx_enclave_id_t) -> ResponseResult { + let result = IpcResults::AddPersonalData { status: Status::Passed }; + Ok(IpcResponse::AddPersonalData { result }) + } + + // TODO + //#[logfn(DEBUG)] + // pub fn compute_task(db: &mut DB, input: IpcTask, eid: sgx_enclave_id_t) -> ResponseResult { + pub fn find_match( input: IpcInput, eid: sgx_enclave_id_t) -> ResponseResult { + let result = IpcResults::FindMatch { status: Status::Passed }; + Ok(IpcResponse::FindMatch { result }) + } + + +} diff --git a/enclave/safetrace/app/src/networking/messages.rs b/enclave/safetrace/app/src/networking/messages.rs new file mode 100644 index 0000000..8c612bb --- /dev/null +++ b/enclave/safetrace/app/src/networking/messages.rs @@ -0,0 +1,121 @@ +use serde_json; +use serde_repr::{Serialize_repr, Deserialize_repr}; +use zmq::Message; +use failure::Error; +use hex::ToHex; + + +// These attributes enable the status to be casted as an i8 object as well +#[derive(Serialize_repr, Deserialize_repr, Clone, Debug)] +#[repr(i8)] +pub enum Status { + Failed = -1, + Passed = 0, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct IpcMessageRequest { + pub id: String, + #[serde(flatten)] + pub request: IpcRequest +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct IpcMessageResponse { + pub id: String, + #[serde(flatten)] + pub response: IpcResponse +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(tag = "type")] +pub enum IpcResponse { + GetEnclaveReport { #[serde(flatten)] result: IpcResults }, + NewTaskEncryptionKey { #[serde(flatten)] result: IpcResults }, + AddPersonalData { #[serde(flatten)] result: IpcResults }, + FindMatch { #[serde(flatten)] result: IpcResults }, + Error { msg: String }, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase", rename = "result")] +pub enum IpcResults { + Errors(Vec), + #[serde(rename = "result")] + Request { request: String, sig: String }, + #[serde(rename = "result")] + //EnclaveReport { #[serde(rename = "signingKey")] signing_key: String, report: String, signature: String }, + EnclaveReport { spid: String }, + #[serde(rename = "result")] + DHKey { dh_key: String, sig: String }, + AddPersonalData { status: Status }, + FindMatch { status: Status }, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(tag = "type")] +pub enum IpcRequest { + GetEnclaveReport, + NewTaskEncryptionKey { userPubKey: String }, + AddPersonalData { input: IpcInput }, + FindMatch { input: IpcInput }, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct IpcInput { + pub encryptedUserId: String, + pub encryptedData: String, + pub userPubKey: String, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct IpcStatusResult { + pub address: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub key: Option, + pub status: Status, +} + +impl IpcMessageResponse { + pub fn from_response(response: IpcResponse, id: String) -> Self { + Self { id, response } + } +} + +impl IpcMessageRequest { + pub fn from_request(request: IpcRequest, id: String) -> Self { + Self { id, request } + } +} + +impl From for IpcMessageRequest { + fn from(msg: Message) -> Self { + let msg_str = msg.as_str().unwrap(); + let req: Self = serde_json::from_str(msg_str).expect(msg_str); + req + } +} + +impl Into for IpcMessageResponse { + fn into(self) -> Message { + let msg = serde_json::to_vec(&self).unwrap(); + Message::from(&msg) + } +} + +pub(crate) trait UnwrapError { + fn unwrap_or_error(self) -> T; +} + +impl UnwrapError for Result { + fn unwrap_or_error(self) -> IpcResponse { + match self { + Ok(m) => m, + Err(e) => { + //error!("Unwrapped Message failed: {}", e); + panic!("Unwrapped Message failed: {}", e); + IpcResponse::Error {msg: format!("{}", e)} + } + } + } +} \ No newline at end of file diff --git a/enclave/safetrace/app/src/networking/mod.rs b/enclave/safetrace/app/src/networking/mod.rs new file mode 100644 index 0000000..576aa7c --- /dev/null +++ b/enclave/safetrace/app/src/networking/mod.rs @@ -0,0 +1,4 @@ +pub mod ipc_listener; +pub mod messages; + +pub use self::ipc_listener::IpcListener; \ No newline at end of file diff --git a/enclave/safetrace/enclave/Cargo.toml b/enclave/safetrace/enclave/Cargo.toml new file mode 100644 index 0000000..228f1db --- /dev/null +++ b/enclave/safetrace/enclave/Cargo.toml @@ -0,0 +1,44 @@ +[package] +name = "safetrace-enclave" +version = "1.0.0" +authors = ["Enigma MPC"] + +[lib] +name = "safetraceenclave" +crate-type = ["staticlib"] + +[features] +default = [] + +[dependencies] +enigma-types = { path = "../../enigma-types", default-features = false, features = ["sgx"] } + +[target.'cfg(not(target_env = "sgx"))'.dependencies] +sgx_types = { git = "https://github.com/apache/teaclave-sgx-sdk.git" } +sgx_tstd = { git = "https://github.com/apache/teaclave-sgx-sdk.git", features = ["backtrace"] } +sgx_trts = { git = "https://github.com/apache/teaclave-sgx-sdk.git" } +[patch.'https://github.com/apache/teaclave-sgx-sdk.git'] +sgx_alloc = { path = "../../incubator-teaclave-sgx-sdk/sgx_alloc" } +sgx_build_helper = { path = "../../incubator-teaclave-sgx-sdk/sgx_build_helper" } +sgx_cov = { path = "../../incubator-teaclave-sgx-sdk/sgx_cov" } +sgx_crypto_helper = { path = "../../incubator-teaclave-sgx-sdk/sgx_crypto_helper" } +sgx_libc = { path = "../../incubator-teaclave-sgx-sdk/sgx_libc" } +sgx_rand = { path = "../../incubator-teaclave-sgx-sdk/sgx_rand" } +sgx_rand_derive = { path = "../../incubator-teaclave-sgx-sdk/sgx_rand_derive" } +sgx_serialize = { path = "../../incubator-teaclave-sgx-sdk/sgx_serialize" } +sgx_serialize_derive = { path = "../../incubator-teaclave-sgx-sdk/sgx_serialize_derive" } +sgx_serialize_derive_internals = { path = "../../incubator-teaclave-sgx-sdk/sgx_serialize_derive_internals" } +sgx_tcrypto = { path = "../../incubator-teaclave-sgx-sdk/sgx_tcrypto" } +sgx_tcrypto_helper = { path = "../../incubator-teaclave-sgx-sdk/sgx_tcrypto_helper" } +sgx_tdh = { path = "../../incubator-teaclave-sgx-sdk/sgx_tdh" } +sgx_tkey_exchange = { path = "../../incubator-teaclave-sgx-sdk/sgx_tkey_exchange" } +sgx_tprotected_fs = { path = "../../incubator-teaclave-sgx-sdk/sgx_tprotected_fs" } +sgx_trts = { path = "../../incubator-teaclave-sgx-sdk/sgx_trts" } +sgx_tse = { path = "../../incubator-teaclave-sgx-sdk/sgx_tse" } +sgx_tseal = { path = "../../incubator-teaclave-sgx-sdk/sgx_tseal" } +sgx_tstd = { path = "../../incubator-teaclave-sgx-sdk/sgx_tstd" } +sgx_tunittest = { path = "../../incubator-teaclave-sgx-sdk/sgx_tunittest" } +sgx_types = { path = "../../incubator-teaclave-sgx-sdk/sgx_types" } +sgx_ucrypto = { path = "../../incubator-teaclave-sgx-sdk/sgx_ucrypto" } +sgx_unwind = { path = "../../incubator-teaclave-sgx-sdk/sgx_unwind" } +sgx_urts = { path = "../../incubator-teaclave-sgx-sdk/sgx_urts" } diff --git a/enclave/safetrace/enclave/Enclave.config.xml b/enclave/safetrace/enclave/Enclave.config.xml new file mode 100644 index 0000000..ee4c3f7 --- /dev/null +++ b/enclave/safetrace/enclave/Enclave.config.xml @@ -0,0 +1,12 @@ + + + 0 + 0 + 0x40000 + 0x100000 + 1 + 1 + 0 + 0 + 0xFFFFFFFF + diff --git a/enclave/safetrace/enclave/Enclave.edl b/enclave/safetrace/enclave/Enclave.edl new file mode 100644 index 0000000..c40477a --- /dev/null +++ b/enclave/safetrace/enclave/Enclave.edl @@ -0,0 +1,38 @@ +// 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. + +enclave { + from "sgx_tstd.edl" import *; + from "sgx_stdio.edl" import *; + from "sgx_backtrace.edl" import *; + from "sgx_tstdc.edl" import *; + + /* data structures */ + include "enigma-types.h" + + trusted { + /* define ECALLs here. */ + + public sgx_status_t say_something([in, size=len] const uint8_t* some_string, size_t len); + + public EnclaveReturn ecall_get_user_key( + [out] uint8_t sig[65], + [in] uint8_t pubkey[64], + [out] uint64_t* serialized_ptr + ); + }; +}; diff --git a/enclave/safetrace/enclave/Enclave.lds b/enclave/safetrace/enclave/Enclave.lds new file mode 100644 index 0000000..e3d9d0e --- /dev/null +++ b/enclave/safetrace/enclave/Enclave.lds @@ -0,0 +1,9 @@ +enclave.so +{ + global: + g_global_data_sim; + g_global_data; + enclave_entry; + local: + *; +}; diff --git a/enclave/safetrace/enclave/Enclave_private.pem b/enclave/safetrace/enclave/Enclave_private.pem new file mode 100644 index 0000000..529d07b --- /dev/null +++ b/enclave/safetrace/enclave/Enclave_private.pem @@ -0,0 +1,39 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIG4gIBAAKCAYEAroOogvsj/fZDZY8XFdkl6dJmky0lRvnWMmpeH41Bla6U1qLZ +AmZuyIF+mQC/cgojIsrBMzBxb1kKqzATF4+XwPwgKz7fmiddmHyYz2WDJfAjIveJ +ZjdMjM4+EytGlkkJ52T8V8ds0/L2qKexJ+NBLxkeQLfV8n1mIk7zX7jguwbCG1Pr +nEMdJ3Sew20vnje+RsngAzdPChoJpVsWi/K7cettX/tbnre1DL02GXc5qJoQYk7b +3zkmhz31TgFrd9VVtmUGyFXAysuSAb3EN+5VnHGr0xKkeg8utErea2FNtNIgua8H +ONfm9Eiyaav1SVKzPHlyqLtcdxH3I8Wg7yqMsaprZ1n5A1v/levxnL8+It02KseD +5HqV4rf/cImSlCt3lpRg8U5E1pyFQ2IVEC/XTDMiI3c+AR+w2jSRB3Bwn9zJtFlW +KHG3m1xGI4ck+Lci1JvWWLXQagQSPtZTsubxTQNx1gsgZhgv1JHVZMdbVlAbbRMC +1nSuJNl7KPAS/VfzAgEDAoIBgHRXxaynbVP5gkO0ug6Qw/E27wzIw4SmjsxG6Wpe +K7kfDeRskKxESdsA/xCrKkwGwhcx1iIgS5+Qscd1Yg+1D9X9asd/P7waPmWoZd+Z +AhlKwhdPsO7PiF3e1AzHhGQwsUTt/Y/aSI1MpHBvy2/s1h9mFCslOUxTmWw0oj/Q +ldIEgWeNR72CE2+jFIJIyml6ftnb6qzPiga8Bm48ubKh0kvySOqnkmnPzgh+JBD6 +JnBmtZbfPT97bwTT+N6rnPqOOApvfHPf15kWI8yDbprG1l4OCUaIUH1AszxLd826 +5IPM+8gINLRDP1MA6azECPjTyHXhtnSIBZCyWSVkc05vYmNXYUNiXWMajcxW9M02 +wKzFELO8NCEAkaTPxwo4SCyIjUxiK1LbQ9h8PSy4c1+gGP4LAMR8xqP4QKg6zdu9 +osUGG/xRe/uufgTBFkcjqBHtK5L5VI0jeNIUAgW/6iNbYXjBMJ0GfauLs+g1VsOm +WfdgXzsb9DYdMa0OXXHypmV4GwKBwQDUwQj8RKJ6c8cT4vcWCoJvJF00+RFL+P3i +Gx2DLERxRrDa8AVGfqaCjsR+3vLgG8V/py+z+dxZYSqeB80Qeo6PDITcRKoeAYh9 +xlT3LJOS+k1cJcEmlbbO2IjLkTmzSwa80fWexKu8/Xv6vv15gpqYl1ngYoqJM3pd +vzmTIOi7MKSZ0WmEQavrZj8zK4endE3v0eAEeQ55j1GImbypSf7Idh7wOXtjZ7WD +Dg6yWDrri+AP/L3gClMj8wsAxMV4ZR8CgcEA0fzDHkFa6raVOxWnObmRoDhAtE0a +cjUj976NM5yyfdf2MrKy4/RhdTiPZ6b08/lBC/+xRfV3xKVGzacm6QjqjZrUpgHC +0LKiZaMtccCJjLtPwQd0jGQEnKfMFaPsnhOc5y8qVkCzVOSthY5qhz0XNotHHFmJ +gffVgB0iqrMTvSL7IA2yqqpOqNRlhaYhNl8TiFP3gIeMtVa9rZy31JPgT2uJ+kfo +gV7sdTPEjPWZd7OshGxWpT6QfVDj/T9T7L6tAoHBAI3WBf2DFvxNL2KXT2QHAZ9t +k3imC4f7U+wSE6zILaDZyzygA4RUbwG0gv8/TJVn2P/Eynf76DuWHGlaiLWnCbSz +Az2DHBQBBaku409zDQym3j1ugMRjzzSQWzJg0SIyBH3hTmnYcn3+Uqcp/lEBvGW6 +O+rsXFt3pukqJmIV8HzLGGaLm62BHUeZf3dyWm+i3p/hQAL7Xvu04QW70xuGqdr5 +afV7p5eaeQIJXyGQJ0eylV/90+qxjMKiB1XYg6WYvwKBwQCL/ddpgOdHJGN8uRom +e7Zq0Csi3hGheMKlKbN3vcxT5U7MdyHtTZZOJbTvxKNNUNYH/8uD+PqDGNneb29G +BfGzvI3EASyLIcGZF3OhKwZd0jUrWk2y7Vhob91jwp2+t73vdMbkKyI4mHOuXvGv +fg95si9oO7EBT+Oqvhccd2J+F1IVXncccYnF4u5ZGWt5lLewN/pVr7MjjykeaHqN +t+rfnQam2psA6fL4zS2zTmZPzR2tnY8Y1GBTi0Ko1OKd1HMCgcAb5cB/7/AQlhP9 +yQa04PLH9ygQkKKptZp7dy5WcWRx0K/hAHRoi2aw1wZqfm7VBNu2SLcs90kCCCxp +6C5sfJi6b8NpNbIPC+sc9wsFr7pGo9SFzQ78UlcWYK2Gu2FxlMjonhka5hvo4zvg +WxlpXKEkaFt3gLd92m/dMqBrHfafH7VwOJY2zT3WIpjwuk0ZzmRg5p0pG/svVQEH +NZmwRwlopysbR69B/n1nefJ84UO50fLh5s5Zr3gBRwbWNZyzhXk= +-----END RSA PRIVATE KEY----- diff --git a/enclave/safetrace/enclave/Makefile b/enclave/safetrace/enclave/Makefile new file mode 100644 index 0000000..231391a --- /dev/null +++ b/enclave/safetrace/enclave/Makefile @@ -0,0 +1,33 @@ +# 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. +Rust_Enclave_Name := libenclave.a +Rust_Enclave_Files := $(wildcard src/*.rs) +Rust_Target_Path := $(CURDIR)/../../incubator-teaclave-sgx-sdk/xargo + +.PHONY: all + +all: $(Rust_Enclave_Name) + +$(Rust_Enclave_Name): $(Rust_Enclave_Files) +ifeq ($(XARGO_SGX), 1) + RUST_TARGET_PATH=$(Rust_Target_Path) xargo build --target x86_64-unknown-linux-sgx --release + cp ./target/x86_64-unknown-linux-sgx/release/libsafetraceenclave.a ../lib/libenclave.a +else + cargo build -p enigma-types $(CARGO_FLAGS) # Meant to make sure `enigma-types.h` already exists and can be included. + cargo build --release + cp ./target/release/libsafetraceenclave.a ../lib/libenclave.a +endif \ No newline at end of file diff --git a/enclave/safetrace/enclave/src/keys_t.rs b/enclave/safetrace/enclave/src/keys_t.rs new file mode 100644 index 0000000..1eee307 --- /dev/null +++ b/enclave/safetrace/enclave/src/keys_t.rs @@ -0,0 +1,21 @@ +use crate::SIGNING_KEY; +// use enigma_tools_t::common::errors_t::EnclaveError; +// use enigma_tools_m::utils::LockExpectMutex; +// use enigma_crypto::asymmetric::KeyPair; +// use enigma_tools_m::primitives::km_primitives::UserMessage; +use enigma_types::{DhKey, PubKey}; +use std::collections::HashMap; +use std::{sync::SgxMutex, vec::Vec}; + +lazy_static! { pub static ref DH_KEYS: SgxMutex, DhKey>> = SgxMutex::new(HashMap::new()); } + +pub(crate) unsafe fn ecall_get_user_key_internal(sig: &mut [u8; 65], user_pubkey: &PubKey) -> Result, EnclaveError> { + // let keys = KeyPair::new()?; + // let req = UserMessage::new(keys.get_pubkey()); + // *sig = SIGNING_KEY.sign(&req.to_sign())?; + // let msg = req.into_message()?; + // let enc_key = keys.derive_key(&user_pubkey)?; + // DH_KEYS.lock_expect("DH Keys").insert(user_pubkey.to_vec(), enc_key); + let msg; + Ok(msg) +} \ No newline at end of file diff --git a/enclave/safetrace/enclave/src/lib.rs b/enclave/safetrace/enclave/src/lib.rs new file mode 100644 index 0000000..b84eb5b --- /dev/null +++ b/enclave/safetrace/enclave/src/lib.rs @@ -0,0 +1,150 @@ +// 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.. + +#![crate_name = "safetraceenclave"] +#![crate_type = "staticlib"] + +#![cfg_attr(not(target_env = "sgx"), no_std)] +#![cfg_attr(target_env = "sgx", feature(rustc_private))] + +extern crate sgx_types; +extern crate sgx_trts; +#[cfg(not(target_env = "sgx"))] +#[macro_use] +extern crate sgx_tstd as std; + +use sgx_types::*; +use sgx_types::metadata::*; +use sgx_trts::enclave; +//use sgx_trts::{is_x86_feature_detected, is_cpu_feature_supported}; +use std::string::String; +use std::vec::Vec; +use std::io::{self, Write}; +use std::slice; +use std::backtrace::{self, PrintFormat}; + +extern crate enigma_types; + +// use enigma_types::{ +// traits::SliceCPtr, ContractAddress, DhKey, EnclaveReturn, ExecuteResult, Hash256, PubKey, RawPointer, ResultStatus, +// }; +use enigma_types::{EnclaveReturn}; + +#[no_mangle] +pub extern "C" fn say_something(some_string: *const u8, some_len: usize) -> sgx_status_t { + + let str_slice = unsafe { slice::from_raw_parts(some_string, some_len) }; + let _ = io::stdout().write(str_slice); + + // A sample &'static string + let rust_raw_string = "This is a in-Enclave "; + // An array + let word:[u8;4] = [82, 117, 115, 116]; + // An vector + let word_vec:Vec = vec![32, 115, 116, 114, 105, 110, 103, 33]; + + // Construct a string from &'static string + let mut hello_string = String::from(rust_raw_string); + + // Iterate on word array + for c in word.iter() { + hello_string.push(*c as char); + } + + // Rust style convertion + hello_string += String::from_utf8(word_vec).expect("Invalid UTF-8") + .as_str(); + + // Ocall to normal world for output + println!("{}", &hello_string); + + let _ = backtrace::enable_backtrace("enclave.signed.so", PrintFormat::Full); + + let gd = enclave::SgxGlobalData::new(); + println!("gd: {} {} {} {} ", gd.get_static_tcs_num(), gd.get_eremove_tcs_num(), gd.get_dyn_tcs_num(), gd.get_tcs_max_num()); + let (static_num, eremove_num, dyn_num) = get_thread_num(); + println!("static: {} eremove: {} dyn: {}", static_num, eremove_num, dyn_num); + + unsafe { + println!("EDMM: {}, feature: {}", EDMM_supported, g_cpu_feature_indicator); + } + if is_x86_feature_detected!("sgx") { + println!("supported sgx"); + } + + sgx_status_t::SGX_SUCCESS +} + +#[link(name = "sgx_trts")] +extern { + static g_cpu_feature_indicator: uint64_t; + static EDMM_supported: c_int; +} + + +fn get_thread_num() -> (u32, u32, u32) { + let gd = unsafe { + let p = enclave::rsgx_get_global_data(); + &*p + }; + + let mut static_thread_num: u32 = 0; + let mut eremove_thread_num: u32 = 0; + let mut dyn_thread_num: u32 = 0; + let layout_table = &gd.layout_table[0..gd.layout_entry_num as usize]; + unsafe { traversal_layout(&mut static_thread_num, &mut dyn_thread_num, &mut eremove_thread_num, layout_table); } + + unsafe fn traversal_layout(static_num: &mut u32, dyn_num: &mut u32, eremove_num: &mut u32, layout_table: &[layout_t]) + { + for (i, layout) in layout_table.iter().enumerate() { + if !is_group_id!(layout.group.id as u32) { + if (layout.entry.attributes & PAGE_ATTR_EADD) != 0 { + if (layout.entry.content_offset != 0) && (layout.entry.si_flags == SI_FLAGS_TCS) { + if (layout.entry.attributes & PAGE_ATTR_EREMOVE) == 0 { + *static_num += 1; + } else { + *eremove_num += 1; + } + } + } + if (layout.entry.attributes & PAGE_ATTR_POST_ADD) != 0 { + if layout.entry.id == LAYOUT_ID_TCS_DYN as u16 { + *dyn_num += 1; + } + } + } else { + for _ in 0..layout.group.load_times { + traversal_layout(static_num, dyn_num, eremove_num, &layout_table[i - layout.group.entry_count as usize..i]) + } + } + } + } + (static_thread_num, eremove_thread_num, dyn_thread_num) +} + +#[no_mangle] +pub unsafe extern "C" fn ecall_get_user_key(sig: &mut [u8; 65], user_pubkey: &PubKey, serialized_ptr: *mut u64) -> EnclaveReturn { + // let msg = match ecall_get_user_key_internal(sig, user_pubkey) { + // Ok(msg) => msg, + // Err(e) => return e.into(), + // }; + // *serialized_ptr = match ocalls_t::save_to_untrusted_memory(&msg[..]) { + // Ok(ptr) => ptr, + // Err(e) => return e.into(), + // }; + EnclaveReturn::Success +} \ No newline at end of file diff --git a/enclave/safetrace/enclave/x86_64-unknown-linux-sgx.json b/enclave/safetrace/enclave/x86_64-unknown-linux-sgx.json new file mode 100644 index 0000000..10d37a7 --- /dev/null +++ b/enclave/safetrace/enclave/x86_64-unknown-linux-sgx.json @@ -0,0 +1,31 @@ +{ + "arch": "x86_64", + "cpu": "x86-64", + "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", + "dynamic-linking": true, + "env": "sgx", + "exe-allocation-crate": "alloc_system", + "executables": true, + "has-elf-tls": true, + "has-rpath": true, + "linker-flavor": "gcc", + "linker-is-gnu": true, + "llvm-target": "x86_64-unknown-linux-gnu", + "max-atomic-width": 64, + "os": "linux", + "position-independent-executables": true, + "pre-link-args": { + "gcc": [ + "-Wl,--as-needed", + "-Wl,-z,noexecstack", + "-m64" + ] + }, + "relro-level": "full", + "stack-probes": true, + "target-c-int-width": "32", + "target-endian": "little", + "target-family": "unix", + "target-pointer-width": "64", + "vendor": "mesalock" +}