cryptohome: [USS] Autogenerated flatbuffer binding

Refactor the UserSecretStash implementation to use the new helpers
autogenerated by the Python script instead of directly calling low-level
flatbuffer primitives. This greatly simplifies the USS' own
implementation and makes it much simpler to add new fields in the
future.

This commit also migrates away the unit tests from the flatbuffers
Object API to the new helpers: they're equally convenient, and the
consistency of the code improves.

BUG=b:218943323
TEST=cros_workon_make --board=$BOARD --test cryptohome

Change-Id: I5d0c2548c378eae47542538da80fc90918b52c2c
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/3456222
Reviewed-by: Yi Chou <yich@google.com>
Reviewed-by: Greg Kerr <kerrnel@chromium.org>
Reviewed-by: Daniil Lunev <dlunev@chromium.org>
Commit-Queue: Maksim Ivanov <emaxx@chromium.org>
Tested-by: Maksim Ivanov <emaxx@chromium.org>
diff --git a/cryptohome/flatbuffer_schemas/user_secret_stash_container.fbs b/cryptohome/flatbuffer_schemas/user_secret_stash_container.fbs
index 1377126..d2dcc5d 100644
--- a/cryptohome/flatbuffer_schemas/user_secret_stash_container.fbs
+++ b/cryptohome/flatbuffer_schemas/user_secret_stash_container.fbs
@@ -2,7 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-namespace cryptohome;
+// Our Python generator removes the "_serialized_" namespace when generating
+// the code, to avoid symbol clash with the code generated by flatc.
+namespace cryptohome._serialized_;
+
+// Defined the attributes that may be used in this schema file.
+attribute "secure";
+attribute "serializable";
 
 // Encryption algorithms used in the user secret stash.
 enum UserSecretStashEncryptionAlgorithm : int {
@@ -11,7 +17,8 @@
 
 // Container for the encrypted user secret stash. It can be persisted to disk
 // as-is.
-table UserSecretStashContainer {
+// TODO(b/218943323): Drop the "secure" attribute as this is persisted in clear.
+table UserSecretStashContainer (serializable, secure) {
   // The algorithm used for encrypting UserSecretStashPayload.
   encryption_algorithm:UserSecretStashEncryptionAlgorithm = null (id: 0);
   // This is the encrypted UserSecretStashPayload.
@@ -26,7 +33,8 @@
 }
 
 // Holds the USS main key, wrapped (encrypted) using an intermediate key.
-table UserSecretStashWrappedKeyBlock {
+// TODO(b/218943323): Drop the "secure" attribute as this is persisted in clear.
+table UserSecretStashWrappedKeyBlock (secure) {
   // The wrapping ID that allows the programmatic layers to identify the
   // intermediate key needed for decrypting this table.
   wrapping_id:string (id: 0);
diff --git a/cryptohome/flatbuffer_schemas/user_secret_stash_payload.fbs b/cryptohome/flatbuffer_schemas/user_secret_stash_payload.fbs
index 8c478bb..ca62f2c 100644
--- a/cryptohome/flatbuffer_schemas/user_secret_stash_payload.fbs
+++ b/cryptohome/flatbuffer_schemas/user_secret_stash_payload.fbs
@@ -2,11 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-namespace cryptohome;
+// Our Python generator removes the "_serialized_" namespace when generating
+// the code, to avoid symbol clash with the code generated by flatc.
+namespace cryptohome._serialized_;
+
+// Defined the attributes that may be used in this schema file.
+attribute "secure";
+attribute "serializable";
 
 // The user secret stash payload. Because it contains sensitive secrets, it can
 // be stored to disk only in encrypted form.
-table UserSecretStashPayload {
+table UserSecretStashPayload (serializable, secure) {
   // The raw file system key used for the, say, ext4 file encryption. The actual
   // filesystem encryption implementation used by Chrome OS changes over time.
   file_system_key:[ubyte] (id: 0);
diff --git a/cryptohome/fuzzers/user_secret_stash_parser_fuzzer.cc b/cryptohome/fuzzers/user_secret_stash_parser_fuzzer.cc
index 8ae2bcf..03389d9 100644
--- a/cryptohome/fuzzers/user_secret_stash_parser_fuzzer.cc
+++ b/cryptohome/fuzzers/user_secret_stash_parser_fuzzer.cc
@@ -17,15 +17,17 @@
 
 #include "cryptohome/crypto/aes.h"
 #include "cryptohome/cryptohome_common.h"
+#include "cryptohome/flatbuffer_schemas/user_secret_stash_container.h"
+#include "cryptohome/flatbuffer_schemas/user_secret_stash_payload.h"
 #include "cryptohome/fuzzers/blob_mutator.h"
 #include "cryptohome/user_secret_stash.h"
-#include "cryptohome/user_secret_stash_container_generated.h"
-#include "cryptohome/user_secret_stash_payload_generated.h"
 
 using brillo::Blob;
 using brillo::BlobFromString;
 using brillo::SecureBlob;
 using cryptohome::UserSecretStash;
+using cryptohome::UserSecretStashContainer;
+using cryptohome::UserSecretStashPayload;
 
 namespace {
 
@@ -46,21 +48,19 @@
 void PrepareMutatedArguments(FuzzedDataProvider* fuzzed_data_provider,
                              SecureBlob* mutated_uss_container,
                              SecureBlob* mutated_uss_main_key) {
-  flatbuffers::FlatBufferBuilder builder;
-
   // Create USS payload.
-  cryptohome::UserSecretStashPayloadT uss_payload_obj;
-  uss_payload_obj.file_system_key =
-      BlobFromString(fuzzed_data_provider->ConsumeRandomLengthString());
-  uss_payload_obj.reset_secret =
-      BlobFromString(fuzzed_data_provider->ConsumeRandomLengthString());
+  UserSecretStashPayload uss_payload_struct;
+  uss_payload_struct.file_system_key =
+      SecureBlob(fuzzed_data_provider->ConsumeRandomLengthString());
+  uss_payload_struct.reset_secret =
+      SecureBlob(fuzzed_data_provider->ConsumeRandomLengthString());
 
   // Serialize the USS payload to flatbuffer and mutate it.
-  builder.Finish(
-      cryptohome::UserSecretStashPayload::Pack(builder, &uss_payload_obj));
-  Blob uss_payload(builder.GetBufferPointer(),
-                   builder.GetBufferPointer() + builder.GetSize());
-  builder.Clear();
+  std::optional<SecureBlob> uss_payload_optional =
+      uss_payload_struct.Serialize();
+  CHECK(uss_payload_optional.has_value());
+  Blob uss_payload(uss_payload_optional.value().begin(),
+                   uss_payload_optional.value().end());
   Blob mutated_uss_payload = MutateBlob(
       uss_payload, /*min_length=*/1, /*max_length=*/1000, fuzzed_data_provider);
 
@@ -77,25 +77,25 @@
                                   &iv, &tag, &ciphertext));
 
   // Create USS container from mutated fields.
-  cryptohome::UserSecretStashContainerT uss_container_obj;
-  uss_container_obj.encryption_algorithm =
+  UserSecretStashContainer uss_container_struct;
+  uss_container_struct.encryption_algorithm =
       cryptohome::UserSecretStashEncryptionAlgorithm::AES_GCM_256;
-  uss_container_obj.ciphertext =
+  uss_container_struct.ciphertext = SecureBlob(
       MutateBlob(Blob(ciphertext.begin(), ciphertext.end()),
-                 /*min_length=*/0, /*max_length=*/1000, fuzzed_data_provider);
-  uss_container_obj.iv =
+                 /*min_length=*/0, /*max_length=*/1000, fuzzed_data_provider));
+  uss_container_struct.iv = SecureBlob(
       MutateBlob(Blob(iv.begin(), iv.end()),
-                 /*min_length=*/0, /*max_length=*/1000, fuzzed_data_provider);
-  uss_container_obj.gcm_tag =
-      MutateBlob(Blob(tag.begin(), tag.end()), /*min_length=*/0,
-                 /*max_length=*/1000, fuzzed_data_provider);
+                 /*min_length=*/0, /*max_length=*/1000, fuzzed_data_provider));
+  uss_container_struct.gcm_tag =
+      SecureBlob(MutateBlob(Blob(tag.begin(), tag.end()), /*min_length=*/0,
+                            /*max_length=*/1000, fuzzed_data_provider));
 
   // Serialize the USS container to flatbuffer and mutate it.
-  builder.Finish(
-      cryptohome::UserSecretStashContainer::Pack(builder, &uss_container_obj));
-  Blob uss_container(builder.GetBufferPointer(),
-                     builder.GetBufferPointer() + builder.GetSize());
-  builder.Clear();
+  std::optional<SecureBlob> uss_container_optional =
+      uss_container_struct.Serialize();
+  CHECK(uss_container_optional.has_value());
+  Blob uss_container(uss_container_optional.value().begin(),
+                     uss_container_optional.value().end());
   *mutated_uss_container =
       SecureBlob(MutateBlob(uss_container, /*min_length=*/0,
                             /*max_length=*/1000, fuzzed_data_provider));
diff --git a/cryptohome/libs/BUILD.gn b/cryptohome/libs/BUILD.gn
index 55cc2ab..91ab2eb 100644
--- a/cryptohome/libs/BUILD.gn
+++ b/cryptohome/libs/BUILD.gn
@@ -66,6 +66,18 @@
   sources = [ "../flatbuffer_schemas/auth_block_state.fbs" ]
 }
 
+flatbuffer("user-secret-stash-flatbuffers-binding-binary") {
+  flatc_out_dir = "bfbs"
+  flatc_args = [
+    "--binary",
+    "--schema",
+  ]
+  sources = [
+    "../flatbuffer_schemas/user_secret_stash_container.fbs",
+    "../flatbuffer_schemas/user_secret_stash_payload.fbs",
+  ]
+}
+
 # Put the generator in the same folder that the generated flatbuffers
 # reflection python library exist.
 copy("cryptohome-flatbuffers-binding-generator") {
@@ -110,12 +122,60 @@
   ]
 }
 
+action("user-secret-stash-flatbuffers-binding-generate") {
+  script = "${root_gen_dir}/python/flatbuffer_cpp_binding_generator.py"
+  inputs = [
+    "../flatbuffer_schemas/user_secret_stash_container.fbs",
+    "../flatbuffer_schemas/user_secret_stash_payload.fbs",
+  ]
+  outputs = [
+    "${root_gen_dir}/include/cryptohome/flatbuffer_schemas/user_secret_stash.h",
+    "${root_gen_dir}/include/cryptohome/flatbuffer_schemas/user_secret_stash_flatbuffer.h",
+    "${root_gen_dir}/include/cryptohome/flatbuffer_schemas/user_secret_stash_container.cc",
+    "${root_gen_dir}/include/cryptohome/flatbuffer_schemas/user_secret_stash_payload.cc",
+    "${root_gen_dir}/include/cryptohome/flatbuffer_schemas/user_secret_stash_test_utils.h",
+  ]
+  args = [
+    "--output_dir=${root_gen_dir}/include/cryptohome/flatbuffer_schemas",
+    "--guard_prefix=CRYPTOHOME_FLATBUFFER_SCHEMAS",
+    "--flatbuffer_header_include_paths",
+    "cryptohome/user_secret_stash_container_generated.h",
+    "--flatbuffer_header_include_paths",
+    "cryptohome/user_secret_stash_payload_generated.h",
+    "--flatbuffer_header_include_paths",
+    "cryptohome/flatbuffer_schemas/basic_objects.h",
+    "--impl_include_paths",
+    "cryptohome/flatbuffer_schemas/user_secret_stash_container.h",
+    "--impl_include_paths",
+    "cryptohome/flatbuffer_schemas/user_secret_stash_container_flatbuffer.h",
+    "--impl_include_paths",
+    "cryptohome/flatbuffer_schemas/user_secret_stash_payload.h",
+    "--impl_include_paths",
+    "cryptohome/flatbuffer_schemas/user_secret_stash_payload_flatbuffer.h",
+    "--impl_include_paths",
+    "cryptohome/flatbuffer_secure_allocator_bridge.h",
+    "--test_utils_header_include_path",
+    "cryptohome/flatbuffer_schemas/user_secret_stash.h",
+    "${root_gen_dir}/bfbs/user_secret_stash_container.bfbs",
+    "${root_gen_dir}/bfbs/user_secret_stash_payload.bfbs",
+  ]
+  deps = [
+    ":cryptohome-flatbuffers-binding-generator",
+    ":user-secret-stash-flatbuffers-binding-binary",
+  ]
+}
+
 source_set("cryptohome-flatbuffers-binding") {
   sources = [
     "${root_gen_dir}/include/cryptohome/flatbuffer_schemas/auth_block_state.cc",
+    "${root_gen_dir}/include/cryptohome/flatbuffer_schemas/user_secret_stash_container.cc",
+    "${root_gen_dir}/include/cryptohome/flatbuffer_schemas/user_secret_stash_payload.cc",
   ]
   configs += [ ":target_defaults" ]
-  deps = [ ":cryptohome-flatbuffers-binding-generate" ]
+  deps = [
+    ":cryptohome-flatbuffers-binding-generate",
+    ":user-secret-stash-flatbuffers-binding-generate",
+  ]
 }
 
 flatbuffer("cryptohome-flatbuffers") {
diff --git a/cryptohome/user_secret_stash.cc b/cryptohome/user_secret_stash.cc
index 399a063..11a7131 100644
--- a/cryptohome/user_secret_stash.cc
+++ b/cryptohome/user_secret_stash.cc
@@ -22,9 +22,8 @@
 #include "cryptohome/crypto/aes.h"
 #include "cryptohome/crypto/secure_blob_util.h"
 #include "cryptohome/cryptohome_common.h"
-#include "cryptohome/flatbuffer_secure_allocator_bridge.h"
-#include "cryptohome/user_secret_stash_container_generated.h"
-#include "cryptohome/user_secret_stash_payload_generated.h"
+#include "cryptohome/flatbuffer_schemas/user_secret_stash_container.h"
+#include "cryptohome/flatbuffer_schemas/user_secret_stash_payload.h"
 
 namespace cryptohome {
 
@@ -43,221 +42,132 @@
   return base::PathExists(base::FilePath(kUssExperimentFlagPath));
 }
 
-// Serializes the UserSecretStashWrappedKeyBlock table into the given flatbuffer
-// builder. Returns the flatbuffer offset, to be used for building the outer
-// table.
-flatbuffers::Offset<UserSecretStashWrappedKeyBlock>
-GenerateUserSecretStashWrappedKeyBlock(
-    const std::string& wrapping_id,
-    const UserSecretStash::WrappedKeyBlock& wrapped_key_block,
-    flatbuffers::FlatBufferBuilder* builder) {
-  // Serialize the table's fields.
-  auto wrapping_id_string = builder->CreateString(wrapping_id);
-  auto encrypted_key_vector =
-      builder->CreateVector(wrapped_key_block.encrypted_key.data(),
-                            wrapped_key_block.encrypted_key.size());
-  auto iv_vector = builder->CreateVector(wrapped_key_block.iv.data(),
-                                         wrapped_key_block.iv.size());
-  auto gcm_tag_vector = builder->CreateVector(wrapped_key_block.gcm_tag.data(),
-                                              wrapped_key_block.gcm_tag.size());
-
-  // Serialize the table itself.
-  UserSecretStashWrappedKeyBlockBuilder table_builder(*builder);
-  table_builder.add_wrapping_id(wrapping_id_string);
-  table_builder.add_encryption_algorithm(
-      wrapped_key_block.encryption_algorithm);
-  table_builder.add_encrypted_key(encrypted_key_vector);
-  table_builder.add_iv(iv_vector);
-  table_builder.add_gcm_tag(gcm_tag_vector);
-  return table_builder.Finish();
-}
-
-// Serializes the UserSecretStashContainer table. Returns the resulting
-// flatbuffer as a blob.
-brillo::SecureBlob GenerateUserSecretStashContainer(
-    const brillo::SecureBlob& ciphertext,
-    const brillo::SecureBlob& tag,
-    const brillo::SecureBlob& iv,
-    const std::map<std::string, UserSecretStash::WrappedKeyBlock>&
-        wrapped_key_blocks) {
-  FlatbufferSecureAllocatorBridge allocator;
-  flatbuffers::FlatBufferBuilder builder(/*initial_size=*/4096, &allocator,
-                                         /*own_allocator=*/false);
-
-  auto ciphertext_vector =
-      builder.CreateVector(ciphertext.data(), ciphertext.size());
-  auto tag_vector = builder.CreateVector(tag.data(), tag.size());
-  auto iv_vector = builder.CreateVector(iv.data(), iv.size());
-  std::vector<flatbuffers::Offset<UserSecretStashWrappedKeyBlock>>
-      wrapped_key_block_items;
-  for (const auto& item : wrapped_key_blocks) {
-    const std::string& wrapping_id = item.first;
-    const UserSecretStash::WrappedKeyBlock& wrapped_key_block = item.second;
-    wrapped_key_block_items.push_back(GenerateUserSecretStashWrappedKeyBlock(
-        wrapping_id, wrapped_key_block, &builder));
-  }
-  auto wrapped_key_blocks_vector =
-      builder.CreateVector(wrapped_key_block_items);
-
-  UserSecretStashContainerBuilder uss_container_builder(builder);
-  uss_container_builder.add_encryption_algorithm(
-      UserSecretStashEncryptionAlgorithm::AES_GCM_256);
-  uss_container_builder.add_ciphertext(ciphertext_vector);
-  uss_container_builder.add_gcm_tag(tag_vector);
-  uss_container_builder.add_iv(iv_vector);
-  uss_container_builder.add_wrapped_key_blocks(wrapped_key_blocks_vector);
-  auto uss_container = uss_container_builder.Finish();
-
-  builder.Finish(uss_container);
-
-  auto ret_val =
-      brillo::SecureBlob(builder.GetBufferPointer(),
-                         builder.GetBufferPointer() + builder.GetSize());
-
-  builder.Clear();
-
-  return ret_val;
-}
-
+// Converts the wrapped key block information from serializable structs
+// (autogenerated by the Python script) into the mapping from wrapping_id to
+// `UserSecretStash::WrappedKeyBlock`.
+// Malformed and duplicate entries are logged and skipped.
 std::map<std::string, UserSecretStash::WrappedKeyBlock>
-LoadUserSecretStashWrappedKeyBlocks(
-    const flatbuffers::Vector<
-        flatbuffers::Offset<UserSecretStashWrappedKeyBlock>>&
-        wrapped_key_block_vector) {
-  std::map<std::string, UserSecretStash::WrappedKeyBlock> loaded_key_blocks;
+GetKeyBlocksFromSerializableStructs(
+    const std::vector<UserSecretStashWrappedKeyBlock>& serializable_blocks) {
+  std::map<std::string, UserSecretStash::WrappedKeyBlock> key_blocks;
 
-  for (const UserSecretStashWrappedKeyBlock* wrapped_key_block :
-       wrapped_key_block_vector) {
-    std::string wrapping_id;
-    if (wrapped_key_block->wrapping_id()) {
-      wrapping_id = wrapped_key_block->wrapping_id()->str();
-    }
-    if (wrapping_id.empty()) {
+  for (const UserSecretStashWrappedKeyBlock& serializable_block :
+       serializable_blocks) {
+    if (serializable_block.wrapping_id.empty()) {
       LOG(WARNING)
           << "Ignoring UserSecretStash wrapped key block with an empty ID.";
       continue;
     }
-    if (loaded_key_blocks.count(wrapping_id)) {
+    if (key_blocks.count(serializable_block.wrapping_id)) {
       LOG(WARNING)
           << "Ignoring UserSecretStash wrapped key block with duplicate ID "
-          << wrapping_id << ".";
+          << serializable_block.wrapping_id << ".";
       continue;
     }
-    UserSecretStash::WrappedKeyBlock loaded_block;
 
-    if (!wrapped_key_block->encryption_algorithm().has_value()) {
+    if (!serializable_block.encryption_algorithm.has_value()) {
       LOG(WARNING) << "Ignoring UserSecretStash wrapped key block with an "
                       "unset algorithm";
       continue;
     }
-    if (wrapped_key_block->encryption_algorithm().value() !=
+    if (serializable_block.encryption_algorithm.value() !=
         UserSecretStashEncryptionAlgorithm::AES_GCM_256) {
       LOG(WARNING) << "Ignoring UserSecretStash wrapped key block with an "
                       "unknown algorithm: "
                    << static_cast<int>(
-                          wrapped_key_block->encryption_algorithm().value());
+                          serializable_block.encryption_algorithm.value());
       continue;
     }
-    loaded_block.encryption_algorithm =
-        wrapped_key_block->encryption_algorithm().value();
 
-    if (!wrapped_key_block->encrypted_key() ||
-        !wrapped_key_block->encrypted_key()->size()) {
+    if (serializable_block.encrypted_key.empty()) {
       LOG(WARNING) << "Ignoring UserSecretStash wrapped key block with an "
                       "empty encrypted key.";
       continue;
     }
-    loaded_block.encrypted_key.assign(
-        wrapped_key_block->encrypted_key()->begin(),
-        wrapped_key_block->encrypted_key()->end());
 
-    if (!wrapped_key_block->iv() || !wrapped_key_block->iv()->size()) {
+    if (serializable_block.iv.empty()) {
       LOG(WARNING)
           << "Ignoring UserSecretStash wrapped key block with an empty IV.";
       continue;
     }
-    loaded_block.iv.assign(wrapped_key_block->iv()->begin(),
-                           wrapped_key_block->iv()->end());
 
-    if (!wrapped_key_block->gcm_tag() ||
-        !wrapped_key_block->gcm_tag()->size()) {
+    if (serializable_block.gcm_tag.empty()) {
       LOG(WARNING) << "Ignoring UserSecretStash wrapped key block with an "
                       "empty AES-GCM tag.";
       continue;
     }
-    loaded_block.gcm_tag.assign(wrapped_key_block->gcm_tag()->begin(),
-                                wrapped_key_block->gcm_tag()->end());
 
-    loaded_key_blocks.insert({std::move(wrapping_id), std::move(loaded_block)});
+    UserSecretStash::WrappedKeyBlock key_block = {
+        .encryption_algorithm = serializable_block.encryption_algorithm.value(),
+        .encrypted_key = serializable_block.encrypted_key,
+        .iv = serializable_block.iv,
+        .gcm_tag = serializable_block.gcm_tag,
+    };
+    key_blocks.insert({serializable_block.wrapping_id, std::move(key_block)});
   }
 
-  return loaded_key_blocks;
+  return key_blocks;
 }
 
-bool LoadUserSecretStashContainer(
+// Parses the USS container flatbuffer. On success, populates `ciphertext`,
+// `iv`, `tag` and `wrapped_key_blocks`; on failure, returns false.
+bool GetContainerFromFlatbuffer(
     const brillo::SecureBlob& flatbuffer,
     brillo::SecureBlob* ciphertext,
     brillo::SecureBlob* iv,
     brillo::SecureBlob* tag,
     std::map<std::string, UserSecretStash::WrappedKeyBlock>*
         wrapped_key_blocks) {
-  flatbuffers::Verifier container_verifier(flatbuffer.data(),
-                                           flatbuffer.size());
-  if (!VerifyUserSecretStashContainerBuffer(container_verifier)) {
-    LOG(ERROR) << "The UserSecretStashContainer flatbuffer is invalid";
+  std::optional<UserSecretStashContainer> deserialized =
+      UserSecretStashContainer::Deserialize(flatbuffer);
+  if (!deserialized.has_value()) {
+    LOG(ERROR) << "Failed to deserialize UserSecretStashContainer";
     return false;
   }
 
-  auto uss_container = GetUserSecretStashContainer(flatbuffer.data());
-
-  if (!uss_container->encryption_algorithm().has_value()) {
+  if (!deserialized.value().encryption_algorithm.has_value()) {
     LOG(ERROR) << "UserSecretStashContainer has no algorithm set";
     return false;
   }
-  UserSecretStashEncryptionAlgorithm algorithm =
-      uss_container->encryption_algorithm().value();
-  if (algorithm != UserSecretStashEncryptionAlgorithm::AES_GCM_256) {
+  if (deserialized.value().encryption_algorithm.value() !=
+      UserSecretStashEncryptionAlgorithm::AES_GCM_256) {
     LOG(ERROR) << "UserSecretStashContainer uses unknown algorithm: "
-               << static_cast<int>(algorithm);
+               << static_cast<int>(deserialized->encryption_algorithm.value());
     return false;
   }
 
-  if (!uss_container->ciphertext() || !uss_container->ciphertext()->size()) {
+  if (deserialized.value().ciphertext.empty()) {
     LOG(ERROR) << "UserSecretStash has empty ciphertext";
     return false;
   }
-  ciphertext->assign(uss_container->ciphertext()->begin(),
-                     uss_container->ciphertext()->end());
+  *ciphertext = deserialized.value().ciphertext;
 
-  if (!uss_container->iv() || !uss_container->iv()->size()) {
+  if (deserialized.value().iv.empty()) {
     LOG(ERROR) << "UserSecretStash has empty IV";
     return false;
   }
-  if (uss_container->iv()->size() != kAesGcmIVSize) {
+  if (deserialized.value().iv.size() != kAesGcmIVSize) {
     LOG(ERROR) << "UserSecretStash has IV of wrong length: "
-               << uss_container->iv()->size()
+               << deserialized.value().iv.size()
                << ", expected: " << kAesGcmIVSize;
     return false;
   }
-  iv->assign(uss_container->iv()->begin(), uss_container->iv()->end());
+  *iv = deserialized.value().iv;
 
-  if (!uss_container->gcm_tag() || !uss_container->gcm_tag()->size()) {
+  if (deserialized.value().gcm_tag.empty()) {
     LOG(ERROR) << "UserSecretStash has empty AES-GCM tag";
     return false;
   }
-  if (uss_container->gcm_tag()->size() != kAesGcmTagSize) {
+  if (deserialized.value().gcm_tag.size() != kAesGcmTagSize) {
     LOG(ERROR) << "UserSecretStash has AES-GCM tag of wrong length: "
-               << uss_container->gcm_tag()->size()
+               << deserialized.value().gcm_tag.size()
                << ", expected: " << kAesGcmTagSize;
     return false;
   }
-  tag->assign(uss_container->gcm_tag()->begin(),
-              uss_container->gcm_tag()->end());
+  *tag = deserialized.value().gcm_tag;
 
-  if (uss_container->wrapped_key_blocks()) {
-    *wrapped_key_blocks = LoadUserSecretStashWrappedKeyBlocks(
-        *uss_container->wrapped_key_blocks());
-  }
+  *wrapped_key_blocks = GetKeyBlocksFromSerializableStructs(
+      deserialized.value().wrapped_key_blocks);
 
   return true;
 }
@@ -366,8 +276,8 @@
 
   brillo::SecureBlob ciphertext, iv, gcm_tag;
   std::map<std::string, WrappedKeyBlock> wrapped_key_blocks;
-  if (!LoadUserSecretStashContainer(flatbuffer, &ciphertext, &iv, &gcm_tag,
-                                    &wrapped_key_blocks)) {
+  if (!GetContainerFromFlatbuffer(flatbuffer, &ciphertext, &iv, &gcm_tag,
+                                  &wrapped_key_blocks)) {
     // Note: the error is already logged.
     return nullptr;
   }
@@ -390,34 +300,26 @@
     return nullptr;
   }
 
-  flatbuffers::Verifier payload_verifier(serialized_uss_payload.data(),
-                                         serialized_uss_payload.size());
-  if (!VerifyUserSecretStashPayloadBuffer(payload_verifier)) {
-    LOG(ERROR) << "The UserSecretStashPayload flatbuffer is invalid";
+  std::optional<UserSecretStashPayload> uss_payload =
+      UserSecretStashPayload::Deserialize(serialized_uss_payload);
+  if (!uss_payload.has_value()) {
+    LOG(ERROR) << "Failed to deserialize UserSecretStashPayload";
     return nullptr;
   }
 
-  auto uss_payload = GetUserSecretStashPayload(serialized_uss_payload.data());
-
-  if (!uss_payload->file_system_key() ||
-      !uss_payload->file_system_key()->size()) {
+  if (uss_payload.value().file_system_key.empty()) {
     LOG(ERROR) << "UserSecretStashPayload has no file system key";
     return nullptr;
   }
-  brillo::SecureBlob file_system_key(uss_payload->file_system_key()->begin(),
-                                     uss_payload->file_system_key()->end());
-
-  if (!uss_payload->reset_secret() || !uss_payload->reset_secret()->size()) {
+  if (uss_payload.value().reset_secret.empty()) {
     LOG(ERROR) << "UserSecretStashPayload has no reset secret";
     return nullptr;
   }
-  brillo::SecureBlob reset_secret(uss_payload->reset_secret()->begin(),
-                                  uss_payload->reset_secret()->end());
 
   // Note: make_unique() wouldn't work due to the constructor being private.
-  std::unique_ptr<UserSecretStash> stash(
-      new UserSecretStash(file_system_key, reset_secret));
-  stash->wrapped_key_blocks_ = std::move(wrapped_key_blocks);
+  std::unique_ptr<UserSecretStash> stash(new UserSecretStash(
+      uss_payload.value().file_system_key, uss_payload.value().reset_secret));
+  stash->wrapped_key_blocks_ = wrapped_key_blocks;
 
   return stash;
 }
@@ -431,8 +333,8 @@
     brillo::SecureBlob* main_key) {
   brillo::SecureBlob ciphertext, iv, gcm_tag;
   std::map<std::string, WrappedKeyBlock> wrapped_key_blocks;
-  if (!LoadUserSecretStashContainer(flatbuffer, &ciphertext, &iv, &gcm_tag,
-                                    &wrapped_key_blocks)) {
+  if (!GetContainerFromFlatbuffer(flatbuffer, &ciphertext, &iv, &gcm_tag,
+                                  &wrapped_key_blocks)) {
     // Note: the error is already logged.
     return nullptr;
   }
@@ -543,40 +445,50 @@
 
 std::optional<brillo::SecureBlob> UserSecretStash::GetEncryptedContainer(
     const brillo::SecureBlob& main_key) {
-  FlatbufferSecureAllocatorBridge allocator;
-  flatbuffers::FlatBufferBuilder builder(/*initial_size=*/4096, &allocator,
-                                         /*own_allocator=*/false);
-
-  auto fs_key_vector =
-      builder.CreateVector(file_system_key_.data(), file_system_key_.size());
-  auto reset_secret_vector =
-      builder.CreateVector(reset_secret_.data(), reset_secret_.size());
-
-  UserSecretStashPayloadBuilder uss_builder(builder);
-  uss_builder.add_file_system_key(fs_key_vector);
-  uss_builder.add_reset_secret(reset_secret_vector);
-  auto uss = uss_builder.Finish();
-
-  builder.Finish(uss);
-
-  brillo::SecureBlob serialized_uss(
-      builder.GetBufferPointer(),
-      builder.GetBufferPointer() + builder.GetSize());
+  UserSecretStashPayload payload = {
+      .file_system_key = file_system_key_,
+      .reset_secret = reset_secret_,
+  };
+  std::optional<brillo::SecureBlob> serialized_payload = payload.Serialize();
+  if (!serialized_payload.has_value()) {
+    LOG(ERROR) << "Failed to serialize UserSecretStashPayload";
+    return std::nullopt;
+  }
 
   brillo::SecureBlob tag, iv, ciphertext;
-  if (!AesGcmEncrypt(serialized_uss, /*ad=*/std::nullopt, main_key, &iv, &tag,
-                     &ciphertext)) {
+  if (!AesGcmEncrypt(serialized_payload.value(), /*ad=*/std::nullopt, main_key,
+                     &iv, &tag, &ciphertext)) {
     LOG(ERROR) << "Failed to encrypt UserSecretStash";
     return std::nullopt;
   }
 
-  builder.Clear();
-
+  UserSecretStashContainer container = {
+      .encryption_algorithm = UserSecretStashEncryptionAlgorithm::AES_GCM_256,
+      .ciphertext = ciphertext,
+      .iv = iv,
+      .gcm_tag = tag,
+  };
   // Note: It can happen that the USS container is created with empty
   // |wrapped_key_blocks_| - they may be added later, when the user registers
   // the first credential with their cryptohome.
-  return GenerateUserSecretStashContainer(ciphertext, tag, iv,
-                                          wrapped_key_blocks_);
+  for (const auto& item : wrapped_key_blocks_) {
+    const std::string& wrapping_id = item.first;
+    const UserSecretStash::WrappedKeyBlock& wrapped_key_block = item.second;
+    container.wrapped_key_blocks.push_back(UserSecretStashWrappedKeyBlock{
+        .wrapping_id = wrapping_id,
+        .encryption_algorithm = wrapped_key_block.encryption_algorithm,
+        .encrypted_key = wrapped_key_block.encrypted_key,
+        .iv = wrapped_key_block.iv,
+        .gcm_tag = wrapped_key_block.gcm_tag,
+    });
+  }
+
+  std::optional<brillo::SecureBlob> serialized_contaner = container.Serialize();
+  if (!serialized_contaner.has_value()) {
+    LOG(ERROR) << "Failed to serialize UserSecretStashContainer";
+    return std::nullopt;
+  }
+  return serialized_contaner.value();
 }
 
 UserSecretStash::UserSecretStash(const brillo::SecureBlob& file_system_key,
diff --git a/cryptohome/user_secret_stash.h b/cryptohome/user_secret_stash.h
index c48ecc7..4969c05 100644
--- a/cryptohome/user_secret_stash.h
+++ b/cryptohome/user_secret_stash.h
@@ -13,8 +13,7 @@
 #include <optional>
 #include <string>
 
-#include "cryptohome/flatbuffer_secure_allocator_bridge.h"
-#include "cryptohome/user_secret_stash_container_generated.h"
+#include "cryptohome/flatbuffer_schemas/user_secret_stash_container.h"
 
 namespace cryptohome {
 
diff --git a/cryptohome/user_secret_stash_unittest.cc b/cryptohome/user_secret_stash_unittest.cc
index 60dfce8..72fde09 100644
--- a/cryptohome/user_secret_stash_unittest.cc
+++ b/cryptohome/user_secret_stash_unittest.cc
@@ -8,13 +8,15 @@
 #include <gtest/gtest.h>
 
 #include <algorithm>
+#include <limits>
 #include <memory>
 #include <optional>
+#include <type_traits>
 #include <utility>
 
 #include "cryptohome/crypto/aes.h"
-#include "cryptohome/user_secret_stash_container_generated.h"
-#include "cryptohome/user_secret_stash_payload_generated.h"
+#include "cryptohome/flatbuffer_schemas/user_secret_stash_container.h"
+#include "cryptohome/flatbuffer_schemas/user_secret_stash_payload.h"
 
 namespace cryptohome {
 
@@ -259,115 +261,114 @@
 }
 
 // Fixture that helps to read/manipulate the USS flatbuffer's internals using
-// FlatBuffers Object API.
-class UserSecretStashObjectApiTest : public UserSecretStashTest {
+// the flatbuffer C++ bindings.
+class UserSecretStashInternalsTest : public UserSecretStashTest {
  protected:
   void SetUp() override {
     ASSERT_NO_FATAL_FAILURE(UserSecretStashTest::SetUp());
-    ASSERT_NO_FATAL_FAILURE(UpdateObjectApiState());
+    ASSERT_NO_FATAL_FAILURE(UpdateBindingStrusts());
   }
 
-  // Populates |uss_container_obj_| and |uss_payload_obj_| based on |stash_|.
-  void UpdateObjectApiState() {
+  // Populates |uss_container_struct_| and |uss_payload_struct_| based on
+  // |stash_|.
+  void UpdateBindingStrusts() {
     // Encrypt the USS.
     std::optional<brillo::SecureBlob> uss_container =
         stash_->GetEncryptedContainer(kMainKey);
     ASSERT_TRUE(uss_container);
 
-    // Unpack the wrapped USS flatbuffer to |uss_container_obj_|.
-    std::unique_ptr<UserSecretStashContainerT> uss_container_obj_ptr =
-        UnPackUserSecretStashContainer(uss_container->data());
-    ASSERT_TRUE(uss_container_obj_ptr);
-    uss_container_obj_ = std::move(*uss_container_obj_ptr);
+    // Unpack the wrapped USS flatbuffer to |uss_container_struct_|.
+    std::optional<UserSecretStashContainer> uss_container_struct =
+        UserSecretStashContainer::Deserialize(uss_container.value());
+    ASSERT_TRUE(uss_container_struct);
+    uss_container_struct_ = std::move(uss_container_struct.value());
 
-    // Decrypt and unpack the USS flatbuffer to |uss_payload_obj_|.
+    // Decrypt and unpack the USS flatbuffer to |uss_payload_struct_|.
     brillo::SecureBlob uss_payload;
     ASSERT_TRUE(AesGcmDecrypt(
-        brillo::SecureBlob(uss_container_obj_.ciphertext),
-        /*ad=*/std::nullopt, brillo::SecureBlob(uss_container_obj_.gcm_tag),
-        kMainKey, brillo::SecureBlob(uss_container_obj_.iv), &uss_payload));
-    std::unique_ptr<UserSecretStashPayloadT> uss_payload_obj_ptr =
-        UnPackUserSecretStashPayload(uss_payload.data());
-    ASSERT_TRUE(uss_payload_obj_ptr);
-    uss_payload_obj_ = std::move(*uss_payload_obj_ptr);
+        brillo::SecureBlob(uss_container_struct_.ciphertext),
+        /*ad=*/std::nullopt, brillo::SecureBlob(uss_container_struct_.gcm_tag),
+        kMainKey, brillo::SecureBlob(uss_container_struct_.iv), &uss_payload));
+    std::optional<UserSecretStashPayload> uss_payload_struct =
+        UserSecretStashPayload::Deserialize(uss_payload);
+    ASSERT_TRUE(uss_payload_struct);
+    uss_payload_struct_ = std::move(*uss_payload_struct);
   }
 
-  // Converts |uss_container_obj_| => "container flatbuffer".
-  brillo::SecureBlob GetFlatbufferFromUssContainerObj() const {
-    flatbuffers::FlatBufferBuilder builder;
-    builder.Finish(
-        UserSecretStashContainer::Pack(builder, &uss_container_obj_));
-    return brillo::SecureBlob(builder.GetBufferPointer(),
-                              builder.GetBufferPointer() + builder.GetSize());
+  // Converts |uss_container_struct_| => "container flatbuffer".
+  brillo::SecureBlob GetFlatbufferFromUssContainerStruct() const {
+    std::optional<brillo::SecureBlob> serialized =
+        uss_container_struct_.Serialize();
+    if (!serialized.has_value()) {
+      ADD_FAILURE() << "Failed to serialized UserSecretStashContainer";
+      return brillo::SecureBlob();
+    }
+    return serialized.value();
   }
 
-  // Converts |uss_payload_obj_| => "payload flatbuffer" =>
+  // Converts |uss_payload_struct_| => "payload flatbuffer" =>
   // UserSecretStashContainer => "container flatbuffer".
-  brillo::SecureBlob GetFlatbufferFromUssPayloadObj() const {
-    return GetFlatbufferFromUssPayloadBlob(PackUssPayloadObj());
+  brillo::SecureBlob GetFlatbufferFromUssPayloadStruct() const {
+    return GetFlatbufferFromUssPayloadBlob(PackUssPayloadStruct());
   }
 
-  // Converts |uss_payload_obj_| => "payload flatbuffer".
-  brillo::SecureBlob PackUssPayloadObj() const {
-    flatbuffers::FlatBufferBuilder builder;
-    builder.Finish(UserSecretStashPayload::Pack(builder, &uss_payload_obj_));
-    return brillo::SecureBlob(builder.GetBufferPointer(),
-                              builder.GetBufferPointer() + builder.GetSize());
+  // Converts |uss_payload_struct_| => "payload flatbuffer".
+  brillo::SecureBlob PackUssPayloadStruct() const {
+    std::optional<brillo::SecureBlob> serialized =
+        uss_payload_struct_.Serialize();
+    if (!serialized.has_value()) {
+      ADD_FAILURE() << "Failed to serialized UserSecretStashPayload";
+      return brillo::SecureBlob();
+    }
+    return serialized.value();
   }
 
   // Converts "payload flatbuffer" => UserSecretStashContainer => "container
   // flatbuffer".
   brillo::SecureBlob GetFlatbufferFromUssPayloadBlob(
       const brillo::SecureBlob& uss_payload) const {
-    // Encrypt the packed |uss_payload_obj_|.
+    // Encrypt the packed |uss_payload_struct_|.
     brillo::SecureBlob iv, tag, ciphertext;
     EXPECT_TRUE(AesGcmEncrypt(uss_payload, /*ad=*/std::nullopt, kMainKey, &iv,
                               &tag, &ciphertext));
 
-    // Create a copy of |uss_container_obj_|, with the encrypted blob replaced.
-    UserSecretStashContainerT new_uss_container_obj;
-    new_uss_container_obj.encryption_algorithm =
-        uss_container_obj_.encryption_algorithm;
-    new_uss_container_obj.ciphertext.assign(ciphertext.begin(),
-                                            ciphertext.end());
-    new_uss_container_obj.iv.assign(iv.begin(), iv.end());
-    new_uss_container_obj.gcm_tag.assign(tag.begin(), tag.end());
-    // Need to clone the nested tables manually, as Flatbuffers don't provide a
-    // copy constructor.
-    for (const std::unique_ptr<UserSecretStashWrappedKeyBlockT>& key_block :
-         uss_container_obj_.wrapped_key_blocks) {
-      new_uss_container_obj.wrapped_key_blocks.push_back(
-          std::make_unique<UserSecretStashWrappedKeyBlockT>(*key_block));
-    }
+    // Create a copy of |uss_container_struct_|, with the encrypted blob
+    // replaced.
+    UserSecretStashContainer new_uss_container_struct = uss_container_struct_;
+    new_uss_container_struct.ciphertext = ciphertext;
+    new_uss_container_struct.iv = iv;
+    new_uss_container_struct.gcm_tag = tag;
 
-    // Pack |new_uss_container_obj|.
-    flatbuffers::FlatBufferBuilder builder;
-    builder.Finish(
-        UserSecretStashContainer::Pack(builder, &new_uss_container_obj));
-    return brillo::SecureBlob(builder.GetBufferPointer(),
-                              builder.GetBufferPointer() + builder.GetSize());
+    // Pack |new_uss_container_struct|.
+    std::optional<brillo::SecureBlob> serialized =
+        new_uss_container_struct.Serialize();
+    if (!serialized.has_value()) {
+      ADD_FAILURE() << "Failed to seralize the USS container";
+      return brillo::SecureBlob();
+    }
+    return serialized.value();
   }
 
-  UserSecretStashContainerT uss_container_obj_;
-  UserSecretStashPayloadT uss_payload_obj_;
+  UserSecretStashContainer uss_container_struct_;
+  UserSecretStashPayload uss_payload_struct_;
 };
 
-// Verify that the test fixture correctly generates the flatbuffers from the
-// Object API.
-TEST_F(UserSecretStashObjectApiTest, SmokeTest) {
+// Verify that the test fixture correctly generates the USS flatbuffers from the
+// binding structs.
+TEST_F(UserSecretStashInternalsTest, SmokeTest) {
   EXPECT_TRUE(UserSecretStash::FromEncryptedContainer(
-      GetFlatbufferFromUssPayloadBlob(PackUssPayloadObj()), kMainKey));
+      GetFlatbufferFromUssPayloadBlob(PackUssPayloadStruct()), kMainKey));
   EXPECT_TRUE(UserSecretStash::FromEncryptedContainer(
-      GetFlatbufferFromUssPayloadObj(), kMainKey));
+      GetFlatbufferFromUssPayloadStruct(), kMainKey));
   EXPECT_TRUE(UserSecretStash::FromEncryptedContainer(
-      GetFlatbufferFromUssContainerObj(), kMainKey));
+      GetFlatbufferFromUssContainerStruct(), kMainKey));
 }
 
 // Test that decryption fails when the USS payload is a corrupted flatbuffer.
 // Normally this never occurs, but we verify to be resilient against accidental
 // or intentional file corruption.
-TEST_F(UserSecretStashObjectApiTest, DecryptErrorBadPayload) {
-  brillo::SecureBlob uss_payload = PackUssPayloadObj();
+TEST_F(UserSecretStashInternalsTest, DecryptErrorBadPayload) {
+  brillo::SecureBlob uss_payload = PackUssPayloadStruct();
   for (uint8_t& byte : uss_payload)
     byte ^= 1;
 
@@ -378,8 +379,8 @@
 // Test that decryption fails when the USS payload is a truncated flatbuffer.
 // Normally this never occurs, but we verify to be resilient against accidental
 // or intentional file corruption.
-TEST_F(UserSecretStashObjectApiTest, DecryptErrorPayloadBadSize) {
-  brillo::SecureBlob uss_payload = PackUssPayloadObj();
+TEST_F(UserSecretStashInternalsTest, DecryptErrorPayloadBadSize) {
+  brillo::SecureBlob uss_payload = PackUssPayloadStruct();
   uss_payload.resize(uss_payload.size() / 2);
 
   EXPECT_FALSE(UserSecretStash::FromEncryptedContainer(
@@ -389,147 +390,147 @@
 // Test that decryption fails when the encryption algorithm is not set. Normally
 // this never occurs, but we verify to be resilient against accidental or
 // intentional file corruption.
-TEST_F(UserSecretStashObjectApiTest, DecryptErrorNoAlgorithm) {
-  uss_container_obj_.encryption_algorithm.reset();
+TEST_F(UserSecretStashInternalsTest, DecryptErrorNoAlgorithm) {
+  uss_container_struct_.encryption_algorithm.reset();
 
   EXPECT_FALSE(UserSecretStash::FromEncryptedContainer(
-      GetFlatbufferFromUssContainerObj(), kMainKey));
+      GetFlatbufferFromUssContainerStruct(), kMainKey));
 }
 
 // Test that decryption fails when the encryption algorithm is unknown. Normally
 // this never occurs, but we verify to be resilient against accidental or
 // intentional file corruption.
-TEST_F(UserSecretStashObjectApiTest, DecryptErrorUnknownAlgorithm) {
-  // It's OK to increment MAX and get an unknown enum, since the schema defines
-  // the enum's underlying type to be a 32-bit int.
-  uss_container_obj_.encryption_algorithm =
-      static_cast<UserSecretStashEncryptionAlgorithm>(
-          static_cast<int>(UserSecretStashEncryptionAlgorithm::MAX) + 1);
+TEST_F(UserSecretStashInternalsTest, DecryptErrorUnknownAlgorithm) {
+  uss_container_struct_
+      .encryption_algorithm = static_cast<UserSecretStashEncryptionAlgorithm>(
+      std::numeric_limits<
+          std::underlying_type_t<UserSecretStashEncryptionAlgorithm>>::max());
 
   EXPECT_FALSE(UserSecretStash::FromEncryptedContainer(
-      GetFlatbufferFromUssContainerObj(), kMainKey));
+      GetFlatbufferFromUssContainerStruct(), kMainKey));
 }
 
 // Test that decryption fails when the ciphertext field is missing. Normally
 // this never occurs, but we verify to be resilient against accidental or
 // intentional file corruption.
-TEST_F(UserSecretStashObjectApiTest, DecryptErrorNoCiphertext) {
-  uss_container_obj_.ciphertext.clear();
+TEST_F(UserSecretStashInternalsTest, DecryptErrorNoCiphertext) {
+  uss_container_struct_.ciphertext.clear();
 
   EXPECT_FALSE(UserSecretStash::FromEncryptedContainer(
-      GetFlatbufferFromUssContainerObj(), kMainKey));
+      GetFlatbufferFromUssContainerStruct(), kMainKey));
 }
 
 // Test that decryption fails when the ciphertext field is corrupted. Normally
 // this never occurs, but we verify to be resilient against accidental or
 // intentional file corruption.
-TEST_F(UserSecretStashObjectApiTest, DecryptErrorCorruptedCiphertext) {
-  for (uint8_t& byte : uss_container_obj_.ciphertext)
+TEST_F(UserSecretStashInternalsTest, DecryptErrorCorruptedCiphertext) {
+  for (uint8_t& byte : uss_container_struct_.ciphertext)
     byte ^= 1;
 
   EXPECT_FALSE(UserSecretStash::FromEncryptedContainer(
-      GetFlatbufferFromUssContainerObj(), kMainKey));
+      GetFlatbufferFromUssContainerStruct(), kMainKey));
 }
 
 // Test that decryption fails when the iv field is missing. Normally this never
 // occurs, but we verify to be resilient against accidental or intentional file
 // corruption.
-TEST_F(UserSecretStashObjectApiTest, DecryptErrorNoIv) {
-  uss_container_obj_.iv.clear();
+TEST_F(UserSecretStashInternalsTest, DecryptErrorNoIv) {
+  uss_container_struct_.iv.clear();
 
   EXPECT_FALSE(UserSecretStash::FromEncryptedContainer(
-      GetFlatbufferFromUssContainerObj(), kMainKey));
+      GetFlatbufferFromUssContainerStruct(), kMainKey));
 }
 
 // Test that decryption fails when the iv field has a wrong value. Normally this
 // never occurs, but we verify to be resilient against accidental or intentional
 // file corruption.
-TEST_F(UserSecretStashObjectApiTest, DecryptErrorWrongIv) {
-  uss_container_obj_.iv[0] ^= 1;
+TEST_F(UserSecretStashInternalsTest, DecryptErrorWrongIv) {
+  uss_container_struct_.iv[0] ^= 1;
 
   EXPECT_FALSE(UserSecretStash::FromEncryptedContainer(
-      GetFlatbufferFromUssContainerObj(), kMainKey));
+      GetFlatbufferFromUssContainerStruct(), kMainKey));
 }
 
 // Test that decryption fails when the iv field is of a wrong size. Normally
 // this never occurs, but we verify to be resilient against accidental or
 // intentional file corruption.
-TEST_F(UserSecretStashObjectApiTest, DecryptErrorIvBadSize) {
-  uss_container_obj_.iv.resize(uss_container_obj_.iv.size() - 1);
+TEST_F(UserSecretStashInternalsTest, DecryptErrorIvBadSize) {
+  uss_container_struct_.iv.resize(uss_container_struct_.iv.size() - 1);
 
   EXPECT_FALSE(UserSecretStash::FromEncryptedContainer(
-      GetFlatbufferFromUssContainerObj(), kMainKey));
+      GetFlatbufferFromUssContainerStruct(), kMainKey));
 }
 
 // Test that decryption fails when the gcm_tag field is missing. Normally this
 // never occurs, but we verify to be resilient against accidental or intentional
 // file corruption.
-TEST_F(UserSecretStashObjectApiTest, DecryptErrorNoGcmTag) {
-  uss_container_obj_.gcm_tag.clear();
+TEST_F(UserSecretStashInternalsTest, DecryptErrorNoGcmTag) {
+  uss_container_struct_.gcm_tag.clear();
 
   EXPECT_FALSE(UserSecretStash::FromEncryptedContainer(
-      GetFlatbufferFromUssContainerObj(), kMainKey));
+      GetFlatbufferFromUssContainerStruct(), kMainKey));
 }
 
 // Test that decryption fails when the gcm_tag field has a wrong value.
-TEST_F(UserSecretStashObjectApiTest, DecryptErrorWrongGcmTag) {
-  uss_container_obj_.gcm_tag[0] ^= 1;
+TEST_F(UserSecretStashInternalsTest, DecryptErrorWrongGcmTag) {
+  uss_container_struct_.gcm_tag[0] ^= 1;
 
   EXPECT_FALSE(UserSecretStash::FromEncryptedContainer(
-      GetFlatbufferFromUssContainerObj(), kMainKey));
+      GetFlatbufferFromUssContainerStruct(), kMainKey));
 }
 
 // Test that decryption fails when the gcm_tag field is of a wrong size.
 // Normally this never occurs, but we verify to be resilient against accidental
 // or intentional file corruption.
-TEST_F(UserSecretStashObjectApiTest, DecryptErrorGcmTagBadSize) {
-  uss_container_obj_.gcm_tag.resize(uss_container_obj_.gcm_tag.size() - 1);
+TEST_F(UserSecretStashInternalsTest, DecryptErrorGcmTagBadSize) {
+  uss_container_struct_.gcm_tag.resize(uss_container_struct_.gcm_tag.size() -
+                                       1);
 
   EXPECT_FALSE(UserSecretStash::FromEncryptedContainer(
-      GetFlatbufferFromUssContainerObj(), kMainKey));
+      GetFlatbufferFromUssContainerStruct(), kMainKey));
 }
 
 // Test the decryption fails when the payload's file_system_key field is
 // missing. Normally this never occurs, but we verify to be resilient against
 // accidental or intentional file corruption.
-TEST_F(UserSecretStashObjectApiTest, DecryptErrorNoFileSystemKey) {
-  uss_payload_obj_.file_system_key.clear();
+TEST_F(UserSecretStashInternalsTest, DecryptErrorNoFileSystemKey) {
+  uss_payload_struct_.file_system_key.clear();
 
   EXPECT_FALSE(UserSecretStash::FromEncryptedContainer(
-      GetFlatbufferFromUssPayloadObj(), kMainKey));
+      GetFlatbufferFromUssPayloadStruct(), kMainKey));
 }
 
 // Test the decryption fails when the payload's reset_secret field is missing.
 // Normally this never occurs, but we verify to be resilient against accidental
 // or intentional file corruption.
-TEST_F(UserSecretStashObjectApiTest, DecryptErrorNoResetSecret) {
-  uss_payload_obj_.reset_secret.clear();
+TEST_F(UserSecretStashInternalsTest, DecryptErrorNoResetSecret) {
+  uss_payload_struct_.reset_secret.clear();
 
   EXPECT_FALSE(UserSecretStash::FromEncryptedContainer(
-      GetFlatbufferFromUssPayloadObj(), kMainKey));
+      GetFlatbufferFromUssPayloadStruct(), kMainKey));
 }
 
 // Fixture that prebundles the USS object with a wrapped key block.
-class UserSecretStashObjectApiWrappingTest
-    : public UserSecretStashObjectApiTest {
+class UserSecretStashInternalsWrappingTest
+    : public UserSecretStashInternalsTest {
  protected:
   const char* const kWrappingId = "id";
   const brillo::SecureBlob kWrappingKey =
       brillo::SecureBlob(kAesGcm256KeySize, 0xB);
 
   void SetUp() override {
-    ASSERT_NO_FATAL_FAILURE(UserSecretStashObjectApiTest::SetUp());
+    ASSERT_NO_FATAL_FAILURE(UserSecretStashInternalsTest::SetUp());
     EXPECT_TRUE(stash_->AddWrappedMainKey(kMainKey, kWrappingId, kWrappingKey));
-    ASSERT_NO_FATAL_FAILURE(UpdateObjectApiState());
+    ASSERT_NO_FATAL_FAILURE(UpdateBindingStrusts());
   }
 };
 
 // Verify that the test fixture correctly generates the flatbuffers from the
 // Object API.
-TEST_F(UserSecretStashObjectApiWrappingTest, SmokeTest) {
+TEST_F(UserSecretStashInternalsWrappingTest, SmokeTest) {
   brillo::SecureBlob main_key;
   EXPECT_TRUE(UserSecretStash::FromEncryptedContainerWithWrappingKey(
-      GetFlatbufferFromUssContainerObj(), kWrappingId, kWrappingKey,
+      GetFlatbufferFromUssContainerStruct(), kWrappingId, kWrappingKey,
       &main_key));
   EXPECT_EQ(main_key, kMainKey);
 }
@@ -537,12 +538,12 @@
 // Test that decryption via wrapping key fails when the only block's wrapping_id
 // is empty. Normally this never occurs, but we verify to be resilient against
 // accidental or intentional file corruption.
-TEST_F(UserSecretStashObjectApiWrappingTest, ErrorNoWrappingId) {
-  uss_container_obj_.wrapped_key_blocks[0]->wrapping_id = std::string();
+TEST_F(UserSecretStashInternalsWrappingTest, ErrorNoWrappingId) {
+  uss_container_struct_.wrapped_key_blocks[0].wrapping_id = std::string();
 
   brillo::SecureBlob main_key;
   EXPECT_FALSE(UserSecretStash::FromEncryptedContainerWithWrappingKey(
-      GetFlatbufferFromUssContainerObj(), kWrappingId, kWrappingKey,
+      GetFlatbufferFromUssContainerStruct(), kWrappingId, kWrappingKey,
       &main_key));
 }
 
@@ -550,15 +551,15 @@
 // with an empty wrapping_id (this block should be ignored). Normally this never
 // occurs, but we verify to be resilient against accidental or intentional file
 // corruption.
-TEST_F(UserSecretStashObjectApiWrappingTest, SuccessWithExtraNoWrappingId) {
-  auto bad_key_block = std::make_unique<UserSecretStashWrappedKeyBlockT>(
-      *uss_container_obj_.wrapped_key_blocks[0]);
-  bad_key_block->wrapping_id = std::string();
-  uss_container_obj_.wrapped_key_blocks.push_back(std::move(bad_key_block));
+TEST_F(UserSecretStashInternalsWrappingTest, SuccessWithExtraNoWrappingId) {
+  UserSecretStashWrappedKeyBlock key_block_clone =
+      uss_container_struct_.wrapped_key_blocks[0];
+  key_block_clone.wrapping_id = std::string();
+  uss_container_struct_.wrapped_key_blocks.push_back(key_block_clone);
 
   brillo::SecureBlob main_key;
   EXPECT_TRUE(UserSecretStash::FromEncryptedContainerWithWrappingKey(
-      GetFlatbufferFromUssContainerObj(), kWrappingId, kWrappingKey,
+      GetFlatbufferFromUssContainerStruct(), kWrappingId, kWrappingKey,
       &main_key));
 }
 
@@ -566,139 +567,138 @@
 // with a duplicate wrapping_id (this block should be ignored). Normally this
 // never occurs, but we verify to be resilient against accidental or intentional
 // file corruption.
-TEST_F(UserSecretStashObjectApiWrappingTest, SuccessWithDuplicateWrappingId) {
-  auto key_block_clone = std::make_unique<UserSecretStashWrappedKeyBlockT>(
-      *uss_container_obj_.wrapped_key_blocks[0]);
-  uss_container_obj_.wrapped_key_blocks.push_back(std::move(key_block_clone));
+TEST_F(UserSecretStashInternalsWrappingTest, SuccessWithDuplicateWrappingId) {
+  UserSecretStashWrappedKeyBlock key_block_clone =
+      uss_container_struct_.wrapped_key_blocks[0];
+  uss_container_struct_.wrapped_key_blocks.push_back(key_block_clone);
 
   brillo::SecureBlob main_key;
   EXPECT_TRUE(UserSecretStash::FromEncryptedContainerWithWrappingKey(
-      GetFlatbufferFromUssContainerObj(), kWrappingId, kWrappingKey,
+      GetFlatbufferFromUssContainerStruct(), kWrappingId, kWrappingKey,
       &main_key));
 }
 
 // Test that decryption via wrapping key fails when the algorithm is not
 // specified in the stored block. Normally this never occurs, but we verify to
 // be resilient against accidental or intentional file corruption.
-TEST_F(UserSecretStashObjectApiWrappingTest, ErrorNoAlgorithm) {
-  uss_container_obj_.wrapped_key_blocks[0]->encryption_algorithm =
-      flatbuffers::nullopt;
+TEST_F(UserSecretStashInternalsWrappingTest, ErrorNoAlgorithm) {
+  uss_container_struct_.wrapped_key_blocks[0].encryption_algorithm =
+      std::nullopt;
 
   brillo::SecureBlob main_key;
   EXPECT_FALSE(UserSecretStash::FromEncryptedContainerWithWrappingKey(
-      GetFlatbufferFromUssContainerObj(), kWrappingId, kWrappingKey,
+      GetFlatbufferFromUssContainerStruct(), kWrappingId, kWrappingKey,
       &main_key));
 }
 
 // Test that decryption via wrapping key fails when the algorithm is unknown.
 // Normally this never occurs, but we verify to be resilient against accidental
 // or intentional file corruption.
-TEST_F(UserSecretStashObjectApiWrappingTest, ErrorUnknownAlgorithm) {
-  // It's OK to increment MAX and get an unknown enum, since the schema defines
-  // the enum's underlying type to be a 32-bit int.
-  uss_container_obj_.wrapped_key_blocks[0]->encryption_algorithm =
-      static_cast<UserSecretStashEncryptionAlgorithm>(
-          static_cast<int>(UserSecretStashEncryptionAlgorithm::MAX) + 1);
+TEST_F(UserSecretStashInternalsWrappingTest, ErrorUnknownAlgorithm) {
+  uss_container_struct_.wrapped_key_blocks[0]
+      .encryption_algorithm = static_cast<UserSecretStashEncryptionAlgorithm>(
+      std::numeric_limits<
+          std::underlying_type_t<UserSecretStashEncryptionAlgorithm>>::max());
 
   brillo::SecureBlob main_key;
   EXPECT_FALSE(UserSecretStash::FromEncryptedContainerWithWrappingKey(
-      GetFlatbufferFromUssContainerObj(), kWrappingId, kWrappingKey,
+      GetFlatbufferFromUssContainerStruct(), kWrappingId, kWrappingKey,
       &main_key));
 }
 
 // Test that decryption via wrapping key fails when the encrypted_key is empty
 // in the stored block.
-TEST_F(UserSecretStashObjectApiWrappingTest, ErrorEmptyEncryptedKey) {
-  uss_container_obj_.wrapped_key_blocks[0]->encrypted_key.clear();
+TEST_F(UserSecretStashInternalsWrappingTest, ErrorEmptyEncryptedKey) {
+  uss_container_struct_.wrapped_key_blocks[0].encrypted_key.clear();
 
   brillo::SecureBlob main_key;
   EXPECT_FALSE(UserSecretStash::FromEncryptedContainerWithWrappingKey(
-      GetFlatbufferFromUssContainerObj(), kWrappingId, kWrappingKey,
+      GetFlatbufferFromUssContainerStruct(), kWrappingId, kWrappingKey,
       &main_key));
 }
 
 // Test that decryption via wrapping key fails when the encrypted_key in the
 // stored block is corrupted.
-TEST_F(UserSecretStashObjectApiWrappingTest, ErrorBadEncryptedKey) {
-  uss_container_obj_.wrapped_key_blocks[0]->encrypted_key[0] ^= 1;
+TEST_F(UserSecretStashInternalsWrappingTest, ErrorBadEncryptedKey) {
+  uss_container_struct_.wrapped_key_blocks[0].encrypted_key[0] ^= 1;
 
   brillo::SecureBlob main_key;
   EXPECT_FALSE(UserSecretStash::FromEncryptedContainerWithWrappingKey(
-      GetFlatbufferFromUssContainerObj(), kWrappingId, kWrappingKey,
+      GetFlatbufferFromUssContainerStruct(), kWrappingId, kWrappingKey,
       &main_key));
 }
 
 // Test that decryption via wrapping key fails when the iv is empty in the
 // stored block. Normally this never occurs, but we verify to be resilient
 // against accidental or intentional file corruption.
-TEST_F(UserSecretStashObjectApiWrappingTest, ErrorNoIv) {
-  uss_container_obj_.wrapped_key_blocks[0]->iv.clear();
+TEST_F(UserSecretStashInternalsWrappingTest, ErrorNoIv) {
+  uss_container_struct_.wrapped_key_blocks[0].iv.clear();
 
   brillo::SecureBlob main_key;
   EXPECT_FALSE(UserSecretStash::FromEncryptedContainerWithWrappingKey(
-      GetFlatbufferFromUssContainerObj(), kWrappingId, kWrappingKey,
+      GetFlatbufferFromUssContainerStruct(), kWrappingId, kWrappingKey,
       &main_key));
 }
 
 // Test that decryption via wrapping key fails when the iv in the stored block
 // is corrupted. Normally this never occurs, but we verify to be resilient
 // against accidental or intentional file corruption.
-TEST_F(UserSecretStashObjectApiWrappingTest, ErrorWrongIv) {
-  uss_container_obj_.wrapped_key_blocks[0]->iv[0] ^= 1;
+TEST_F(UserSecretStashInternalsWrappingTest, ErrorWrongIv) {
+  uss_container_struct_.wrapped_key_blocks[0].iv[0] ^= 1;
 
   brillo::SecureBlob main_key;
   EXPECT_FALSE(UserSecretStash::FromEncryptedContainerWithWrappingKey(
-      GetFlatbufferFromUssContainerObj(), kWrappingId, kWrappingKey,
+      GetFlatbufferFromUssContainerStruct(), kWrappingId, kWrappingKey,
       &main_key));
 }
 
 // Test that decryption via wrapping key fails when the iv in the stored block
 // is of wrong size. Normally this never occurs, but we verify to be resilient
 // against accidental or intentional file corruption.
-TEST_F(UserSecretStashObjectApiWrappingTest, ErrorIvBadSize) {
-  uss_container_obj_.wrapped_key_blocks[0]->iv.resize(
-      uss_container_obj_.wrapped_key_blocks[0]->iv.size() - 1);
+TEST_F(UserSecretStashInternalsWrappingTest, ErrorIvBadSize) {
+  uss_container_struct_.wrapped_key_blocks[0].iv.resize(
+      uss_container_struct_.wrapped_key_blocks[0].iv.size() - 1);
 
   brillo::SecureBlob main_key;
   EXPECT_FALSE(UserSecretStash::FromEncryptedContainerWithWrappingKey(
-      GetFlatbufferFromUssContainerObj(), kWrappingId, kWrappingKey,
+      GetFlatbufferFromUssContainerStruct(), kWrappingId, kWrappingKey,
       &main_key));
 }
 
 // Test that decryption via wrapping key fails when the gcm_tag is empty in the
 // stored block. Normally this never occurs, but we verify to be resilient
 // against accidental or intentional file corruption.
-TEST_F(UserSecretStashObjectApiWrappingTest, ErrorNoGcmTag) {
-  uss_container_obj_.wrapped_key_blocks[0]->gcm_tag.clear();
+TEST_F(UserSecretStashInternalsWrappingTest, ErrorNoGcmTag) {
+  uss_container_struct_.wrapped_key_blocks[0].gcm_tag.clear();
 
   brillo::SecureBlob main_key;
   EXPECT_FALSE(UserSecretStash::FromEncryptedContainerWithWrappingKey(
-      GetFlatbufferFromUssContainerObj(), kWrappingId, kWrappingKey,
+      GetFlatbufferFromUssContainerStruct(), kWrappingId, kWrappingKey,
       &main_key));
 }
 
 // Test that decryption via wrapping key fails when the gcm_tag in the stored
 // block is corrupted. Normally this never occurs, but we verify to be resilient
 // against accidental or intentional file corruption.
-TEST_F(UserSecretStashObjectApiWrappingTest, ErrorWrongGcmTag) {
-  uss_container_obj_.wrapped_key_blocks[0]->gcm_tag[0] ^= 1;
+TEST_F(UserSecretStashInternalsWrappingTest, ErrorWrongGcmTag) {
+  uss_container_struct_.wrapped_key_blocks[0].gcm_tag[0] ^= 1;
 
   brillo::SecureBlob main_key;
   EXPECT_FALSE(UserSecretStash::FromEncryptedContainerWithWrappingKey(
-      GetFlatbufferFromUssContainerObj(), kWrappingId, kWrappingKey,
+      GetFlatbufferFromUssContainerStruct(), kWrappingId, kWrappingKey,
       &main_key));
 }
 
 // Test that decryption via wrapping key fails when the gcm_tag in the stored
 // block is of wrong size. Normally this never occurs, but we verify to be
 // resilient against accidental or intentional file corruption.
-TEST_F(UserSecretStashObjectApiWrappingTest, ErrorGcmTagBadSize) {
-  uss_container_obj_.wrapped_key_blocks[0]->gcm_tag.resize(
-      uss_container_obj_.wrapped_key_blocks[0]->gcm_tag.size() - 1);
+TEST_F(UserSecretStashInternalsWrappingTest, ErrorGcmTagBadSize) {
+  uss_container_struct_.wrapped_key_blocks[0].gcm_tag.resize(
+      uss_container_struct_.wrapped_key_blocks[0].gcm_tag.size() - 1);
 
   brillo::SecureBlob main_key;
   EXPECT_FALSE(UserSecretStash::FromEncryptedContainerWithWrappingKey(
-      GetFlatbufferFromUssContainerObj(), kWrappingId, kWrappingKey,
+      GetFlatbufferFromUssContainerStruct(), kWrappingId, kWrappingKey,
       &main_key));
 }