Merge remote-tracking branch 'goog/upstream-master' into merge-citadel-pre-1.0.0

* goog/upstream-master:
  keymaster: add HardwareAuth & Verification Token types
  keymaster: document bootloader parameters
  Add protocol for session bound physical input events
  Add auth token HMAC key sharing protocol
  Revert "Support message CRCs in the transport protocol."
  Support message CRCs in the transport protocol.
  Retrieve repo snapshot info from Nugget OS
  Improve Nugget OS version reporting
  NUGGET_PARAM_REBOOT always does a hard reboot
  Print more debug information about image header

Test: manual -- boot, set and change credential
Test: selected CTS and VTS tests from release-tests.sh
Bug: 79416307
Change-Id: Ieea084bb0b64d3c66ce2c2e43f3a93514e79a4d1
diff --git a/citadel/updater/updater.cpp b/citadel/updater/updater.cpp
index 776401e..a4250ef 100644
--- a/citadel/updater/updater.cpp
+++ b/citadel/updater/updater.cpp
@@ -48,11 +48,24 @@
 using nos::CitadeldProxyClient;
 #endif
 
+enum hdr_section {
+  SEC_BOGUS = 0,
+  SEC_RO_A,
+  SEC_RO_B,
+  SEC_RW_A,
+  SEC_RW_B,
+};
+
 /* Global options */
 struct options_s {
   /* actions to take */
   int version;
+  int long_version;
+  enum hdr_section section;
+  int file_version;
+  enum hdr_section file_section;
   int id;
+  int repo_snapshot;
   int stats;
   int ro;
   int rw;
@@ -69,6 +82,7 @@
 enum no_short_opts_for_these {
   OPT_DEVICE = 1000,
   OPT_ID,
+  OPT_REPO_SNAPSHOT,
   OPT_STATS,
   OPT_RO,
   OPT_RW,
@@ -80,24 +94,26 @@
   OPT_ERASE,
 };
 
-const char *short_opts = ":hv";
+const char *short_opts = ":hvlV:fF:";
 const struct option long_opts[] = {
   /* name    hasarg *flag val */
-  {"version",     0, NULL, 'v'},
-  {"id",          0, NULL, OPT_ID},
-  {"stats",       0, NULL, OPT_STATS},
-  {"ro",          0, NULL, OPT_RO},
-  {"rw",          0, NULL, OPT_RW},
-  {"reboot",      0, NULL, OPT_REBOOT},
-  {"force_reset", 0, NULL, OPT_FORCE_RESET},
-  {"enable_ro",   0, NULL, OPT_ENABLE_RO},
-  {"enable_rw",   0, NULL, OPT_ENABLE_RW},
-  {"change_pw",   0, NULL, OPT_CHANGE_PW},
-  {"erase",       1, NULL, OPT_ERASE},
+  {"version",       0, NULL, 'v'},
+  {"long_version",  0, NULL, 'l'},
+  {"id",            0, NULL, OPT_ID},
+  {"repo_snapshot", 0, NULL, OPT_REPO_SNAPSHOT},
+  {"stats",         0, NULL, OPT_STATS},
+  {"ro",            0, NULL, OPT_RO},
+  {"rw",            0, NULL, OPT_RW},
+  {"reboot",        0, NULL, OPT_REBOOT},
+  {"force_reset",   0, NULL, OPT_FORCE_RESET},
+  {"enable_ro",     0, NULL, OPT_ENABLE_RO},
+  {"enable_rw",     0, NULL, OPT_ENABLE_RW},
+  {"change_pw",     0, NULL, OPT_CHANGE_PW},
+  {"erase",         1, NULL, OPT_ERASE},
 #ifndef ANDROID
-  {"device",      1, NULL, OPT_DEVICE},
+  {"device",        1, NULL, OPT_DEVICE},
 #endif
-  {"help",        0, NULL, 'h'},
+  {"help",          0, NULL, 'h'},
   {NULL, 0, NULL, 0},
 };
 
@@ -126,29 +142,34 @@
     "\n"
     "Actions:\n"
     "\n"
-    "  -v, --version       Display the Citadel version info\n"
-    "      --id            Display the Citadel device ID\n"
-    "      --stats         Display Low Power stats\n"
-    "      --rw            Update RW firmware from the image file\n"
-    "      --ro            Update RO firmware from the image file\n"
-    "      --reboot        Tell Citadel to reboot\n"
-    "      --force_reset   Pulse Citadel's reset line\n"
+    "  -v, --version        Display the running version\n"
+    "  -l, --long_version   Display the full version info\n"
+    "  --id                 Display the Citadel device ID\n"
+    "  --stats              Display Low Power stats\n"
+    "  -V SECTION           Show Citadel headers for RO_A | RO_B | RW_A | RW_B\n"
+    "  -f                   Show image file version info\n"
+    "  -F SECTION           Show file headers for RO_A | RO_B | RW_A | RW_B\n"
+    "  --repo_snapshot      Show the repo sha1sums for the running image\n"
     "\n"
-    "      --enable_ro     Mark new RO image as good\n"
-    "      --enable_rw     Mark new RW image as good\n"
+    "  --rw                 Update RW firmware from the image file\n"
+    "  --ro                 Update RO firmware from the image file\n"
+    "  --enable_ro          Mark new RO image as good (requires password)\n"
+    "  --enable_rw          Mark new RW image as good (requires password)\n"
+    "  --reboot             Tell Citadel to reboot\n"
+    "  --force_reset        Pulse Citadel's reset line\n"
     "\n"
-    "      --change_pw     Change update password\n"
+    "  --change_pw          Change the update password\n"
     "\n\n"
-    "      --erase=CODE    Erase all user secrets and reboot.\n"
-    "                      This skips all other actions.\n"
+    "  --erase=CODE         Erase all user secrets and reboot.\n"
+    "                       This skips all other actions.\n"
 #ifndef ANDROID
     "\n"
     "Options:\n"
     "\n"
-    "      --device=SN     Connect to the FDTI device with the given\n"
-    "                      serial number (try \"lsusb -v\"). A default\n"
-    "                      can be specified with the CITADEL_DEVICE\n"
-    "                      environment variable.\n"
+    "  --device=SN          Connect to the FDTI device with the given\n"
+    "                       serial number (try \"lsusb -v\"). A default\n"
+    "                       can be specified with the CITADEL_DEVICE\n"
+    "                       environment variable.\n"
 #endif
     "\n",
     progname);
@@ -368,6 +389,192 @@
   return retval;
 }
 
+uint32_t do_long_version(AppClient &app)
+{
+  uint32_t retval;
+  std::vector<uint8_t> buffer;
+  buffer.reserve(1024);
+
+  retval = app.Call(NUGGET_PARAM_LONG_VERSION, buffer, &buffer);
+
+  if (is_app_success(retval)) {
+    printf("%.*s\n", (int)buffer.size(), buffer.data());
+  }
+
+  return retval;
+}
+
+static enum hdr_section parse_section(const char *str)
+{
+  bool is_ro, is_a;
+
+  // matching this:  /r?[ow]_?[ab]/i
+
+  if (tolower(*str) == 'r') {
+    str++;
+  }
+
+  if (tolower(*str) == 'o') {
+    is_ro = true;
+  } else if (tolower(*str) == 'w') {
+    is_ro = false;
+  } else {
+    Error("Invalid section \"%s\"", str);
+    return SEC_BOGUS;
+  }
+  str++;
+
+  if (*str == '_') {
+    str++;
+  }
+
+  if (tolower(*str) == 'a') {
+    is_a = true;
+  } else if (tolower(*str) == 'b') {
+    is_a = false;
+  } else {
+    Error("Invalid section \"%s\"", str);
+    return SEC_BOGUS;
+  }
+
+  if (is_ro) {
+    return is_a ? SEC_RO_A : SEC_RO_B;
+  }
+
+  return is_a ? SEC_RW_A : SEC_RW_B;
+}
+
+static void show_header(const uint8_t *ptr)
+{
+  const struct SignedHeader *hdr;
+
+  hdr = reinterpret_cast<const struct SignedHeader*>(ptr);
+  hdr->print();
+}
+
+#define CROS_EC_VERSION_COOKIE1 0xce112233
+#define CROS_EC_VERSION_COOKIE2 0xce445566
+
+// The start of the RW sections looks like this
+struct compiled_version_struct {
+  // The header comes first
+  const struct SignedHeader hdr;
+  // The the vector table. Citadel has 239 entries
+  uint32_t vectors[239];
+  // A magic number to be sure we're looking at the right thing
+  uint32_t cookie1;
+  // Then the short version string
+  char version[32];
+  // And another magic number
+  uint32_t cookie2;
+};
+
+static void show_ro_string(const char *name, const uint8_t *ptr)
+{
+  const struct SignedHeader *hdr;
+
+  hdr = reinterpret_cast<const struct SignedHeader*>(ptr);
+  printf("%s:    %d.%d.%d/%08x %s\n", name,
+         hdr->epoch_, hdr->major_, hdr->minor_, be32toh(hdr->img_chk_),
+         hdr->magic == MAGIC_VALID ? "ok" : "--");
+}
+
+static void show_rw_string(const char *name, const uint8_t *ptr)
+{
+  const struct compiled_version_struct *v;
+  v = reinterpret_cast<const struct compiled_version_struct*>(ptr);
+
+  if (v->cookie1 == CROS_EC_VERSION_COOKIE1 &&
+      v->cookie2 == CROS_EC_VERSION_COOKIE2 &&
+      (v->hdr.magic == MAGIC_DEFAULT || v->hdr.magic == MAGIC_VALID)) {
+    printf("%s:    %d.%d.%d/%s %s\n", name,
+           v->hdr.epoch_, v->hdr.major_, v->hdr.minor_, v->version,
+           v->hdr.magic == MAGIC_VALID ? "ok" : "--");
+  } else {
+    printf("<invalid>\n");
+  }
+}
+
+uint32_t do_section(AppClient &app __attribute__((unused)))
+{
+  uint16_t param;
+
+  switch (options.section) {
+  case SEC_RO_A:
+    param = NUGGET_PARAM_HEADER_RO_A;
+    break;
+  case SEC_RO_B:
+    param = NUGGET_PARAM_HEADER_RO_B;
+    break;
+  case SEC_RW_A:
+    param = NUGGET_PARAM_HEADER_RW_A;
+    break;
+  case SEC_RW_B:
+    param = NUGGET_PARAM_HEADER_RW_B;
+    break;
+  default:
+    return 1;
+  }
+
+  uint32_t retval;
+  std::vector<uint8_t> buffer;
+  buffer.reserve(sizeof(SignedHeader));
+
+  retval = app.Call(param, buffer, &buffer);
+
+  if (is_app_success(retval)) {
+    show_header(buffer.data());
+  }
+
+  return retval;
+}
+
+uint32_t do_file_version(const std::vector<uint8_t> &image)
+{
+  show_ro_string("RO_A", image.data() + CHIP_RO_A_MEM_OFF);
+  show_ro_string("RO_B", image.data() + CHIP_RO_B_MEM_OFF);
+  show_rw_string("RW_A", image.data() + CHIP_RW_A_MEM_OFF);
+  show_rw_string("RW_B", image.data() + CHIP_RW_B_MEM_OFF);
+  return 0;
+}
+
+uint32_t do_file_section(const std::vector<uint8_t> &image)
+{
+  switch (options.file_section) {
+  case SEC_RO_A:
+    show_header(image.data() + CHIP_RO_A_MEM_OFF);
+    break;
+  case SEC_RO_B:
+    show_header(image.data() + CHIP_RO_B_MEM_OFF);
+    break;
+  case SEC_RW_A:
+    show_header(image.data() + CHIP_RW_A_MEM_OFF);
+    break;
+  case SEC_RW_B:
+    show_header(image.data() + CHIP_RW_B_MEM_OFF);
+    break;
+  default:
+    return 1;
+  }
+
+  return 0;
+}
+
+uint32_t do_repo_snapshot(AppClient &app)
+{
+  uint32_t retval;
+  std::vector<uint8_t> buffer;
+  buffer.reserve(1200);
+
+  retval = app.Call(NUGGET_PARAM_REPO_SNAPSHOT, buffer, &buffer);
+
+  if (is_app_success(retval)) {
+    printf("%.*s\n", (int)buffer.size(), buffer.data());
+  }
+
+  return retval;
+}
+
 uint32_t do_stats(AppClient &app)
 {
   struct nugget_app_low_power_stats stats;
@@ -406,9 +613,9 @@
 uint32_t do_reboot(AppClient &app)
 {
   uint32_t retval;
-  std::vector<uint8_t> data = {NUGGET_REBOOT_HARD};
+  std::vector<uint8_t> ignored = {1};           // older images need this
 
-  retval = app.Call(NUGGET_PARAM_REBOOT, data, nullptr);
+  retval = app.Call(NUGGET_PARAM_REBOOT, ignored, nullptr);
 
   if (is_app_success(retval)) {
     printf("Citadel reboot requested\n");
@@ -533,6 +740,26 @@
     return 2;
   }
 
+  if (options.long_version &&
+      do_long_version(app) != APP_SUCCESS) {
+    return 2;
+  }
+
+  if (options.section &&
+      do_section(app) != APP_SUCCESS) {
+    return 2;
+  }
+
+  if (options.file_version &&
+      do_file_version(image) != APP_SUCCESS) {
+    return 2;
+  }
+
+  if (options.file_section &&
+      do_file_section(image) != APP_SUCCESS) {
+    return 2;
+  }
+
   if (options.id &&
       do_id(app) != APP_SUCCESS) {
     return 2;
@@ -543,6 +770,10 @@
     return 2;
   }
 
+  if (options.repo_snapshot &&
+      do_repo_snapshot(app) != APP_SUCCESS) {
+    return 2;
+  }
   if (options.rw &&
       do_update(app, image,
           CHIP_RW_A_MEM_OFF, CHIP_RW_B_MEM_OFF) != APP_SUCCESS) {
@@ -588,6 +819,7 @@
   std::vector<uint8_t> image;
   int got_action = 0;
   char *e = 0;
+  int need_file = 0;
 
   this_prog= strrchr(argv[0], '/');
   if (this_prog) {
@@ -611,20 +843,44 @@
       options.version = 1;
       got_action = 1;
       break;
+    case 'l':
+      options.long_version = 1;
+      got_action = 1;
+      break;
+    case 'V':
+      options.section = parse_section(optarg);
+      got_action = 1;
+      break;
+    case 'f':
+      options.file_version = 1;
+      need_file = 1;
+      got_action = 1;
+      break;
+    case 'F':
+      options.file_section = parse_section(optarg);
+      need_file = 1;
+      got_action = 1;
+      break;
     case OPT_ID:
       options.id = 1;
       got_action = 1;
       break;
+    case OPT_REPO_SNAPSHOT:
+      options.repo_snapshot = 1;
+      got_action = 1;
+      break;
     case OPT_STATS:
       options.stats = 1;
       got_action = 1;
       break;
     case OPT_RO:
       options.ro = 1;
+      need_file = 1;
       got_action = 1;
       break;
     case OPT_RW:
       options.rw = 1;
+      need_file = 1;
       got_action = 1;
       break;
     case OPT_REBOOT:
@@ -691,14 +947,14 @@
     goto out;
   }
 
-  if (options.ro || options.rw) {
+  if (need_file) {
     if (optind < argc) {
       /* Sets errorcnt on failure */
       image = read_image_from_file(argv[optind++]);
       if (errorcnt)
         goto out;
     } else {
-      Error("An image file is required with --ro and --rw");
+      Error("Missing required image file");
       goto out;
     }
   }
@@ -708,8 +964,7 @@
     if (optind < argc) {
       passwd = argv[optind++];
     } else {
-      Error("Need a new password at least."
-            " Use '' to clear it.");
+      Error("Need a new password at least. Use '' to clear it.");
       goto out;
     }
     /* two args provided, use both old & new passwords */
diff --git a/nugget/include/app_nugget.h b/nugget/include/app_nugget.h
index aa8a798..669e82c 100644
--- a/nugget/include/app_nugget.h
+++ b/nugget/include/app_nugget.h
@@ -39,7 +39,7 @@
 
 #define NUGGET_PARAM_VERSION 0x0000
 /*
- * Return the current build string
+ * Return the one-line version string of the running image
  *
  * @param args         <none>
  * @param arg_len      0
@@ -74,18 +74,12 @@
 /*
  * Reboot Citadel
  *
- * @param args         uint8_t hard        0 = soft reboot, 1 = hard reboot
- * @param arg_len      sizeof(uint8_t)
+ * @param args         <none>
+ * @param arg_len      0
  * @param reply        <none>
  * @param reply_len    0
  */
 
-enum NUGGET_REBOOT_ARG_TYPE {
-  NUGGET_REBOOT_SOFT = 0,
-  NUGGET_REBOOT_HARD = 1,
-};
-
-
 /*********
  * Firmware updates are written to flash with invalid headers. If an update
  * password exists, headers can only be marked valid by providing that
@@ -167,6 +161,78 @@
  */
 
 
+#define NUGGET_PARAM_LONG_VERSION 0x0007
+/*
+ * Return the multi-line description of all images
+ *
+ * @param args         <none>
+ * @param arg_len      0
+ * @param reply        Null-terminated ASCII string
+ * @param reply_len    Max length to return
+ *
+ * @errors             APP_ERROR_TOO_MUCH
+ */
+
+#define NUGGET_PARAM_HEADER_RO_A 0x0008
+/*
+ * Return the signature header for RO_A
+ *
+ * @param args         <none>
+ * @param arg_len      0
+ * @param reply        struct SignedHeader
+ * @param reply_len    Max length to return
+ *
+ * @errors             APP_ERROR_TOO_MUCH
+ */
+
+#define NUGGET_PARAM_HEADER_RO_B 0x0009
+/*
+ * Return the signature header for RO_B
+ *
+ * @param args         <none>
+ * @param arg_len      0
+ * @param reply        struct SignedHeader
+ * @param reply_len    Max length to return
+ *
+ * @errors             APP_ERROR_TOO_MUCH
+ */
+
+#define NUGGET_PARAM_HEADER_RW_A 0x000a
+/*
+ * Return the signature header for RW_A
+ *
+ * @param args         <none>
+ * @param arg_len      0
+ * @param reply        struct SignedHeader
+ * @param reply_len    Max length to return
+ *
+ * @errors             APP_ERROR_TOO_MUCH
+ */
+
+#define NUGGET_PARAM_HEADER_RW_B 0x000b
+/*
+ * Return the signature header for RW_B
+ *
+ * @param args         <none>
+ * @param arg_len      0
+ * @param reply        struct SignedHeader
+ * @param reply_len    Max length to return
+ *
+ * @errors             APP_ERROR_TOO_MUCH
+ */
+
+#define NUGGET_PARAM_REPO_SNAPSHOT 0x000c
+/*
+ * Return the multi-line repo snapshot info for the current image
+ *
+ * @param args         <none>
+ * @param arg_len      0
+ * @param reply        Null-terminated ASCII string
+ * @param reply_len    Max length to return
+ *
+ * @errors             APP_ERROR_TOO_MUCH
+ */
+
 /****************************************************************************/
 /* Test related commands */
 
diff --git a/nugget/include/signed_header.h b/nugget/include/signed_header.h
index 9ce33e6..81be877 100644
--- a/nugget/include/signed_header.h
+++ b/nugget/include/signed_header.h
@@ -82,6 +82,7 @@
   }
 
   void print() const {
+    printf("hdr.magic          : %08x\n", magic);
     printf("hdr.keyid          : %08x\n", keyid);
     printf("hdr.tag            : ");
     const uint8_t* p = reinterpret_cast<const uint8_t*>(&tag);
@@ -92,8 +93,13 @@
     printf("hdr.epoch          : %08x\n", epoch_);
     printf("hdr.major          : %08x\n", major_);
     printf("hdr.minor          : %08x\n", minor_);
-    printf("hdr.timestamp      : %016" PRIu64 "x, %s", timestamp_,
+    printf("hdr.timestamp      : %016" PRIx64 ", %s", timestamp_,
            asctime(localtime(reinterpret_cast<const time_t*>(&timestamp_))));
+    printf("hdr.image_size     : %08x\n", image_size);
+    printf("hdr.ro_base        : %08x\n", ro_base);
+    printf("hdr.ro_max         : %08x\n", ro_max);
+    printf("hdr.rx_base        : %08x\n", rx_base);
+    printf("hdr.rx_max         : %08x\n", rx_max);
     printf("hdr.img_chk        : %08x\n", be32toh(img_chk_));
     printf("hdr.fuses_chk      : %08x\n", be32toh(fuses_chk_));
     printf("hdr.info_chk       : %08x\n", be32toh(info_chk_));
diff --git a/nugget/proto/nugget/app/keymaster/keymaster.options b/nugget/proto/nugget/app/keymaster/keymaster.options
index 99730ae..2081eaf 100644
--- a/nugget/proto/nugget/app/keymaster/keymaster.options
+++ b/nugget/proto/nugget/app/keymaster/keymaster.options
@@ -2,4 +2,10 @@
 nugget.app.keymaster.ImportWrappedKeyRequest.gcm_tag max_size:16
 nugget.app.keymaster.ImportWrappedKeyRequest.masking_key max_size:32
 nugget.app.keymaster.SetRootOfTrustRequest.digest max_size:32
-nugget.app.keymaster.SetBootStateRequest.public_key max_size:32
\ No newline at end of file
+nugget.app.keymaster.SetBootStateRequest.public_key max_size:32
+nugget.app.keymaster.ComputeSharedHmacRequest.hmac_sharing_params max_count:3
+nugget.app.keymaster.ComputeSharedHmacResponse.sharing_check max_size:32
+nugget.app.keymaster.DTupHandshakeRequest.nonce_client max_size:32
+nugget.app.keymaster.DTupHandshakeResponse.nonce_citadel max_size:32
+nugget.app.keymaster.DTupHandshakeResponse.signature max_size:32
+nugget.app.keymaster.DTupFetchInputEventResponse.signature max_size:32
diff --git a/nugget/proto/nugget/app/keymaster/keymaster.proto b/nugget/proto/nugget/app/keymaster/keymaster.proto
index 603e041..092603c 100644
--- a/nugget/proto/nugget/app/keymaster/keymaster.proto
+++ b/nugget/proto/nugget/app/keymaster/keymaster.proto
@@ -79,6 +79,18 @@
   rpc ProvisionDeviceIds (ProvisionDeviceIdsRequest) returns (ProvisionDeviceIdsResponse);
   // Only callable at the Device Factory.
   rpc ReadTeeBatchCertificate (ReadTeeBatchCertificateRequest) returns (ReadTeeBatchCertificateResponse);
+
+  /*
+   * More KM4 methods.
+   */
+  rpc GetHmacSharingParameters (GetHmacSharingParametersRequest) returns (GetHmacSharingParametersResponse);
+  rpc ComputeSharedHmac (ComputeSharedHmacRequest) returns (ComputeSharedHmacResponse);
+
+  /*
+   * DTup input session methods.
+   */
+  rpc HandshakeDTup (DTupHandshakeRequest) returns (DTupHandshakeResponse);
+  rpc FetchDTupInputEvent (DTupFetchInputEventRequest) returns (DTupFetchInputEventResponse);
 }
 
 /*
@@ -186,6 +198,7 @@
   KeyPurpose purpose = 1;
   KeyBlob blob = 2;
   KeyParameters params = 3;
+  HardwareAuthToken auth_token = 4;
 }
 message BeginOperationResponse {
   ErrorCode error_code = 1;
@@ -198,6 +211,8 @@
   OperationHandle handle = 1;
   KeyParameters params = 2;
   bytes input = 3;
+  HardwareAuthToken auth_token = 4;
+  VerificationToken verification_token = 5;
 }
 message UpdateOperationResponse {
   ErrorCode error_code = 1;
@@ -212,6 +227,8 @@
   KeyParameters params = 2;
   bytes input = 3;
   bytes signature = 4;
+  HardwareAuthToken auth_token = 5;
+  VerificationToken verification_token = 6;
 };
 message FinishOperationResponse {
   ErrorCode error_code = 1;
@@ -245,6 +262,23 @@
 }
 // ImportWrappedKey returns a ImportKeyResponse.
 
+// GetHmacSharingParametersRequest
+message GetHmacSharingParametersRequest {
+}
+message GetHmacSharingParametersResponse {
+  ErrorCode error_code = 1;
+  HmacSharingParameters hmac_sharing_params = 2;
+}
+
+// ComputeSharedHmacRequest
+message ComputeSharedHmacRequest {
+  repeated HmacSharingParameters hmac_sharing_params = 1;
+}
+message ComputeSharedHmacResponse {
+  ErrorCode error_code = 1;
+  bytes sharing_check = 2;
+}
+
 /*
  * Vendor HAL.
  */
@@ -252,7 +286,7 @@
 // SetRootOfTrustRequest
 // Only callable by the Bootloader.
 message SetRootOfTrustRequest {
-  bytes digest = 1;
+  bytes digest = 1;                  // This is a SHA256 digest.
 }
 message SetRootOfTrustResponse {
   // Specified in keymaster_defs.proto:ErrorCode
@@ -263,7 +297,7 @@
 // Only callable by the Bootloader.
 message SetBootStateRequest {
   bool is_unlocked = 1;
-  bytes public_key = 2;
+  bytes public_key = 2;              // This is a SHA256 digest.
   uint32 color = 3;
   uint32 system_version = 4;
   uint32 system_security_level = 5;
@@ -301,3 +335,21 @@
   ECKey ec = 3;
   bytes batch_cert = 4;
 }
+
+message DTupHandshakeRequest {
+  bytes nonce_client = 1;
+}
+
+message DTupHandshakeResponse {
+  DTupError error_code = 1;
+  bytes nonce_citadel = 2;
+  bytes signature = 3;
+}
+
+message DTupFetchInputEventRequest {}
+
+message DTupFetchInputEventResponse {
+  DTupError error_code = 1;
+  DTupKeyEvent event = 2;
+  bytes signature = 3;
+}
diff --git a/nugget/proto/nugget/app/keymaster/keymaster_defs.proto b/nugget/proto/nugget/app/keymaster/keymaster_defs.proto
index c3fbbc8..5958838 100644
--- a/nugget/proto/nugget/app/keymaster/keymaster_defs.proto
+++ b/nugget/proto/nugget/app/keymaster/keymaster_defs.proto
@@ -263,3 +263,16 @@
   PKCS8 = 1;  /* for asymmetric key pair import */
   RAW = 3;    /* for symmetric key import and export*/
 }
+
+enum DTupError {
+  DTUP_OK = 0;
+  DTUP_NO_EVENT = 1;
+}
+
+/* matches Linux event device codes */
+enum DTupKeyEvent {
+    DTUP_RESERVED = 0;
+    DTUP_VOL_DOWN = 114;
+    DTUP_VOL_UP = 115;
+    DTUP_PWR = 116;
+}
diff --git a/nugget/proto/nugget/app/keymaster/keymaster_types.options b/nugget/proto/nugget/app/keymaster/keymaster_types.options
index 18678aa..ab60bbf 100644
--- a/nugget/proto/nugget/app/keymaster/keymaster_types.options
+++ b/nugget/proto/nugget/app/keymaster/keymaster_types.options
@@ -1 +1,3 @@
-nugget.app.keymaster.KeyParameters.params max_count:20
\ No newline at end of file
+nugget.app.keymaster.KeyParameters.params max_count:20
+nugget.app.keymaster.HmacSharingParameters.seed max_size:32
+nugget.app.keymaster.HmacSharingParameters.nonce max_size:32
diff --git a/nugget/proto/nugget/app/keymaster/keymaster_types.proto b/nugget/proto/nugget/app/keymaster/keymaster_types.proto
index f5399ee..9c62baf 100644
--- a/nugget/proto/nugget/app/keymaster/keymaster_types.proto
+++ b/nugget/proto/nugget/app/keymaster/keymaster_types.proto
@@ -59,6 +59,15 @@
   bytes nonce = 2;
 }
 
+message HardwareAuthToken {
+  uint64 challenge = 1;
+  uint64 user_id = 2;
+  uint64 authenticator_id = 3;
+  HardwareAuthenticatorType authenticator_type = 4;
+  uint64 timestamp = 5;
+  bytes mac = 6;
+}
+
 message VerificationToken {
   uint64 challenge = 1;
   uint64 timestamp = 2;