chromium/chrome/browser/webauthn/proto/enclave_local_state.proto

// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

syntax = "proto3";

package webauthn_pb;

option objc_class_prefix = "WAP";
option optimize_for = LITE_RUNTIME;

message EnclaveLocalState {
  // Google Password Manager PINs are assumed to have low entropy and so cannot
  // be validated locally. Instead the enclave can validate them and enforce
  // rate limiting. Thus, locally and in the metadata of the virtual member of
  // the security domain, there is a wrapped version.
  message WrappedPIN {
    // The PIN, encrypted to the security domain secret. The plaintext is a
    // CBOR structure containing the scrypt-hash of the PIN, claim key,
    // generation number, plus recovery key store counter ID and handle.
    bytes wrapped_pin = 1;

    // A key used to encrypt claimed PIN hashes for validation at the enclave.
    // These are encrypted to ensure that the enclave has access to the local
    // state needed to unwrap the security domain secret.
    bytes claim_key = 2;

    // The generation number of the GPM PIN. Starts from zero and increases
    // strictly monotonically when the GPM PIN changes. The enclave enforces
    // a high-water mark.
    int64 generation = 3;

    enum Form {
      // Never used. Only for detecting when the form is missing.
      FORM_UNSPECIFIED = 0;
      // The GPM PIN is six digits.
      FORM_SIX_DIGITS = 1;
      // The GPM PIN is an arbitrary, alphanumeric string.
      FORM_ARBITRARY = 2;
    }
    // The form of the PIN, for showing the right UI.
    Form form = 4;

    enum Hash {
      // Never used. Only for detecting when the hash is missing.
      HASH_UNSPECIFIED = 0;
      // scrypt, where `hash_difficulty` is N.
      HASH_SCRYPT = 1;
    }
    // Which hash is used to form the PIN hash.
    Hash hash = 5;

    // A difficulty factor for the hash.
    int32 hash_difficulty = 6;

    // Salt used when hashing the PIN.
    bytes hash_salt = 7;
  }

  // User contains state for a specific GAIA ID.
  message User {
    // The not-user-verification-interlocked device key:
    //
    // These three members are either all empty or all non-empty.
    bytes wrapped_identity_private_key = 1;
    // If non-empty, this contains a valid SubjectPublicKeyInfo.
    bytes identity_public_key = 2;
    // True if `wrapped_identity_private_key` is not hardware bound and is thus
    // registered at the enclave as a "sw" key.
    bool identity_key_is_software_backed = 15;
    // This is currently SHA-256(identity_public_key) but need not be.
    bytes device_id = 5;

    // The hardware-bound, user-verification-interlocked device key.
    // (This is optional and might not be present if the device doesn't
    // support UV-interlocked keys.)
    //
    // These two members are either both empty or both non-empty.
    bytes wrapped_uv_private_key = 3;
    bytes uv_public_key = 4;

    // Whether this device has been registered with the enclave. If this is
    // true then `identity_public_key` and `member_public_key` must be
    // non-empty.
    bool registered = 6;

    // The enclave-wrapped, security domain physical member key.
    //
    // These two members are either both empty or both non-empty.
    bytes wrapped_member_private_key = 7;
    // If non-empty, contains a P-256 point in uncompressed X9.62 format.
    bytes member_public_key = 8;

    // Whether this device has joined the hw_protected security domain. If this
    // is true then `wrapped_security_domain_secrets` must be non-empty.
    bool joined = 9;

    // A map from security domain epoch to the enclave-wrapped security domain
    // secret for that epoch.
    map<int32, bytes> wrapped_security_domain_secrets = 10;

    // The wrapped Google Password Manager PIN.
    optional WrappedPIN wrapped_pin = 11;

    // The public key of the GPM PIN member of the security domain.
    optional bytes pin_public_key = 12;

    // Flag set when the device is in a newly-registered state but the UV key
    // has not yet been created, and should be created at the time of the first
    // UV request.
    optional bool deferred_uv_key_creation = 13;

    // The time at which the GPM PIN was last renewed.
    optional double last_refreshed_pin_epoch_secs = 14;
  }

  map<string, User> users = 1;
}