From 5c10af738e378c8703e757832b62639befd0107d Mon Sep 17 00:00:00 2001 From: "Zheng, Qi" Date: Tue, 19 Jul 2022 15:19:29 +0800 Subject: [PATCH] Add maa init demo --- .../azure_attestation/README.md | 4 + .../azure_attestation/maa_init/README.md | 53 + .../azure_attestation/maa_init/bom.yaml | 9 + .../azure_attestation/maa_init/build.sh | 46 + .../maa_init/init/Cargo.lock | 1080 +++++++++++++++++ .../maa_init/init/Cargo.toml | 15 + .../azure_attestation/maa_init/init/Makefile | 16 + .../maa_init/init/src/maa.rs | 82 ++ .../maa_init/init/src/main.rs | 126 ++ .../azure_attestation/maa_init/init_maa.yaml | 19 + .../azure_attestation/maa_init/maa_init.png | Bin 0 -> 81848 bytes 11 files changed, 1450 insertions(+) create mode 100644 demos/remote_attestation/azure_attestation/maa_init/README.md create mode 100644 demos/remote_attestation/azure_attestation/maa_init/bom.yaml create mode 100755 demos/remote_attestation/azure_attestation/maa_init/build.sh create mode 100644 demos/remote_attestation/azure_attestation/maa_init/init/Cargo.lock create mode 100644 demos/remote_attestation/azure_attestation/maa_init/init/Cargo.toml create mode 100644 demos/remote_attestation/azure_attestation/maa_init/init/Makefile create mode 100644 demos/remote_attestation/azure_attestation/maa_init/init/src/maa.rs create mode 100644 demos/remote_attestation/azure_attestation/maa_init/init/src/main.rs create mode 100644 demos/remote_attestation/azure_attestation/maa_init/init_maa.yaml create mode 100644 demos/remote_attestation/azure_attestation/maa_init/maa_init.png diff --git a/demos/remote_attestation/azure_attestation/README.md b/demos/remote_attestation/azure_attestation/README.md index 7183d436..4e170bfb 100644 --- a/demos/remote_attestation/azure_attestation/README.md +++ b/demos/remote_attestation/azure_attestation/README.md @@ -10,6 +10,10 @@ This demo is programming in C, covering the SGX quote generation and format the This demo is programming in RUST, based on the Azure provided [`REST APIs`](https://docs.microsoft.com/en-us/rest/api/attestation/). It provides steps to do SGX quote generation and attestation. +### MAA attestation in Occlum init stage [`maa_init`](./maa_init) + +This demo bases on [`maa_attestation`](./maa_attestation), provides steps to do SGX quote generation and attestation in Occlum init process and save the attestation token to rootfs. With this flow, the real application loaded after Occlum init process may get the attestation token and do whatever it wants, without getting involved in the messy attestation part. + ## Prerequisites ### Platform diff --git a/demos/remote_attestation/azure_attestation/maa_init/README.md b/demos/remote_attestation/azure_attestation/maa_init/README.md new file mode 100644 index 00000000..37be7b12 --- /dev/null +++ b/demos/remote_attestation/azure_attestation/maa_init/README.md @@ -0,0 +1,53 @@ +## Sample code for doing Microsoft Azure Attestation in Occlum init + +This demo is programming in RUST, based on the Azure provided [`REST APIs`](https://docs.microsoft.com/en-us/rest/api/attestation/). It provides steps to do SGX quote generation and attestation in Occlum init process and save the attestation token to rootfs. + +![Flow Overview](./maa_init.png) + +### Flow + +1. **`Occlum run`** to start the Occlum instance. + +2. For every Occlum instance, it starts `init` process first, then starts the real application in RootFS. The default [`init`](../../../tools/init/) process just run RootFS integrity check and then load the RootFS where the real application is located. For this demo, a modified [`init`](./init/) is used. Besides the general `init` operation, it does Azure Attestation and saves the token to `/root/token` in RootFS where the real application can access. + +3. The real application starts with easy access to the Azure Attestation token. The application can set its own strategy for the token. In this demo, a simple `busybox` as real application is used to print the content of attestation token obtained in init process. + +### Environments + +There are three environments below which are provided to users to modify according to the actual scenarios. + +* **MAA_PROVIDER_URL** +The MAA provider URL, this demo uses "https://shareduks.uks.attest.azure.net" +In default. + +* **MAA_REPORT_DATA** +The report data (base64 encoded string) to be used for MAA quote generation. + +* **MAA_TOKEN_PATH** +The MAA token and raw quote saved path in rootfs which is `/root` in default. Thus applications could find the attestation response token and raw quote (base64 encoded) in `/root/token` and `/root/quote_base64`. + +Please refer to the [`scrit`](./build.sh) for how to modify the above environments. + + +* Build + +1. Pull rust-sgx-sdk submodule which is the dependence of occlum dcap library. + +``` +# cd occlum +# git submodule update --init +``` + +2. Do the build with the [`scrit`](./build.sh). + +``` +# ./build.sh +``` + +* Run +``` +# cd occlum_instance +# occlum run /bin/busybox cat /root/token +``` + +If successful, it prints the Azure attestation token. \ No newline at end of file diff --git a/demos/remote_attestation/azure_attestation/maa_init/bom.yaml b/demos/remote_attestation/azure_attestation/maa_init/bom.yaml new file mode 100644 index 00000000..983e1124 --- /dev/null +++ b/demos/remote_attestation/azure_attestation/maa_init/bom.yaml @@ -0,0 +1,9 @@ +includes: + - base.yaml +targets: + # copy busybox + - target: /bin + copy: + - files: + - /opt/occlum/toolchains/busybox/glibc/busybox + diff --git a/demos/remote_attestation/azure_attestation/maa_init/build.sh b/demos/remote_attestation/azure_attestation/maa_init/build.sh new file mode 100755 index 00000000..faca591b --- /dev/null +++ b/demos/remote_attestation/azure_attestation/maa_init/build.sh @@ -0,0 +1,46 @@ +#!/bin/bash +set -e + +BLUE='\033[1;34m' +NC='\033[0m' +INSTANCE_DIR="occlum_instance" +IMG_BOM="../bom.yaml" +INIT_BOM="../init_maa.yaml" + +function build() { + pushd init + cargo clean + cargo build --release + popd + + echo "Generate example base64 encoded string as report data" + openssl genrsa -out key.pem 2048 + report_data=$(base64 -w 0 key.pem) + + rm -rf ${INSTANCE_DIR} && occlum new ${INSTANCE_DIR} + pushd ${INSTANCE_DIR} + + rm -rf image + copy_bom -f ${IMG_BOM} --root image --include-dir /opt/occlum/etc/template + + # Update env + new_json="$(jq '.env.default += ["MAA_PROVIDER_URL=https://shareduks.uks.attest.azure.net"] | + .env.default += ["MAA_TOKEN_PATH=/root"] | + .env.default += ["MAA_REPORT_DATA=BASE64_STRING"]' Occlum.json)" && \ + echo "${new_json}" > Occlum.json + + # Update report data string + sed -i "s/BASE64_STRING/$report_data/g" Occlum.json + + # prepare init maa content + rm -rf initfs + copy_bom -f ${INIT_BOM} --root initfs --include-dir /opt/occlum/etc/template + + occlum build + + popd +} + +build + + diff --git a/demos/remote_attestation/azure_attestation/maa_init/init/Cargo.lock b/demos/remote_attestation/azure_attestation/maa_init/init/Cargo.lock new file mode 100644 index 00000000..18d72cb0 --- /dev/null +++ b/demos/remote_attestation/azure_attestation/maa_init/init/Cargo.lock @@ -0,0 +1,1080 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base64" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" +dependencies = [ + "byteorder", + "safemem", +] + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "cpufeatures" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +dependencies = [ + "libc", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "encoding_rs" +version = "0.8.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "fastrand" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +dependencies = [ + "instant", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" + +[[package]] +name = "futures-io" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" + +[[package]] +name = "futures-sink" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" + +[[package]] +name = "futures-task" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" + +[[package]] +name = "futures-util" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +dependencies = [ + "futures-core", + "futures-io", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "h2" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "http" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" +dependencies = [ + "bytes", + "fnv", + "itoa 1.0.2", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "hyper" +version = "0.14.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02c929dc5c39e335a03c405292728118860721b10190d98c2a0f0efd5baafbac" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa 1.0.2", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "init" +version = "0.0.1" +dependencies = [ + "base64 0.9.3", + "libc", + "occlum_dcap", + "reqwest", + "serde", + "serde_json", + "sha2", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "ipnet" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" + +[[package]] +name = "itoa" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" + +[[package]] +name = "itoa" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" + +[[package]] +name = "js-sys" +version = "0.3.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + +[[package]] +name = "mio" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys", +] + +[[package]] +name = "native-tls" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd7e2f3618557f980e0b17e8856252eee3c97fa12c54dff0ca290fb6266ca4a9" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "occlum_dcap" +version = "0.1.0" +dependencies = [ + "cfg-if", + "libc", + "sgx_types", +] + +[[package]] +name = "once_cell" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "openssl" +version = "0.10.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "618febf65336490dfcf20b73f885f5651a0c89c64c2d4a8c3662585a70bf5bd0" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5f9bd0c2710541a3cda73d6f9ac4f1b240de4ae261065d309dbe73d9dceb42f" +dependencies = [ + "autocfg", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" + +[[package]] +name = "proc-macro2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +dependencies = [ + "bitflags", +] + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "reqwest" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b75aa69a3f06bbcc66ede33af2af253c6f7a86b1ca0033f60c580a27074fbf92" +dependencies = [ + "base64 0.13.0", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "lazy_static", + "log", + "mime", + "native-tls", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + +[[package]] +name = "safemem" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" + +[[package]] +name = "schannel" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" +dependencies = [ + "lazy_static", + "windows-sys", +] + +[[package]] +name = "security-framework" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.123" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.123" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea1c6153794552ea7cf7cf63b1231a25de00ec90db326ba6264440fa08e31486" +dependencies = [ + "itoa 0.4.7", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa 1.0.2", + "ryu", + "serde", +] + +[[package]] +name = "sgx_types" +version = "1.1.4" + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer", + "cfg-if", + "cpufeatures", + "digest", + "opaque-debug", +] + +[[package]] +name = "slab" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" + +[[package]] +name = "socket2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "syn" +version = "1.0.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6498a9efc342871f91cc2d0d694c674368b4ceb40f62b65a7a08c3792935e702" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "tokio" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57aec3cfa4c296db7255446efb4928a6be304b431a806216105542a67b6ca82e" +dependencies = [ + "autocfg", + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "once_cell", + "pin-project-lite", + "socket2", + "winapi", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc463cd8deddc3770d20f9852143d50bf6094e640b485cb2e189a2099085ff45" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "unicode-bidi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" + +[[package]] +name = "unicode-normalization" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" + +[[package]] +name = "url" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +dependencies = [ + "form_urlencoded", + "idna", + "matches", + "percent-encoding", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de9a9cec1733468a8c657e57fa2413d2ae2c0129b95e87c5b72b8ace4d13f31f" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be" + +[[package]] +name = "web-sys" +version = "0.3.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fed94beee57daf8dd7d51f2b15dc2bcde92d7a72304cdf662a4371008b71b90" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] diff --git a/demos/remote_attestation/azure_attestation/maa_init/init/Cargo.toml b/demos/remote_attestation/azure_attestation/maa_init/init/Cargo.toml new file mode 100644 index 00000000..5f01a9b0 --- /dev/null +++ b/demos/remote_attestation/azure_attestation/maa_init/init/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "init" +version = "0.0.1" +authors = ["LI Qing geding.lq@antgroup.com"] +edition = "2018" + +[dependencies] +libc = "0.2.84" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +base64 = "0.9" +sha2 = "0.9.5" +reqwest = { version = "0.11", features = ["blocking", "json"] } +occlum_dcap = { path = "../../../../../tools/toolchains/dcap_lib" } + diff --git a/demos/remote_attestation/azure_attestation/maa_init/init/Makefile b/demos/remote_attestation/azure_attestation/maa_init/init/Makefile new file mode 100644 index 00000000..6777227c --- /dev/null +++ b/demos/remote_attestation/azure_attestation/maa_init/init/Makefile @@ -0,0 +1,16 @@ +include ../../src/sgxenv.mk + +SRC_FILES := $(shell find . -type f -name '*.rs') Cargo.toml +RUST_TARGET_DIR := $(BUILD_DIR)/internal/tools/init/cargo-target +RUST_OUT_DIR := $(BUILD_DIR)/bin +TARGET_BINARY := $(RUST_OUT_DIR)/init + +.PHONY: all clean + +all: $(SRC_FILES) + @RUSTC_BOOTSTRAP=1 occlum-cargo build --release --target-dir=$(RUST_TARGET_DIR) -Z unstable-options --out-dir=$(RUST_OUT_DIR) + @echo "CARGO (release) => init" + +clean: + @occlum-cargo clean --target-dir=$(RUST_TARGET_DIR) + @-$(RM) -f $(TARGET_BINARY) diff --git a/demos/remote_attestation/azure_attestation/maa_init/init/src/maa.rs b/demos/remote_attestation/azure_attestation/maa_init/init/src/maa.rs new file mode 100644 index 00000000..49d3f51a --- /dev/null +++ b/demos/remote_attestation/azure_attestation/maa_init/init/src/maa.rs @@ -0,0 +1,82 @@ +use serde_json::json; +use sha2::{Digest, Sha256}; +use reqwest::blocking::Client; +use occlum_dcap::*; + + +pub const MAX_REPORT_DATA_SIZE: usize = 64; + +fn maa_get_quote_base64(user_data: &[u8]) -> Result { + let mut dcap = DcapQuote::new(); + let quote_size = dcap.get_quote_size(); + let mut quote_buf: Vec = vec![0; quote_size as usize]; + let mut report_data = sgx_report_data_t::default(); + + //fill in the report data array + let len = { + if user_data.len() > MAX_REPORT_DATA_SIZE { + MAX_REPORT_DATA_SIZE + } else { + user_data.len() + } + }; + + for i in 0..len { + report_data.d[i] = user_data[i]; + } + + dcap.generate_quote(quote_buf.as_mut_ptr(), &mut report_data).unwrap(); + dcap.close(); + let quote = base64::encode("e_buf); + + Ok(quote) +} + +pub fn maa_generate_json(user_data: &[u8]) -> Result { + let mut hasher = Sha256::new(); + hasher.update(user_data); + let hash = hasher.finalize(); + + let quote_base64 = maa_get_quote_base64(&hash).unwrap(); + + // Format to MAA rest attestation API request body + // https://docs.microsoft.com/en-us/rest/api/attestation/attestation/attest-sgx-enclave#request-body + let mut maa_json: serde_json::Value = json!({ + "quote": "0", + "runtimeData": { + "data": "0", + "dataType":"Binary" + } + }); + + *maa_json + .pointer_mut("/quote") + .unwrap() = serde_json::Value::String(quote_base64); + + *maa_json + .pointer_mut("/runtimeData/data") + .unwrap() = serde_json::Value::String(base64::encode(&user_data)); + + Ok(maa_json.to_owned()) +} + + +pub fn maa_attestation(url: String, request_body: serde_json::Value) -> Result> { + let client = Client::new(); + let att_url = format!("{}/attest/SgxEnclave?api-version=2020-10-01", url); + + let resp = client.post(att_url) + .json(&request_body) + .send()?; + + match resp.status() { + reqwest::StatusCode::OK => { + // println!("success!"); + Ok(resp.json().unwrap()) + }, + s => { + println!("Received response status: {:?}", s); + Err("maa attestation failed".into()) + } + } +} diff --git a/demos/remote_attestation/azure_attestation/maa_init/init/src/main.rs b/demos/remote_attestation/azure_attestation/maa_init/init/src/main.rs new file mode 100644 index 00000000..caca8859 --- /dev/null +++ b/demos/remote_attestation/azure_attestation/maa_init/init/src/main.rs @@ -0,0 +1,126 @@ +extern crate libc; +extern crate serde; +extern crate serde_json; + +use libc::syscall; +use serde::Deserialize; + +use std::error::Error; +use std::fs::{write, File}; +use std::io::{ErrorKind, Read}; +use std::env; + +use crate::maa::{maa_generate_json, maa_attestation}; +pub mod maa; + +fn main() -> Result<(), Box> { + // Load the configuration from initfs + const IMAGE_CONFIG_FILE: &str = "/etc/image_config.json"; + let image_config = load_config(IMAGE_CONFIG_FILE)?; + + // Get the MAC of Occlum.json.protected file + let occlum_json_mac = { + let mut mac: sgx_aes_gcm_128bit_tag_t = Default::default(); + parse_str_to_bytes(&image_config.occlum_json_mac, &mut mac)?; + mac + }; + let occlum_json_mac_ptr = &occlum_json_mac as *const sgx_aes_gcm_128bit_tag_t; + + // Get the key of FS image if needed + let key = match &image_config.image_type[..] { + "encrypted" => { + // TODO: Get the key through RA or LA + const IMAGE_KEY_FILE: &str = "/etc/image_key"; + let key_str = load_key(IMAGE_KEY_FILE)?; + let mut key: sgx_key_128bit_t = Default::default(); + parse_str_to_bytes(&key_str, &mut key)?; + Some(key) + } + "integrity-only" => None, + _ => unreachable!(), + }; + let key_ptr = key + .as_ref() + .map(|key| key as *const sgx_key_128bit_t) + .unwrap_or(std::ptr::null()); + + // Do Azure attestation and save attestation json to rootfs + // Get Attestation provider URL, rootfs token path and report data string from env + let maa_provider_url = env::var("MAA_PROVIDER_URL") + .unwrap_or("https://shareduks.uks.attest.azure.net".to_string()); + let maa_token_path = env::var("MAA_TOKEN_PATH") + .unwrap_or("/root".to_string()); + let report_data_base64 = env::var("MAA_REPORT_DATA") + .unwrap_or("example".to_string()); + let report_data = base64::decode(&report_data_base64).unwrap(); + + // Get maa quote json + let maa_json = maa_generate_json(report_data.as_slice()).unwrap(); + let quote_base64 = serde_json::to_string(&maa_json["quote"]).unwrap(); + // Do maa attestation and get json token response + let response = maa_attestation(maa_provider_url, maa_json).unwrap(); + let token = serde_json::to_string(&response).unwrap(); + + // Mount the image + const SYS_MOUNT_FS: i64 = 363; + let ret = unsafe { syscall(SYS_MOUNT_FS, key_ptr, occlum_json_mac_ptr) }; + if ret < 0 { + return Err(Box::new(std::io::Error::last_os_error())); + } + + // Write the raw quote and json token to rootfs + let quote_file = maa_token_path.clone() + "/quote_base64"; + write(quote_file, quote_base64)?; + let token_file = maa_token_path.clone() + "/token"; + write(token_file, token)?; + + Ok(()) +} + +#[allow(non_camel_case_types)] +type sgx_key_128bit_t = [u8; 16]; +#[allow(non_camel_case_types)] +type sgx_aes_gcm_128bit_tag_t = [u8; 16]; + +#[derive(Deserialize, Debug)] +#[serde(deny_unknown_fields)] +struct ImageConfig { + occlum_json_mac: String, + image_type: String, +} + +fn load_config(config_path: &str) -> Result> { + let mut config_file = File::open(config_path)?; + let config_json = { + let mut config_json = String::new(); + config_file.read_to_string(&mut config_json)?; + config_json + }; + let config: ImageConfig = serde_json::from_str(&config_json)?; + Ok(config) +} + +fn load_key(key_path: &str) -> Result> { + let mut key_file = File::open(key_path)?; + let mut key = String::new(); + key_file.read_to_string(&mut key)?; + Ok(key.trim_end_matches(|c| c == '\r' || c == '\n').to_string()) +} + +fn parse_str_to_bytes(arg_str: &str, bytes: &mut [u8]) -> Result<(), Box> { + let bytes_str_vec = { + let bytes_str_vec: Vec<&str> = arg_str.split('-').collect(); + if bytes_str_vec.len() != bytes.len() { + return Err(Box::new(std::io::Error::new( + ErrorKind::InvalidData, + "The length or format of Key/MAC string is invalid", + ))); + } + bytes_str_vec + }; + + for (byte_i, byte_str) in bytes_str_vec.iter().enumerate() { + bytes[byte_i] = u8::from_str_radix(byte_str, 16)?; + } + Ok(()) +} diff --git a/demos/remote_attestation/azure_attestation/maa_init/init_maa.yaml b/demos/remote_attestation/azure_attestation/maa_init/init_maa.yaml new file mode 100644 index 00000000..e39c85cf --- /dev/null +++ b/demos/remote_attestation/azure_attestation/maa_init/init_maa.yaml @@ -0,0 +1,19 @@ +includes: + - base.yaml +targets: + - target: /bin/ + copy: + - files: + - ../init/target/release/init + # copy libnss_files + - target: /opt/occlum/glibc/lib + copy: + - files: + - /opt/occlum/glibc/lib/libnss_files.so.2 + - /opt/occlum/glibc/lib/libnss_dns.so.2 + - /opt/occlum/glibc/lib/libresolv.so.2 + # copy root CA + - target: /etc/ssl + copy: + - dirs: + - /etc/ssl/ diff --git a/demos/remote_attestation/azure_attestation/maa_init/maa_init.png b/demos/remote_attestation/azure_attestation/maa_init/maa_init.png new file mode 100644 index 0000000000000000000000000000000000000000..31527a000650013d264c1f026e2593b18070bc6a GIT binary patch literal 81848 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 Pft>B>>gTe~DWM4fC