pin.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. // Copyright 2019 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. // This file contains structures to implement the CTAP2 PIN protocol, version
  5. // one. See
  6. // https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-client-to-authenticator-protocol-v2.0-rd-20180702.html#authenticatorClientPIN
  7. #ifndef DEVICE_FIDO_PIN_H_
  8. #define DEVICE_FIDO_PIN_H_
  9. #include <stdint.h>
  10. #include <array>
  11. #include <string>
  12. #include <vector>
  13. #include "base/component_export.h"
  14. #include "base/containers/span.h"
  15. #include "components/cbor/values.h"
  16. #include "device/fido/fido_constants.h"
  17. #include "third_party/abseil-cpp/absl/types/optional.h"
  18. namespace device {
  19. namespace pin {
  20. // The reason we are prompting for a new PIN.
  21. enum class PINEntryReason {
  22. // Indicates a new PIN is being set.
  23. kSet,
  24. // The existing PIN must be changed before using this authenticator.
  25. kChange,
  26. // The existing PIN is being collected to prove user verification.
  27. kChallenge
  28. };
  29. // The errors that may prompt asking for a PIN.
  30. enum class PINEntryError {
  31. // No error has occurred.
  32. kNoError,
  33. // Internal UV is locked, so we are falling back to PIN.
  34. kInternalUvLocked,
  35. // The PIN the user entered does not match the authenticator PIN.
  36. kWrongPIN,
  37. // The new PIN the user entered is too short.
  38. kTooShort,
  39. // The new PIN the user entered contains invalid characters.
  40. kInvalidCharacters,
  41. // The new PIN the user entered is the same as the currently set PIN.
  42. kSameAsCurrentPIN,
  43. };
  44. // Permission list flags. See
  45. // https://drafts.fidoalliance.org/fido-2/stable-links-to-latest/fido-client-to-authenticator-protocol.html#permissions
  46. enum class Permissions : uint8_t {
  47. kMakeCredential = 0x01,
  48. kGetAssertion = 0x02,
  49. kCredentialManagement = 0x04,
  50. kBioEnrollment = 0x08,
  51. kLargeBlobWrite = 0x10,
  52. };
  53. // Some commands that validate PinUvAuthTokens include this padding to ensure a
  54. // PinUvAuthParam cannot be reused across different commands.
  55. constexpr std::array<uint8_t, 32> kPinUvAuthTokenSafetyPadding = {
  56. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  57. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  58. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
  59. // Validates |pin|, returning |kNoError| if valid or an appropriate error code
  60. // otherwise.
  61. COMPONENT_EXPORT(DEVICE_FIDO)
  62. PINEntryError ValidatePIN(
  63. const std::string& pin,
  64. uint32_t min_pin_length = kMinPinLength,
  65. absl::optional<std::string> current_pin = absl::nullopt);
  66. // Like |ValidatePIN| above but takes a wide string.
  67. COMPONENT_EXPORT(DEVICE_FIDO)
  68. PINEntryError ValidatePIN(
  69. const std::u16string& pin16,
  70. uint32_t min_pin_length = kMinPinLength,
  71. absl::optional<std::string> current_pin = absl::nullopt);
  72. // kMinBytes is the minimum number of *bytes* of PIN data that a CTAP2 device
  73. // will accept. Since the PIN is UTF-8 encoded, this could be a single code
  74. // point. However, the platform is supposed to additionally enforce a 4
  75. // *character* minimum
  76. constexpr size_t kMinBytes = 4;
  77. // kMaxBytes is the maximum number of bytes of PIN data that a CTAP2 device will
  78. // accept.
  79. constexpr size_t kMaxBytes = 63;
  80. // EncodeCOSEPublicKey converts an X9.62 public key to a COSE structure.
  81. COMPONENT_EXPORT(DEVICE_FIDO)
  82. cbor::Value::MapValue EncodeCOSEPublicKey(
  83. base::span<const uint8_t, kP256X962Length> x962);
  84. // PinRetriesRequest asks an authenticator for the number of remaining PIN
  85. // attempts before the device is locked.
  86. struct PinRetriesRequest {
  87. PINUVAuthProtocol protocol;
  88. };
  89. // UVRetriesRequest asks an authenticator for the number of internal user
  90. // verification attempts before the feature is locked.
  91. struct UvRetriesRequest {
  92. PINUVAuthProtocol protocol;
  93. };
  94. // RetriesResponse reflects an authenticator's response to a |PinRetriesRequest|
  95. // or a |UvRetriesRequest|.
  96. struct RetriesResponse {
  97. static absl::optional<RetriesResponse> ParsePinRetries(
  98. const absl::optional<cbor::Value>& cbor);
  99. static absl::optional<RetriesResponse> ParseUvRetries(
  100. const absl::optional<cbor::Value>& cbor);
  101. // retries is the number of PIN attempts remaining before the authenticator
  102. // locks.
  103. int retries;
  104. private:
  105. static absl::optional<RetriesResponse> Parse(
  106. const absl::optional<cbor::Value>& cbor,
  107. const int retries_key);
  108. RetriesResponse();
  109. };
  110. // KeyAgreementRequest asks an authenticator for an ephemeral ECDH key for
  111. // encrypting PIN material in future requests.
  112. struct KeyAgreementRequest {
  113. PINUVAuthProtocol protocol;
  114. };
  115. // KeyAgreementResponse reflects an authenticator's response to a
  116. // |KeyAgreementRequest| and is also used as representation of the
  117. // authenticator's ephemeral key.
  118. struct COMPONENT_EXPORT(DEVICE_FIDO) KeyAgreementResponse {
  119. static absl::optional<KeyAgreementResponse> Parse(
  120. const absl::optional<cbor::Value>& cbor);
  121. static absl::optional<KeyAgreementResponse> ParseFromCOSE(
  122. const cbor::Value::MapValue& cose_key);
  123. // X962 returns the public key from the response in X9.62 form.
  124. std::array<uint8_t, kP256X962Length> X962() const;
  125. // x and y contain the big-endian coordinates of a P-256 point. It is ensured
  126. // that this is a valid point on the curve.
  127. uint8_t x[32], y[32];
  128. private:
  129. KeyAgreementResponse();
  130. };
  131. // SetRequest sets an initial PIN on an authenticator. (This is distinct from
  132. // changing a PIN.)
  133. class SetRequest {
  134. public:
  135. // IsValid(pin) must be true.
  136. SetRequest(PINUVAuthProtocol protocol,
  137. const std::string& pin,
  138. const KeyAgreementResponse& peer_key);
  139. friend std::pair<CtapRequestCommand, absl::optional<cbor::Value>>
  140. AsCTAPRequestValuePair(const SetRequest&);
  141. private:
  142. const PINUVAuthProtocol protocol_;
  143. const KeyAgreementResponse peer_key_;
  144. uint8_t pin_[kMaxBytes + 1];
  145. };
  146. struct EmptyResponse {
  147. static absl::optional<EmptyResponse> Parse(
  148. const absl::optional<cbor::Value>& cbor);
  149. };
  150. // ChangeRequest changes the PIN on an authenticator that already has a PIN set.
  151. // (This is distinct from setting an initial PIN.)
  152. class ChangeRequest {
  153. public:
  154. // IsValid(new_pin) must be true.
  155. ChangeRequest(PINUVAuthProtocol protocol,
  156. const std::string& old_pin,
  157. const std::string& new_pin,
  158. const KeyAgreementResponse& peer_key);
  159. friend std::pair<CtapRequestCommand, absl::optional<cbor::Value>>
  160. AsCTAPRequestValuePair(const ChangeRequest&);
  161. private:
  162. const PINUVAuthProtocol protocol_;
  163. const KeyAgreementResponse peer_key_;
  164. uint8_t old_pin_hash_[16];
  165. uint8_t new_pin_[kMaxBytes + 1];
  166. };
  167. // ResetRequest resets an authenticator, which should invalidate all
  168. // credentials and clear any configured PIN. This is not strictly a
  169. // PIN-related command, but is generally used to reset a PIN and so is
  170. // included here.
  171. struct ResetRequest {};
  172. using ResetResponse = EmptyResponse;
  173. // TokenRequest requests a pin-token from an authenticator. These tokens can be
  174. // used to show user-verification in other operations, e.g. when getting an
  175. // assertion.
  176. class TokenRequest {
  177. public:
  178. TokenRequest(const TokenRequest&) = delete;
  179. // shared_key returns the shared ECDH key that was used to encrypt the PIN.
  180. // This is needed to decrypt the response.
  181. const std::vector<uint8_t>& shared_key() const;
  182. protected:
  183. TokenRequest(TokenRequest&&);
  184. TokenRequest(PINUVAuthProtocol protocol,
  185. const KeyAgreementResponse& peer_key);
  186. ~TokenRequest();
  187. const PINUVAuthProtocol protocol_;
  188. std::vector<uint8_t> shared_key_;
  189. std::array<uint8_t, kP256X962Length> public_key_;
  190. };
  191. class PinTokenRequest : public TokenRequest {
  192. public:
  193. PinTokenRequest(PINUVAuthProtocol protocol,
  194. const std::string& pin,
  195. const KeyAgreementResponse& peer_key);
  196. PinTokenRequest(PinTokenRequest&&);
  197. PinTokenRequest(const PinTokenRequest&) = delete;
  198. virtual ~PinTokenRequest();
  199. friend std::pair<CtapRequestCommand, absl::optional<cbor::Value>>
  200. AsCTAPRequestValuePair(const PinTokenRequest&);
  201. protected:
  202. uint8_t pin_hash_[16];
  203. };
  204. class PinTokenWithPermissionsRequest : public PinTokenRequest {
  205. public:
  206. PinTokenWithPermissionsRequest(PINUVAuthProtocol protocol,
  207. const std::string& pin,
  208. const KeyAgreementResponse& peer_key,
  209. base::span<const pin::Permissions> permissions,
  210. const absl::optional<std::string> rp_id);
  211. PinTokenWithPermissionsRequest(PinTokenWithPermissionsRequest&&);
  212. PinTokenWithPermissionsRequest(const PinTokenWithPermissionsRequest&) =
  213. delete;
  214. ~PinTokenWithPermissionsRequest() override;
  215. friend std::pair<CtapRequestCommand, absl::optional<cbor::Value>>
  216. AsCTAPRequestValuePair(const PinTokenWithPermissionsRequest&);
  217. private:
  218. uint8_t permissions_;
  219. absl::optional<std::string> rp_id_;
  220. };
  221. class UvTokenRequest : public TokenRequest {
  222. public:
  223. UvTokenRequest(PINUVAuthProtocol protocol,
  224. const KeyAgreementResponse& peer_key,
  225. absl::optional<std::string> rp_id,
  226. base::span<const pin::Permissions> permissions);
  227. UvTokenRequest(UvTokenRequest&&);
  228. UvTokenRequest(const UvTokenRequest&) = delete;
  229. virtual ~UvTokenRequest();
  230. friend std::pair<CtapRequestCommand, absl::optional<cbor::Value>>
  231. AsCTAPRequestValuePair(const UvTokenRequest&);
  232. private:
  233. absl::optional<std::string> rp_id_;
  234. uint8_t permissions_;
  235. };
  236. class HMACSecretRequest {
  237. public:
  238. HMACSecretRequest(PINUVAuthProtocol protocol,
  239. const KeyAgreementResponse& peer_key,
  240. base::span<const uint8_t, 32> salt1,
  241. const absl::optional<std::array<uint8_t, 32>>& salt2);
  242. HMACSecretRequest(const HMACSecretRequest&);
  243. ~HMACSecretRequest();
  244. HMACSecretRequest& operator=(const HMACSecretRequest&);
  245. absl::optional<std::vector<uint8_t>> Decrypt(
  246. base::span<const uint8_t> ciphertext);
  247. private:
  248. const PINUVAuthProtocol protocol_;
  249. std::vector<uint8_t> shared_key_;
  250. public:
  251. const std::array<uint8_t, kP256X962Length> public_key_x962;
  252. const std::vector<uint8_t> encrypted_salts;
  253. const std::vector<uint8_t> salts_auth;
  254. };
  255. // TokenResponse represents the response to a pin-token request. In order to
  256. // decrypt a response, the shared key from the request is needed. Once a pin-
  257. // token has been decrypted, it can be used to calculate the pinAuth parameters
  258. // needed to show user-verification in future operations.
  259. class COMPONENT_EXPORT(DEVICE_FIDO) TokenResponse {
  260. public:
  261. ~TokenResponse();
  262. TokenResponse(const TokenResponse&);
  263. TokenResponse& operator=(const TokenResponse&);
  264. static absl::optional<TokenResponse> Parse(
  265. PINUVAuthProtocol protocol,
  266. base::span<const uint8_t> shared_key,
  267. const absl::optional<cbor::Value>& cbor);
  268. std::pair<PINUVAuthProtocol, std::vector<uint8_t>> PinAuth(
  269. base::span<const uint8_t> client_data_hash) const;
  270. PINUVAuthProtocol protocol() const { return protocol_; }
  271. const std::vector<uint8_t>& token_for_testing() const { return token_; }
  272. private:
  273. explicit TokenResponse(PINUVAuthProtocol protocol);
  274. PINUVAuthProtocol protocol_;
  275. std::vector<uint8_t> token_;
  276. };
  277. std::pair<CtapRequestCommand, absl::optional<cbor::Value>>
  278. AsCTAPRequestValuePair(const PinRetriesRequest&);
  279. std::pair<CtapRequestCommand, absl::optional<cbor::Value>>
  280. AsCTAPRequestValuePair(const UvRetriesRequest&);
  281. std::pair<CtapRequestCommand, absl::optional<cbor::Value>>
  282. AsCTAPRequestValuePair(const KeyAgreementRequest&);
  283. std::pair<CtapRequestCommand, absl::optional<cbor::Value>>
  284. AsCTAPRequestValuePair(const SetRequest&);
  285. std::pair<CtapRequestCommand, absl::optional<cbor::Value>>
  286. AsCTAPRequestValuePair(const ChangeRequest&);
  287. std::pair<CtapRequestCommand, absl::optional<cbor::Value>>
  288. AsCTAPRequestValuePair(const ResetRequest&);
  289. std::pair<CtapRequestCommand, absl::optional<cbor::Value>>
  290. AsCTAPRequestValuePair(const TokenRequest&);
  291. } // namespace pin
  292. } // namespace device
  293. #endif // DEVICE_FIDO_PIN_H_