| // Copyright 2019 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef U2FD_U2F_ADPU_H_ |
| #define U2FD_U2F_ADPU_H_ |
| |
| #include <stdint.h> |
| #include <string> |
| #include <vector> |
| |
| #include <base/optional.h> |
| |
| #include "u2fd/util.h" |
| |
| // Classes for dealing with command and response ADPUs, as described in the "U2F |
| // Raw Message Formats" specification. |
| |
| namespace u2f { |
| |
| // INS codes used in U2F Command ADPUs. |
| enum class U2fIns : uint8_t { |
| kU2fRegister = 1, // U2F_REGISTER |
| kU2fAuthenticate = 2, // U2F_AUTHENTICATE |
| kU2fVersion = 3, // U2F_VERSION |
| kInsInvalid = 0xff, |
| }; |
| |
| // Represents a command ADPU. |
| class U2fCommandAdpu { |
| public: |
| // Fixed-size header of a command ADPU. |
| struct Header { |
| U2fIns ins_; |
| uint8_t p1_; |
| uint8_t p2_; |
| }; |
| |
| // Attempts to parse the specified string as an ADPU, and returns a valid |
| // U2fCommandAdpu if successful, or base::nullopt otherwise. If unsuccessful, |
| // and u2f_status is not null, populates it with a U2F status code indicating |
| // the type of failure, if an appropriate code is available, or 0 otherwise. |
| static base::Optional<U2fCommandAdpu> ParseFromString( |
| const std::string& adpu_raw, uint16_t* u2f_status); |
| |
| // Creates an 'empty' ADPU for the command with the specified INS command |
| // code. |
| static U2fCommandAdpu CreateForU2fIns(U2fIns ins); |
| |
| // Returns the INS command code for this ADPU. |
| U2fIns Ins() const { return header_.ins_; } |
| // Returns the P1 parameter for this ADPU. |
| uint8_t P1() const { return header_.p1_; } |
| // Returns the request body for this ADPU. |
| const std::string& Body() const { return data_; } |
| // Returns the max response length for this ADPU. |
| uint32_t MaxResponseLength() const { return max_response_length_; } |
| // Serializes this ADPU to a string. |
| std::string ToString() const; |
| |
| protected: |
| Header header_; |
| std::string data_; |
| uint32_t max_response_length_; |
| |
| private: |
| // Private constructor, use factory methods above. |
| U2fCommandAdpu() = default; |
| // Internal parser class called by ParseFromString(). |
| class Parser; |
| friend class Parser; |
| }; |
| |
| // Represents an ADPU for a U2F_REGISTER request. |
| class U2fRegisterRequestAdpu { |
| public: |
| // Attempt to parse the body of the specified ADPU as a U2F_REGISTER request. |
| // Returns a valid U2fRegisterRequestAdpu if successful, or base::nullopt |
| // otherwise. If unsuccessful, and u2f_status is not null, populates it with |
| // a U2F status code indicating the type of failure, if an appropriate code |
| // is available, or 0 otherwise. |
| static base::Optional<U2fRegisterRequestAdpu> FromCommandAdpu( |
| const U2fCommandAdpu& adpu, uint16_t* u2f_status); |
| |
| // Whether the request response should use the G2F attestation certificate (if |
| // available). |
| bool UseG2fAttestation() const { return g2f_attestation_; } |
| |
| // Whether the request is a 'bogus' request sent by Chrome, solely to cause a |
| // USB device to flash its LED. |
| bool IsChromeDummyWinkRequest() const; |
| |
| // Accessors for the request fields. |
| const std::vector<uint8_t>& GetAppId() const { return app_id_; } |
| const std::vector<uint8_t>& GetChallenge() const { return challenge_; } |
| |
| private: |
| bool g2f_attestation_; |
| std::vector<uint8_t> app_id_; |
| std::vector<uint8_t> challenge_; |
| }; |
| |
| class U2fAuthenticateRequestAdpu { |
| public: |
| // Attempt to parse the body of the specified ADPU as a U2F_AUTHENTICATE |
| // request. Returns a valid U2fRegisterRequestAdpu if successful, or |
| // base::nullopt otherwise. If unsuccessful, and u2f_status is not null, |
| // populates it with a U2F status code indicating the type of failure, |
| // if an appropriate code is available, or 0 otherwise. |
| static base::Optional<U2fAuthenticateRequestAdpu> FromCommandAdpu( |
| const U2fCommandAdpu& adpu, uint16_t* u2f_status); |
| |
| // Returns true if the ADPU is for a U2F_AUTHENTICATE check-only |
| // request. Check-only requests should verify whether the specified key handle |
| // is owned by this U2F device, but not perform any authentication. |
| bool IsAuthenticateCheckOnly() const { return auth_check_only_; } |
| |
| // Accessors for the request fields. |
| const std::vector<uint8_t>& GetAppId() const { return app_id_; } |
| const std::vector<uint8_t>& GetChallenge() const { return challenge_; } |
| const std::vector<uint8_t>& GetKeyHandle() const { return key_handle_; } |
| |
| private: |
| bool auth_check_only_; |
| std::vector<uint8_t> app_id_; |
| std::vector<uint8_t> challenge_; |
| std::vector<uint8_t> key_handle_; |
| }; |
| |
| // Represents a response ADPU. Provides methods for building and serializing a |
| // response. |
| class U2fResponseAdpu { |
| public: |
| // Constructs an empty response. |
| U2fResponseAdpu() = default; |
| |
| // Serialize the response to the specified string. |
| bool ToString(std::string* out) const; |
| |
| // Methods to append data to the response. |
| void AppendByte(uint8_t byte) { data_.push_back(byte); } |
| void AppendBytes(const std::vector<uint8_t>& bytes) { |
| util::AppendToVector(bytes, &data_); |
| } |
| void AppendString(const std::string& string) { |
| util::AppendToVector(string, &data_); |
| } |
| template <typename T> |
| void AppendObject(const T& obj) { |
| util::AppendToVector(obj, &data_); |
| } |
| |
| // Sets the return status for the response. |
| void SetStatus(uint16_t sw) { |
| sw1_ = sw >> 8; |
| sw2_ = static_cast<uint8_t>(sw); |
| } |
| |
| private: |
| std::vector<uint8_t> data_; |
| uint8_t sw1_; |
| uint8_t sw2_; |
| }; |
| |
| } // namespace u2f |
| |
| #endif // U2FD_U2F_ADPU_H_ |