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

Side by Side Diff: chrome/browser/chromeos/platform_keys/platform_keys_nss.cc

Issue 214863002: Extension API enterprise.platformKeys. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Some minor cleanups. 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/chromeos/platform_keys/platform_keys.h"
6
7 #include <cryptohi.h>
8
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/callback.h"
12 #include "base/compiler_specific.h"
13 #include "base/logging.h"
14 #include "base/macros.h"
15 #include "chrome/browser/extensions/api/enterprise_platform_keys/enterprise_plat form_keys_api.h"
16 #include "chrome/browser/net/nss_context.h"
17 #include "crypto/rsa_private_key.h"
18 #include "net/base/crypto_module.h"
19 #include "net/base/net_errors.h"
20 #include "net/cert/cert_database.h"
21 #include "net/cert/nss_cert_database.h"
22 #include "net/cert/x509_certificate.h"
23
24 namespace {
25 const char kErrorInternal[] = "Internal Error.";
26 const char kErrorKeyNotFound[] = "Key not found.";
27 const char kErrorCertificateNotFound[] = "Certificate could not be found.";
28 const char kErrorAlgorithmNotSupported[] = "Algorithm not supported.";
29 }
30
31 namespace chromeos {
32
33 namespace platform_keys {
34
35 namespace {
36
37 // Base class to store state that is common to all NSS database operations and
38 // to provide convenience methods to call back.
39 class NSSOperationState {
40 public:
41 explicit NSSOperationState(Profile* profile);
42 virtual ~NSSOperationState() {}
43
44 // Called if an error occurred during the execution of the NSS operation
45 // described by this object.
46 virtual void OnError(const std::string& error_message) = 0;
47
48 Profile* profile_;
49 crypto::ScopedPK11Slot slot_;
50 net::NSSCertDatabase* cert_db_;
51
52 private:
53 DISALLOW_COPY_AND_ASSIGN(NSSOperationState);
54 };
55
56 typedef base::Closure GetCertDBCallback;
57
58 // Callback of GetCertDatabase. Called back with the NSSCertDatabase associated
59 // to the given |token_id|.
60 void DidGetCertDB(const GetCertDBCallback& callback,
61 NSSOperationState* state,
62 net::NSSCertDatabase* cert_db) {
63 if (!cert_db) {
64 LOG(ERROR) << "Couldn't get NSSCertDatabase.";
65 state->OnError(kErrorInternal);
66 return;
67 }
68
69 state->cert_db_ = cert_db;
70 state->slot_ = cert_db->GetPrivateSlot();
71 if (!state->slot_) {
72 LOG(ERROR) << "No private slot";
73 state->OnError(kErrorInternal);
74 return;
75 }
76 callback.Run();
77 }
78
79 // Asynchronously fetches the NSSCertDatabase for |token_id| and passes it to
80 // |callback|.
81 void GetCertDatabase(const std::string& token_id,
82 const GetCertDBCallback& callback,
83 NSSOperationState* state) {
84 GetNSSCertDatabaseForProfile(state->profile_,
85 base::Bind(&DidGetCertDB, callback, state));
86 }
87
88 class GenerateRSAKeyState : public NSSOperationState {
89 public:
90 GenerateRSAKeyState(int modulus_length,
91 const GenerateKeyCallback& callback,
92 Profile* profile);
93 virtual ~GenerateRSAKeyState() {}
94
95 virtual void OnError(const std::string& error_message) OVERRIDE {
96 callback_.Run(std::string() /* no public key */, error_message);
97 }
98
99 int modulus_length_;
100 GenerateKeyCallback callback_;
101 };
102
103 class SignState : public NSSOperationState {
104 public:
105 SignState(const std::string& public_key,
106 const std::string& data,
107 const SignCallback& callback,
108 Profile* profile);
109 virtual ~SignState() {}
110
111 virtual void OnError(const std::string& error_message) OVERRIDE {
112 callback_.Run(std::string() /* no signature */, error_message);
113 }
114
115 std::string public_key_;
116 std::string data_;
117 SignCallback callback_;
118 };
119
120 class GetCertificatesState : public NSSOperationState {
121 public:
122 GetCertificatesState(const GetCertificatesCallback& callback,
123 Profile* profile);
124 virtual ~GetCertificatesState() {}
125
126 virtual void OnError(const std::string& error_message) OVERRIDE {
127 callback_.Run(scoped_ptr<net::CertificateList>() /* no certificates */,
128 error_message);
129 }
130
131 GetCertificatesCallback callback_;
132 };
133
134 class ImportCertificateState : public NSSOperationState {
135 public:
136 ImportCertificateState(scoped_refptr<net::X509Certificate> certificate,
137 const ImportCertificateCallback& callback,
138 Profile* profile);
139 virtual ~ImportCertificateState() {}
140
141 virtual void OnError(const std::string& error_message) OVERRIDE {
142 callback_.Run(error_message);
143 }
144
145 scoped_refptr<net::X509Certificate> certificate_;
146 ImportCertificateCallback callback_;
147 };
148
149 class RemoveCertificateState : public NSSOperationState {
150 public:
151 RemoveCertificateState(scoped_refptr<net::X509Certificate> certificate,
152 const RemoveCertificateCallback& callback,
153 Profile* profile);
154 virtual ~RemoveCertificateState() {}
155
156 virtual void OnError(const std::string& error_message) OVERRIDE {
157 callback_.Run(error_message);
158 }
159
160 scoped_refptr<net::X509Certificate> certificate_;
161 RemoveCertificateCallback callback_;
162 };
163
164 NSSOperationState::NSSOperationState(Profile* profile)
165 : profile_(profile), cert_db_(NULL) {
166 }
167
168 GenerateRSAKeyState::GenerateRSAKeyState(int modulus_length,
169 const GenerateKeyCallback& callback,
170 Profile* profile)
171 : NSSOperationState(profile),
172 modulus_length_(modulus_length),
173 callback_(callback) {
174 }
175
176 SignState::SignState(const std::string& public_key,
177 const std::string& data,
178 const SignCallback& callback,
179 Profile* profile)
180 : NSSOperationState(profile),
181 public_key_(public_key),
182 data_(data),
183 callback_(callback) {
184 }
185
186 GetCertificatesState::GetCertificatesState(
187 const GetCertificatesCallback& callback,
188 Profile* profile)
189 : NSSOperationState(profile), callback_(callback) {
190 }
191
192 ImportCertificateState::ImportCertificateState(
193 scoped_refptr<net::X509Certificate> certificate,
194 const ImportCertificateCallback& callback,
195 Profile* profile)
196 : NSSOperationState(profile),
197 certificate_(certificate),
198 callback_(callback) {
199 }
200
201 RemoveCertificateState::RemoveCertificateState(
202 scoped_refptr<net::X509Certificate> certificate,
203 const RemoveCertificateCallback& callback,
204 Profile* profile)
205 : NSSOperationState(profile),
206 certificate_(certificate),
207 callback_(callback) {
208 }
209
210 // Continues generating a RSA key with the obtained NSSCertDatabase. Used by
211 // GenerateRSAKey().
212 void GenerateRSAKeyWithDB(scoped_ptr<GenerateRSAKeyState> state) {
213 if (state->modulus_length_ > 2048) {
214 state->OnError(kErrorAlgorithmNotSupported);
215 return;
216 }
217 scoped_ptr<crypto::RSAPrivateKey> rsa_key(
218 crypto::RSAPrivateKey::CreateSensitive(state->slot_.get(),
219 state->modulus_length_));
220 if (!rsa_key) {
221 LOG(ERROR) << "Couldn't create key.";
222 state->OnError(kErrorInternal);
223 return;
224 }
225
226 std::vector<uint8> public_key_der;
227 if (!rsa_key->ExportPublicKey(&public_key_der)) {
228 // TODO(pneubeck): Remove rsa_key from storage.
229 LOG(ERROR) << "Couldn't export public key.";
230 state->OnError(kErrorInternal);
231 return;
232 }
233 std::string public_key_der_str(public_key_der.begin(), public_key_der.end());
234 state->callback_.Run(public_key_der_str, std::string() /* no error */);
235 }
236
237 // Continues signing with the obtained NSSCertDatabase. Used by Sign().
238 void RSASignWithDB(scoped_ptr<SignState> state) {
239 const uint8* public_key_uint8 =
240 reinterpret_cast<const uint8*>(state->public_key_.data());
241 std::vector<uint8> public_key_vector(
242 public_key_uint8, public_key_uint8 + state->public_key_.size());
243
244 // TODO(pneubeck): This searches all slots. Change to look only at |slot_|.
245 scoped_ptr<crypto::RSAPrivateKey> rsa_key(
246 crypto::RSAPrivateKey::FindFromPublicKeyInfo(public_key_vector));
247 if (!rsa_key) {
248 state->OnError(kErrorKeyNotFound);
249 return;
250 }
251
252 SECItem sign_result = {siBuffer, NULL, 0};
253 if (SEC_SignData(&sign_result,
254 reinterpret_cast<const unsigned char*>(state->data_.data()),
255 state->data_.size(),
256 rsa_key->key(),
257 SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION) != SECSuccess) {
258 LOG(ERROR) << "Couldn't sign.";
259 state->OnError(kErrorInternal);
260 return;
261 }
262
263 std::string signature(reinterpret_cast<const char*>(sign_result.data),
264 sign_result.len);
265 state->callback_.Run(signature, std::string() /* no error */);
266 }
267
268 // Continues getting certificates with the certificates returned by
269 // NSSCertDatabase::ListCertsInSlot. Used by GetCertificatesWithDB().
270 void DidGetCertificates(scoped_ptr<GetCertificatesState> state,
271 scoped_ptr<net::CertificateList> all_certs) {
272 scoped_ptr<net::CertificateList> client_certs(new net::CertificateList);
273 for (net::CertificateList::const_iterator it = all_certs->begin();
274 it != all_certs->end();
275 ++it) {
276 net::X509Certificate::OSCertHandle cert_handle = (*it)->os_cert_handle();
277 crypto::ScopedPK11Slot cert_slot(PK11_KeyForCertExists(cert_handle,
278 NULL, // keyPtr
279 NULL)); // wincx
280
281 // Keep only user certificates, i.e. certs for which the private key is
282 // present and stored in the queried slot.
283 if (cert_slot != state->slot_)
284 continue;
285
286 client_certs->push_back(*it);
287 }
288
289 state->callback_.Run(client_certs.Pass(), std::string() /* no error */);
290 }
291
292 // Continues getting certificates with the obtained NSSCertDatabase. Used by
293 // GetCertificates().
294 void GetCertificatesWithDB(scoped_ptr<GetCertificatesState> state) {
295 // Get the pointer to slot before base::Passed releases |state|.
296 PK11SlotInfo* slot = state->slot_.get();
297 state->cert_db_->ListCertsInSlot(
298 base::Bind(&DidGetCertificates, base::Passed(&state)), slot);
299 }
300
301 // Continues certificate importing with the obtained NSSCertDatabase. Used by
302 // ImportCertificate().
303 void ImportCertificateWithDB(scoped_ptr<ImportCertificateState> state) {
304 net::CertDatabase* db = net::CertDatabase::GetInstance();
305
306 const net::Error cert_status = db->CheckUserCert(state->certificate_);
307 if (cert_status == net::ERR_NO_PRIVATE_KEY_FOR_CERT) {
308 state->OnError(kErrorKeyNotFound);
309 return;
310 } else if (cert_status != net::OK) {
311 state->OnError(net::ErrorToString(cert_status));
312 return;
313 }
314
315 const net::Error import_status = db->AddUserCert(state->certificate_.get());
316 if (import_status != net::OK) {
317 LOG(ERROR) << "Could not import certificate.";
318 state->OnError(net::ErrorToString(import_status));
319 return;
320 }
321
322 state->callback_.Run(std::string() /* no error */);
323 }
324
325 // Continues certificate removal with the obtained NSSCertDatabase. Used by
326 // RemoveCertificate().
327 void RemoveCertificateWithDB(scoped_ptr<RemoveCertificateState> state) {
328 bool certificate_found = state->certificate_->os_cert_handle()->isperm;
329 bool success = state->cert_db_->DeleteCertAndKey(state->certificate_);
330
331 // CertificateNotFound error has precedence over an internal error.
332 if (!certificate_found) {
333 state->OnError(kErrorCertificateNotFound);
334 return;
335 }
336 if (!success) {
337 state->OnError(kErrorInternal);
338 return;
339 }
340
341 state->callback_.Run(std::string() /* no error */);
342 }
343
344 } // namespace
345
346 void GenerateRSAKey(const std::string& token_id,
347 int modulus_length,
348 const GenerateKeyCallback& callback,
349 Profile* profile) {
350 scoped_ptr<GenerateRSAKeyState> state(
351 new GenerateRSAKeyState(modulus_length, callback, profile));
352 // Get the pointer to |state| before base::Passed releases |state|.
353 NSSOperationState* state_ptr = state.get();
354 GetCertDatabase(token_id,
355 base::Bind(&GenerateRSAKeyWithDB, base::Passed(&state)),
356 state_ptr);
357 }
358
359 void Sign(const std::string& token_id,
360 const std::string& public_key,
361 const std::string& data,
362 const SignCallback& callback,
363 Profile* profile) {
364 scoped_ptr<SignState> state(
365 new SignState(public_key, data, callback, profile));
366 // Get the pointer to |state| before base::Passed releases |state|.
367 NSSOperationState* state_ptr = state.get();
368 GetCertDatabase(
369 token_id, base::Bind(&RSASignWithDB, base::Passed(&state)), state_ptr);
370 }
371
372 void GetCertificates(const std::string& token_id,
373 const GetCertificatesCallback& callback,
374 Profile* profile) {
375 scoped_ptr<GetCertificatesState> state(
376 new GetCertificatesState(callback, profile));
377 // Get the pointer to |state| before base::Passed releases |state|.
378 NSSOperationState* state_ptr = state.get();
379 GetCertDatabase(token_id,
380 base::Bind(&GetCertificatesWithDB, base::Passed(&state)),
381 state_ptr);
382 }
383
384 void ImportCertificate(const std::string& token_id,
385 scoped_refptr<net::X509Certificate> certificate,
386 const ImportCertificateCallback& callback,
387 Profile* profile) {
388 scoped_ptr<ImportCertificateState> state(
389 new ImportCertificateState(certificate, callback, profile));
390 // Get the pointer to |state| before base::Passed releases |state|.
391 NSSOperationState* state_ptr = state.get();
392 GetCertDatabase(token_id,
393 base::Bind(&ImportCertificateWithDB, base::Passed(&state)),
394 state_ptr);
395 }
396
397 void RemoveCertificate(const std::string& token_id,
398 scoped_refptr<net::X509Certificate> certificate,
399 const RemoveCertificateCallback& callback,
400 Profile* profile) {
401 scoped_ptr<RemoveCertificateState> state(
402 new RemoveCertificateState(certificate, callback, profile));
403 // Get the pointer to |state| before base::Passed releases |state|.
404 NSSOperationState* state_ptr = state.get();
405 GetCertDatabase(token_id,
406 base::Bind(&RemoveCertificateWithDB, base::Passed(&state)),
407 state_ptr);
408 }
409
410 } // namespace platform_keys
411
412 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698