Skip to content

Commit

Permalink
Add centralized C++ utilities for oak::Variant.
Browse files Browse the repository at this point in the history
Library can be imported via copybara and then used in the hostlibs. This will make the present ad-hoc solution in the hostlibs obsolete, and also keeps anthing variant-related (in particular the UUID definitions) with the proto definitions in open source.

Bug: 373829620
Change-Id: I0e715126807a96fc2b48662350011d3e031a0521
  • Loading branch information
thmsbinder committed Jan 10, 2025
1 parent 177e291 commit e41a678
Show file tree
Hide file tree
Showing 5 changed files with 328 additions and 0 deletions.
45 changes: 45 additions & 0 deletions cc/utils/variant/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#
# Copyright 2025 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.
#

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

cc_library(
name = "variant",
srcs = [
"uuids.h",
"variant.cc",
],
hdrs = ["variant.h"],
deps = [
"//proto:variant_cc_proto",
"//proto/attestation:endorsement_cc_proto",
"@com_google_absl//absl/log:check",
"@com_google_absl//absl/strings",
],
)

cc_test(
name = "variant_test",
srcs = ["variant_test.cc"],
deps = [
":variant",
"//proto/attestation:endorsement_cc_proto",
"@com_google_googletest//:gtest_main",
],
)
41 changes: 41 additions & 0 deletions cc/utils/variant/uuids.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright 2025 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.
*/

#ifndef CC_UTILS_VARIANT_UUIDS_H_
#define CC_UTILS_VARIANT_UUIDS_H_

#include "absl/strings/string_view.h"

namespace oak {
namespace internal {

constexpr absl::string_view kAmdSevSnpPlatformEndorsementUuid =
"5a12d00f-48a0-4224-bff4-975c7657438f";
constexpr absl::string_view kFirmwareEndorsementUuid =
"de4a0d55-60ea-4dc6-abd1-09ed744f80ea";
constexpr absl::string_view kKernelEndorsementUuid =
"89511d65-5d35-4601-900b-1e6dbaf842b6";
constexpr absl::string_view kSystemEndorsementUuid =
"4722655d-963d-4fc9-8443-f14571dd32a2";
constexpr absl::string_view kContainerEndorsementUuid =
"7297a51f-a05d-49a1-afdb-64cdee07862d";
constexpr absl::string_view kApplicationEndorsementUuid =
"e84ed714-669d-430a-a60f-8a651e5a5503";

} // namespace internal
} // namespace oak

#endif // CC_UTILS_VARIANT_UUIDS_H_
139 changes: 139 additions & 0 deletions cc/utils/variant/variant.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*
* Copyright 2025 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.
*/

#include "cc/utils/variant/variant.h"

#include <optional>
#include <string>

#include "absl/log/check.h"
#include "absl/strings/escaping.h"
#include "absl/strings/str_replace.h"
#include "absl/strings/string_view.h"
#include "cc/utils/variant/uuids.h"
#include "proto/attestation/endorsement.pb.h"

namespace oak {
namespace {

using ::oak::attestation::v1::AmdSevSnpEndorsement;
using ::oak::attestation::v1::ApplicationEndorsement;
using ::oak::attestation::v1::ContainerEndorsement;
using ::oak::attestation::v1::FirmwareEndorsement;
using ::oak::attestation::v1::KernelEndorsement;
using ::oak::attestation::v1::SystemEndorsement;

std::string RawUuid(absl::string_view uuidHex) {
std::string strip = absl::StrReplaceAll(uuidHex, {{"-", ""}});
std::string raw;
CHECK(absl::HexStringToBytes(strip, &raw));
CHECK_EQ(raw.length(), 16u); // 128 bits
return raw;
}

template <typename T>
Variant CreateVariant(absl::string_view uuidHex, const T& message) {
std::string serialized;
CHECK(message.SerializeToString(&serialized));

Variant variant;
variant.set_id(RawUuid(uuidHex));
variant.set_value(serialized);
return variant;
}

template <typename T>
std::optional<T> ParseVariant(absl::string_view uuidHex,
const Variant& variant) {
if (RawUuid(uuidHex) != variant.id()) {
return std::nullopt;
}

T message;
message.ParseFromString(variant.value());
return message;
}

} // namespace

template <>
Variant ToVariant<AmdSevSnpEndorsement>(const AmdSevSnpEndorsement& message) {
return CreateVariant(internal::kAmdSevSnpPlatformEndorsementUuid, message);
}

template <>
Variant ToVariant<FirmwareEndorsement>(const FirmwareEndorsement& message) {
return CreateVariant(internal::kFirmwareEndorsementUuid, message);
}

template <>
Variant ToVariant<KernelEndorsement>(const KernelEndorsement& message) {
return CreateVariant(internal::kKernelEndorsementUuid, message);
}

template <>
Variant ToVariant<SystemEndorsement>(const SystemEndorsement& message) {
return CreateVariant(internal::kSystemEndorsementUuid, message);
}

template <>
Variant ToVariant<ContainerEndorsement>(const ContainerEndorsement& message) {
return CreateVariant(internal::kContainerEndorsementUuid, message);
}

template <>
Variant ToVariant<ApplicationEndorsement>(
const ApplicationEndorsement& message) {
return CreateVariant(internal::kApplicationEndorsementUuid, message);
}

template <>
std::optional<AmdSevSnpEndorsement> FromVariant(const Variant& variant) {
return ParseVariant<AmdSevSnpEndorsement>(
internal::kAmdSevSnpPlatformEndorsementUuid, variant);
}

template <>
std::optional<FirmwareEndorsement> FromVariant(const Variant& variant) {
return ParseVariant<FirmwareEndorsement>(internal::kFirmwareEndorsementUuid,
variant);
}

template <>
std::optional<KernelEndorsement> FromVariant(const Variant& variant) {
return ParseVariant<KernelEndorsement>(internal::kKernelEndorsementUuid,
variant);
}

template <>
std::optional<SystemEndorsement> FromVariant(const Variant& variant) {
return ParseVariant<SystemEndorsement>(internal::kSystemEndorsementUuid,
variant);
}

template <>
std::optional<ContainerEndorsement> FromVariant(const Variant& variant) {
return ParseVariant<ContainerEndorsement>(internal::kContainerEndorsementUuid,
variant);
}

template <>
std::optional<ApplicationEndorsement> FromVariant(const Variant& variant) {
return ParseVariant<ApplicationEndorsement>(
internal::kApplicationEndorsementUuid, variant);
}

} // namespace oak
38 changes: 38 additions & 0 deletions cc/utils/variant/variant.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2025 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.
*/

#ifndef CC_UTILS_VARIANT_VARIANT_H_
#define CC_UTILS_VARIANT_VARIANT_H_

#include <optional>

#include "proto/variant.pb.h"

namespace oak {

// Converts a proto message to a Variant proto.
// Compiles as long as we have UUID coverage for message type T.
template <typename T>
Variant ToVariant(const T& message);

// Converts a Variant proto to a proto message.
// Returns empty whenever `variant` does not contain type T.
template <typename T>
std::optional<T> FromVariant(const Variant& variant);

} // namespace oak

#endif // CC_UTILS_VARIANT_VARIANT_H_
65 changes: 65 additions & 0 deletions cc/utils/variant/variant_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright 2025 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.
*/

#include "cc/utils/variant/variant.h"

#include <string>

#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "proto/attestation/endorsement.pb.h"

namespace oak {
namespace {

using ::oak::attestation::v1::AmdSevSnpEndorsement;
using ::oak::attestation::v1::ApplicationEndorsement;
using ::oak::attestation::v1::ContainerEndorsement;
using ::oak::attestation::v1::FirmwareEndorsement;
using ::oak::attestation::v1::KernelEndorsement;
using ::oak::attestation::v1::SystemEndorsement;

template <typename T>
class VariantTest : public testing::Test {
public:
bool CompareProtos(const T& proto1, const T& proto2) {
std::string serialized1, serialized2;
EXPECT_TRUE(proto1.SerializeToString(&serialized1));
EXPECT_TRUE(proto2.SerializeToString(&serialized2));
return serialized1 == serialized2;
}

T CreateInstance() { return T(); }
};

TYPED_TEST_SUITE_P(VariantTest);

TYPED_TEST_P(VariantTest, Inverse) {
TypeParam expected = this->CreateInstance();
TypeParam actual = FromVariant<TypeParam>(ToVariant(expected)).value();
EXPECT_TRUE(this->CompareProtos(actual, expected));
}

REGISTER_TYPED_TEST_SUITE_P(VariantTest, Inverse);

using TestTypes = testing::Types<AmdSevSnpEndorsement, FirmwareEndorsement,
KernelEndorsement, SystemEndorsement,
ContainerEndorsement, ApplicationEndorsement>;

INSTANTIATE_TYPED_TEST_SUITE_P(TypedTestSuite, VariantTest, TestTypes);

} // namespace
} // namespace oak

0 comments on commit e41a678

Please sign in to comment.