diff --git a/Cargo.lock b/Cargo.lock index 9896aa9..c6ac814 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -314,14 +314,13 @@ dependencies = [ [[package]] name = "axum" -version = "0.7.9" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" +checksum = "6d6fd624c75e18b3b4c6b9caf42b1afe24437daaee904069137d8bab077be8b8" dependencies = [ - "async-trait", "axum-core", - "axum-macros", "bytes", + "form_urlencoded", "futures-util", "http", "http-body", @@ -349,11 +348,10 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.4.5" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" +checksum = "df1362f362fd16024ae199c1970ce98f9661bf5ef94b9808fee734bc3698b733" dependencies = [ - "async-trait", "bytes", "futures-util", "http", @@ -368,17 +366,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "axum-macros" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57d123550fa8d071b7255cb0cc04dc302baa6c8c4a79f55701552684d8399bce" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.95", -] - [[package]] name = "axum-server" version = "0.7.1" @@ -727,9 +714,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.24" +version = "4.5.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9560b07a799281c7e0958b9296854d6fafd4c5f31444a7e5bb1ad6dde5ccf1bd" +checksum = "b95dca1b68188a08ca6af9d96a6576150f598824bdb528c1190460c2940a0b48" dependencies = [ "clap_builder", "clap_derive", @@ -737,9 +724,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.24" +version = "4.5.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "874e0dd3eb68bf99058751ac9712f622e61e6f393a94f7128fa26e3f02f5c7cd" +checksum = "9ab52925392148efd3f7562f2136a81ffb778076bcc85727c6e020d6dd57cf15" dependencies = [ "anstream", "anstyle", @@ -2493,14 +2480,15 @@ dependencies = [ [[package]] name = "ic_tee_agent" -version = "0.2.2" +version = "0.2.3" dependencies = [ - "axum", + "axum-core", "base64 0.22.1", "bytes", "candid", "ciborium", "ed25519-consensus", + "http", "ic-agent", "ic-canister-sig-creation", "ic-crypto-standalone-sig-verifier", @@ -2521,7 +2509,7 @@ dependencies = [ [[package]] name = "ic_tee_cdk" -version = "0.2.2" +version = "0.2.3" dependencies = [ "candid", "ciborium", @@ -2533,7 +2521,7 @@ dependencies = [ [[package]] name = "ic_tee_cli" -version = "0.2.2" +version = "0.2.3" dependencies = [ "anyhow", "candid", @@ -2556,7 +2544,7 @@ dependencies = [ [[package]] name = "ic_tee_host_daemon" -version = "0.2.2" +version = "0.2.3" dependencies = [ "anyhow", "clap", @@ -2569,7 +2557,7 @@ dependencies = [ [[package]] name = "ic_tee_identity" -version = "0.2.2" +version = "0.2.3" dependencies = [ "candid", "ciborium", @@ -2587,7 +2575,7 @@ dependencies = [ [[package]] name = "ic_tee_logtail" -version = "0.2.2" +version = "0.2.3" dependencies = [ "anyhow", "clap", @@ -2598,7 +2586,7 @@ dependencies = [ [[package]] name = "ic_tee_nitro_attestation" -version = "0.2.2" +version = "0.2.3" dependencies = [ "candid", "ciborium", @@ -2614,7 +2602,7 @@ dependencies = [ [[package]] name = "ic_tee_nitro_gateway" -version = "0.2.2" +version = "0.2.3" dependencies = [ "anyhow", "aws-nitro-enclaves-nsm-api", @@ -3000,9 +2988,9 @@ checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" [[package]] name = "matchit" -version = "0.7.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" [[package]] name = "memchr" diff --git a/Cargo.toml b/Cargo.toml index 5c4c530..165ab47 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ strip = true opt-level = 's' [workspace.package] -version = "0.2.2" +version = "0.2.3" edition = "2021" repository = "https://github.com/ldclabs/ic-tee" keywords = ["tee", "canister", "icp", "nitro"] @@ -27,16 +27,18 @@ license = "MIT OR Apache-2.0" [workspace.dependencies] anyhow = "1" -axum = { version = "0.7", features = [ +axum = { version = "0.8", features = [ "http1", "http2", "json", - "macros", + # "macros", "matched-path", "tokio", "query", ], default-features = true } +axum-core = "0.5" axum-server = { version = "0.7", features = ["tls-rustls"] } +http = "1.2" bytes = "1" base64 = "0.22" clap = { version = "4.5", features = ["derive"] } diff --git a/LICENSE-MIT b/LICENSE-MIT index 5630aee..d9dad0d 100644 --- a/LICENSE-MIT +++ b/LICENSE-MIT @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 LDC Labs +Copyright (c) 2024-2025 LDC Labs Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 304e39f..947322f 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,6 @@ Relation project: | [ic_tee_nitro_gateway](https://github.com/ldclabs/ic-tee/tree/main/src/ic_tee_nitro_gateway) | A gateway service within an AWS Nitro enclave. | ## License -Copyright © 2024 [LDC Labs](https://github.com/ldclabs). +Copyright © 2024-2025 [LDC Labs](https://github.com/ldclabs). `ldclabs/ic-tee` is licensed under the MIT License. See [LICENSE](./LICENSE-MIT) for the full license text. \ No newline at end of file diff --git a/src/ic_tee_agent/Cargo.toml b/src/ic_tee_agent/Cargo.toml index 6e67062..fbd43b0 100644 --- a/src/ic_tee_agent/Cargo.toml +++ b/src/ic_tee_agent/Cargo.toml @@ -11,6 +11,8 @@ license.workspace = true [dependencies] ic_tee_cdk = { path = "../ic_tee_cdk", version = "0.2" } +http = { workspace = true } +axum-core = { workspace = true } base64 = { workspace = true } candid = { workspace = true } ed25519-consensus = { workspace = true } @@ -21,7 +23,6 @@ serde_bytes = { workspace = true } ic-agent = { workspace = true } rand = { workspace = true } tokio = { workspace = true } -axum = { workspace = true } bytes = { workspace = true } mime = { workspace = true } thiserror = { workspace = true } diff --git a/src/ic_tee_agent/src/http/authentication.rs b/src/ic_tee_agent/src/http/authentication.rs index 5b92d2f..2ad6c1d 100644 --- a/src/ic_tee_agent/src/http/authentication.rs +++ b/src/ic_tee_agent/src/http/authentication.rs @@ -1,3 +1,37 @@ +use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine}; +use candid::Principal; +use ciborium::from_reader; +use http::header::{HeaderMap, HeaderName}; +use ic_agent::Identity; +use ic_canister_sig_creation::delegation_signature_msg; +use ic_cose_types::{cose::sha3_256, to_cbor_bytes}; +use ic_tee_cdk::SignedDelegation; +use thiserror::Error; + +pub const PERMITTED_DRIFT_MS: u64 = 30 * 1000; +pub const ANONYMOUS_PRINCIPAL: Principal = Principal::anonymous(); + +pub static HEADER_X_FORWARDED_FOR: HeaderName = HeaderName::from_static("x-forwarded-for"); +pub static HEADER_X_FORWARDED_HOST: HeaderName = HeaderName::from_static("x-forwarded-host"); +pub static HEADER_X_FORWARDED_PROTO: HeaderName = HeaderName::from_static("x-forwarded-proto"); + +/// Caller's public key for authentication +pub static HEADER_IC_TEE_PUBKEY: HeaderName = HeaderName::from_static("ic-tee-pubkey"); +/// Delegation chain for authentication +pub static HEADER_IC_TEE_DELEGATION: HeaderName = HeaderName::from_static("ic-tee-delegation"); +/// Request content hash (customizable by business logic) +pub static HEADER_IC_TEE_CONTENT_DIGEST: HeaderName = + HeaderName::from_static("ic-tee-content-digest"); +/// Signature of the content digest +pub static HEADER_IC_TEE_SIGNATURE: HeaderName = HeaderName::from_static("ic-tee-signature"); + +/// TEE ID added to upstream requests +pub static HEADER_IC_TEE_ID: HeaderName = HeaderName::from_static("ic-tee-id"); +/// TEE instance ID added to upstream requests +pub static HEADER_IC_TEE_INSTANCE: HeaderName = HeaderName::from_static("ic-tee-instance"); +/// Authenticated caller principal (or anonymous principal) +pub static HEADER_IC_TEE_CALLER: HeaderName = HeaderName::from_static("ic-tee-caller"); + /// The `UserSignature` struct represents an end user's signature and provides methods to /// parse and validate the signature from HTTP headers. /// @@ -41,41 +75,6 @@ /// # Static Variables /// - `IC_ROOT_PUBLIC_KEY`: The IC root public key used when verifying canister signatures. /// -use axum::http::header::{HeaderMap, HeaderName}; -use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine}; -use candid::Principal; -use ciborium::from_reader; -use ic_agent::Identity; -use ic_canister_sig_creation::delegation_signature_msg; -use ic_cose_types::{cose::sha3_256, to_cbor_bytes}; -use ic_tee_cdk::SignedDelegation; -use thiserror::Error; - -pub const PERMITTED_DRIFT_MS: u64 = 30 * 1000; -pub const ANONYMOUS_PRINCIPAL: Principal = Principal::anonymous(); - -pub static HEADER_X_FORWARDED_FOR: HeaderName = HeaderName::from_static("x-forwarded-for"); -pub static HEADER_X_FORWARDED_HOST: HeaderName = HeaderName::from_static("x-forwarded-host"); -pub static HEADER_X_FORWARDED_PROTO: HeaderName = HeaderName::from_static("x-forwarded-proto"); - -/// Caller's public key for authentication -pub static HEADER_IC_TEE_PUBKEY: HeaderName = HeaderName::from_static("ic-tee-pubkey"); -/// Delegation chain for authentication -pub static HEADER_IC_TEE_DELEGATION: HeaderName = HeaderName::from_static("ic-tee-delegation"); -/// Request content hash (customizable by business logic) -pub static HEADER_IC_TEE_CONTENT_DIGEST: HeaderName = - HeaderName::from_static("ic-tee-content-digest"); -/// Signature of the content digest -pub static HEADER_IC_TEE_SIGNATURE: HeaderName = HeaderName::from_static("ic-tee-signature"); - -/// TEE ID added to upstream requests -pub static HEADER_IC_TEE_ID: HeaderName = HeaderName::from_static("ic-tee-id"); -/// TEE instance ID added to upstream requests -pub static HEADER_IC_TEE_INSTANCE: HeaderName = HeaderName::from_static("ic-tee-instance"); -/// Authenticated caller principal (or anonymous principal) -pub static HEADER_IC_TEE_CALLER: HeaderName = HeaderName::from_static("ic-tee-caller"); - -/// Represents an end user's signature for HTTP request authentication. #[derive(Clone, Debug)] pub struct UserSignature { pub pubkey: Vec, diff --git a/src/ic_tee_agent/src/http/content.rs b/src/ic_tee_agent/src/http/content.rs index 5e65003..4bb5703 100644 --- a/src/ic_tee_agent/src/http/content.rs +++ b/src/ic_tee_agent/src/http/content.rs @@ -1,14 +1,12 @@ -use axum::{ - async_trait, - body::Bytes, +use axum_core::{ extract::{FromRequest, Request}, - http::{ - header::{self, HeaderMap, HeaderValue}, - StatusCode, - }, response::{IntoResponse, Response}, }; -use bytes::{BufMut, BytesMut}; +use bytes::{BufMut, Bytes, BytesMut}; +use http::{ + header::{self, HeaderMap, HeaderValue}, + StatusCode, +}; use serde::{de::DeserializeOwned, Serialize}; pub static CONTENT_TYPE_CBOR: &str = "application/cbor"; @@ -64,11 +62,9 @@ impl Content<()> { } } -#[async_trait] -impl FromRequest for Content +impl FromRequest for Content where - T: DeserializeOwned + Send + Sync, - Bytes: FromRequest, + T: DeserializeOwned, S: Send + Sync, { type Rejection = Response; diff --git a/src/ic_tee_nitro_gateway/src/handler.rs b/src/ic_tee_nitro_gateway/src/handler.rs index 83f10fd..0a8f027 100644 --- a/src/ic_tee_nitro_gateway/src/handler.rs +++ b/src/ic_tee_nitro_gateway/src/handler.rs @@ -32,11 +32,6 @@ use crate::{attestation::sign_attestation, crypto, ic_sig_verifier::verify_sig, type Client = hyper_util::client::legacy::Client; -pub fn new_client() -> Client { - hyper_util::client::legacy::Client::<(), ()>::builder(TokioExecutor::new()) - .build(HttpConnector::new()) -} - #[derive(Clone)] pub struct AppState { info: Arc, @@ -49,11 +44,14 @@ pub struct AppState { impl AppState { pub fn new( info: Arc, - http_client: Arc, tee_agent: Arc, root_secret: [u8; 48], upstream_port: Option, ) -> Self { + let http_client = Arc::new( + hyper_util::client::legacy::Client::<(), ()>::builder(TokioExecutor::new()) + .build(HttpConnector::new()), + ); Self { info, http_client, @@ -396,7 +394,7 @@ pub async fn proxy( Ok(res) => Ok(res.into_response()), Err(err) => Err(Content::Text( err.to_string(), - Some(StatusCode::INTERNAL_SERVER_ERROR), + Some(StatusCode::BAD_REQUEST), )), } } diff --git a/src/ic_tee_nitro_gateway/src/main.rs b/src/ic_tee_nitro_gateway/src/main.rs index b03018f..1facade 100644 --- a/src/ic_tee_nitro_gateway/src/main.rs +++ b/src/ic_tee_nitro_gateway/src/main.rs @@ -250,10 +250,8 @@ async fn bootstrap(cli: Cli) -> Result<()> { elapsed = start.elapsed().as_millis() as u64; "TEE app information, principal: {:?}", principal.to_text()); - let http_client = Arc::new(handler::new_client()); - let tee_agent = Arc::new(tee_agent); let info = Arc::new(info); - + let tee_agent = Arc::new(tee_agent); let handle = axum_server::Handle::new(); let cancel_token = CancellationToken::new(); let shutdown_future = shutdown_signal(handle.clone(), cancel_token.clone()); @@ -313,7 +311,6 @@ async fn bootstrap(cli: Cli) -> Result<()> { .route("/keys", routing::post(handler::local_call_keys)) .with_state(handler::AppState::new( info.clone(), - http_client.clone(), tee_agent.clone(), root_secret, None, @@ -341,10 +338,9 @@ async fn bootstrap(cli: Cli) -> Result<()> { "/.well-known/attestation", routing::get(handler::get_attestation), ) - .route("/*any", routing::any(handler::proxy)) + .route("/{*any}", routing::any(handler::proxy)) .with_state(handler::AppState::new( info.clone(), - http_client.clone(), tee_agent.clone(), [0u8; 48], None,