1 // Copyright 2018 The Chromium 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 "content/browser/webauth/virtual_authenticator.h"
6 
7 #include <utility>
8 
9 #include "base/bind.h"
10 #include "base/guid.h"
11 #include "base/optional.h"
12 #include "crypto/ec_private_key.h"
13 #include "device/fido/fido_parsing_utils.h"
14 #include "device/fido/public_key_credential_rp_entity.h"
15 #include "device/fido/public_key_credential_user_entity.h"
16 #include "device/fido/virtual_ctap2_device.h"
17 #include "device/fido/virtual_u2f_device.h"
18 
19 namespace content {
20 
VirtualAuthenticator(device::ProtocolVersion protocol,device::Ctap2Version ctap2_version,device::FidoTransportProtocol transport,device::AuthenticatorAttachment attachment,bool has_resident_key,bool has_user_verification,bool has_large_blob)21 VirtualAuthenticator::VirtualAuthenticator(
22     device::ProtocolVersion protocol,
23     device::Ctap2Version ctap2_version,
24     device::FidoTransportProtocol transport,
25     device::AuthenticatorAttachment attachment,
26     bool has_resident_key,
27     bool has_user_verification,
28     bool has_large_blob)
29     : protocol_(protocol),
30       ctap2_version_(ctap2_version),
31       attachment_(attachment),
32       has_resident_key_(has_resident_key),
33       has_user_verification_(has_user_verification),
34       has_large_blob_(has_large_blob),
35       unique_id_(base::GenerateGUID()),
36       state_(base::MakeRefCounted<device::VirtualFidoDevice::State>()) {
37   state_->transport = transport;
38   // If the authenticator has user verification, simulate having set it up
39   // already.
40   state_->fingerprints_enrolled = has_user_verification_;
41   SetUserPresence(true);
42 }
43 
44 VirtualAuthenticator::~VirtualAuthenticator() = default;
45 
AddReceiver(mojo::PendingReceiver<blink::test::mojom::VirtualAuthenticator> receiver)46 void VirtualAuthenticator::AddReceiver(
47     mojo::PendingReceiver<blink::test::mojom::VirtualAuthenticator> receiver) {
48   receiver_set_.Add(this, std::move(receiver));
49 }
50 
AddRegistration(std::vector<uint8_t> key_handle,const std::string & rp_id,base::span<const uint8_t> private_key,int32_t counter)51 bool VirtualAuthenticator::AddRegistration(
52     std::vector<uint8_t> key_handle,
53     const std::string& rp_id,
54     base::span<const uint8_t> private_key,
55     int32_t counter) {
56   base::Optional<std::unique_ptr<device::VirtualFidoDevice::PrivateKey>>
57       fido_private_key =
58           device::VirtualFidoDevice::PrivateKey::FromPKCS8(private_key);
59   if (!fido_private_key)
60     return false;
61 
62   return state_->registrations
63       .emplace(
64           std::move(key_handle),
65           device::VirtualFidoDevice::RegistrationData(
66               std::move(*fido_private_key),
67               device::fido_parsing_utils::CreateSHA256Hash(rp_id), counter))
68       .second;
69 }
70 
AddResidentRegistration(std::vector<uint8_t> key_handle,std::string rp_id,base::span<const uint8_t> private_key,int32_t counter,std::vector<uint8_t> user_handle)71 bool VirtualAuthenticator::AddResidentRegistration(
72     std::vector<uint8_t> key_handle,
73     std::string rp_id,
74     base::span<const uint8_t> private_key,
75     int32_t counter,
76     std::vector<uint8_t> user_handle) {
77   base::Optional<std::unique_ptr<device::VirtualFidoDevice::PrivateKey>>
78       fido_private_key =
79           device::VirtualFidoDevice::PrivateKey::FromPKCS8(private_key);
80   if (!fido_private_key)
81     return false;
82 
83   return state_->InjectResidentKey(
84       std::move(key_handle),
85       device::PublicKeyCredentialRpEntity(std::move(rp_id)),
86       device::PublicKeyCredentialUserEntity(std::move(user_handle)), counter,
87       std::move(*fido_private_key));
88 }
89 
ClearRegistrations()90 void VirtualAuthenticator::ClearRegistrations() {
91   state_->registrations.clear();
92 }
93 
RemoveRegistration(const std::vector<uint8_t> & key_handle)94 bool VirtualAuthenticator::RemoveRegistration(
95     const std::vector<uint8_t>& key_handle) {
96   return state_->registrations.erase(key_handle) != 0;
97 }
98 
SetUserPresence(bool is_user_present)99 void VirtualAuthenticator::SetUserPresence(bool is_user_present) {
100   is_user_present_ = is_user_present;
101   state_->simulate_press_callback = base::BindRepeating(
102       [](bool is_user_present, device::VirtualFidoDevice* device) {
103         return is_user_present;
104       },
105       is_user_present);
106 }
107 
ConstructDevice()108 std::unique_ptr<device::FidoDevice> VirtualAuthenticator::ConstructDevice() {
109   switch (protocol_) {
110     case device::ProtocolVersion::kU2f:
111       return std::make_unique<device::VirtualU2fDevice>(state_);
112     case device::ProtocolVersion::kCtap2: {
113       device::VirtualCtap2Device::Config config;
114       switch (ctap2_version_) {
115         case device::Ctap2Version::kCtap2_0:
116           config.ctap2_versions = {std::begin(device::kCtap2Versions2_0),
117                                    std::end(device::kCtap2Versions2_0)};
118           break;
119         case device::Ctap2Version::kCtap2_1:
120           config.ctap2_versions = {std::begin(device::kCtap2Versions2_1),
121                                    std::end(device::kCtap2Versions2_1)};
122           break;
123       }
124       config.resident_key_support = has_resident_key_;
125       config.large_blob_support = has_large_blob_;
126       if (has_large_blob_ && has_user_verification_) {
127         // Writing a large blob requires obtaining a PinUvAuthToken with
128         // permissions if the authenticator is protected by user verification.
129         config.pin_uv_auth_token_support = true;
130       }
131       config.internal_uv_support = has_user_verification_;
132       config.is_platform_authenticator =
133           attachment_ == device::AuthenticatorAttachment::kPlatform;
134       config.user_verification_succeeds = is_user_verified_;
135       return std::make_unique<device::VirtualCtap2Device>(state_, config);
136     }
137     default:
138       NOTREACHED();
139       return std::make_unique<device::VirtualU2fDevice>(state_);
140   }
141 }
142 
GetLargeBlob(const std::vector<uint8_t> & key_handle,GetLargeBlobCallback callback)143 void VirtualAuthenticator::GetLargeBlob(const std::vector<uint8_t>& key_handle,
144                                         GetLargeBlobCallback callback) {
145   auto registration = state_->registrations.find(key_handle);
146   if (registration == state_->registrations.end()) {
147     std::move(callback).Run(base::nullopt);
148     return;
149   }
150   base::Optional<std::vector<uint8_t>> blob =
151       state_->GetLargeBlob(registration->second);
152   if (!blob) {
153     std::move(callback).Run(base::nullopt);
154     return;
155   }
156   data_decoder_.GzipUncompress(
157       std::move(*blob),
158       base::BindOnce(&VirtualAuthenticator::OnLargeBlobUncompressed,
159                      weak_factory_.GetWeakPtr(), std::move(callback)));
160 }
161 
SetLargeBlob(const std::vector<uint8_t> & key_handle,const std::vector<uint8_t> & blob,SetLargeBlobCallback callback)162 void VirtualAuthenticator::SetLargeBlob(const std::vector<uint8_t>& key_handle,
163                                         const std::vector<uint8_t>& blob,
164                                         SetLargeBlobCallback callback) {
165   data_decoder_.GzipCompress(
166       blob, base::BindOnce(&VirtualAuthenticator::OnLargeBlobCompressed,
167                            weak_factory_.GetWeakPtr(), key_handle,
168                            std::move(callback)));
169 }
170 
GetUniqueId(GetUniqueIdCallback callback)171 void VirtualAuthenticator::GetUniqueId(GetUniqueIdCallback callback) {
172   std::move(callback).Run(unique_id_);
173 }
174 
GetRegistrations(GetRegistrationsCallback callback)175 void VirtualAuthenticator::GetRegistrations(GetRegistrationsCallback callback) {
176   std::vector<blink::test::mojom::RegisteredKeyPtr> mojo_registered_keys;
177   for (const auto& registration : state_->registrations) {
178     auto mojo_registered_key = blink::test::mojom::RegisteredKey::New();
179     mojo_registered_key->key_handle = registration.first;
180     mojo_registered_key->counter = registration.second.counter;
181     mojo_registered_key->rp_id =
182         registration.second.rp ? registration.second.rp->id : "";
183     mojo_registered_key->private_key =
184         registration.second.private_key->GetPKCS8PrivateKey();
185     mojo_registered_keys.push_back(std::move(mojo_registered_key));
186   }
187   std::move(callback).Run(std::move(mojo_registered_keys));
188 }
189 
AddRegistration(blink::test::mojom::RegisteredKeyPtr registration,AddRegistrationCallback callback)190 void VirtualAuthenticator::AddRegistration(
191     blink::test::mojom::RegisteredKeyPtr registration,
192     AddRegistrationCallback callback) {
193   std::move(callback).Run(AddRegistration(
194       std::move(registration->key_handle), std::move(registration->rp_id),
195       registration->private_key, registration->counter));
196 }
197 
ClearRegistrations(ClearRegistrationsCallback callback)198 void VirtualAuthenticator::ClearRegistrations(
199     ClearRegistrationsCallback callback) {
200   ClearRegistrations();
201   std::move(callback).Run();
202 }
203 
RemoveRegistration(const std::vector<uint8_t> & key_handle,RemoveRegistrationCallback callback)204 void VirtualAuthenticator::RemoveRegistration(
205     const std::vector<uint8_t>& key_handle,
206     RemoveRegistrationCallback callback) {
207   std::move(callback).Run(RemoveRegistration(std::move(key_handle)));
208 }
209 
SetUserVerified(bool verified,SetUserVerifiedCallback callback)210 void VirtualAuthenticator::SetUserVerified(bool verified,
211                                            SetUserVerifiedCallback callback) {
212   is_user_verified_ = verified;
213   std::move(callback).Run();
214 }
215 
OnLargeBlobUncompressed(GetLargeBlobCallback callback,data_decoder::DataDecoder::ResultOrError<mojo_base::BigBuffer> result)216 void VirtualAuthenticator::OnLargeBlobUncompressed(
217     GetLargeBlobCallback callback,
218     data_decoder::DataDecoder::ResultOrError<mojo_base::BigBuffer> result) {
219   std::move(callback).Run(
220       device::fido_parsing_utils::MaterializeOrNull(result.value));
221 }
222 
OnLargeBlobCompressed(base::span<const uint8_t> key_handle,SetLargeBlobCallback callback,data_decoder::DataDecoder::ResultOrError<mojo_base::BigBuffer> result)223 void VirtualAuthenticator::OnLargeBlobCompressed(
224     base::span<const uint8_t> key_handle,
225     SetLargeBlobCallback callback,
226     data_decoder::DataDecoder::ResultOrError<mojo_base::BigBuffer> result) {
227   auto registration = state_->registrations.find(key_handle);
228   if (registration == state_->registrations.end()) {
229     std::move(callback).Run(false);
230     return;
231   }
232   if (!result.value) {
233     std::move(callback).Run(false);
234     return;
235   }
236   state_->InjectLargeBlob(&registration->second, *result.value);
237   std::move(callback).Run(true);
238 }
239 
240 }  // namespace content
241