// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// If you change or add any fields in this file, update proto_visitors.h and
// potentially proto_enum_conversions.{h, cc}.
syntax = "proto2";
option java_multiple_files = true;
option java_package = "org.chromium.components.sync.protocol";
option optimize_for = LITE_RUNTIME;
package sync_pb;
// WebauthnCredentialSpecifics is an entity that backs a WebAuthn
// PublicKeyCredential. Since it contains the authenticator’s view of this
// object, it has a private key rather than a public key.
// (https://www.w3.org/TR/webauthn-2/#iface-pkcredential).
//
// Names of fields are taken from WebAuthn where possible. E.g.
// user.displayName in WebAuthn becomes user_display_name here.
//
// All fields are immutable after creation except for user_name and
// user_display_name, which may be updated by a user.
message WebauthnCredentialSpecifics {
// Sync's ID for this entity (sometimes called the client unique tag), 16
// random bytes. This value is used within Sync to identify this entity. The
// credential ID is not used because the (hashed) sync_id is exposed to the
// Sync server, and we don’t want Google to be able to map a credential ID to
// an account. Password entities construct this value from the concatenation
// of many fields and depend on the fact that the server only sees a hash of
// it. But the only high-entropy secret here is the private key, which will
// have different encryption in the future, and private keys are not the sort
// of data to copy into other fields. Therefore this independent value is
// provided to form the client's ID.
optional bytes sync_id = 1;
// The credential ID, 16 random bytes. This is a value surfaced in
// the WebAuthn API (https://www.w3.org/TR/webauthn-2/#credential-id).
optional bytes credential_id = 2;
// An RP ID is a WebAuthn concept:
// https://www.w3.org/TR/webauthn-2/#rp-id. It’s usually a domain name,
// although in non-Web contexts it can be a URL with a non-Web scheme.
optional string rp_id = 3;
// The user ID, which is also called a “user handle” in WebAuthn
// (https://www.w3.org/TR/webauthn-2/#user-handle), is an RP-specific
// identifier that is up to 64-bytes long. An authenticator conceptually only
// stores a single credential for a given (rp_id, user_id) pair, but there
// may be several credentials in Sync. They are prioritised using
// newly_shadowed_credential_ids and creation_time. See below.
//
// (We wish to be able to retain several entities for a single (rp_id,
// user_id) pair because there’s an edge case where we may wish to revert to
// an older entry and thus need to keep the older entry around in Sync. The
// revert could happen on a different device too.)
optional bytes user_id = 4;
// The id of credentials with the same (rp_id, user_id) that were
// shadowed by the creation of this entity.
//
// A credential is shadowed if one or more other credentials (from the same
// account, and with the same (rp_id, user_id)) include its credential_id in
// their list of shadowed IDs. Shadowed credentials are ignored when finding
// a credential to sign with. If there is more than one candidate remaining
// after filtering shadowed credentials then the most recently created (based
// on creation_time) is used.
//
// The reason for all this is that sites can replace a credential by creating
// another one with the same (rp_id, user_id) pair. However, we don't
// immediately know whether the WebAuthn response reached the website's
// server. Consider a user with a poor internet connection. Javascript in the
// site's origin triggers a credential creation that “overwrites” an existing
// credential, but the Javascript is unable to send the new public key to the
// website's server. The user is now locked out: the old credential has been
// over-written but the website's server doesn't know about the new one.
//
// Thus we wish to keep “overwritten” credentials around for a while to allow
// for some sort of recovery. In the simple case, a new credential shadows
// the single, previous old credential. We could depend on creation_time, but
// client clocks aren't always accurate, thus this field.
//
// In complicated cases two devices might race to replace a credential, in
// which case (after mutual syncing) two candidate credentials exist for the
// same (rp_id, user_id) pair because neither shadows the other. In this case
// we pick the newest based on |creation_time| but it's quite possible that
// some recovery will be needed because the website's server thinks the other
// one is correct.
//
// A generation counter isn't used because a single device might replace a
// series of credentials as it tries to update the website's server. But that
// doesn't mean that it should dominate a different device that replaced it
// only once, but later.
repeated bytes newly_shadowed_credential_ids = 5;
// The local time on the device when this credential was created. Given in
// milliseconds since the UNIX epoch. This is used to break ties between
// credentials. See newly_shadowed_credential_ids.
optional int64 creation_time = 6;
// The human-readable account identifier. Usually an email address. This is
// mutable.
// https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialentity-name
optional string user_name = 7;
// The human-readable name. Usually a legal name. This is mutable.
// https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialuserentity-displayname.
optional string user_display_name = 8;
// Reserving obsolete field.
reserved 10;
// Credentials may optionally be enabled for Secure Payment Confirmation[1] on
// third-party sites. This is opt-in at creation time.
//
// [1] https://www.w3.org/TR/secure-payment-confirmation/
optional bool third_party_payments_support = 11;
// Time when this passkey was last successfully asserted. Number of
// microseconds since 1601, aka Windows epoch. This mirrors the
// `date_last_used` field in PasswordSpecificsData.
optional int64 last_used_time_windows_epoch_micros = 13;
message Encrypted {
// The bytes of the private key, in PKCS#8 format.
optional bytes private_key = 1;
// The secret for implementing the hmac-secret extension
// https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-errata-20220621.html#sctn-hmac-secret-extension
optional bytes hmac_secret = 2;
// The contents of the credential's credBlob.
// https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-errata-20220621.html#sctn-credBlob-extension
optional bytes cred_blob = 3;
// The contents of the credential's largeBlob value(*). Unlike with security
// keys, largeBlob data is not stored in a single lump for all credentials,
// but as per-credential data. This data is presented to the authenticator
// over CTAP and thus has already had the required DEFLATE compression
// applied by the remote platform. The uncompressed size of this data is in
// the next field.
//
// (*) "large" with respect to embedded devices. Maximum length is 2KiB for
// Google Password Manager.
//
// https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-errata-20220621.html#authenticatorLargeBlobs
optional bytes large_blob = 4;
// The claimed uncompressed size of the DEFLATE-compressed data in
// `large_blob`. This corresponds to the `origSize` field from the spec:
// https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-errata-20220621.html#large-blob
optional uint64 large_blob_uncompressed_size = 5;
}
// The "version" (sometimes called the epoch) of the key that `encrypted_data`
// is encrypted with. This allows trial decryption to be avoided when present.
optional int32 key_version = 14;
oneof encrypted_data {
// The bytes of the private key, encrypted with a feature-specific security
// domain.
bytes private_key = 9;
// A serialized, `Encrypted` message, encrypted with a feature-specific
// security domain.
bytes encrypted = 12;
}
// `edited_by_user` is set to `true` the first time a user manually changes
// the credential's `user_name` or `user_display_name`.
optional bool edited_by_user = 15;
// `hidden` is set to `true` if the credential should not be shown on
// authentication surfaces, e.g. because a site marked it as obsolete.
optional bool hidden = 16;
}