Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(325)

Side by Side Diff: chrome/browser/extensions/api/enterprise_platform_keys/token_method_nss.cc

Issue 214863002: Extension API enterprise.platformKeys. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: @kalman only Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698