1 // Copyright 2014 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.
5 #include "chrome/browser/extensions/api/networking_private/crypto_verify_impl.h"
7 #include "base/base64.h"
9 #include "base/bind_helpers.h"
10 #include "base/sequenced_task_runner.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_util.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "base/threading/sequenced_worker_pool.h"
15 #include "chrome/browser/extensions/api/networking_private/networking_private_credentials_getter.h"
16 #include "chrome/common/extensions/api/networking_private/networking_private_crypto.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "extensions/browser/api/networking_private/networking_private_api.h"
19 #include "extensions/browser/api/networking_private/networking_private_service_client.h"
20 #include "extensions/common/api/networking_private.h"
22 namespace extensions
{
26 const char kCryptoVerifySequenceTokenName
[] = "CryptoVerify";
28 // Called from a blocking pool task runner. Returns true and sets |verified| if
29 // able to decode the credentials, otherwise sets |verified| to false and
31 bool DecodeAndVerifyCredentials(
32 const CryptoVerifyImpl::Credentials
& credentials
,
34 std::string decoded_signed_data
;
35 if (!base::Base64Decode(credentials
.signed_data
, &decoded_signed_data
)) {
36 LOG(ERROR
) << "Failed to decode signed data";
40 *verified
= networking_private_crypto::VerifyCredentials(
41 credentials
.certificate
, credentials
.intermediate_certificates
,
42 decoded_signed_data
, credentials
.unsigned_data
, credentials
.device_bssid
);
46 void VerifyDestinationCompleted(
47 const CryptoVerifyImpl::BoolCallback
& success_callback
,
48 const CryptoVerifyImpl::FailureCallback
& failure_callback
,
51 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
53 failure_callback
.Run(networking_private::kErrorEncryptionError
);
55 success_callback
.Run(*verified
);
58 // Called from a blocking pool task runner. Returns |data| encoded using
59 // |credentials| on success, or an empty string on failure.
60 std::string
DoVerifyAndEncryptData(
61 const CryptoVerifyImpl::Credentials
& credentials
,
62 const std::string
& data
) {
64 if (!DecodeAndVerifyCredentials(credentials
, &verified
) || !verified
)
67 std::string decoded_public_key
;
68 if (!base::Base64Decode(credentials
.public_key
, &decoded_public_key
)) {
69 LOG(ERROR
) << "Failed to decode public key";
73 std::vector
<uint8_t> public_key_data(decoded_public_key
.begin(),
74 decoded_public_key
.end());
75 std::vector
<uint8_t> ciphertext
;
76 if (!networking_private_crypto::EncryptByteString(public_key_data
, data
,
78 LOG(ERROR
) << "Failed to encrypt data";
82 std::string base64_encoded_ciphertext
;
83 base::Base64Encode(std::string(ciphertext
.begin(), ciphertext
.end()),
84 &base64_encoded_ciphertext
);
85 return base64_encoded_ciphertext
;
88 void VerifyAndEncryptDataCompleted(
89 const CryptoVerifyImpl::StringCallback
& success_callback
,
90 const CryptoVerifyImpl::FailureCallback
& failure_callback
,
91 const std::string
& encrypted_data
) {
92 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
93 if (encrypted_data
.empty())
94 failure_callback
.Run(networking_private::kErrorEncryptionError
);
96 success_callback
.Run(encrypted_data
);
99 // Called when NetworkingPrivateCredentialsGetter completes (from an arbitrary
100 // thread). Posts the result to the UI thread.
101 void CredentialsGetterCompleted(
102 const CryptoVerifyImpl::StringCallback
& success_callback
,
103 const CryptoVerifyImpl::FailureCallback
& failure_callback
,
104 const std::string
& key_data
,
105 const std::string
& error
) {
106 if (!error
.empty()) {
107 content::BrowserThread::PostTask(content::BrowserThread::UI
, FROM_HERE
,
108 base::Bind(failure_callback
, error
));
110 content::BrowserThread::PostTask(content::BrowserThread::UI
, FROM_HERE
,
111 base::Bind(success_callback
, key_data
));
115 // Called from a blocking pool task runner. Returns true if
116 // NetworkingPrivateCredentialsGetter is successfully started (which will
117 // invoke the appropriate callback when completed), or false if unable
118 // to start the getter (credentials or public key decode failed).
119 bool DoVerifyAndEncryptCredentials(
120 const std::string
& guid
,
121 const CryptoVerifyImpl::Credentials
& credentials
,
122 const CryptoVerifyImpl::StringCallback
& success_callback
,
123 const CryptoVerifyImpl::FailureCallback
& failure_callback
) {
125 if (!DecodeAndVerifyCredentials(credentials
, &verified
) || !verified
)
128 std::string decoded_public_key
;
129 if (!base::Base64Decode(credentials
.public_key
, &decoded_public_key
)) {
130 LOG(ERROR
) << "Failed to decode public key";
134 // Start getting credentials. CredentialsGetterCompleted will be called on
135 // completion. On Windows it will be called from a different thread after
136 // |credentials_getter| is deleted.
137 scoped_ptr
<NetworkingPrivateCredentialsGetter
> credentials_getter(
138 NetworkingPrivateCredentialsGetter::Create());
139 credentials_getter
->Start(guid
, decoded_public_key
,
140 base::Bind(&CredentialsGetterCompleted
,
141 success_callback
, failure_callback
));
145 void VerifyAndEncryptCredentialsCompleted(
146 const CryptoVerifyImpl::FailureCallback
& failure_callback
,
148 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
149 // If VerifyAndEncryptCredentials succeeded, then the appropriate callback
150 // will be triggered from CredentialsGetterCompleted.
153 failure_callback
.Run(networking_private::kErrorEncryptionError
);
158 CryptoVerifyImpl::Credentials::Credentials(
159 const VerificationProperties
& properties
) {
160 certificate
= properties
.certificate
;
161 if (properties
.intermediate_certificates
.get())
162 intermediate_certificates
= *properties
.intermediate_certificates
;
163 signed_data
= properties
.signed_data
;
165 std::vector
<std::string
> data_parts
;
166 data_parts
.push_back(properties
.device_ssid
);
167 data_parts
.push_back(properties
.device_serial
);
168 data_parts
.push_back(properties
.device_bssid
);
169 data_parts
.push_back(properties
.public_key
);
170 data_parts
.push_back(properties
.nonce
);
171 unsigned_data
= base::JoinString(data_parts
, ",");
173 device_bssid
= properties
.device_bssid
;
174 public_key
= properties
.public_key
;
177 CryptoVerifyImpl::Credentials::~Credentials() {
180 CryptoVerifyImpl::CryptoVerifyImpl() {
181 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
182 base::SequencedWorkerPool::SequenceToken sequence_token
=
183 content::BrowserThread::GetBlockingPool()->GetNamedSequenceToken(
184 kCryptoVerifySequenceTokenName
);
185 blocking_pool_task_runner_
=
186 content::BrowserThread::GetBlockingPool()
187 ->GetSequencedTaskRunnerWithShutdownBehavior(
188 sequence_token
, base::SequencedWorkerPool::SKIP_ON_SHUTDOWN
);
191 CryptoVerifyImpl::~CryptoVerifyImpl() {
192 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
195 void CryptoVerifyImpl::VerifyDestination(
196 const VerificationProperties
& verification_properties
,
197 const BoolCallback
& success_callback
,
198 const FailureCallback
& failure_callback
) {
199 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
200 Credentials
credentials(verification_properties
);
201 bool* verified
= new bool;
202 base::PostTaskAndReplyWithResult(
203 blocking_pool_task_runner_
.get(), FROM_HERE
,
204 base::Bind(&DecodeAndVerifyCredentials
, credentials
, verified
),
205 base::Bind(&VerifyDestinationCompleted
, success_callback
,
206 failure_callback
, base::Owned(verified
)));
209 void CryptoVerifyImpl::VerifyAndEncryptCredentials(
210 const std::string
& guid
,
211 const VerificationProperties
& verification_properties
,
212 const StringCallback
& success_callback
,
213 const FailureCallback
& failure_callback
) {
214 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
215 Credentials
credentials(verification_properties
);
216 base::PostTaskAndReplyWithResult(
217 blocking_pool_task_runner_
.get(), FROM_HERE
,
218 base::Bind(&DoVerifyAndEncryptCredentials
, guid
, credentials
,
219 success_callback
, failure_callback
),
220 base::Bind(&VerifyAndEncryptCredentialsCompleted
, failure_callback
));
223 void CryptoVerifyImpl::VerifyAndEncryptData(
224 const VerificationProperties
& verification_properties
,
225 const std::string
& data
,
226 const StringCallback
& success_callback
,
227 const FailureCallback
& failure_callback
) {
228 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
229 Credentials
credentials(verification_properties
);
230 base::PostTaskAndReplyWithResult(
231 blocking_pool_task_runner_
.get(), FROM_HERE
,
232 base::Bind(&DoVerifyAndEncryptData
, credentials
, data
),
233 base::Bind(&VerifyAndEncryptDataCompleted
, success_callback
,
237 } // namespace extensions