blob: 3630ce0f3ebd1cd285ce4ab102c59e27418a1204 [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_APDU_H_
#define U2FD_U2F_APDU_H_
#include <stdint.h>
#include <string>
#include <vector>
#include <base/optional.h>
#include "u2fd/util.h"
// Classes for dealing with command and response APDUs, as described in the "U2F
// Raw Message Formats" specification.
namespace u2f {
// INS codes used in U2F Command APDUs.
enum class U2fIns : uint8_t {
kU2fRegister = 1, // U2F_REGISTER
kU2fAuthenticate = 2, // U2F_AUTHENTICATE
kU2fVersion = 3, // U2F_VERSION
// TODO(crbug.com/1218246) Change UMA enum name kU2fCommand if new enums are
// added to avoid data discontinuity.
kInsInvalid = 0xff,
};
// Represents a command APDU.
class U2fCommandApdu {
public:
// Fixed-size header of a command APDU.
struct Header {
U2fIns ins_;
uint8_t p1_;
uint8_t p2_;
};
// Attempts to parse the specified string as an APDU, and returns a valid
// U2fCommandApdu 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<U2fCommandApdu> ParseFromString(
const std::string& apdu_raw, uint16_t* u2f_status);
// Creates an 'empty' APDU for the command with the specified INS command
// code.
static U2fCommandApdu CreateForU2fIns(U2fIns ins);
// Returns the INS command code for this APDU.
U2fIns Ins() const { return header_.ins_; }
// Returns the P1 parameter for this APDU.
uint8_t P1() const { return header_.p1_; }
// Returns the request body for this APDU.
const std::string& Body() const { return data_; }
// Returns the max response length for this APDU.
uint32_t MaxResponseLength() const { return max_response_length_; }
// Serializes this APDU 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.
U2fCommandApdu() = default;
// Internal parser class called by ParseFromString().
class Parser;
friend class Parser;
};
// Represents an APDU for a U2F_REGISTER request.
class U2fRegisterRequestApdu {
public:
// Attempt to parse the body of the specified APDU as a U2F_REGISTER request.
// Returns a valid U2fRegisterRequestApdu 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<U2fRegisterRequestApdu> FromCommandApdu(
const U2fCommandApdu& apdu, 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 U2fAuthenticateRequestApdu {
public:
// Attempt to parse the body of the specified APDU as a U2F_AUTHENTICATE
// request. Returns a valid U2fRegisterRequestApdu 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<U2fAuthenticateRequestApdu> FromCommandApdu(
const U2fCommandApdu& apdu, uint16_t* u2f_status);
// Returns true if the APDU 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 APDU. Provides methods for building nd serializing a
// response.
class U2fResponseApdu {
public:
// Constructs an empty response.
U2fResponseApdu() = 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_APDU_H_