Skip to content

Commit

Permalink
Oak Standalone: Milestone 1: No-Op attestation PoC
Browse files Browse the repository at this point in the history
In milestone 1 of Oak Standalone, we'll focus only on estabilshing the
crypto channel to communicate with a demo server, see: go/oak-standalone

As a first step, this CL introduces the no-op attestation flow that
provides the encryption PK without requiring any attestation
verification.

The primary goal of the CL is to lay out some boilerplate and set us up
for quick iterative improvements on the standalone concept.

The facade is based on the existing stream_session.proto service API.

Key elements:
* Create the oak_standalone crate
* Create a standalone client crate that instantiates a new OakClient
  using a special standalone AttestationVerifier.
* Create a standalone service that can establish an encrypted channel
  with an OakClient using the stream sesion protocol.
* Add a "Standalone" mode to endorsements. It's mostly ignored for now
  but may be more useful later.

Fixed: b/347967540

Change-Id: I8f789fcbb061dcafc3c7bf696367f578aae6e913
  • Loading branch information
jblebrun committed Jun 22, 2024
1 parent 4c05a03 commit bb42b4a
Show file tree
Hide file tree
Showing 15 changed files with 585 additions and 20 deletions.
2 changes: 2 additions & 0 deletions bazel/test_workspace/.envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Added this empty .envrc to prevent nix dependencies from loading, since a depender of Oak would
# not have that available.
42 changes: 22 additions & 20 deletions oak_attestation_verification/src/verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,26 +114,28 @@ pub fn verify(
// Ensure the Attestation report is properly signed by the platform and that it
// includes the root public key used in the DICE chain.
{
let tee_certificate = match endorsements.r#type.as_ref().context("no endorsements")? {
endorsements::Type::OakRestrictedKernel(endorsements) => endorsements
.root_layer
.as_ref()
.context("no root layer endorsements")?
.tee_certificate
.as_ref(),
endorsements::Type::OakContainers(endorsements) => endorsements
.root_layer
.as_ref()
.context("no root layer endorsements")?
.tee_certificate
.as_ref(),
endorsements::Type::Cb(endorsements) => endorsements
.root_layer
.as_ref()
.context("no root layer endorsements")?
.tee_certificate
.as_ref(),
};
let tee_certificate: &[u8] =
match endorsements.r#type.as_ref().context("no endorsements")? {
endorsements::Type::OakRestrictedKernel(endorsements) => endorsements
.root_layer
.as_ref()
.context("no root layer endorsements")?
.tee_certificate
.as_ref(),
endorsements::Type::OakContainers(endorsements) => endorsements
.root_layer
.as_ref()
.context("no root layer endorsements")?
.tee_certificate
.as_ref(),
endorsements::Type::Cb(endorsements) => endorsements
.root_layer
.as_ref()
.context("no root layer endorsements")?
.tee_certificate
.as_ref(),
endorsements::Type::Standalone(_) => &[],
};
let root_layer = evidence.root_layer.as_ref().context("no root layer evidence")?;
verify_root_attestation_signature(now_utc_millis, root_layer, tee_certificate)?;
};
Expand Down
1 change: 1 addition & 0 deletions oak_attestation_verification_test_utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ pub fn reference_values_from_evidence(evidence: ExtractedEvidence) -> ReferenceV
}))
}
EvidenceValues::Cb(_) => panic!("not yet supported"),
EvidenceValues::Standalone(_) => panic!("not yet supported"),
};
ReferenceValues { r#type }
}
Expand Down
37 changes: 37 additions & 0 deletions oak_standalone/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Oak Standalone Libraries

NOTE: The crates in this project currently only build with Bazel, as an
experiment to see what the gaps are. So, the following tasks will be missing:

* cargo fmt
* cargo udeps
* cargo

Oak standalone is a collection of Oak utilities that can be used to provide
confidential computing functionality to applications that are deployed into
scenarios where using one of the full Oak stack deployment models is not
feasible.

Oak Standalone is designed to be easy to integrate with an existing service that
provides a normal, unencrypted gRPC-style interface, defined using proto files
and gRPC services.

## Server

The server component is a gRPC frontend that sits in front of the developer's
client application to provide a facade that speaks the Oak protocol.

It's built on the streaming_session.proto service API.

In order to use it, you should compile it into your existing client server
application, but rather than exposing (for example) a gRPC interface to your
application, you will integrate with the Oak Standalone server facade (details
on this this works TBD).

## Client

The client library provides some convenience methods for creating an Oak Client
instance that can speak to an Oak Standalone server instance. Primarily, it
provides an AttestationVerifier that does not actually verify any attestation,
but does provide an attested evidence structure containing the public key that
can be used to establish the crypto session.
33 changes: 33 additions & 0 deletions oak_standalone/client/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#
# Copyright 202424 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.
#

load("@rules_rust//rust:defs.bzl", "rust_library")

package(
default_visibility = ["//visibility:public"],
licenses = ["notice"],
)

rust_library(
name = "client",
srcs = ["src/client.rs"],
crate_name = "oak_standalone_client",
deps = [
"//oak_attestation_verification",
"//oak_client",
"@oak_crates_index//:anyhow",
],
)
60 changes: 60 additions & 0 deletions oak_standalone/client/src/client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//
// 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 anyhow::Context;
use oak_client::{
client::OakClient,
proto::oak::attestation::v1::{
extracted_evidence, Endorsements, Evidence, ExtractedEvidence, OakStandaloneData,
},
transport::{EvidenceProvider, Transport},
verifier::AttestationVerifier,
};

/// An [AttestationVerifier] that skips attestation, but still receives the
/// public key from the server to set up an encryption channel.
struct StandaloneAttestationVerifier {}

impl AttestationVerifier for StandaloneAttestationVerifier {
fn verify(&self, evidence: &Evidence, _: &Endorsements) -> anyhow::Result<ExtractedEvidence> {
// Ignore everything about Evidence, Endorsements.
// For this PoC, we just pull the key directly out of ApplicationKeys,
// treating it as a plain old encryption key
// TODO: b/347970899 - Rather than hard coding this, incorporate Oak Standalone
// into the existing attestation verification framework.
Ok(ExtractedEvidence {
evidence_values: Some(extracted_evidence::EvidenceValues::Standalone(
OakStandaloneData {},
)),
encryption_public_key: evidence
.application_keys
.as_ref()
.context("no application key was present in the evidence")?
.encryption_public_key_certificate
.clone(),
signing_public_key: vec![],
})
}
}

/// Create a new [OakClient] instance that is meant to interact with an Oak
/// Standalone server facade.
///
/// Attestation will not be verified, but the server should provide an
/// encryption PK that can be used to establish a crypto channel.
pub async fn new<T: Transport + EvidenceProvider>(transport: T) -> anyhow::Result<OakClient<T>> {
let verifier = StandaloneAttestationVerifier {};
OakClient::create(transport, &verifier).await
}
56 changes: 56 additions & 0 deletions oak_standalone/proto/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#
# 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.
#

load("@rules_rust//cargo:defs.bzl", "cargo_build_script")
load("@rules_rust//rust:defs.bzl", "rust_library")

package(
default_visibility = ["//visibility:public"],
licenses = ["notice"],
)

rust_library(
name = "oak_standalone_rust_bs_proto",
srcs = ["lib.rs"],
deps = [
":build",
"//oak_proto_rust",
"@oak_crates_index//:prost",
"@oak_crates_index//:prost-types",
"@oak_crates_index//:tonic",
],
)

cargo_build_script(
name = "build",
srcs = [
"build.rs",
],
build_script_env = {
"PROTOC": "$(execpath @com_google_protobuf//:protoc)",
},
crate_features = ["bazel"],
data = [
"//proto/session:service_streaming_proto",
],
tools = [
"@com_google_protobuf//:protoc",
],
deps = [
"//oak_grpc_utils",
"@oak_crates_index//:prost-build",
],
)
33 changes: 33 additions & 0 deletions oak_standalone/proto/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// 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 oak_grpc_utils::{generate_grpc_code, CodegenOptions, ExternPath};

fn main() -> Result<(), Box<dyn std::error::Error>> {
generate_grpc_code(
&["../../proto/session/service_streaming.proto"],
&[".", "../.."],
CodegenOptions {
build_server: true,
extern_paths: vec![
ExternPath::new(".oak.crypto.v1", "oak_proto_rust::oak::crypto::v1"),
ExternPath::new(".oak.attestation.v1", "oak_proto_rust::oak::attestation::v1"),
],
..Default::default()
},
)?;

Ok(())
}
25 changes: 25 additions & 0 deletions oak_standalone/proto/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// 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.
//

pub mod oak {
pub mod session {
pub mod v1 {
#![allow(clippy::return_self_not_must_use)]
#![allow(clippy::large_enum_variant)]
tonic::include_proto!("oak.session.v1");
}
}
}
45 changes: 45 additions & 0 deletions oak_standalone/service/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#
# 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.
#

load("@rules_rust//rust:defs.bzl", "rust_library")

package(
default_visibility = ["//visibility:public"],
licenses = ["notice"],
)

rust_library(
name = "service",
srcs = ["src/service.rs"],
crate_name = "oak_standalone_service",
deps = [
"//oak_client",
"//oak_crypto",
"//oak_proto_rust",
"//oak_sev_snp_attestation_report",
"//oak_standalone/proto:oak_standalone_rust_bs_proto",
"@oak_crates_index//:anyhow",
"@oak_crates_index//:async-stream",
"@oak_crates_index//:futures",
"@oak_crates_index//:log",
"@oak_crates_index//:prost",
"@oak_crates_index//:prost-types",
"@oak_crates_index//:tokio",
"@oak_crates_index//:tokio-stream",
"@oak_crates_index//:tonic",
"@oak_crates_index//:zerocopy",
],
)
Loading

0 comments on commit bb42b4a

Please sign in to comment.