Louis Collard | 99e4024 | 2019-08-30 14:57:39 +0800 | [diff] [blame] | 1 | // Copyright 2019 The Chromium OS Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "u2fd/u2f_msg_handler.h" |
| 6 | |
| 7 | #include <utility> |
| 8 | |
| 9 | #include <brillo/secure_blob.h> |
| 10 | #include <trunks/cr50_headers/u2f.h> |
| 11 | |
| 12 | #include "u2fd/util.h" |
| 13 | |
| 14 | namespace u2f { |
| 15 | |
| 16 | namespace { |
| 17 | |
| 18 | // Response to the APDU requesting the U2F protocol version |
| 19 | constexpr char kSupportedU2fVersion[] = "U2F_V2"; |
| 20 | |
| 21 | // U2F_REGISTER response prefix, indicating U2F_VER_2. |
| 22 | // See FIDO "U2F Raw Message Formats" spec. |
| 23 | constexpr uint8_t kU2fVer2Prefix = 5; |
| 24 | |
| 25 | // UMA Metric names. |
| 26 | constexpr char kU2fCommand[] = "Platform.U2F.Command"; |
| 27 | |
| 28 | } // namespace |
| 29 | |
| 30 | U2fMessageHandler::U2fMessageHandler( |
Louis Collard | d4ee40d | 2019-10-01 14:19:01 +0800 | [diff] [blame] | 31 | std::unique_ptr<AllowlistingUtil> allowlisting_util, |
Louis Collard | 99e4024 | 2019-08-30 14:57:39 +0800 | [diff] [blame] | 32 | std::function<void()> request_user_presence, |
Louis Collard | a5fa3c3 | 2019-10-07 15:02:25 +0800 | [diff] [blame] | 33 | UserState* user_state, |
Louis Collard | 99e4024 | 2019-08-30 14:57:39 +0800 | [diff] [blame] | 34 | TpmVendorCommandProxy* proxy, |
| 35 | MetricsLibraryInterface* metrics, |
| 36 | bool allow_legacy_kh_sign, |
| 37 | bool allow_g2f_attestation) |
Louis Collard | a5fa3c3 | 2019-10-07 15:02:25 +0800 | [diff] [blame] | 38 | : allowlisting_util_(std::move(allowlisting_util)), |
Louis Collard | 99e4024 | 2019-08-30 14:57:39 +0800 | [diff] [blame] | 39 | request_user_presence_(request_user_presence), |
Louis Collard | a5fa3c3 | 2019-10-07 15:02:25 +0800 | [diff] [blame] | 40 | |
| 41 | user_state_(user_state), |
Louis Collard | 99e4024 | 2019-08-30 14:57:39 +0800 | [diff] [blame] | 42 | proxy_(proxy), |
| 43 | metrics_(metrics), |
| 44 | allow_legacy_kh_sign_(allow_legacy_kh_sign), |
| 45 | allow_g2f_attestation_(allow_g2f_attestation) {} |
| 46 | |
| 47 | U2fResponseAdpu U2fMessageHandler::ProcessMsg(const std::string& req) { |
| 48 | uint16_t u2f_status = 0; |
| 49 | |
| 50 | base::Optional<U2fCommandAdpu> adpu = |
| 51 | U2fCommandAdpu::ParseFromString(req, &u2f_status); |
| 52 | |
| 53 | if (!adpu.has_value()) { |
| 54 | return BuildEmptyResponse(u2f_status ?: U2F_SW_WTF); |
| 55 | } |
| 56 | |
| 57 | U2fIns ins = adpu->Ins(); |
| 58 | |
| 59 | metrics_->SendEnumToUMA(kU2fCommand, static_cast<int>(ins), |
| 60 | static_cast<int>(U2fIns::kU2fVersion)); |
| 61 | |
| 62 | // TODO(louiscollard): Check expected response length is large enough. |
| 63 | |
| 64 | switch (ins) { |
| 65 | case U2fIns::kU2fRegister: { |
| 66 | base::Optional<U2fRegisterRequestAdpu> reg_adpu = |
| 67 | U2fRegisterRequestAdpu::FromCommandAdpu(*adpu, &u2f_status); |
| 68 | // Chrome may send a dummy register request, which is designed to |
| 69 | // cause a USB device to flash it's LED. We should simply ignore |
| 70 | // these. |
| 71 | if (reg_adpu.has_value()) { |
| 72 | if (reg_adpu->IsChromeDummyWinkRequest()) { |
| 73 | return BuildEmptyResponse(U2F_SW_CONDITIONS_NOT_SATISFIED); |
| 74 | } else { |
| 75 | return ProcessU2fRegister(*reg_adpu); |
| 76 | } |
| 77 | } |
| 78 | break; // Handle error. |
| 79 | } |
| 80 | case U2fIns::kU2fAuthenticate: { |
| 81 | base::Optional<U2fAuthenticateRequestAdpu> auth_adpu = |
| 82 | U2fAuthenticateRequestAdpu::FromCommandAdpu(*adpu, &u2f_status); |
| 83 | if (auth_adpu.has_value()) { |
| 84 | return ProcessU2fAuthenticate(*auth_adpu); |
| 85 | } |
| 86 | break; // Handle error. |
| 87 | } |
| 88 | case U2fIns::kU2fVersion: { |
| 89 | if (!adpu->Body().empty()) { |
| 90 | u2f_status = U2F_SW_WRONG_LENGTH; |
| 91 | break; |
| 92 | } |
| 93 | |
| 94 | U2fResponseAdpu response; |
| 95 | response.AppendString(kSupportedU2fVersion); |
| 96 | response.SetStatus(U2F_SW_NO_ERROR); |
| 97 | return response; |
| 98 | } |
| 99 | default: |
| 100 | u2f_status = U2F_SW_INS_NOT_SUPPORTED; |
| 101 | break; |
| 102 | } |
| 103 | |
| 104 | return BuildEmptyResponse(u2f_status ?: U2F_SW_WTF); |
| 105 | } |
| 106 | |
Louis Collard | 99e4024 | 2019-08-30 14:57:39 +0800 | [diff] [blame] | 107 | U2fResponseAdpu U2fMessageHandler::ProcessU2fRegister( |
| 108 | const U2fRegisterRequestAdpu& request) { |
| 109 | std::vector<uint8_t> pub_key; |
| 110 | std::vector<uint8_t> key_handle; |
| 111 | |
| 112 | Cr50CmdStatus generate_status = |
| 113 | DoU2fGenerate(request.GetAppId(), &pub_key, &key_handle); |
| 114 | |
| 115 | if (generate_status == Cr50CmdStatus::kNotAllowed) { |
| 116 | request_user_presence_(); |
| 117 | } |
| 118 | |
| 119 | if (generate_status != Cr50CmdStatus::kSuccess) { |
| 120 | return BuildErrorResponse(generate_status); |
| 121 | } |
| 122 | |
Yicheng Li | 1bbf529 | 2021-01-25 17:19:56 -0800 | [diff] [blame] | 123 | std::vector<uint8_t> data_to_sign = util::BuildU2fRegisterResponseSignedData( |
Louis Collard | 99e4024 | 2019-08-30 14:57:39 +0800 | [diff] [blame] | 124 | request.GetAppId(), request.GetChallenge(), pub_key, key_handle); |
| 125 | |
| 126 | std::vector<uint8_t> attestation_cert; |
| 127 | std::vector<uint8_t> signature; |
Louis Collard | d4ee40d | 2019-10-01 14:19:01 +0800 | [diff] [blame] | 128 | std::vector<uint8_t> allowlisting_data; |
Louis Collard | 99e4024 | 2019-08-30 14:57:39 +0800 | [diff] [blame] | 129 | |
| 130 | if (allow_g2f_attestation_ && request.UseG2fAttestation()) { |
Yicheng Li | 1bbf529 | 2021-01-25 17:19:56 -0800 | [diff] [blame] | 131 | base::Optional<std::vector<uint8_t>> g2f_cert = util::GetG2fCert(proxy_); |
Louis Collard | 99e4024 | 2019-08-30 14:57:39 +0800 | [diff] [blame] | 132 | |
| 133 | if (g2f_cert.has_value()) { |
| 134 | attestation_cert = *g2f_cert; |
| 135 | } else { |
| 136 | return BuildEmptyResponse(U2F_SW_WTF); |
| 137 | } |
| 138 | |
| 139 | Cr50CmdStatus attest_status = |
| 140 | DoG2fAttest(data_to_sign, U2F_ATTEST_FORMAT_REG_RESP, &signature); |
| 141 | |
| 142 | if (attest_status != Cr50CmdStatus::kSuccess) { |
| 143 | return BuildEmptyResponse(U2F_SW_WTF); |
| 144 | } |
Louis Collard | d4ee40d | 2019-10-01 14:19:01 +0800 | [diff] [blame] | 145 | |
| 146 | if (allowlisting_util_ != nullptr && |
| 147 | !allowlisting_util_->AppendDataToCert(&attestation_cert)) { |
| 148 | LOG(ERROR) << "Failed to get allowlisting data for G2F Enroll Request"; |
| 149 | return BuildEmptyResponse(U2F_SW_WTF); |
| 150 | } |
Yicheng Li | 1bbf529 | 2021-01-25 17:19:56 -0800 | [diff] [blame] | 151 | } else if (!util::DoSoftwareAttest(data_to_sign, &attestation_cert, |
| 152 | &signature)) { |
Louis Collard | 99e4024 | 2019-08-30 14:57:39 +0800 | [diff] [blame] | 153 | return BuildEmptyResponse(U2F_SW_WTF); |
| 154 | } |
| 155 | |
| 156 | // Prepare response, as specified by "U2F Raw Message Formats". |
| 157 | U2fResponseAdpu register_resp; |
| 158 | register_resp.AppendByte(kU2fVer2Prefix); |
| 159 | register_resp.AppendBytes(pub_key); |
| 160 | register_resp.AppendByte(key_handle.size()); |
| 161 | register_resp.AppendBytes(key_handle); |
| 162 | register_resp.AppendBytes(attestation_cert); |
| 163 | register_resp.AppendBytes(signature); |
| 164 | register_resp.SetStatus(U2F_SW_NO_ERROR); |
| 165 | |
| 166 | return register_resp; |
| 167 | } |
| 168 | |
| 169 | namespace { |
| 170 | |
| 171 | // A success response to a U2F_AUTHENTICATE request includes a signature over |
| 172 | // the following data, in this format. |
| 173 | std::vector<uint8_t> BuildU2fAuthenticateResponseSignedData( |
| 174 | const std::vector<uint8_t>& app_id, |
| 175 | const std::vector<uint8_t>& challenge, |
| 176 | const std::vector<uint8_t>& counter) { |
| 177 | std::vector<uint8_t> to_sign; |
| 178 | util::AppendToVector(app_id, &to_sign); |
| 179 | to_sign.push_back(U2F_AUTH_FLAG_TUP); |
| 180 | util::AppendToVector(counter, &to_sign); |
| 181 | util::AppendToVector(challenge, &to_sign); |
| 182 | return to_sign; |
| 183 | } |
| 184 | |
| 185 | } // namespace |
| 186 | |
| 187 | U2fResponseAdpu U2fMessageHandler::ProcessU2fAuthenticate( |
| 188 | const U2fAuthenticateRequestAdpu& request) { |
| 189 | if (request.IsAuthenticateCheckOnly()) { |
| 190 | // The authenticate only version of this command always returns an error (on |
| 191 | // success, returns an error requesting presence). |
| 192 | Cr50CmdStatus sign_status = |
| 193 | DoU2fSignCheckOnly(request.GetAppId(), request.GetKeyHandle()); |
| 194 | if (sign_status == Cr50CmdStatus::kSuccess) { |
| 195 | return BuildEmptyResponse(U2F_SW_CONDITIONS_NOT_SATISFIED); |
| 196 | } else { |
| 197 | return BuildErrorResponse(sign_status); |
| 198 | } |
| 199 | } |
| 200 | |
| 201 | base::Optional<std::vector<uint8_t>> counter = user_state_->GetCounter(); |
| 202 | if (!counter.has_value()) { |
| 203 | LOG(ERROR) << "Failed to retrieve counter value"; |
| 204 | return BuildEmptyResponse(U2F_SW_WTF); |
| 205 | } |
| 206 | |
| 207 | std::vector<uint8_t> to_sign = BuildU2fAuthenticateResponseSignedData( |
| 208 | request.GetAppId(), request.GetChallenge(), *counter); |
| 209 | |
| 210 | std::vector<uint8_t> signature; |
| 211 | |
| 212 | Cr50CmdStatus sign_status = |
| 213 | DoU2fSign(request.GetAppId(), request.GetKeyHandle(), |
| 214 | util::Sha256(to_sign), &signature); |
| 215 | |
| 216 | if (sign_status == Cr50CmdStatus::kNotAllowed) { |
| 217 | request_user_presence_(); |
| 218 | } |
| 219 | |
| 220 | if (sign_status != Cr50CmdStatus::kSuccess) { |
| 221 | return BuildErrorResponse(sign_status); |
| 222 | } |
| 223 | |
| 224 | if (!user_state_->IncrementCounter()) { |
| 225 | // If we can't increment the counter we must not return the signed |
| 226 | // response, as the next authenticate response would end up having |
| 227 | // the same counter value. |
| 228 | return BuildEmptyResponse(U2F_SW_WTF); |
| 229 | } |
| 230 | |
| 231 | // Everything succeeded; build response. |
| 232 | |
| 233 | // Prepare response, as specified by "U2F Raw Message Formats". |
| 234 | U2fResponseAdpu auth_resp; |
| 235 | auth_resp.AppendByte(U2F_AUTH_FLAG_TUP); |
| 236 | auth_resp.AppendBytes(*counter); |
| 237 | auth_resp.AppendBytes(signature); |
| 238 | auth_resp.SetStatus(U2F_SW_NO_ERROR); |
| 239 | |
| 240 | return auth_resp; |
| 241 | } |
| 242 | |
| 243 | U2fMessageHandler::Cr50CmdStatus U2fMessageHandler::DoU2fGenerate( |
| 244 | const std::vector<uint8_t>& app_id, |
| 245 | std::vector<uint8_t>* pub_key, |
| 246 | std::vector<uint8_t>* key_handle) { |
Yicheng Li | c03ac7e | 2019-12-09 16:13:26 -0800 | [diff] [blame] | 247 | base::AutoLock(proxy_->GetLock()); |
Louis Collard | 99e4024 | 2019-08-30 14:57:39 +0800 | [diff] [blame] | 248 | base::Optional<brillo::SecureBlob> user_secret = user_state_->GetUserSecret(); |
| 249 | if (!user_secret.has_value()) { |
| 250 | return Cr50CmdStatus::kInvalidState; |
| 251 | } |
| 252 | |
Yicheng Li | 519a56d | 2020-09-17 19:16:31 +0000 | [diff] [blame] | 253 | struct u2f_generate_req generate_req = { |
Louis Collard | 99e4024 | 2019-08-30 14:57:39 +0800 | [diff] [blame] | 254 | .flags = U2F_AUTH_ENFORCE // Require user presence, consume. |
| 255 | }; |
Yi Chou | ad18f17 | 2020-11-18 14:54:18 +0800 | [diff] [blame] | 256 | if (!util::VectorToObject(app_id, generate_req.appId, |
| 257 | sizeof(generate_req.appId))) { |
| 258 | return Cr50CmdStatus::kInvalidState; |
| 259 | } |
| 260 | if (!util::VectorToObject(*user_secret, generate_req.userSecret, |
| 261 | sizeof(generate_req.userSecret))) { |
| 262 | return Cr50CmdStatus::kInvalidState; |
| 263 | } |
Louis Collard | 99e4024 | 2019-08-30 14:57:39 +0800 | [diff] [blame] | 264 | |
Louis Collard | be15928 | 2020-02-12 15:29:56 +0800 | [diff] [blame] | 265 | struct u2f_generate_resp generate_resp = {}; |
Louis Collard | 99e4024 | 2019-08-30 14:57:39 +0800 | [diff] [blame] | 266 | Cr50CmdStatus generate_status = static_cast<Cr50CmdStatus>( |
| 267 | proxy_->SendU2fGenerate(generate_req, &generate_resp)); |
| 268 | |
Tom Hughes | bd48f33 | 2021-01-07 10:18:05 -0800 | [diff] [blame] | 269 | brillo::SecureClearBytes(&generate_req.userSecret, |
| 270 | sizeof(generate_req.userSecret)); |
Louis Collard | 292e213 | 2020-02-12 15:08:46 +0800 | [diff] [blame] | 271 | |
Louis Collard | 99e4024 | 2019-08-30 14:57:39 +0800 | [diff] [blame] | 272 | if (generate_status != Cr50CmdStatus::kSuccess) { |
| 273 | return generate_status; |
| 274 | } |
| 275 | |
| 276 | util::AppendToVector(generate_resp.pubKey, pub_key); |
| 277 | util::AppendToVector(generate_resp.keyHandle, key_handle); |
| 278 | |
| 279 | return Cr50CmdStatus::kSuccess; |
| 280 | } |
| 281 | |
| 282 | U2fMessageHandler::Cr50CmdStatus U2fMessageHandler::DoU2fSign( |
| 283 | const std::vector<uint8_t>& app_id, |
| 284 | const std::vector<uint8_t>& key_handle, |
| 285 | const std::vector<uint8_t>& hash, |
| 286 | std::vector<uint8_t>* signature_out) { |
Yicheng Li | c03ac7e | 2019-12-09 16:13:26 -0800 | [diff] [blame] | 287 | base::AutoLock(proxy_->GetLock()); |
Louis Collard | 99e4024 | 2019-08-30 14:57:39 +0800 | [diff] [blame] | 288 | base::Optional<brillo::SecureBlob> user_secret = user_state_->GetUserSecret(); |
| 289 | if (!user_secret.has_value()) { |
| 290 | return Cr50CmdStatus::kInvalidState; |
| 291 | } |
| 292 | |
Louis Collard | be15928 | 2020-02-12 15:29:56 +0800 | [diff] [blame] | 293 | struct u2f_sign_req sign_req = { |
Louis Collard | 99e4024 | 2019-08-30 14:57:39 +0800 | [diff] [blame] | 294 | .flags = U2F_AUTH_ENFORCE // Require user presence, consume. |
| 295 | }; |
| 296 | if (allow_legacy_kh_sign_) |
| 297 | sign_req.flags |= SIGN_LEGACY_KH; |
Yi Chou | ad18f17 | 2020-11-18 14:54:18 +0800 | [diff] [blame] | 298 | if (!util::VectorToObject(app_id, sign_req.appId, sizeof(sign_req.appId))) { |
| 299 | return Cr50CmdStatus::kInvalidState; |
| 300 | } |
| 301 | if (!util::VectorToObject(*user_secret, sign_req.userSecret, |
| 302 | sizeof(sign_req.userSecret))) { |
| 303 | return Cr50CmdStatus::kInvalidState; |
| 304 | } |
| 305 | if (!util::VectorToObject(key_handle, &sign_req.keyHandle, |
| 306 | sizeof(sign_req.keyHandle))) { |
| 307 | return Cr50CmdStatus::kInvalidState; |
| 308 | } |
| 309 | if (!util::VectorToObject(hash, sign_req.hash, sizeof(sign_req.hash))) { |
| 310 | return Cr50CmdStatus::kInvalidState; |
| 311 | } |
Louis Collard | 99e4024 | 2019-08-30 14:57:39 +0800 | [diff] [blame] | 312 | |
Louis Collard | be15928 | 2020-02-12 15:29:56 +0800 | [diff] [blame] | 313 | struct u2f_sign_resp sign_resp = {}; |
Louis Collard | 99e4024 | 2019-08-30 14:57:39 +0800 | [diff] [blame] | 314 | Cr50CmdStatus sign_status = |
| 315 | static_cast<Cr50CmdStatus>(proxy_->SendU2fSign(sign_req, &sign_resp)); |
| 316 | |
Tom Hughes | bd48f33 | 2021-01-07 10:18:05 -0800 | [diff] [blame] | 317 | brillo::SecureClearBytes(&sign_req.userSecret, sizeof(sign_req.userSecret)); |
Louis Collard | 292e213 | 2020-02-12 15:08:46 +0800 | [diff] [blame] | 318 | |
Louis Collard | 99e4024 | 2019-08-30 14:57:39 +0800 | [diff] [blame] | 319 | if (sign_status != Cr50CmdStatus::kSuccess) { |
| 320 | return sign_status; |
| 321 | } |
| 322 | |
| 323 | base::Optional<std::vector<uint8_t>> signature = |
| 324 | util::SignatureToDerBytes(sign_resp.sig_r, sign_resp.sig_s); |
| 325 | |
| 326 | if (!signature.has_value()) { |
| 327 | return Cr50CmdStatus::kInvalidResponseData; |
| 328 | } |
| 329 | |
| 330 | *signature_out = *signature; |
| 331 | |
| 332 | return Cr50CmdStatus::kSuccess; |
| 333 | } |
| 334 | |
| 335 | U2fMessageHandler::Cr50CmdStatus U2fMessageHandler::DoU2fSignCheckOnly( |
| 336 | const std::vector<uint8_t>& app_id, |
| 337 | const std::vector<uint8_t>& key_handle) { |
Yicheng Li | c03ac7e | 2019-12-09 16:13:26 -0800 | [diff] [blame] | 338 | base::AutoLock(proxy_->GetLock()); |
Louis Collard | 99e4024 | 2019-08-30 14:57:39 +0800 | [diff] [blame] | 339 | base::Optional<brillo::SecureBlob> user_secret = user_state_->GetUserSecret(); |
| 340 | if (!user_secret.has_value()) { |
| 341 | return Cr50CmdStatus::kInvalidState; |
| 342 | } |
| 343 | |
Louis Collard | be15928 | 2020-02-12 15:29:56 +0800 | [diff] [blame] | 344 | struct u2f_sign_req sign_req = { |
Louis Collard | 99e4024 | 2019-08-30 14:57:39 +0800 | [diff] [blame] | 345 | .flags = U2F_AUTH_CHECK_ONLY // No user presence required, no consume. |
| 346 | }; |
Yi Chou | ad18f17 | 2020-11-18 14:54:18 +0800 | [diff] [blame] | 347 | if (!util::VectorToObject(app_id, sign_req.appId, sizeof(sign_req.appId))) { |
| 348 | return Cr50CmdStatus::kInvalidState; |
| 349 | } |
| 350 | if (!util::VectorToObject(*user_secret, sign_req.userSecret, |
| 351 | sizeof(sign_req.userSecret))) { |
| 352 | return Cr50CmdStatus::kInvalidState; |
| 353 | } |
| 354 | if (!util::VectorToObject(key_handle, &sign_req.keyHandle, |
| 355 | sizeof(sign_req.keyHandle))) { |
| 356 | return Cr50CmdStatus::kInvalidState; |
| 357 | } |
Louis Collard | 99e4024 | 2019-08-30 14:57:39 +0800 | [diff] [blame] | 358 | |
Louis Collard | 292e213 | 2020-02-12 15:08:46 +0800 | [diff] [blame] | 359 | Cr50CmdStatus sign_status = |
| 360 | static_cast<Cr50CmdStatus>(proxy_->SendU2fSign(sign_req, nullptr)); |
| 361 | |
Tom Hughes | bd48f33 | 2021-01-07 10:18:05 -0800 | [diff] [blame] | 362 | brillo::SecureClearBytes(&sign_req.userSecret, sizeof(sign_req.userSecret)); |
Louis Collard | 292e213 | 2020-02-12 15:08:46 +0800 | [diff] [blame] | 363 | |
| 364 | return sign_status; |
Louis Collard | 99e4024 | 2019-08-30 14:57:39 +0800 | [diff] [blame] | 365 | } |
| 366 | |
| 367 | U2fMessageHandler::Cr50CmdStatus U2fMessageHandler::DoG2fAttest( |
| 368 | const std::vector<uint8_t>& data, |
| 369 | uint8_t format, |
| 370 | std::vector<uint8_t>* signature_out) { |
Yicheng Li | c03ac7e | 2019-12-09 16:13:26 -0800 | [diff] [blame] | 371 | base::AutoLock(proxy_->GetLock()); |
Louis Collard | 99e4024 | 2019-08-30 14:57:39 +0800 | [diff] [blame] | 372 | base::Optional<brillo::SecureBlob> user_secret = user_state_->GetUserSecret(); |
| 373 | if (!user_secret.has_value()) { |
| 374 | return Cr50CmdStatus::kInvalidState; |
| 375 | } |
| 376 | |
Louis Collard | be15928 | 2020-02-12 15:29:56 +0800 | [diff] [blame] | 377 | struct u2f_attest_req attest_req = { |
| 378 | .format = format, .dataLen = static_cast<uint8_t>(data.size())}; |
Yi Chou | ad18f17 | 2020-11-18 14:54:18 +0800 | [diff] [blame] | 379 | if (!util::VectorToObject(*user_secret, attest_req.userSecret, |
| 380 | sizeof(attest_req.userSecret))) { |
| 381 | return Cr50CmdStatus::kInvalidState; |
| 382 | } |
| 383 | if (!util::VectorToObject(data, attest_req.data, sizeof(attest_req.data))) { |
| 384 | return Cr50CmdStatus::kInvalidState; |
| 385 | } |
Louis Collard | 99e4024 | 2019-08-30 14:57:39 +0800 | [diff] [blame] | 386 | |
Louis Collard | be15928 | 2020-02-12 15:29:56 +0800 | [diff] [blame] | 387 | struct u2f_attest_resp attest_resp = {}; |
Louis Collard | 99e4024 | 2019-08-30 14:57:39 +0800 | [diff] [blame] | 388 | Cr50CmdStatus attest_status = static_cast<Cr50CmdStatus>( |
| 389 | proxy_->SendU2fAttest(attest_req, &attest_resp)); |
| 390 | |
Tom Hughes | bd48f33 | 2021-01-07 10:18:05 -0800 | [diff] [blame] | 391 | brillo::SecureClearBytes(&attest_req.userSecret, |
| 392 | sizeof(attest_req.userSecret)); |
Louis Collard | 292e213 | 2020-02-12 15:08:46 +0800 | [diff] [blame] | 393 | |
Louis Collard | 99e4024 | 2019-08-30 14:57:39 +0800 | [diff] [blame] | 394 | if (attest_status != Cr50CmdStatus::kSuccess) { |
| 395 | // We are attesting to a key handle that we just created, so if |
| 396 | // attestation fails we have hit some internal error. |
| 397 | LOG(ERROR) << "U2F_ATTEST failed, status: " << std::hex |
| 398 | << static_cast<uint32_t>(attest_status); |
| 399 | return attest_status; |
| 400 | } |
| 401 | |
| 402 | base::Optional<std::vector<uint8_t>> signature = |
| 403 | util::SignatureToDerBytes(attest_resp.sig_r, attest_resp.sig_s); |
| 404 | |
| 405 | if (!signature.has_value()) { |
| 406 | LOG(ERROR) << "DER encoding of U2F_ATTEST signature failed."; |
| 407 | return Cr50CmdStatus::kInvalidResponseData; |
| 408 | } |
| 409 | |
| 410 | *signature_out = *signature; |
| 411 | |
| 412 | return Cr50CmdStatus::kSuccess; |
| 413 | } |
| 414 | |
| 415 | U2fResponseAdpu U2fMessageHandler::BuildEmptyResponse(uint16_t sw) { |
| 416 | U2fResponseAdpu resp_adpu; |
| 417 | resp_adpu.SetStatus(sw); |
| 418 | return resp_adpu; |
| 419 | } |
| 420 | |
| 421 | U2fResponseAdpu U2fMessageHandler::BuildErrorResponse(Cr50CmdStatus status) { |
| 422 | uint16_t sw; |
| 423 | |
| 424 | switch (status) { |
| 425 | case Cr50CmdStatus::kNotAllowed: |
| 426 | sw = U2F_SW_CONDITIONS_NOT_SATISFIED; |
| 427 | break; |
| 428 | case Cr50CmdStatus::kPasswordRequired: |
| 429 | sw = U2F_SW_WRONG_DATA; |
| 430 | break; |
| 431 | case Cr50CmdStatus::kInvalidState: |
| 432 | sw = U2F_SW_WTF; |
| 433 | break; |
| 434 | default: |
| 435 | LOG(ERROR) << "Unexpected Cr50CmdStatus: " << std::hex |
| 436 | << static_cast<uint32_t>(status); |
| 437 | sw = U2F_SW_WTF; |
| 438 | } |
| 439 | |
| 440 | return BuildEmptyResponse(sw); |
| 441 | } |
| 442 | |
Louis Collard | 99e4024 | 2019-08-30 14:57:39 +0800 | [diff] [blame] | 443 | } // namespace u2f |