-
Notifications
You must be signed in to change notification settings - Fork 111
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Incorporate Oak Standalone into the SDK, add demo
This CR does the following: * Moves Oak Standalone functionality out of a separate crate, and into a module inside the `oak_containers_sdk`. * Updates the Oak Standalone helpers to conform to the new "thinhost" approach to TEE app creation. With this change, a separate service is no longer needed, all crypto and attestation functionality are handled directly by the TEE app. * Updates the hello world trusted app to include an integration test demonstrating the standalone configuration. Fixed: b/356954630 Fixed: b/356955062 Change-Id: I1c3e0c331e7f75caabc2c5a3b83640b8ed72595a
- Loading branch information
Showing
16 changed files
with
264 additions
and
457 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,5 +15,6 @@ | |
// | ||
|
||
pub mod client; | ||
pub mod standalone; | ||
pub mod transport; | ||
pub mod verifier; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
96 changes: 96 additions & 0 deletions
96
oak_containers_examples/hello_world/trusted_app/tests/standalone_test.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
// | ||
// Copyright 2024 The Project Oak Authors | ||
// | ||
// Licensed 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::net::{IpAddr, Ipv4Addr, SocketAddr}; | ||
|
||
use anyhow::{Context, Result}; | ||
use oak_client::{ | ||
client::OakClient, standalone::StandaloneNoOpAttestationVerifier, | ||
transport::GrpcStreamingTransport, | ||
}; | ||
use oak_containers_sdk::{ | ||
standalone::{ | ||
standalone_endorsed_evidence_containing_only_public_keys, StandaloneEncryptionKeyHandle, | ||
}, | ||
OakSessionContext, | ||
}; | ||
use oak_hello_world_proto::oak::containers::example::trusted_application_client::TrustedApplicationClient; | ||
use tokio::net::TcpListener; | ||
use tonic::transport::Channel; | ||
|
||
async fn start_server() -> Result<(SocketAddr, tokio::task::JoinHandle<Result<()>>)> { | ||
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0); | ||
let listener = TcpListener::bind(addr).await?; | ||
let addr = listener.local_addr()?; | ||
|
||
let encryption_key_handle = StandaloneEncryptionKeyHandle::default(); | ||
|
||
let application_config = vec![1, 2, 3, 4]; | ||
|
||
let endorsed_evidence = standalone_endorsed_evidence_containing_only_public_keys( | ||
encryption_key_handle.public_key(), | ||
); | ||
|
||
Ok(( | ||
addr, | ||
tokio::spawn(oak_containers_hello_world_trusted_app::app_service::create( | ||
listener, | ||
OakSessionContext::new( | ||
Box::new(encryption_key_handle), | ||
endorsed_evidence, | ||
Box::new( | ||
oak_containers_hello_world_trusted_app::app::HelloWorldApplicationHandler { | ||
application_config, | ||
}, | ||
), | ||
), | ||
)), | ||
)) | ||
} | ||
|
||
#[tokio::test] | ||
async fn test1() { | ||
// Start server | ||
let (addr, _join_handle) = start_server().await.unwrap(); | ||
|
||
let url = format!("http://{addr}"); | ||
|
||
println!("Connecting to test server on {}", url); | ||
|
||
let channel = Channel::from_shared(url) | ||
.context("couldn't create gRPC channel") | ||
.unwrap() | ||
.connect() | ||
.await | ||
.context("couldn't connect via gRPC channel") | ||
.unwrap(); | ||
|
||
let mut client = TrustedApplicationClient::new(channel); | ||
|
||
let transport = GrpcStreamingTransport::new(|rx| client.session(rx)) | ||
.await | ||
.expect("couldn't create GRPC streaming transport"); | ||
|
||
let attestation_verifier = StandaloneNoOpAttestationVerifier::new(); | ||
|
||
// Create client | ||
let mut oak_client = OakClient::create(transport, &attestation_verifier).await.unwrap(); | ||
|
||
// Send single request, see the response | ||
assert_eq!( | ||
oak_client.invoke(b"standalone user").await.unwrap(), | ||
b"Hello from the trusted side, standalone user! Btw, the Trusted App has a config with a length of 4 bytes." | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
// | ||
// Copyright 2024 The Project Oak Authors | ||
// | ||
// Licensed 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. | ||
|
||
//! The Oak Standalone SDK allows easy development iteration and testing for an | ||
//! Oak-enabled trusted binary without requiring the entire Oak containers | ||
//! stack. | ||
//! | ||
//! Oak Standalone supports setting up an encrypted channel based on randomly | ||
//! generated public keys. | ||
//! | ||
//! It does not currently support any sort of attestation flow. | ||
|
||
use oak_crypto::{ | ||
encryption_key::{generate_encryption_key_pair, AsyncEncryptionKeyHandle, EncryptionKey}, | ||
hpke::RecipientContext, | ||
}; | ||
use oak_proto_rust::oak::{ | ||
attestation::v1::{ | ||
endorsements, ApplicationKeys, Endorsements, Evidence, OakStandaloneEndorsements, | ||
RootLayerEvidence, TeePlatform, | ||
}, | ||
session::v1::EndorsedEvidence, | ||
}; | ||
|
||
/// Create an [`EndorsedEvidence`] instance that your TEE application can use. | ||
/// This can be provided in circumstances where you'd normally request an | ||
/// [`EndorsedEvidence`] from the Orchestrator. | ||
pub fn standalone_endorsed_evidence_containing_only_public_keys( | ||
public_key: impl Into<Vec<u8>>, | ||
) -> EndorsedEvidence { | ||
EndorsedEvidence { | ||
evidence: Some(Evidence { | ||
// TODO: b/347970899 - Create something here that will be compatible with the | ||
// verification framework. | ||
root_layer: Some(RootLayerEvidence { | ||
platform: TeePlatform::None.into(), | ||
eca_public_key: vec![], | ||
remote_attestation_report: vec![], | ||
}), | ||
layers: vec![], | ||
application_keys: Some(ApplicationKeys { | ||
// TODO: b/347970899 - Store the public key in the format expected by | ||
// the attestation verification framework. | ||
encryption_public_key_certificate: public_key.into(), | ||
group_encryption_public_key_certificate: vec![], | ||
signing_public_key_certificate: vec![], | ||
group_signing_public_key_certificate: vec![], | ||
}), | ||
}), | ||
endorsements: Some(Endorsements { | ||
r#type: Some(endorsements::Type::Standalone(OakStandaloneEndorsements {})), | ||
}), | ||
} | ||
} | ||
|
||
/// A structure implementing [`AsyncEncryptionKeyHandle``] trait, which can be | ||
/// provided to a TEE application instead of the normal orchestrator-driven | ||
/// instance type. | ||
pub struct StandaloneEncryptionKeyHandle { | ||
public_key: Vec<u8>, | ||
private_key: EncryptionKey, | ||
} | ||
|
||
impl StandaloneEncryptionKeyHandle { | ||
/// Generates a new public/private keypair and returns a new instance | ||
/// containing them. | ||
pub fn new( | ||
private_key: EncryptionKey, | ||
public_key: impl Into<Vec<u8>>, | ||
) -> StandaloneEncryptionKeyHandle { | ||
Self { private_key, public_key: public_key.into() } | ||
} | ||
|
||
/// Return the public_key created on construction. | ||
pub fn public_key(&self) -> &[u8] { | ||
&self.public_key | ||
} | ||
} | ||
|
||
impl Default for StandaloneEncryptionKeyHandle { | ||
fn default() -> Self { | ||
let (private_key, public_key) = generate_encryption_key_pair(); | ||
Self::new(private_key, public_key) | ||
} | ||
} | ||
|
||
#[async_trait::async_trait] | ||
impl AsyncEncryptionKeyHandle for StandaloneEncryptionKeyHandle { | ||
async fn generate_recipient_context( | ||
&self, | ||
encapsulated_public_key: &[u8], | ||
) -> anyhow::Result<RecipientContext> { | ||
self.private_key.generate_recipient_context(encapsulated_public_key).await | ||
} | ||
} |
Oops, something went wrong.