OLD | NEW |
---|---|
(Empty) | |
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. | |
4 | |
5 #include "chrome/browser/extensions/api/enterprise_platform_keys/token_method.h" | |
6 | |
7 #include <cryptohi.h> | |
Ryan Sleevi
2014/05/08 20:52:04
style: newline
pneubeck (no reviews)
2014/05/14 15:01:49
Done.
| |
8 #include "base/bind.h" | |
9 #include "base/bind_helpers.h" | |
10 #include "base/callback.h" | |
11 #include "base/compiler_specific.h" | |
12 #include "base/logging.h" | |
13 #include "base/memory/weak_ptr.h" | |
14 #include "chrome/browser/extensions/api/enterprise_platform_keys/enterprise_plat form_keys_api.h" | |
15 #include "chrome/browser/net/nss_context.h" | |
16 #include "crypto/rsa_private_key.h" | |
17 #include "net/base/crypto_module.h" | |
18 #include "net/base/net_errors.h" | |
19 #include "net/cert/cert_database.h" | |
20 #include "net/cert/nss_cert_database.h" | |
21 #include "net/cert/x509_certificate.h" | |
22 | |
23 namespace { | |
24 const char kErrorInternal[] = "Internal Error"; | |
25 const char kErrorKeyNotFound[] = "Key not found."; | |
26 const char kErrorInvalidX509Cert[] = | |
27 "Certificate is not a valid X.509 certificate."; | |
28 const char kErrorCertificateNotFound[] = "Certificate could not be found."; | |
29 const char kErrorAlgorithmNotSupported[] = "Algorithm not supported."; | |
30 } | |
31 | |
32 namespace extensions { | |
33 | |
34 namespace enterprise_platform_keys_details { | |
35 | |
36 namespace { | |
37 | |
38 namespace api_epk = api::enterprise_platform_keys; | |
39 namespace api_epki = api::enterprise_platform_keys_internal; | |
40 | |
41 typedef base::Callback<void(crypto::ScopedPK11Slot slot, | |
42 net::NSSCertDatabase* cert_db)> GetCertDBCallback; | |
43 | |
44 void DidGetCertDB(const GetCertDBCallback& callback, | |
45 const TokenMethod::ErrorCallback& error_callback, | |
46 net::NSSCertDatabase* cert_db) { | |
47 if (!cert_db) { | |
48 LOG(ERROR) << "Couldn't get NSSCertDatabase."; | |
49 error_callback.Run(kErrorInternal); | |
50 return; | |
51 } | |
52 | |
53 crypto::ScopedPK11Slot slot = cert_db->GetPrivateSlot(); | |
54 if (!slot) { | |
55 LOG(ERROR) << "No private slot"; | |
56 error_callback.Run(kErrorInternal); | |
57 return; | |
58 } | |
59 callback.Run(slot.Pass(), cert_db); | |
60 } | |
61 | |
62 void GetCertDatabase(const std::string& token_id, | |
63 const GetCertDBCallback& callback, | |
64 const TokenMethod::ErrorCallback& error_callback, | |
65 Profile* profile) { | |
66 GetNSSCertDatabaseForProfile( | |
67 profile, base::Bind(&DidGetCertDB, callback, error_callback)); | |
68 } | |
69 | |
70 class GenerateKey : public TokenMethod { | |
71 public: | |
72 GenerateKey(scoped_ptr<api_epki::GenerateKey::Params> params, | |
73 const GenerateKeyCallback& callback, | |
74 const ErrorCallback& error_callback, | |
75 Profile* profile); | |
76 virtual ~GenerateKey() {} | |
77 virtual void Run() OVERRIDE; | |
78 | |
79 void DidGetDB(crypto::ScopedPK11Slot slot, net::NSSCertDatabase* cert_db); | |
Ryan Sleevi
2014/05/08 20:52:04
Document
pneubeck (no reviews)
2014/05/14 15:01:49
Done.
| |
80 | |
81 private: | |
82 scoped_ptr<api_epki::GenerateKey::Params> params_; | |
83 GenerateKeyCallback callback_; | |
84 base::WeakPtrFactory<GenerateKey> weak_factory_; | |
85 }; | |
86 | |
87 class Sign : public TokenMethod { | |
88 public: | |
89 Sign(scoped_ptr<api_epki::Sign::Params> params, | |
90 EnterprisePlatformKeysTokenMethodExtensionFunction* func); | |
91 virtual ~Sign() {} | |
92 virtual void Run() OVERRIDE; | |
93 | |
94 void DidGetDB(crypto::ScopedPK11Slot slot, net::NSSCertDatabase* cert_db); | |
Ryan Sleevi
2014/05/08 20:52:04
Document
pneubeck (no reviews)
2014/05/14 15:01:49
Done.
| |
95 | |
96 private: | |
97 scoped_ptr<api_epki::Sign::Params> params_; | |
98 base::WeakPtrFactory<Sign> weak_factory_; | |
99 }; | |
100 | |
101 class GetCertificates : public TokenMethod { | |
102 public: | |
103 GetCertificates(scoped_ptr<api_epk::GetCertificates::Params> params, | |
104 EnterprisePlatformKeysTokenMethodExtensionFunction* func); | |
105 virtual ~GetCertificates() {} | |
106 virtual void Run() OVERRIDE; | |
107 | |
108 void DidGetDB(crypto::ScopedPK11Slot slot, net::NSSCertDatabase* cert_db); | |
Ryan Sleevi
2014/05/08 20:52:04
Document
pneubeck (no reviews)
2014/05/14 15:01:49
Done.
| |
109 void DidGetCertificates(scoped_ptr<net::CertificateList> certs); | |
110 | |
111 private: | |
112 scoped_ptr<api_epk::GetCertificates::Params> params_; | |
113 crypto::ScopedPK11Slot slot_; | |
114 base::WeakPtrFactory<GetCertificates> weak_factory_; | |
115 }; | |
116 | |
117 class ImportCertificate : public TokenMethod { | |
118 public: | |
119 ImportCertificate(scoped_ptr<api_epk::ImportCertificate::Params> params, | |
120 EnterprisePlatformKeysTokenMethodExtensionFunction* func); | |
121 virtual ~ImportCertificate() {} | |
122 virtual void Run() OVERRIDE; | |
123 | |
124 void DidGetDB(crypto::ScopedPK11Slot slot, net::NSSCertDatabase* cert_db); | |
Ryan Sleevi
2014/05/08 20:52:04
Document
pneubeck (no reviews)
2014/05/14 15:01:49
Done.
| |
125 | |
126 private: | |
127 scoped_ptr<api_epk::ImportCertificate::Params> params_; | |
128 base::WeakPtrFactory<ImportCertificate> weak_factory_; | |
129 }; | |
130 | |
131 class RemoveCertificate : public TokenMethod { | |
132 public: | |
133 RemoveCertificate(scoped_ptr<api_epk::RemoveCertificate::Params> params, | |
134 EnterprisePlatformKeysTokenMethodExtensionFunction* func); | |
135 virtual ~RemoveCertificate() {} | |
136 virtual void Run() OVERRIDE; | |
137 | |
138 void DidGetDB(crypto::ScopedPK11Slot slot, net::NSSCertDatabase* cert_db); | |
Ryan Sleevi
2014/05/08 20:52:04
Document
pneubeck (no reviews)
2014/05/14 15:01:49
Done.
| |
139 | |
140 private: | |
141 scoped_ptr<api_epk::RemoveCertificate::Params> params_; | |
142 base::WeakPtrFactory<RemoveCertificate> weak_factory_; | |
143 }; | |
144 | |
145 GenerateKey::GenerateKey(scoped_ptr<api_epki::GenerateKey::Params> params, | |
146 const GenerateKeyCallback& callback, | |
147 const TokenMethod::ErrorCallback& error_callback, | |
148 Profile* profile) | |
149 : TokenMethod(error_callback, profile), | |
150 params_(params.Pass()), | |
151 callback_(callback), | |
152 weak_factory_(this) { | |
153 } | |
154 | |
155 void GenerateKey::Run() { | |
156 GetCertDatabase( | |
157 params_->token_id, | |
158 base::Bind(&GenerateKey::DidGetDB, weak_factory_.GetWeakPtr()), | |
159 error_callback_, | |
160 profile_); | |
161 } | |
162 | |
163 void GenerateKey::DidGetDB(crypto::ScopedPK11Slot slot, | |
164 net::NSSCertDatabase* cert_db) { | |
165 const int modulus_length = params_->modulus_length; | |
166 if (modulus_length > 2048) { | |
Ryan Sleevi
2014/05/08 20:52:04
Why do this check here?
Is it because the TPM doe
pneubeck (no reviews)
2014/05/14 15:01:49
RSAPrivateKey seems to understand 'sensitive' as '
Ryan Sleevi
2014/05/15 19:57:13
Hrm. I really wish Chaps used separate slots then,
| |
167 error_callback_.Run(kErrorAlgorithmNotSupported); | |
168 return; | |
169 } | |
170 scoped_ptr<crypto::RSAPrivateKey> rsa_key( | |
171 crypto::RSAPrivateKey::CreateSensitive(slot.get(), modulus_length)); | |
Ryan Sleevi
2014/05/08 20:52:04
What thread will this run on? It will block whatev
pneubeck (no reviews)
2014/05/14 15:01:49
Yes, I still have to move that to another thread.
Ryan Sleevi
2014/05/15 19:57:13
I don't think we should enable this API until that
| |
172 if (!rsa_key) { | |
173 LOG(ERROR) << "Couldn't create key."; | |
174 error_callback_.Run(kErrorInternal); | |
175 return; | |
176 } | |
177 | |
178 std::vector<uint8> public_key_der; | |
179 if (!rsa_key->ExportPublicKey(&public_key_der)) { | |
Ryan Sleevi
2014/05/08 20:52:04
Don't use this function if you want this API to be
pneubeck (no reviews)
2014/05/14 15:01:49
Hm. I thought about this one too and stopped inves
Ryan Sleevi
2014/05/15 19:57:13
Yeah, I did. Thanks for digging in.
| |
180 // TODO(pneubeck): Remove rsa_key from storage. | |
181 LOG(ERROR) << "Couldn't export public key."; | |
182 error_callback_.Run(kErrorInternal); | |
183 return; | |
184 } | |
185 std::string public_key_der_str(public_key_der.begin(), public_key_der.end()); | |
186 callback_.Run(public_key_der_str); | |
187 } | |
188 | |
189 /* | |
190 Sign::Sign(scoped_ptr<api_epki::Sign::Params> params, | |
191 EnterprisePlatformKeysTokenMethodExtensionFunction* func) | |
192 : TokenMethod(func), params_(params.Pass()), weak_factory_(this) { | |
193 } | |
194 | |
195 void Sign::Run() { | |
196 GetCertDatabase(params_->token_id, | |
197 base::Bind(&Sign::DidGetDB, weak_factory_.GetWeakPtr()), | |
198 func_); | |
199 } | |
200 | |
201 void Sign::DidGetDB(crypto::ScopedPK11Slot slot, | |
Ryan Sleevi
2014/05/08 20:52:04
Should this class be "RSASign", since you've coupl
pneubeck (no reviews)
2014/05/14 15:01:49
Done.
| |
202 net::NSSCertDatabase* cert_db) { | |
203 const std::string& public_key = params_->public_key; | |
204 const uint8* public_key_uint8 = | |
205 reinterpret_cast<const uint8*>(public_key.data()); | |
206 std::vector<uint8> public_key_vector(public_key_uint8, | |
207 public_key_uint8 + public_key.size()); | |
208 | |
209 // TODO(pneubeck): This searches all slots. Change to look only at |slot_|. | |
210 scoped_ptr<crypto::RSAPrivateKey> rsa_key( | |
211 crypto::RSAPrivateKey::FindFromPublicKeyInfo(public_key_vector)); | |
212 if (!rsa_key) { | |
213 func_->RespondWithError(kErrorKeyNotFound); | |
214 return; | |
215 } | |
216 | |
217 const std::string& data = params_->data; | |
218 SECItem sign_result = {siBuffer, NULL, 0}; | |
219 if (SEC_SignData(&sign_result, | |
220 reinterpret_cast<const unsigned char*>(data.data()), | |
221 data.size(), | |
222 rsa_key->key(), | |
223 SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION) != SECSuccess) { | |
224 LOG(ERROR) << "Couldn't sign."; | |
225 func_->RespondWithError(kErrorInternal); | |
226 return; | |
227 } | |
228 | |
229 std::string signature(reinterpret_cast<const char*>(sign_result.data), | |
230 sign_result.len); | |
231 func_->RespondWithResults(api_epki::Sign::Results::Create(signature)); | |
232 } | |
233 | |
234 GetCertificates::GetCertificates( | |
235 scoped_ptr<api_epk::GetCertificates::Params> params, | |
236 EnterprisePlatformKeysTokenMethodExtensionFunction* func) | |
237 : TokenMethod(func), params_(params.Pass()), weak_factory_(this) { | |
238 } | |
239 | |
240 void GetCertificates::Run() { | |
241 GetCertDatabase( | |
242 params_->token_id, | |
243 base::Bind(&GetCertificates::DidGetDB, weak_factory_.GetWeakPtr()), | |
244 func_); | |
245 } | |
246 | |
247 void GetCertificates::DidGetDB(crypto::ScopedPK11Slot slot, | |
248 net::NSSCertDatabase* cert_db) { | |
249 slot_ = slot.Pass(); | |
250 cert_db->ListCertsInSlot(base::Bind(&GetCertificates::DidGetCertificates, | |
251 weak_factory_.GetWeakPtr()), | |
252 slot_.get()); | |
253 } | |
254 | |
255 void GetCertificates::DidGetCertificates( | |
256 scoped_ptr<net::CertificateList> certs) { | |
257 // std::vector<std::string> client_certs; | |
258 scoped_ptr<base::ListValue> client_certs(new base::ListValue()); | |
259 for (net::CertificateList::const_iterator it = certs->begin(); | |
260 it != certs->end(); | |
261 ++it) { | |
262 net::X509Certificate::OSCertHandle cert_handle = (*it)->os_cert_handle(); | |
263 crypto::ScopedPK11Slot cert_slot(PK11_KeyForCertExists(cert_handle, | |
264 NULL, // keyPtr | |
265 NULL)); // wincx | |
266 | |
267 // Keep only user certificate, i.e. certs for which the private key is | |
268 // present, and certs where the private key is stored in the queried slot. | |
269 if (cert_slot != slot_) | |
270 continue; | |
271 | |
272 std::string der_encoding; | |
273 net::X509Certificate::GetDEREncoded(cert_handle, &der_encoding); | |
274 // client_certs.push_back(der_encoding); | |
Ryan Sleevi
2014/05/08 20:52:04
delete?
pneubeck (no reviews)
2014/05/14 15:01:49
Done.
| |
275 client_certs->Append(base::BinaryValue::CreateWithCopiedBuffer( | |
276 der_encoding.data(), der_encoding.size())); | |
277 } | |
278 scoped_ptr<base::ListValue> results(new base::ListValue()); | |
279 results->Append(client_certs.release()); | |
280 func_->RespondWithResults(results.Pass()); | |
281 // results_ = api_eci::GetClientCertificates::Results::Create(client_certs); | |
Ryan Sleevi
2014/05/08 20:52:04
delete?
pneubeck (no reviews)
2014/05/14 15:01:49
Done.
| |
282 } | |
283 | |
284 ImportCertificate::ImportCertificate( | |
285 scoped_ptr<api_epk::ImportCertificate::Params> params, | |
286 EnterprisePlatformKeysTokenMethodExtensionFunction* func) | |
287 : TokenMethod(func), params_(params.Pass()), weak_factory_(this) { | |
Ryan Sleevi
2014/05/08 20:52:04
git cl format will show this is bad style.
pneubeck (no reviews)
2014/05/14 15:01:49
sorry to disappoint you, it doesn't.
I can change
| |
288 } | |
289 | |
290 void ImportCertificate::Run() { | |
291 GetCertDatabase( | |
292 params_->token_id, | |
293 base::Bind(&ImportCertificate::DidGetDB, weak_factory_.GetWeakPtr()), | |
294 func_); | |
295 } | |
296 | |
297 void ImportCertificate::DidGetDB(crypto::ScopedPK11Slot slot, | |
298 net::NSSCertDatabase* cert_db) { | |
299 const std::string& certificate = params_->certificate; | |
300 scoped_refptr<net::X509Certificate> cert_x509 = | |
301 net::X509Certificate::CreateFromBytes(certificate.data(), | |
302 certificate.size()); | |
303 if (!cert_x509) { | |
304 func_->RespondWithError(kErrorInvalidX509Cert); | |
305 return; | |
306 } | |
307 | |
308 net::CertDatabase* db = net::CertDatabase::GetInstance(); | |
309 | |
310 const net::Error cert_status = db->CheckUserCert(cert_x509); | |
311 if (cert_status == net::ERR_NO_PRIVATE_KEY_FOR_CERT) { | |
312 func_->RespondWithError(kErrorKeyNotFound); | |
313 return; | |
314 } else if (cert_status != net::OK) { | |
315 func_->RespondWithError(net::ErrorToString(cert_status)); | |
316 return; | |
317 } | |
318 | |
319 const net::Error import_status = db->AddUserCert(cert_x509.get()); | |
320 if (import_status != net::OK) { | |
321 LOG(ERROR) << "Could not import certificate."; | |
322 func_->RespondWithError(net::ErrorToString(import_status)); | |
323 return; | |
324 } | |
325 | |
326 func_->RespondWithoutResult(); | |
327 } | |
328 | |
329 RemoveCertificate::RemoveCertificate( | |
330 scoped_ptr<api_epk::RemoveCertificate::Params> params, | |
331 EnterprisePlatformKeysTokenMethodExtensionFunction* func) | |
332 : TokenMethod(func), params_(params.Pass()), weak_factory_(this) { | |
333 } | |
334 | |
335 void RemoveCertificate::Run() { | |
336 GetCertDatabase( | |
337 params_->token_id, | |
338 base::Bind(&RemoveCertificate::DidGetDB, weak_factory_.GetWeakPtr()), | |
339 func_); | |
340 } | |
341 | |
342 void RemoveCertificate::DidGetDB(crypto::ScopedPK11Slot slot, | |
343 net::NSSCertDatabase* cert_db) { | |
344 const std::string& certificate = params_->certificate; | |
345 scoped_refptr<net::X509Certificate> cert_x509 = | |
346 net::X509Certificate::CreateFromBytes(certificate.data(), | |
347 certificate.size()); | |
348 if (!cert_x509) { | |
349 func_->RespondWithError(kErrorInvalidX509Cert); | |
350 return; | |
351 } | |
352 | |
353 bool certificate_found = cert_x509->os_cert_handle()->isperm; | |
354 bool success = cert_db->DeleteCertAndKey(cert_x509); | |
355 | |
356 // CertificateNotFound error has precedence over an internal error. | |
357 if (!certificate_found) { | |
358 func_->RespondWithError(kErrorCertificateNotFound); | |
359 return; | |
360 } | |
361 if (!success) { | |
362 func_->RespondWithError(kErrorInternal); | |
363 return; | |
364 } | |
365 | |
366 func_->RespondWithoutResult(); | |
367 } | |
368 */ | |
369 | |
370 } // namespace | |
371 | |
372 scoped_ptr<TokenMethod> CreateGenerateKey( | |
373 scoped_ptr<api_epki::GenerateKey::Params> params, | |
374 const GenerateKeyCallback& callback, | |
375 const TokenMethod::ErrorCallback& error_callback, | |
376 Profile* profile) { | |
377 return scoped_ptr<TokenMethod>( | |
378 new GenerateKey(params.Pass(), callback, error_callback, profile)); | |
379 } | |
380 | |
381 scoped_ptr<TokenMethod> CreateSign( | |
382 scoped_ptr<api_epki::Sign::Params> params, | |
383 EnterprisePlatformKeysTokenMethodExtensionFunction* func) { | |
384 return scoped_ptr<TokenMethod>(new Sign(params.Pass(), func)); | |
385 } | |
386 | |
387 scoped_ptr<TokenMethod> CreateGetCertificates( | |
388 scoped_ptr<api_epk::GetCertificates::Params> params, | |
389 EnterprisePlatformKeysTokenMethodExtensionFunction* func) { | |
390 return scoped_ptr<TokenMethod>(new GetCertificates(params.Pass(), func)); | |
391 } | |
392 | |
393 scoped_ptr<TokenMethod> CreateImportCertificate( | |
394 scoped_ptr<api_epk::ImportCertificate::Params> params, | |
395 EnterprisePlatformKeysTokenMethodExtensionFunction* func) { | |
396 return scoped_ptr<TokenMethod>(new ImportCertificate(params.Pass(), func)); | |
397 } | |
398 | |
399 scoped_ptr<TokenMethod> CreateRemoveCertificate( | |
400 scoped_ptr<api_epk::RemoveCertificate::Params> params, | |
401 EnterprisePlatformKeysTokenMethodExtensionFunction* func) { | |
402 return scoped_ptr<TokenMethod>(new RemoveCertificate(params.Pass(), func)); | |
403 } | |
404 | |
405 } // namespace enterprise_platform_keys_details | |
406 | |
407 } // namespace extensions | |
OLD | NEW |