123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368 |
- // Copyright 2019 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- // This file contains structures to implement the CTAP2 PIN protocol, version
- // one. See
- // https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-client-to-authenticator-protocol-v2.0-rd-20180702.html#authenticatorClientPIN
- #ifndef DEVICE_FIDO_PIN_H_
- #define DEVICE_FIDO_PIN_H_
- #include <stdint.h>
- #include <array>
- #include <string>
- #include <vector>
- #include "base/component_export.h"
- #include "base/containers/span.h"
- #include "components/cbor/values.h"
- #include "device/fido/fido_constants.h"
- #include "third_party/abseil-cpp/absl/types/optional.h"
- namespace device {
- namespace pin {
- // The reason we are prompting for a new PIN.
- enum class PINEntryReason {
- // Indicates a new PIN is being set.
- kSet,
- // The existing PIN must be changed before using this authenticator.
- kChange,
- // The existing PIN is being collected to prove user verification.
- kChallenge
- };
- // The errors that may prompt asking for a PIN.
- enum class PINEntryError {
- // No error has occurred.
- kNoError,
- // Internal UV is locked, so we are falling back to PIN.
- kInternalUvLocked,
- // The PIN the user entered does not match the authenticator PIN.
- kWrongPIN,
- // The new PIN the user entered is too short.
- kTooShort,
- // The new PIN the user entered contains invalid characters.
- kInvalidCharacters,
- // The new PIN the user entered is the same as the currently set PIN.
- kSameAsCurrentPIN,
- };
- // Permission list flags. See
- // https://drafts.fidoalliance.org/fido-2/stable-links-to-latest/fido-client-to-authenticator-protocol.html#permissions
- enum class Permissions : uint8_t {
- kMakeCredential = 0x01,
- kGetAssertion = 0x02,
- kCredentialManagement = 0x04,
- kBioEnrollment = 0x08,
- kLargeBlobWrite = 0x10,
- };
- // Some commands that validate PinUvAuthTokens include this padding to ensure a
- // PinUvAuthParam cannot be reused across different commands.
- constexpr std::array<uint8_t, 32> kPinUvAuthTokenSafetyPadding = {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- // Validates |pin|, returning |kNoError| if valid or an appropriate error code
- // otherwise.
- COMPONENT_EXPORT(DEVICE_FIDO)
- PINEntryError ValidatePIN(
- const std::string& pin,
- uint32_t min_pin_length = kMinPinLength,
- absl::optional<std::string> current_pin = absl::nullopt);
- // Like |ValidatePIN| above but takes a wide string.
- COMPONENT_EXPORT(DEVICE_FIDO)
- PINEntryError ValidatePIN(
- const std::u16string& pin16,
- uint32_t min_pin_length = kMinPinLength,
- absl::optional<std::string> current_pin = absl::nullopt);
- // kMinBytes is the minimum number of *bytes* of PIN data that a CTAP2 device
- // will accept. Since the PIN is UTF-8 encoded, this could be a single code
- // point. However, the platform is supposed to additionally enforce a 4
- // *character* minimum
- constexpr size_t kMinBytes = 4;
- // kMaxBytes is the maximum number of bytes of PIN data that a CTAP2 device will
- // accept.
- constexpr size_t kMaxBytes = 63;
- // EncodeCOSEPublicKey converts an X9.62 public key to a COSE structure.
- COMPONENT_EXPORT(DEVICE_FIDO)
- cbor::Value::MapValue EncodeCOSEPublicKey(
- base::span<const uint8_t, kP256X962Length> x962);
- // PinRetriesRequest asks an authenticator for the number of remaining PIN
- // attempts before the device is locked.
- struct PinRetriesRequest {
- PINUVAuthProtocol protocol;
- };
- // UVRetriesRequest asks an authenticator for the number of internal user
- // verification attempts before the feature is locked.
- struct UvRetriesRequest {
- PINUVAuthProtocol protocol;
- };
- // RetriesResponse reflects an authenticator's response to a |PinRetriesRequest|
- // or a |UvRetriesRequest|.
- struct RetriesResponse {
- static absl::optional<RetriesResponse> ParsePinRetries(
- const absl::optional<cbor::Value>& cbor);
- static absl::optional<RetriesResponse> ParseUvRetries(
- const absl::optional<cbor::Value>& cbor);
- // retries is the number of PIN attempts remaining before the authenticator
- // locks.
- int retries;
- private:
- static absl::optional<RetriesResponse> Parse(
- const absl::optional<cbor::Value>& cbor,
- const int retries_key);
- RetriesResponse();
- };
- // KeyAgreementRequest asks an authenticator for an ephemeral ECDH key for
- // encrypting PIN material in future requests.
- struct KeyAgreementRequest {
- PINUVAuthProtocol protocol;
- };
- // KeyAgreementResponse reflects an authenticator's response to a
- // |KeyAgreementRequest| and is also used as representation of the
- // authenticator's ephemeral key.
- struct COMPONENT_EXPORT(DEVICE_FIDO) KeyAgreementResponse {
- static absl::optional<KeyAgreementResponse> Parse(
- const absl::optional<cbor::Value>& cbor);
- static absl::optional<KeyAgreementResponse> ParseFromCOSE(
- const cbor::Value::MapValue& cose_key);
- // X962 returns the public key from the response in X9.62 form.
- std::array<uint8_t, kP256X962Length> X962() const;
- // x and y contain the big-endian coordinates of a P-256 point. It is ensured
- // that this is a valid point on the curve.
- uint8_t x[32], y[32];
- private:
- KeyAgreementResponse();
- };
- // SetRequest sets an initial PIN on an authenticator. (This is distinct from
- // changing a PIN.)
- class SetRequest {
- public:
- // IsValid(pin) must be true.
- SetRequest(PINUVAuthProtocol protocol,
- const std::string& pin,
- const KeyAgreementResponse& peer_key);
- friend std::pair<CtapRequestCommand, absl::optional<cbor::Value>>
- AsCTAPRequestValuePair(const SetRequest&);
- private:
- const PINUVAuthProtocol protocol_;
- const KeyAgreementResponse peer_key_;
- uint8_t pin_[kMaxBytes + 1];
- };
- struct EmptyResponse {
- static absl::optional<EmptyResponse> Parse(
- const absl::optional<cbor::Value>& cbor);
- };
- // ChangeRequest changes the PIN on an authenticator that already has a PIN set.
- // (This is distinct from setting an initial PIN.)
- class ChangeRequest {
- public:
- // IsValid(new_pin) must be true.
- ChangeRequest(PINUVAuthProtocol protocol,
- const std::string& old_pin,
- const std::string& new_pin,
- const KeyAgreementResponse& peer_key);
- friend std::pair<CtapRequestCommand, absl::optional<cbor::Value>>
- AsCTAPRequestValuePair(const ChangeRequest&);
- private:
- const PINUVAuthProtocol protocol_;
- const KeyAgreementResponse peer_key_;
- uint8_t old_pin_hash_[16];
- uint8_t new_pin_[kMaxBytes + 1];
- };
- // ResetRequest resets an authenticator, which should invalidate all
- // credentials and clear any configured PIN. This is not strictly a
- // PIN-related command, but is generally used to reset a PIN and so is
- // included here.
- struct ResetRequest {};
- using ResetResponse = EmptyResponse;
- // TokenRequest requests a pin-token from an authenticator. These tokens can be
- // used to show user-verification in other operations, e.g. when getting an
- // assertion.
- class TokenRequest {
- public:
- TokenRequest(const TokenRequest&) = delete;
- // shared_key returns the shared ECDH key that was used to encrypt the PIN.
- // This is needed to decrypt the response.
- const std::vector<uint8_t>& shared_key() const;
- protected:
- TokenRequest(TokenRequest&&);
- TokenRequest(PINUVAuthProtocol protocol,
- const KeyAgreementResponse& peer_key);
- ~TokenRequest();
- const PINUVAuthProtocol protocol_;
- std::vector<uint8_t> shared_key_;
- std::array<uint8_t, kP256X962Length> public_key_;
- };
- class PinTokenRequest : public TokenRequest {
- public:
- PinTokenRequest(PINUVAuthProtocol protocol,
- const std::string& pin,
- const KeyAgreementResponse& peer_key);
- PinTokenRequest(PinTokenRequest&&);
- PinTokenRequest(const PinTokenRequest&) = delete;
- virtual ~PinTokenRequest();
- friend std::pair<CtapRequestCommand, absl::optional<cbor::Value>>
- AsCTAPRequestValuePair(const PinTokenRequest&);
- protected:
- uint8_t pin_hash_[16];
- };
- class PinTokenWithPermissionsRequest : public PinTokenRequest {
- public:
- PinTokenWithPermissionsRequest(PINUVAuthProtocol protocol,
- const std::string& pin,
- const KeyAgreementResponse& peer_key,
- base::span<const pin::Permissions> permissions,
- const absl::optional<std::string> rp_id);
- PinTokenWithPermissionsRequest(PinTokenWithPermissionsRequest&&);
- PinTokenWithPermissionsRequest(const PinTokenWithPermissionsRequest&) =
- delete;
- ~PinTokenWithPermissionsRequest() override;
- friend std::pair<CtapRequestCommand, absl::optional<cbor::Value>>
- AsCTAPRequestValuePair(const PinTokenWithPermissionsRequest&);
- private:
- uint8_t permissions_;
- absl::optional<std::string> rp_id_;
- };
- class UvTokenRequest : public TokenRequest {
- public:
- UvTokenRequest(PINUVAuthProtocol protocol,
- const KeyAgreementResponse& peer_key,
- absl::optional<std::string> rp_id,
- base::span<const pin::Permissions> permissions);
- UvTokenRequest(UvTokenRequest&&);
- UvTokenRequest(const UvTokenRequest&) = delete;
- virtual ~UvTokenRequest();
- friend std::pair<CtapRequestCommand, absl::optional<cbor::Value>>
- AsCTAPRequestValuePair(const UvTokenRequest&);
- private:
- absl::optional<std::string> rp_id_;
- uint8_t permissions_;
- };
- class HMACSecretRequest {
- public:
- HMACSecretRequest(PINUVAuthProtocol protocol,
- const KeyAgreementResponse& peer_key,
- base::span<const uint8_t, 32> salt1,
- const absl::optional<std::array<uint8_t, 32>>& salt2);
- HMACSecretRequest(const HMACSecretRequest&);
- ~HMACSecretRequest();
- HMACSecretRequest& operator=(const HMACSecretRequest&);
- absl::optional<std::vector<uint8_t>> Decrypt(
- base::span<const uint8_t> ciphertext);
- private:
- const PINUVAuthProtocol protocol_;
- std::vector<uint8_t> shared_key_;
- public:
- const std::array<uint8_t, kP256X962Length> public_key_x962;
- const std::vector<uint8_t> encrypted_salts;
- const std::vector<uint8_t> salts_auth;
- };
- // TokenResponse represents the response to a pin-token request. In order to
- // decrypt a response, the shared key from the request is needed. Once a pin-
- // token has been decrypted, it can be used to calculate the pinAuth parameters
- // needed to show user-verification in future operations.
- class COMPONENT_EXPORT(DEVICE_FIDO) TokenResponse {
- public:
- ~TokenResponse();
- TokenResponse(const TokenResponse&);
- TokenResponse& operator=(const TokenResponse&);
- static absl::optional<TokenResponse> Parse(
- PINUVAuthProtocol protocol,
- base::span<const uint8_t> shared_key,
- const absl::optional<cbor::Value>& cbor);
- std::pair<PINUVAuthProtocol, std::vector<uint8_t>> PinAuth(
- base::span<const uint8_t> client_data_hash) const;
- PINUVAuthProtocol protocol() const { return protocol_; }
- const std::vector<uint8_t>& token_for_testing() const { return token_; }
- private:
- explicit TokenResponse(PINUVAuthProtocol protocol);
- PINUVAuthProtocol protocol_;
- std::vector<uint8_t> token_;
- };
- std::pair<CtapRequestCommand, absl::optional<cbor::Value>>
- AsCTAPRequestValuePair(const PinRetriesRequest&);
- std::pair<CtapRequestCommand, absl::optional<cbor::Value>>
- AsCTAPRequestValuePair(const UvRetriesRequest&);
- std::pair<CtapRequestCommand, absl::optional<cbor::Value>>
- AsCTAPRequestValuePair(const KeyAgreementRequest&);
- std::pair<CtapRequestCommand, absl::optional<cbor::Value>>
- AsCTAPRequestValuePair(const SetRequest&);
- std::pair<CtapRequestCommand, absl::optional<cbor::Value>>
- AsCTAPRequestValuePair(const ChangeRequest&);
- std::pair<CtapRequestCommand, absl::optional<cbor::Value>>
- AsCTAPRequestValuePair(const ResetRequest&);
- std::pair<CtapRequestCommand, absl::optional<cbor::Value>>
- AsCTAPRequestValuePair(const TokenRequest&);
- } // namespace pin
- } // namespace device
- #endif // DEVICE_FIDO_PIN_H_
|