| Index: device/u2f/u2f_apdu_command.cc
|
| diff --git a/device/u2f/u2f_apdu_command.cc b/device/u2f/u2f_apdu_command.cc
|
| index cd854825e53d8d64367ea5fe2dd4f22f385f44fa..2bb8efe6e1c40a6efdbe8451ca94688b6f854833 100644
|
| --- a/device/u2f/u2f_apdu_command.cc
|
| +++ b/device/u2f/u2f_apdu_command.cc
|
| @@ -9,8 +9,10 @@ namespace device {
|
| scoped_refptr<U2fApduCommand> U2fApduCommand::CreateFromMessage(
|
| const std::vector<uint8_t>& message) {
|
| uint16_t data_length = 0;
|
| - size_t index = 0, response_length = 0;
|
| + size_t index = 0;
|
| + size_t response_length = 0;
|
| std::vector<uint8_t> data;
|
| + std::vector<uint8_t> suffix;
|
|
|
| if (message.size() < kApduMinHeader || message.size() > kApduMaxLength)
|
| return nullptr;
|
| @@ -59,14 +61,18 @@ scoped_refptr<U2fApduCommand> U2fApduCommand::CreateFromMessage(
|
| // Defined in ISO7816-4
|
| if (response_length == 0)
|
| response_length = kApduMaxResponseLength;
|
| + // Non-ISO7816-4 special legacy case where 2 suffix bytes are passed
|
| + // along with a version message
|
| + if (data_length == 0 && ins == kInsU2fVersion)
|
| + suffix = {0x0, 0x0};
|
| } else {
|
| return nullptr;
|
| }
|
| break;
|
| }
|
|
|
| - return make_scoped_refptr(
|
| - new U2fApduCommand(cla, ins, p1, p2, response_length, std::move(data)));
|
| + return make_scoped_refptr(new U2fApduCommand(
|
| + cla, ins, p1, p2, response_length, std::move(data), std::move(suffix)));
|
| }
|
|
|
| // static
|
| @@ -98,6 +104,8 @@ std::vector<uint8_t> U2fApduCommand::GetEncodedCommand() const {
|
| encoded.push_back((response_length_ >> 8) & 0xff);
|
| encoded.push_back(response_length_ & 0xff);
|
| }
|
| + // Add suffix, if required, for legacy compatibility
|
| + encoded.insert(encoded.end(), suffix_.begin(), suffix_.end());
|
| return encoded;
|
| }
|
|
|
| @@ -109,14 +117,76 @@ U2fApduCommand::U2fApduCommand(uint8_t cla,
|
| uint8_t p1,
|
| uint8_t p2,
|
| size_t response_length,
|
| - std::vector<uint8_t> data)
|
| + std::vector<uint8_t> data,
|
| + std::vector<uint8_t> suffix)
|
| : cla_(cla),
|
| ins_(ins),
|
| p1_(p1),
|
| p2_(p2),
|
| response_length_(response_length),
|
| - data_(std::move(data)) {}
|
| + data_(std::move(data)),
|
| + suffix_(std::move(suffix)) {}
|
|
|
| U2fApduCommand::~U2fApduCommand() {}
|
|
|
| +// static
|
| +scoped_refptr<U2fApduCommand> U2fApduCommand::CreateRegister(
|
| + const std::vector<uint8_t>& appid_digest,
|
| + const std::vector<uint8_t>& challenge_digest) {
|
| + if (appid_digest.size() != kAppIdDigestLen ||
|
| + challenge_digest.size() != kChallengeDigestLen) {
|
| + return nullptr;
|
| + }
|
| +
|
| + scoped_refptr<U2fApduCommand> command = Create();
|
| + std::vector<uint8_t> data(challenge_digest.begin(), challenge_digest.end());
|
| + data.insert(data.end(), appid_digest.begin(), appid_digest.end());
|
| + command->set_ins(kInsU2fEnroll);
|
| + command->set_p1(kP1TupRequiredConsumed);
|
| + command->set_data(data);
|
| + return command;
|
| +}
|
| +
|
| +// static
|
| +scoped_refptr<U2fApduCommand> U2fApduCommand::CreateVersion() {
|
| + scoped_refptr<U2fApduCommand> command = Create();
|
| + command->set_ins(kInsU2fVersion);
|
| + command->set_response_length(kApduMaxResponseLength);
|
| + return command;
|
| +}
|
| +
|
| +// static
|
| +scoped_refptr<U2fApduCommand> U2fApduCommand::CreateLegacyVersion() {
|
| + scoped_refptr<U2fApduCommand> command = Create();
|
| + command->set_ins(kInsU2fVersion);
|
| + command->set_response_length(kApduMaxResponseLength);
|
| + // Early U2F drafts defined the U2F version command in extended
|
| + // length ISO 7816-4 format so 2 additional 0x0 bytes are necessary.
|
| + // https://fidoalliance.org/specs/fido-u2f-v1.1-id-20160915/fido-u2f-raw-message-formats-v1.1-id-20160915.html#implementation-considerations
|
| + command->set_suffix(std::vector<uint8_t>(2, 0));
|
| + return command;
|
| +}
|
| +
|
| +// static
|
| +scoped_refptr<U2fApduCommand> U2fApduCommand::CreateSign(
|
| + const std::vector<uint8_t>& appid_digest,
|
| + const std::vector<uint8_t>& challenge_digest,
|
| + const std::vector<uint8_t>& key_handle) {
|
| + if (appid_digest.size() != kAppIdDigestLen ||
|
| + challenge_digest.size() != kChallengeDigestLen ||
|
| + key_handle.size() > kMaxKeyHandleLength) {
|
| + return nullptr;
|
| + }
|
| +
|
| + scoped_refptr<U2fApduCommand> command = Create();
|
| + std::vector<uint8_t> data(challenge_digest.begin(), challenge_digest.end());
|
| + data.insert(data.end(), appid_digest.begin(), appid_digest.end());
|
| + data.push_back(static_cast<uint8_t>(key_handle.size()));
|
| + data.insert(data.end(), key_handle.begin(), key_handle.end());
|
| + command->set_ins(kInsU2fSign);
|
| + command->set_p1(kP1TupRequiredConsumed);
|
| + command->set_data(data);
|
| + return command;
|
| +}
|
| +
|
| } // namespace device
|
|
|