blob: f8e7bceb44037b3dc63bb5d20a216b0faba31d09 [file] [log] [blame]
// 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_