Skip to content

Commit

Permalink
Use signature label in Private Set Intersection (#1392)
Browse files Browse the repository at this point in the history
This change adds a signature label to Private Set Intersection example.

Fixes #1344
Ref #1066
  • Loading branch information
ipetr0v committed Sep 10, 2020
1 parent 79de881 commit 7d4553f
Show file tree
Hide file tree
Showing 15 changed files with 107 additions and 42 deletions.
2 changes: 1 addition & 1 deletion examples/aggregator/client/aggregator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ int main(int argc, char** argv) {
//
// The particular value corresponds to the hash on the `aggregator.wasm` line in
// https://github.com/project-oak/oak/blob/hashes/reproducibility_index.
oak::label::Label label = oak::WebAssemblyModuleLabel(
oak::label::Label label = oak::WebAssemblyModuleHashLabel(
absl::HexStringToBytes("c995a15ab48aa7e091b65e8bb8d7b67c71f4a10c236b8eaa0599fe7439053530"));
// Connect to the Oak Application.
auto stub = Aggregator::NewStub(oak::ApplicationClient::CreateChannel(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,20 @@

ABSL_FLAG(std::string, address, "localhost:8080", "Address of the Oak application to connect to");
ABSL_FLAG(std::string, ca_cert, "", "Path to the PEM-encoded CA root certificate");
ABSL_FLAG(std::string, public_key, "", "Path to the PEM-encoded public key used as a data label");

using ::oak::examples::private_set_intersection::GetIntersectionResponse;
using ::oak::examples::private_set_intersection::PrivateSetIntersection;
using ::oak::examples::private_set_intersection::SubmitSetRequest;

void SubmitSet(PrivateSetIntersection::Stub* stub, std::vector<std::string> set) {
grpc::Status SubmitSet(PrivateSetIntersection::Stub* stub, std::vector<std::string> set) {
grpc::ClientContext context;
SubmitSetRequest request;
for (auto item : set) {
request.add_values(item);
}
google::protobuf::Empty response;
grpc::Status status = stub->SubmitSet(&context, request, &response);
if (!status.ok()) {
LOG(FATAL) << "Could not submit set: " << status.error_code() << ": " << status.error_message();
}
return stub->SubmitSet(&context, request, &response);
}

std::vector<std::string> RetrieveIntersection(PrivateSetIntersection::Stub* stub) {
Expand Down Expand Up @@ -68,7 +66,8 @@ int main(int argc, char** argv) {

// TODO(#1066): Use a more restrictive Label, based on a bearer token shared between the two
// clients.
oak::label::Label label = oak::PublicUntrustedLabel();
std::string public_key = oak::ApplicationClient::LoadPublicKey(absl::GetFlag(FLAGS_public_key));
oak::label::Label label = oak::WebAssemblyModuleSignatureLabel(public_key);

auto stub_0 = PrivateSetIntersection::NewStub(oak::ApplicationClient::CreateChannel(
address, oak::ApplicationClient::GetTlsChannelCredentials(ca_cert), label));
Expand All @@ -78,14 +77,37 @@ int main(int argc, char** argv) {

// Submit sets from different clients.
std::vector<std::string> set_0{"a", "b", "c"};
SubmitSet(stub_0.get(), set_0);
auto submit_status_0 = SubmitSet(stub_0.get(), set_0);
if (!submit_status_0.ok()) {
LOG(FATAL) << "Could not submit set: " << submit_status_0.error_code() << ": "
<< submit_status_0.error_message();
}

std::vector<std::string> set_1{"b", "c", "d"};
SubmitSet(stub_1.get(), set_1);
auto submit_status_1 = SubmitSet(stub_1.get(), set_1);
if (!submit_status_1.ok()) {
LOG(FATAL) << "Could not submit set: " << submit_status_1.error_code() << ": "
<< submit_status_1.error_message();
}

std::set<std::string> expected_set{"b", "c"};
// Use an invalid public key.
std::string invalid_public_key_base64 = "vpxqTZOUq1FjcaB9uJYCuv4kAg+AsgMwubA6WE+2pmk=";
std::string invalid_public_key;
if (!absl::Base64Unescape(invalid_public_key_base64, &invalid_public_key)) {
LOG(FATAL) << "Could not decode public key: " << invalid_public_key_base64;
}
oak::label::Label invalid_label = oak::WebAssemblyModuleSignatureLabel(invalid_public_key);
auto invalid_stub = PrivateSetIntersection::NewStub(oak::ApplicationClient::CreateChannel(
address, oak::ApplicationClient::GetTlsChannelCredentials(ca_cert), invalid_label));
std::vector<std::string> set_2{"c", "d", "e"};
auto submit_status_2 = SubmitSet(invalid_stub.get(), set_2);
// Error code `3` means `could not process gRPC request`.
if (submit_status_2.error_code() != 3) {
LOG(FATAL) << "Invalid public key was accepted";
}

// Retrieve intersection.
std::set<std::string> expected_set{"b", "c"};
std::vector<std::string> intersection_0 = RetrieveIntersection(stub_0.get());
LOG(INFO) << "client 0 intersection:";
for (auto item : intersection_0) {
Expand Down
9 changes: 8 additions & 1 deletion examples/private_set_intersection/example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,12 @@ out = "examples/private_set_intersection/bin/private_set_intersection.oak"
[applications.rust.modules]
module = { Cargo = { cargo_manifest = "examples/private_set_intersection/module/rust/Cargo.toml" } }

[server]
additional_args = [
"--signatures-manifest=examples/private_set_intersection/signatures.toml"
]

[clients]
cpp = { Bazel = { bazel_target = "//examples/private_set_intersection/client:client" } }
cpp = { Bazel = { bazel_target = "//examples/private_set_intersection/client:client" }, additional_args = [
"--public_key=../../../../../../../../examples/keys/ed25519/test.pub",
] }
3 changes: 2 additions & 1 deletion examples/private_set_intersection/oak_app_manifest.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
name = "private_set_intersection"

[modules]
app = { path = "examples/private_set_intersection/bin/private_set_intersection.wasm" }
# TODO(865): Use locally built module once reproducibility is fixed.
app = { external = { url = "https://storage.googleapis.com/oak-modules/private_set_intersection/b6c9183aaa1d0a65e3056d7ff7a35eb039c6c8f661f833ce8041332e3d8493c1", sha256 = "b6c9183aaa1d0a65e3056d7ff7a35eb039c6c8f661f833ce8041332e3d8493c1" } }
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ f41SClNtR4i46v2Tuh1fQLbt/ZqRr1lENajCW92jyP4=
-----END PUBLIC KEY-----

-----BEGIN SIGNATURE-----
XTMXZqNPeVO5mfT+GURXMBXU3GrjVtIVlpdrnACbkgePpszy+RuL7wzrok6bU+P5
1JY5gTU4vSU8kljTOzJvDw==
SPZRIElc7+ayx35H1j63zSOD19Xi8JZQAMnU9HgBxGgLpyDcKE4tlJhBNTLC0HgU
dKLbbAQGLp7MjVmmJhfCDA==
-----END SIGNATURE-----

-----BEGIN HASH-----
NgaobZ+gHSI9w8sJLBrOueOv4O2XmaxdWyFLFhAgn48=
tskYOqodCmXjBW1/96NesDnGyPZh+DPOgEEzLj2Ek8E=
-----END HASH-----
3 changes: 3 additions & 0 deletions examples/private_set_intersection/signatures.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
signatures = [
{ path = "examples/private_set_intersection/private_set_intersection.sign" },
]
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ int main(int argc, char** argv) {
LOG(INFO) << "Connecting to Oak Application: " << address;

// TODO(#1066): Use a more restrictive Label.
// TODO(#1344): Add Wasm module signature Label.
oak::label::Label label = oak::PublicUntrustedLabel();
// Connect to the Oak Application.
auto stub = TrustedInformationRetrieval::NewStub(oak::ApplicationClient::CreateChannel(
Expand Down
1 change: 0 additions & 1 deletion examples/trusted_information_retrieval/example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ module_1 = { Cargo = { cargo_manifest = "examples/trusted_information_retrieval/
[server]
additional_args = [
"--config-files=config=examples/trusted_information_retrieval/database.toml",
"--signatures-manifest=examples/trusted_information_retrieval/signatures.toml"
]

[clients]
Expand Down
4 changes: 0 additions & 4 deletions examples/trusted_information_retrieval/signatures.toml

This file was deleted.

21 changes: 21 additions & 0 deletions oak/client/application_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,27 @@ class ApplicationClient {
}
return utils::read_file(root_cert_path);
}

// Loads the PEM-encoded public key.
static std::string LoadPublicKey(std::string public_key_path) {
std::string public_key = utils::read_file(public_key_path);

// Parse key file.
auto patterns = {"-----BEGIN PUBLIC KEY-----", "-----END PUBLIC KEY-----", "\r", "\n"};
for (std::string pattern : patterns) {
size_t substring = public_key.find(pattern);
if (substring != std::string::npos) {
public_key.erase(substring, pattern.length());
}
}

// Decode Base64 key.
std::string decoded_public_key;
if (!absl::Base64Unescape(public_key, &decoded_public_key)) {
LOG(FATAL) << "Could not decode public key: " << public_key;
}
return decoded_public_key;
}
};

} // namespace oak
Expand Down
11 changes: 10 additions & 1 deletion oak/common/label.cc
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,23 @@ oak::label::Label AuthorizationBearerTokenLabel(const std::string& authorization
return label;
}

oak::label::Label WebAssemblyModuleLabel(const std::string& web_assembly_module_hash_sha_256) {
oak::label::Label WebAssemblyModuleHashLabel(const std::string& web_assembly_module_hash_sha_256) {
oak::label::Label label;
auto* confidentiality_tag = label.add_confidentiality_tags();
confidentiality_tag->mutable_web_assembly_module_tag()->set_web_assembly_module_hash_sha_256(
web_assembly_module_hash_sha_256);
return label;
}

oak::label::Label WebAssemblyModuleSignatureLabel(
const std::string& web_assembly_module_public_key) {
oak::label::Label label;
auto* confidentiality_tag = label.add_confidentiality_tags();
confidentiality_tag->mutable_web_assembly_module_signature_tag()->set_public_key(
web_assembly_module_public_key);
return label;
}

oak::label::Label TlsEndpointLabel(const std::string& authority) {
oak::label::Label label;
auto* confidentiality_tag = label.add_confidentiality_tags();
Expand Down
7 changes: 6 additions & 1 deletion oak/common/label.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,12 @@ oak::label::Label DeserializeLabel(const std::string& label_bytes);
oak::label::Label AuthorizationBearerTokenLabel(const std::string& authorization_token_hmac);

// Creates a label having as principal the provided WebAssembly module SHA-256 hash.
oak::label::Label WebAssemblyModuleLabel(const std::string& web_asesemblymodule_hash_sha_256);
oak::label::Label WebAssemblyModuleHashLabel(const std::string& web_asesemblymodule_hash_sha_256);

// Creates a label having as principal the provided WebAssembly module Ed25519 public key.
// https://ed25519.cr.yp.to
oak::label::Label WebAssemblyModuleSignatureLabel(
const std::string& web_assembly_module_public_key);

// Creates a label having as principal the provided TLS authority (host:port).
oak::label::Label TlsEndpointLabel(const std::string& authority);
Expand Down
1 change: 1 addition & 0 deletions oak_runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,7 @@ impl Runtime {
pub(crate) fn verify_module_signatures(&self) -> Result<(), OakStatus> {
for (name, module_bytes) in &self.application_configuration.wasm_modules {
let module_hash = sha_256_hex(&module_bytes);

// Get signature by module name.
if let Some(signatures) = self.signature_table.values.get(&module_hash) {
for signature_item in signatures.iter() {
Expand Down
38 changes: 20 additions & 18 deletions oak_runtime/src/node/wasm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

use crate::{
node::ConfigurationError, sha_256_hex, NodeMessage, NodePrivilege, NodeReadStatus,
RuntimeProxy, Signature, SignatureTable,
RuntimeProxy, SignatureTable,
};
use byteorder::{ByteOrder, LittleEndian};
use log::{debug, error, info, trace, warn};
Expand Down Expand Up @@ -815,15 +815,9 @@ impl WasmNode {
ConfigurationError::IncorrectWebAssemblyModuleName
})?;

let signatures = signature_table
.values
.get(&node_configuration.wasm_module_name)
.cloned()
.unwrap_or_default();

// We compute the node privilege once and for all at start and just store it, since it does
// not change throughout the node execution.
let node_privilege = wasm_node_privilege(&wasm_module_bytes, signatures.as_ref());
let node_privilege = wasm_node_privilege(&wasm_module_bytes, signature_table);

Ok(Self {
node_name: node_name.to_string(),
Expand All @@ -836,21 +830,29 @@ impl WasmNode {

/// Computes the [`NodePrivilege`] granted to a WebAssembly Node running the specified WebAssembly
/// module.
/// Created [`NodePrivilege`] consists of Wasm module hash and signature.
fn wasm_node_privilege(wasm_module_bytes: &[u8], signatures: &[Signature]) -> NodePrivilege {
let module_hash =
hex::decode(sha_256_hex(&wasm_module_bytes)).expect("Couldn't decode SHA-256 hex value");
/// Created [`NodePrivilege`] consists of Wasm module hash and any matching signatures.
fn wasm_node_privilege(
wasm_module_bytes: &[u8],
signature_table: &SignatureTable,
) -> NodePrivilege {
let module_hash = sha_256_hex(&wasm_module_bytes);
debug!("Wasm module SHA-256 hash: {:?}", module_hash);
let hash_tag = oak_abi::label::web_assembly_module_tag(&module_hash);

// Create hash tags.
let module_hash_bytes = hex::decode(&module_hash).expect("Couldn't decode SHA-256 hex value");
let hash_tag = oak_abi::label::web_assembly_module_tag(&module_hash_bytes);

let mut confidentiality_tags = hashset! { hash_tag.clone() };
let mut integrity_tags = hashset! { hash_tag };

for signature_item in signatures.iter() {
let signature_tag =
oak_abi::label::web_assembly_module_signature_tag(&signature_item.public_key);
confidentiality_tags.insert(signature_tag.clone());
integrity_tags.insert(signature_tag);
// Create signature tags.
if let Some(signatures) = signature_table.values.get(&module_hash) {
for signature_item in signatures.iter() {
let signature_tag =
oak_abi::label::web_assembly_module_signature_tag(&signature_item.public_key);
confidentiality_tags.insert(signature_tag.clone());
integrity_tags.insert(signature_tag);
}
}

NodePrivilege::new(confidentiality_tags, integrity_tags)
Expand Down
2 changes: 1 addition & 1 deletion oak_runtime/src/node/wasm/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
//

use super::*;
use crate::{RuntimeProxy, SecureServerConfiguration};
use crate::{RuntimeProxy, SecureServerConfiguration, Signature};
use maplit::hashmap;
use oak_abi::{
label::Label,
Expand Down

0 comments on commit 7d4553f

Please sign in to comment.