blob: 03bbbc558ce599158f1aed2ed3c896f8adafaf8a [file]
// 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 {
reserved 3;
reserved "generation";
// The PIN, encrypted to the security domain secret. The plaintext is a CBOR
// map with the following key-value pairs:
// 1: Scrypt-hash of the PIN.
// 2: Optional: Generation number (deprecated, may not be populated).
// 3: Claim key.
// 4: Vault counter ID.
// 5: Vault handle.
// 6: Optional: cert.xml serial number used at the time of wrapping.
// 7: Optional: Cohort public key.
//
// Keys 6 and 7 may not be populated by all clients, but if one is
// populated, the other is required.
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;
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 {
reserved "pin_public_key";
reserved 12;
// 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;
// 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;
}