| OLD | NEW |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "u2f_apdu_command.h" | 5 #include "u2f_apdu_command.h" |
| 6 | 6 |
| 7 namespace device { | 7 namespace device { |
| 8 | 8 |
| 9 scoped_refptr<U2fApduCommand> U2fApduCommand::CreateFromMessage( | 9 scoped_refptr<U2fApduCommand> U2fApduCommand::CreateFromMessage( |
| 10 const std::vector<uint8_t>& message) { | 10 const std::vector<uint8_t>& message) { |
| 11 uint16_t data_length = 0; | 11 uint16_t data_length = 0; |
| 12 size_t index = 0, response_length = 0; | 12 size_t index = 0; |
| 13 size_t response_length = 0; |
| 13 std::vector<uint8_t> data; | 14 std::vector<uint8_t> data; |
| 15 std::vector<uint8_t> suffix; |
| 14 | 16 |
| 15 if (message.size() < kApduMinHeader || message.size() > kApduMaxLength) | 17 if (message.size() < kApduMinHeader || message.size() > kApduMaxLength) |
| 16 return nullptr; | 18 return nullptr; |
| 17 uint8_t cla = message[index++]; | 19 uint8_t cla = message[index++]; |
| 18 uint8_t ins = message[index++]; | 20 uint8_t ins = message[index++]; |
| 19 uint8_t p1 = message[index++]; | 21 uint8_t p1 = message[index++]; |
| 20 uint8_t p2 = message[index++]; | 22 uint8_t p2 = message[index++]; |
| 21 | 23 |
| 22 switch (message.size()) { | 24 switch (message.size()) { |
| 23 // No data present; no expected response | 25 // No data present; no expected response |
| (...skipping 28 matching lines...) Expand all Loading... |
| 52 } else if (message.size() == data_length + index + 2) { | 54 } else if (message.size() == data_length + index + 2) { |
| 53 // Maximum response size is stored in final 2 bytes | 55 // Maximum response size is stored in final 2 bytes |
| 54 data.insert(data.end(), message.begin() + index, message.end() - 2); | 56 data.insert(data.end(), message.begin() + index, message.end() - 2); |
| 55 index += data_length; | 57 index += data_length; |
| 56 response_length = message[index++] << 8; | 58 response_length = message[index++] << 8; |
| 57 response_length |= message[index++]; | 59 response_length |= message[index++]; |
| 58 // Special case where response length of 0x0000 corresponds to 65536 | 60 // Special case where response length of 0x0000 corresponds to 65536 |
| 59 // Defined in ISO7816-4 | 61 // Defined in ISO7816-4 |
| 60 if (response_length == 0) | 62 if (response_length == 0) |
| 61 response_length = kApduMaxResponseLength; | 63 response_length = kApduMaxResponseLength; |
| 64 // Non-ISO7816-4 special legacy case where 2 suffix bytes are passed |
| 65 // along with a version message |
| 66 if (data_length == 0 && ins == kInsU2fVersion) |
| 67 suffix = {0x0, 0x0}; |
| 62 } else { | 68 } else { |
| 63 return nullptr; | 69 return nullptr; |
| 64 } | 70 } |
| 65 break; | 71 break; |
| 66 } | 72 } |
| 67 | 73 |
| 68 return make_scoped_refptr( | 74 return make_scoped_refptr(new U2fApduCommand( |
| 69 new U2fApduCommand(cla, ins, p1, p2, response_length, std::move(data))); | 75 cla, ins, p1, p2, response_length, std::move(data), std::move(suffix))); |
| 70 } | 76 } |
| 71 | 77 |
| 72 // static | 78 // static |
| 73 scoped_refptr<U2fApduCommand> U2fApduCommand::Create() { | 79 scoped_refptr<U2fApduCommand> U2fApduCommand::Create() { |
| 74 return make_scoped_refptr(new U2fApduCommand()); | 80 return make_scoped_refptr(new U2fApduCommand()); |
| 75 } | 81 } |
| 76 | 82 |
| 77 std::vector<uint8_t> U2fApduCommand::GetEncodedCommand() const { | 83 std::vector<uint8_t> U2fApduCommand::GetEncodedCommand() const { |
| 78 std::vector<uint8_t> encoded = {cla_, ins_, p1_, p2_}; | 84 std::vector<uint8_t> encoded = {cla_, ins_, p1_, p2_}; |
| 79 | 85 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 91 encoded.push_back(data_length & 0xff); | 97 encoded.push_back(data_length & 0xff); |
| 92 encoded.insert(encoded.end(), data_.begin(), data_.begin() + data_length); | 98 encoded.insert(encoded.end(), data_.begin(), data_.begin() + data_length); |
| 93 } else if (response_length_ > 0) { | 99 } else if (response_length_ > 0) { |
| 94 encoded.push_back(0x0); | 100 encoded.push_back(0x0); |
| 95 } | 101 } |
| 96 | 102 |
| 97 if (response_length_ > 0) { | 103 if (response_length_ > 0) { |
| 98 encoded.push_back((response_length_ >> 8) & 0xff); | 104 encoded.push_back((response_length_ >> 8) & 0xff); |
| 99 encoded.push_back(response_length_ & 0xff); | 105 encoded.push_back(response_length_ & 0xff); |
| 100 } | 106 } |
| 107 // Add suffix, if required, for legacy compatibility |
| 108 encoded.insert(encoded.end(), suffix_.begin(), suffix_.end()); |
| 101 return encoded; | 109 return encoded; |
| 102 } | 110 } |
| 103 | 111 |
| 104 U2fApduCommand::U2fApduCommand() | 112 U2fApduCommand::U2fApduCommand() |
| 105 : cla_(0), ins_(0), p1_(0), p2_(0), response_length_(0) {} | 113 : cla_(0), ins_(0), p1_(0), p2_(0), response_length_(0) {} |
| 106 | 114 |
| 107 U2fApduCommand::U2fApduCommand(uint8_t cla, | 115 U2fApduCommand::U2fApduCommand(uint8_t cla, |
| 108 uint8_t ins, | 116 uint8_t ins, |
| 109 uint8_t p1, | 117 uint8_t p1, |
| 110 uint8_t p2, | 118 uint8_t p2, |
| 111 size_t response_length, | 119 size_t response_length, |
| 112 std::vector<uint8_t> data) | 120 std::vector<uint8_t> data, |
| 121 std::vector<uint8_t> suffix) |
| 113 : cla_(cla), | 122 : cla_(cla), |
| 114 ins_(ins), | 123 ins_(ins), |
| 115 p1_(p1), | 124 p1_(p1), |
| 116 p2_(p2), | 125 p2_(p2), |
| 117 response_length_(response_length), | 126 response_length_(response_length), |
| 118 data_(std::move(data)) {} | 127 data_(std::move(data)), |
| 128 suffix_(std::move(suffix)) {} |
| 119 | 129 |
| 120 U2fApduCommand::~U2fApduCommand() {} | 130 U2fApduCommand::~U2fApduCommand() {} |
| 121 | 131 |
| 132 // static |
| 133 scoped_refptr<U2fApduCommand> U2fApduCommand::CreateRegister( |
| 134 const std::vector<uint8_t>& appid_digest, |
| 135 const std::vector<uint8_t>& challenge_digest) { |
| 136 if (appid_digest.size() != kAppIdDigestLen || |
| 137 challenge_digest.size() != kChallengeDigestLen) { |
| 138 return nullptr; |
| 139 } |
| 140 |
| 141 scoped_refptr<U2fApduCommand> command = Create(); |
| 142 std::vector<uint8_t> data(challenge_digest.begin(), challenge_digest.end()); |
| 143 data.insert(data.end(), appid_digest.begin(), appid_digest.end()); |
| 144 command->set_ins(kInsU2fEnroll); |
| 145 command->set_p1(kP1TupRequiredConsumed); |
| 146 command->set_data(data); |
| 147 return command; |
| 148 } |
| 149 |
| 150 // static |
| 151 scoped_refptr<U2fApduCommand> U2fApduCommand::CreateVersion() { |
| 152 scoped_refptr<U2fApduCommand> command = Create(); |
| 153 command->set_ins(kInsU2fVersion); |
| 154 command->set_response_length(kApduMaxResponseLength); |
| 155 return command; |
| 156 } |
| 157 |
| 158 // static |
| 159 scoped_refptr<U2fApduCommand> U2fApduCommand::CreateLegacyVersion() { |
| 160 scoped_refptr<U2fApduCommand> command = Create(); |
| 161 command->set_ins(kInsU2fVersion); |
| 162 command->set_response_length(kApduMaxResponseLength); |
| 163 // Early U2F drafts defined the U2F version command in extended |
| 164 // length ISO 7816-4 format so 2 additional 0x0 bytes are necessary. |
| 165 // https://fidoalliance.org/specs/fido-u2f-v1.1-id-20160915/fido-u2f-raw-messa
ge-formats-v1.1-id-20160915.html#implementation-considerations |
| 166 command->set_suffix(std::vector<uint8_t>(2, 0)); |
| 167 return command; |
| 168 } |
| 169 |
| 170 // static |
| 171 scoped_refptr<U2fApduCommand> U2fApduCommand::CreateSign( |
| 172 const std::vector<uint8_t>& appid_digest, |
| 173 const std::vector<uint8_t>& challenge_digest, |
| 174 const std::vector<uint8_t>& key_handle) { |
| 175 if (appid_digest.size() != kAppIdDigestLen || |
| 176 challenge_digest.size() != kChallengeDigestLen || |
| 177 key_handle.size() > kMaxKeyHandleLength) { |
| 178 return nullptr; |
| 179 } |
| 180 |
| 181 scoped_refptr<U2fApduCommand> command = Create(); |
| 182 std::vector<uint8_t> data(challenge_digest.begin(), challenge_digest.end()); |
| 183 data.insert(data.end(), appid_digest.begin(), appid_digest.end()); |
| 184 data.push_back(static_cast<uint8_t>(key_handle.size())); |
| 185 data.insert(data.end(), key_handle.begin(), key_handle.end()); |
| 186 command->set_ins(kInsU2fSign); |
| 187 command->set_p1(kP1TupRequiredConsumed); |
| 188 command->set_data(data); |
| 189 return command; |
| 190 } |
| 191 |
| 122 } // namespace device | 192 } // namespace device |
| OLD | NEW |