blob: 61d1014a3d3e3dbc2b6543edb7c1b96df76974ff [file] [log] [blame]
Louis Collard99e40242019-08-30 14:57:39 +08001// 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
14namespace u2f {
15
16namespace {
17
18// Response to the APDU requesting the U2F protocol version
19constexpr char kSupportedU2fVersion[] = "U2F_V2";
20
21// U2F_REGISTER response prefix, indicating U2F_VER_2.
22// See FIDO "U2F Raw Message Formats" spec.
23constexpr uint8_t kU2fVer2Prefix = 5;
24
25// UMA Metric names.
26constexpr char kU2fCommand[] = "Platform.U2F.Command";
27
28} // namespace
29
30U2fMessageHandler::U2fMessageHandler(
Louis Collardd4ee40d2019-10-01 14:19:01 +080031 std::unique_ptr<AllowlistingUtil> allowlisting_util,
Louis Collard99e40242019-08-30 14:57:39 +080032 std::function<void()> request_user_presence,
Louis Collarda5fa3c32019-10-07 15:02:25 +080033 UserState* user_state,
Louis Collard99e40242019-08-30 14:57:39 +080034 TpmVendorCommandProxy* proxy,
35 MetricsLibraryInterface* metrics,
36 bool allow_legacy_kh_sign,
37 bool allow_g2f_attestation)
Louis Collarda5fa3c32019-10-07 15:02:25 +080038 : allowlisting_util_(std::move(allowlisting_util)),
Louis Collard99e40242019-08-30 14:57:39 +080039 request_user_presence_(request_user_presence),
Louis Collarda5fa3c32019-10-07 15:02:25 +080040
41 user_state_(user_state),
Louis Collard99e40242019-08-30 14:57:39 +080042 proxy_(proxy),
43 metrics_(metrics),
44 allow_legacy_kh_sign_(allow_legacy_kh_sign),
45 allow_g2f_attestation_(allow_g2f_attestation) {}
46
47U2fResponseAdpu 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 Collard99e40242019-08-30 14:57:39 +0800107U2fResponseAdpu 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 Li1bbf5292021-01-25 17:19:56 -0800123 std::vector<uint8_t> data_to_sign = util::BuildU2fRegisterResponseSignedData(
Louis Collard99e40242019-08-30 14:57:39 +0800124 request.GetAppId(), request.GetChallenge(), pub_key, key_handle);
125
126 std::vector<uint8_t> attestation_cert;
127 std::vector<uint8_t> signature;
Louis Collardd4ee40d2019-10-01 14:19:01 +0800128 std::vector<uint8_t> allowlisting_data;
Louis Collard99e40242019-08-30 14:57:39 +0800129
130 if (allow_g2f_attestation_ && request.UseG2fAttestation()) {
Yicheng Li1bbf5292021-01-25 17:19:56 -0800131 base::Optional<std::vector<uint8_t>> g2f_cert = util::GetG2fCert(proxy_);
Louis Collard99e40242019-08-30 14:57:39 +0800132
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 Collardd4ee40d2019-10-01 14:19:01 +0800145
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 Li1bbf5292021-01-25 17:19:56 -0800151 } else if (!util::DoSoftwareAttest(data_to_sign, &attestation_cert,
152 &signature)) {
Louis Collard99e40242019-08-30 14:57:39 +0800153 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
169namespace {
170
171// A success response to a U2F_AUTHENTICATE request includes a signature over
172// the following data, in this format.
173std::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
187U2fResponseAdpu 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
243U2fMessageHandler::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 Lic03ac7e2019-12-09 16:13:26 -0800247 base::AutoLock(proxy_->GetLock());
Louis Collard99e40242019-08-30 14:57:39 +0800248 base::Optional<brillo::SecureBlob> user_secret = user_state_->GetUserSecret();
249 if (!user_secret.has_value()) {
250 return Cr50CmdStatus::kInvalidState;
251 }
252
Yicheng Li519a56d2020-09-17 19:16:31 +0000253 struct u2f_generate_req generate_req = {
Louis Collard99e40242019-08-30 14:57:39 +0800254 .flags = U2F_AUTH_ENFORCE // Require user presence, consume.
255 };
Yi Chouad18f172020-11-18 14:54:18 +0800256 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 Collard99e40242019-08-30 14:57:39 +0800264
Louis Collardbe159282020-02-12 15:29:56 +0800265 struct u2f_generate_resp generate_resp = {};
Louis Collard99e40242019-08-30 14:57:39 +0800266 Cr50CmdStatus generate_status = static_cast<Cr50CmdStatus>(
267 proxy_->SendU2fGenerate(generate_req, &generate_resp));
268
Tom Hughesbd48f332021-01-07 10:18:05 -0800269 brillo::SecureClearBytes(&generate_req.userSecret,
270 sizeof(generate_req.userSecret));
Louis Collard292e2132020-02-12 15:08:46 +0800271
Louis Collard99e40242019-08-30 14:57:39 +0800272 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
282U2fMessageHandler::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 Lic03ac7e2019-12-09 16:13:26 -0800287 base::AutoLock(proxy_->GetLock());
Louis Collard99e40242019-08-30 14:57:39 +0800288 base::Optional<brillo::SecureBlob> user_secret = user_state_->GetUserSecret();
289 if (!user_secret.has_value()) {
290 return Cr50CmdStatus::kInvalidState;
291 }
292
Louis Collardbe159282020-02-12 15:29:56 +0800293 struct u2f_sign_req sign_req = {
Louis Collard99e40242019-08-30 14:57:39 +0800294 .flags = U2F_AUTH_ENFORCE // Require user presence, consume.
295 };
296 if (allow_legacy_kh_sign_)
297 sign_req.flags |= SIGN_LEGACY_KH;
Yi Chouad18f172020-11-18 14:54:18 +0800298 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 Collard99e40242019-08-30 14:57:39 +0800312
Louis Collardbe159282020-02-12 15:29:56 +0800313 struct u2f_sign_resp sign_resp = {};
Louis Collard99e40242019-08-30 14:57:39 +0800314 Cr50CmdStatus sign_status =
315 static_cast<Cr50CmdStatus>(proxy_->SendU2fSign(sign_req, &sign_resp));
316
Tom Hughesbd48f332021-01-07 10:18:05 -0800317 brillo::SecureClearBytes(&sign_req.userSecret, sizeof(sign_req.userSecret));
Louis Collard292e2132020-02-12 15:08:46 +0800318
Louis Collard99e40242019-08-30 14:57:39 +0800319 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
335U2fMessageHandler::Cr50CmdStatus U2fMessageHandler::DoU2fSignCheckOnly(
336 const std::vector<uint8_t>& app_id,
337 const std::vector<uint8_t>& key_handle) {
Yicheng Lic03ac7e2019-12-09 16:13:26 -0800338 base::AutoLock(proxy_->GetLock());
Louis Collard99e40242019-08-30 14:57:39 +0800339 base::Optional<brillo::SecureBlob> user_secret = user_state_->GetUserSecret();
340 if (!user_secret.has_value()) {
341 return Cr50CmdStatus::kInvalidState;
342 }
343
Louis Collardbe159282020-02-12 15:29:56 +0800344 struct u2f_sign_req sign_req = {
Louis Collard99e40242019-08-30 14:57:39 +0800345 .flags = U2F_AUTH_CHECK_ONLY // No user presence required, no consume.
346 };
Yi Chouad18f172020-11-18 14:54:18 +0800347 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 Collard99e40242019-08-30 14:57:39 +0800358
Louis Collard292e2132020-02-12 15:08:46 +0800359 Cr50CmdStatus sign_status =
360 static_cast<Cr50CmdStatus>(proxy_->SendU2fSign(sign_req, nullptr));
361
Tom Hughesbd48f332021-01-07 10:18:05 -0800362 brillo::SecureClearBytes(&sign_req.userSecret, sizeof(sign_req.userSecret));
Louis Collard292e2132020-02-12 15:08:46 +0800363
364 return sign_status;
Louis Collard99e40242019-08-30 14:57:39 +0800365}
366
367U2fMessageHandler::Cr50CmdStatus U2fMessageHandler::DoG2fAttest(
368 const std::vector<uint8_t>& data,
369 uint8_t format,
370 std::vector<uint8_t>* signature_out) {
Yicheng Lic03ac7e2019-12-09 16:13:26 -0800371 base::AutoLock(proxy_->GetLock());
Louis Collard99e40242019-08-30 14:57:39 +0800372 base::Optional<brillo::SecureBlob> user_secret = user_state_->GetUserSecret();
373 if (!user_secret.has_value()) {
374 return Cr50CmdStatus::kInvalidState;
375 }
376
Louis Collardbe159282020-02-12 15:29:56 +0800377 struct u2f_attest_req attest_req = {
378 .format = format, .dataLen = static_cast<uint8_t>(data.size())};
Yi Chouad18f172020-11-18 14:54:18 +0800379 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 Collard99e40242019-08-30 14:57:39 +0800386
Louis Collardbe159282020-02-12 15:29:56 +0800387 struct u2f_attest_resp attest_resp = {};
Louis Collard99e40242019-08-30 14:57:39 +0800388 Cr50CmdStatus attest_status = static_cast<Cr50CmdStatus>(
389 proxy_->SendU2fAttest(attest_req, &attest_resp));
390
Tom Hughesbd48f332021-01-07 10:18:05 -0800391 brillo::SecureClearBytes(&attest_req.userSecret,
392 sizeof(attest_req.userSecret));
Louis Collard292e2132020-02-12 15:08:46 +0800393
Louis Collard99e40242019-08-30 14:57:39 +0800394 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
415U2fResponseAdpu U2fMessageHandler::BuildEmptyResponse(uint16_t sw) {
416 U2fResponseAdpu resp_adpu;
417 resp_adpu.SetStatus(sw);
418 return resp_adpu;
419}
420
421U2fResponseAdpu 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 Collard99e40242019-08-30 14:57:39 +0800443} // namespace u2f