diff --git a/Cargo.lock b/Cargo.lock index 5cc254d8..2d8f60eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -456,9 +456,19 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.5" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64-serde" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba368df5de76a5bea49aaf0cf1b39ccfbbef176924d1ba5db3e4135216cbe3c7" +dependencies = [ + "base64 0.21.7", + "serde", +] [[package]] name = "base64ct" @@ -1058,6 +1068,27 @@ dependencies = [ "subtle", ] +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys", +] + [[package]] name = "doc-comment" version = "0.3.3" @@ -1130,7 +1161,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe81b5c06ecfdbc71dd845216f225f53b62a10cb8a16c946836a3467f701d05b" dependencies = [ - "base64 0.21.5", + "base64 0.21.7", "bytes", "hex 0.4.3", "k256", @@ -1261,7 +1292,7 @@ checksum = "6838fa110e57d572336178b7c79e94ff88ef976306852d8cb87d9e5b1fc7c0b5" dependencies = [ "async-trait", "auto_impl", - "base64 0.21.5", + "base64 0.21.7", "bytes", "const-hex", "enr", @@ -1903,7 +1934,7 @@ version = "8.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6971da4d9c3aa03c3d8f3ff0f4155b534aad021292003895a469716b2a230378" dependencies = [ - "base64 0.21.5", + "base64 0.21.7", "pem", "ring 0.16.20", "serde", @@ -1971,6 +2002,17 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.1", + "libc", + "redox_syscall 0.4.1", +] + [[package]] name = "linux-raw-sys" version = "0.4.10" @@ -2341,6 +2383,12 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + [[package]] name = "overload" version = "0.1.1" @@ -2677,13 +2725,18 @@ name = "raiko-guest" version = "0.1.0" dependencies = [ "anyhow", + "base64 0.21.7", + "base64-serde", "clap 4.4.7", + "dirs", "ethers-core", "hex 0.4.3", "rand", "rand_core", "risc0-zkvm", "secp256k1", + "serde", + "serde_json", "sgx-ra", "sha3", "tokio", @@ -2782,6 +2835,17 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_users" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + [[package]] name = "regex" version = "1.10.2" @@ -2844,7 +2908,7 @@ version = "0.11.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" dependencies = [ - "base64 0.21.5", + "base64 0.21.7", "bytes", "encoding_rs", "futures-core", @@ -3230,7 +3294,7 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" dependencies = [ - "base64 0.21.5", + "base64 0.21.7", ] [[package]] @@ -3470,7 +3534,7 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64cd236ccc1b7a29e7e2739f27c0b2dd199804abc4290e32f59f3b68d6405c23" dependencies = [ - "base64 0.21.5", + "base64 0.21.7", "chrono", "hex 0.4.3", "indexmap 1.9.3", diff --git a/Dockerfile b/Dockerfile index 5e9445bc..8af05160 100644 --- a/Dockerfile +++ b/Dockerfile @@ -23,15 +23,15 @@ RUN apt-get update && \ RUN mkdir -p \ ./bin \ ./guests/sgx \ - ./secrets \ - /etc/opt/raiko \ + /root/.config/raiko/config \ + /root/.config/raiko/secrets \ /tmp/sgx \ /var/log/raiko -COPY --from=builder /opt/raiko/target/release/raiko-guest ./guests/sgx/ -COPY --from=builder /opt/raiko/raiko-guest/config/raiko-guest.manifest.template ./guests/sgx/ +COPY --from=builder /opt/raiko/target/release/raiko-guest ./guests/sgx +COPY --from=builder /opt/raiko/raiko-guest/config/raiko-guest.manifest.template ./guests/sgx COPY --from=builder /opt/raiko/target/release/raiko-host ./bin -COPY --from=builder /opt/raiko/raiko-host/config/config.toml /etc/opt/raiko/ +COPY --from=builder /opt/raiko/raiko-host/config/config.toml /root/.config/raiko/config COPY --from=builder /opt/raiko/docker/entrypoint.sh ./bin COPY ./sgx-ra/src/*.so /usr/lib/ diff --git a/README_Raiko.md b/README_Raiko.md index c7a1580d..17ccbf18 100644 --- a/README_Raiko.md +++ b/README_Raiko.md @@ -116,7 +116,7 @@ To run `raiko-guest` in _one-shot_ mode with SGX using Gramine: ----------------------------------------------------------------------------------------------------------------------- Bootstrapping the app Next public key: 0x021d90eee5c402692fa3a3d3edd43a052367efbd6e4d26b9ca14099516525b9d09 - Entry: /secrets/priv.key + Entry: /root/.config/raiko/secrets/priv.key ``` 1. Run `raiko-guest` with the input file of your choice: diff --git a/docker/docker-compose-pos.yml b/docker/docker-compose-pos.yml index 50acaf04..e34cde91 100644 --- a/docker/docker-compose-pos.yml +++ b/docker/docker-compose-pos.yml @@ -3,14 +3,14 @@ services: raiko: image: gcr.io/evmchain/raiko:latest-pos container_name: raiko - command: --config-path=/etc/opt/raiko/config.toml + command: --config-path=/root/.config/raiko/config/config.toml devices: - "/dev/sgx_enclave:/dev/sgx_enclave" - "/dev/sgx_provision:/dev/sgx_provision" volumes: - - ${HOME}/.config/raiko/secrets:/opt/raiko/secrets - /tmp/sgx:/tmp/sgx - /var/log/raiko:/var/log/raiko - # - YOUR_CONFIG_PATH:/etc/opt/raiko/config.toml + # - YOUR_CONFIG_PATH:$HOME/.config/raiko/config/config.toml + - ${HOME}/.config/raiko:/root/.config/raiko ports: - "8080:8080" diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 4680a39f..65559070 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -3,13 +3,13 @@ services: raiko: image: gcr.io/evmchain/raiko:latest container_name: raiko - command: --config-path=/etc/opt/raiko/config.toml + command: --config-path=/root/.config/raiko/config/config.toml devices: - "/dev/sgx_enclave:/dev/sgx_enclave" - "/dev/sgx_provision:/dev/sgx_provision" volumes: - - ${HOME}/.config/raiko/secrets:/opt/raiko/secrets - /tmp/sgx:/tmp/sgx - /var/log/raiko:/var/log/raiko + - ${HOME}/.config/raiko:/root/.config/raiko ports: - "8080:8080" diff --git a/raiko-guest/Cargo.toml b/raiko-guest/Cargo.toml index 20bf7a1c..17a5e033 100644 --- a/raiko-guest/Cargo.toml +++ b/raiko-guest/Cargo.toml @@ -18,11 +18,16 @@ secp256k1 = { version = "0.27.0", features = [ ] } rand = "0.8.5" hex = "0.4.3" -clap = { version = "4.4.6", features = ["derive"] } +clap = { version = "4.4.6", features = ["derive", "string"] } ethers-core = { version = "2.0", features = ["optimism"] } zeth-primitives = { path = "../primitives", features = ["taiko"] } rand_core = "0.6.4" sha3 = "0.10.8" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +base64-serde = "0.7.0" +base64 = "0.21.7" +dirs = "5.0.1" [features] sgx-ra = ["dep:sgx-ra"] diff --git a/raiko-guest/config/raiko-guest.manifest.template b/raiko-guest/config/raiko-guest.manifest.template index e5f52faa..ca840be0 100644 --- a/raiko-guest/config/raiko-guest.manifest.template +++ b/raiko-guest/config/raiko-guest.manifest.template @@ -1,20 +1,10 @@ # This is Gramine's manifest file. # To learn more see: https://gramine.readthedocs.io/en/stable/manifest-syntax.html -# -# How to use it? -# -# 1. Build the app with `cargo build`. -# 2. Copy this file `target/debug`. -# 3. Run: -# export SECRETS_DIR="./secrets" -# export INPUT_FILES_DIR="/tmp" -# gramine-manifest -Dlog_level=error -Darch_libdir=/lib/x86_64-linux-gnu/ raiko-guest.manifest.template raiko-guest.manifest -# gramine-sgx-sign --manifest raiko-guest.manifest --output raiko-guest.manifest.sgx -# gramine-sgx ./raiko-guest loader.entrypoint = "file:{{ gramine.libos }}" libos.entrypoint = "/raiko-guest" loader.log_level = "{{ log_level }}" +loader.env.HOME = "/root" loader.env.LD_LIBRARY_PATH = "/lib:{{ arch_libdir }}" loader.env.RUST_LOG = "info" @@ -24,7 +14,8 @@ fs.mounts = [ { path = "{{ arch_libdir }}", uri = "file:{{ arch_libdir }}" }, { path = "/usr/lib/ssl/certs/", uri = "file:/usr/lib/ssl/certs/" }, { path = "/tmp", uri = "file:/tmp" }, - { path = "/secrets/", uri = "file:{{ env.get('SECRETS_DIR', '../../secrets') }}", type = "encrypted", key_name = "_sgx_mrsigner" }, + { path = "/root/.config/raiko/config", uri = "file:/root/.config/raiko/config" }, + { path = "/root/.config/raiko/secrets", uri = "file:{{ '/root/.config/raiko/secrets' }}", type = "encrypted", key_name = "_sgx_mrsigner" }, ] sys.insecure__allow_eventfd = true loader.insecure__use_cmdline_argv = true @@ -46,5 +37,6 @@ sys.enable_extra_runtime_domain_names_conf = true sgx.remote_attestation = "dcap" sgx.allowed_files = [ - "file:{{ env.get('INPUT_FILES_DIR', '/tmp') }}", + "file:/tmp/sgx", + "file:/root/.config/raiko/config", ] diff --git a/raiko-guest/src/app_args.rs b/raiko-guest/src/app_args.rs index c3fd8a72..378f8bba 100644 --- a/raiko-guest/src/app_args.rs +++ b/raiko-guest/src/app_args.rs @@ -3,6 +3,8 @@ use std::path::PathBuf; use clap::{ArgAction, Args, Parser, Subcommand}; use zeth_primitives::{Address, B256}; +const DEFAULT_RAIKO_USER_CONFIG_SUBDIR_PATH: &str = ".config/raiko"; + #[derive(Debug, Parser)] pub struct App { #[clap(flatten)] @@ -44,13 +46,25 @@ pub struct OneShotArgs { pub l2_chain: Option, } +fn get_default_raiko_user_config_path(subdir: &str) -> PathBuf { + let mut home_dir = dirs::home_dir().unwrap(); + home_dir.push(DEFAULT_RAIKO_USER_CONFIG_SUBDIR_PATH); + home_dir.push(subdir); + home_dir +} + #[derive(Debug, Args)] pub struct GlobalOpts { - #[clap(short, long, default_value = "/secrets")] + #[clap(short, long, default_value=get_default_raiko_user_config_path("secrets").into_os_string())] /// Path to the directory with the encrypted private keys being used to sign the - /// blocks. + /// blocks. For more details on the encryption see: + /// https://gramine.readthedocs.io/en/stable/manifest-syntax.html#encrypted-files pub secrets_dir: PathBuf, + #[clap(short, long, default_value=get_default_raiko_user_config_path("config").into_os_string())] + /// Path to the directory with raiko configuration files. + pub config_dir: PathBuf, + #[clap(long, short, global = true, action = ArgAction::Count)] /// Verbosity of the application. Use multiple times to increase verbosity. pub verbose: u8, diff --git a/raiko-guest/src/one_shot.rs b/raiko-guest/src/one_shot.rs index 2c85a656..fba30e29 100644 --- a/raiko-guest/src/one_shot.rs +++ b/raiko-guest/src/one_shot.rs @@ -2,11 +2,14 @@ use std::{ fs::{self, File, OpenOptions}, io::prelude::*, os::unix::fs::PermissionsExt, - path::Path, + path::{Path, PathBuf}, str::FromStr, }; use anyhow::{anyhow, bail, Context, Error, Result}; +use base64_serde::base64_serde_type; +use secp256k1::KeyPair; +use serde::Serialize; use zeth_lib::{ consts::{get_taiko_chain_spec, ChainSpec, ETH_MAINNET_CHAIN_SPEC}, host::Init, @@ -18,6 +21,7 @@ use zeth_lib::{ EthereumTxEssence, }; use zeth_primitives::{taiko::EvidenceType, Address, B256}; +base64_serde_type!(Base64Standard, base64::engine::general_purpose::STANDARD); use crate::{ app_args::{GlobalOpts, OneShotArgs}, @@ -27,21 +31,73 @@ use crate::{ pub const ATTESTATION_QUOTE_DEVICE_FILE: &str = "/dev/attestation/quote"; pub const ATTESTATION_TYPE_DEVICE_FILE: &str = "/dev/attestation/attestation_type"; pub const ATTESTATION_USER_REPORT_DATA_DEVICE_FILE: &str = "/dev/attestation/user_report_data"; +pub const BOOTSTRAP_INFO_FILENAME: &str = "bootstrap.json"; pub const PRIV_KEY_FILENAME: &str = "priv.key"; -pub fn bootstrap(global_opts: GlobalOpts) -> Result<()> { - let privkey_path = global_opts.secrets_dir.join(PRIV_KEY_FILENAME); - let key_pair = generate_key(); - let mut file = - fs::File::create(&privkey_path).with_context(|| "Failed to create private key file")?; +#[derive(Serialize)] +struct BootstrapData { + public_key: String, + new_instance: Address, + #[serde(with = "Base64Standard")] + quote: Vec, +} + +fn save_priv_key(key_pair: &KeyPair, privkey_path: &PathBuf) -> Result<()> { + let mut file = fs::File::create(privkey_path).with_context(|| { + format!( + "Failed to create private key file {}", + privkey_path.display() + ) + })?; let permissions = std::fs::Permissions::from_mode(0o600); file.set_permissions(permissions) - .with_context(|| "Failed to set permissions to private key file")?; + .context("Failed to set restrictive permissions of the private key file")?; file.write_all(&key_pair.secret_bytes()) - .with_context(|| format!("Failed to write to {}", privkey_path.display()))?; + .context("Failed to save encrypted private key file")?; + Ok(()) +} + +fn get_sgx_quote() -> Result> { + let mut quote_file = File::open(ATTESTATION_QUOTE_DEVICE_FILE)?; + let mut quote = Vec::new(); + quote_file.read_to_end(&mut quote)?; + Ok(quote) +} + +fn save_bootstrap_details( + key_pair: &KeyPair, + new_instance: Address, + quote: Vec, + bootstrap_details_file_path: &Path, +) -> Result<(), Error> { + let bootstrap_details = BootstrapData { + public_key: format!("0x{}", key_pair.public_key().to_string()), + new_instance, + quote, + }; + let json = serde_json::to_string_pretty(&bootstrap_details)?; + fs::write(bootstrap_details_file_path, json).context(format!( + "Saving bootstrap data file {} failed", + bootstrap_details_file_path.display() + ))?; + Ok(()) +} + +pub fn bootstrap(global_opts: GlobalOpts) -> Result<()> { + let key_pair = generate_key(); + let privkey_path = global_opts.secrets_dir.join(PRIV_KEY_FILENAME); + save_priv_key(&key_pair, &privkey_path)?; println!("Public key: 0x{}", key_pair.public_key()); let new_instance = public_key_to_address(&key_pair.public_key()); println!("Instance address: {}", new_instance); + let quote = get_sgx_quote()?; + let bootstrap_details_file_path = global_opts.config_dir.join(BOOTSTRAP_INFO_FILENAME); + save_bootstrap_details(&key_pair, new_instance, quote, &bootstrap_details_file_path)?; + println!( + "Bootstrap details saved in {}", + bootstrap_details_file_path.display() + ); + println!("Encrypted private key saved in {}", privkey_path.display()); Ok(()) } @@ -68,11 +124,9 @@ pub async fn one_shot(global_opts: GlobalOpts, args: OneShotArgs) -> Result<()> let privkey_path = global_opts.secrets_dir.join(PRIV_KEY_FILENAME); let prev_privkey = load_private_key(&privkey_path)?; - // println!("Private key: {}", prev_privkey.display_secret()); // let (new_privkey, new_pubkey) = generate_new_keypair()?; let new_pubkey = public_key(&prev_privkey); let new_instance = public_key_to_address(&new_pubkey); - let l2_chain_spec = get_taiko_chain_spec(&args.l2_chain.unwrap()); // fs::write(privkey_path, new_privkey.to_bytes())?; @@ -180,9 +234,7 @@ fn print_sgx_info() -> Result<()> { let attestation_type = get_sgx_attestation_type()?; println!("Detected attestation type: {}", attestation_type.trim()); - let mut quote_file = File::open(ATTESTATION_QUOTE_DEVICE_FILE)?; - let mut quote = Vec::new(); - quote_file.read_to_end(&mut quote)?; + let quote = get_sgx_quote()?; println!( "Extracted SGX quote with size = {} and the following fields:", quote.len()