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

Side by Side Diff: content/renderer/webcrypto/webcrypto_impl_nss.cc

Issue 34583010: [webcrypto] Add RSA key generation using NSS. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 7 years, 1 month 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
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/renderer/webcrypto/webcrypto_impl.h" 5 #include "content/renderer/webcrypto/webcrypto_impl.h"
6 6
7 #include <cryptohi.h> 7 #include <cryptohi.h>
8 #include <pk11pub.h> 8 #include <pk11pub.h>
9 #include <sechash.h> 9 #include <sechash.h>
10 10
11 #include <vector> 11 #include <vector>
12 12
13 #include "base/logging.h" 13 #include "base/logging.h"
14 #include "crypto/nss_util.h" 14 #include "crypto/nss_util.h"
15 #include "crypto/scoped_nss_types.h" 15 #include "crypto/scoped_nss_types.h"
16 #include "crypto/secure_util.h" 16 #include "crypto/secure_util.h"
17 #include "third_party/WebKit/public/platform/WebArrayBuffer.h" 17 #include "third_party/WebKit/public/platform/WebArrayBuffer.h"
18 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" 18 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
19 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" 19 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
20 20
21 namespace content { 21 namespace content {
22 22
23 namespace { 23 namespace {
24 24
25 class SymKeyHandle : public WebKit::WebCryptoKeyHandle { 25 class SymKeyHandle : public WebKit::WebCryptoKeyHandle {
26 public: 26 public:
27 explicit SymKeyHandle(crypto::ScopedPK11SymKey key) { 27 explicit SymKeyHandle(crypto::ScopedPK11SymKey key) : key_(key.Pass()) {}
28 DCHECK(!key_.get());
29 key_ = key.Pass();
30 }
31 28
32 PK11SymKey* key() { return key_.get(); } 29 PK11SymKey* key() { return key_.get(); }
33 30
34 private: 31 private:
35 crypto::ScopedPK11SymKey key_; 32 crypto::ScopedPK11SymKey key_;
36 33
37 DISALLOW_COPY_AND_ASSIGN(SymKeyHandle); 34 DISALLOW_COPY_AND_ASSIGN(SymKeyHandle);
38 }; 35 };
39 36
37 class PublicKeyHandle : public WebKit::WebCryptoKeyHandle {
38 public:
39 explicit PublicKeyHandle(crypto::ScopedSECKEYPublicKey key)
40 : key_(key.Pass()) {}
41
42 SECKEYPublicKey* key() { return key_.get(); }
43
44 private:
45 crypto::ScopedSECKEYPublicKey key_;
46
47 DISALLOW_COPY_AND_ASSIGN(PublicKeyHandle);
48 };
49
50 class PrivateKeyHandle : public WebKit::WebCryptoKeyHandle {
51 public:
52 explicit PrivateKeyHandle(crypto::ScopedSECKEYPrivateKey key)
53 : key_(key.Pass()) {}
54
55 SECKEYPrivateKey* key() { return key_.get(); }
56
57 private:
58 crypto::ScopedSECKEYPrivateKey key_;
59
60 DISALLOW_COPY_AND_ASSIGN(PrivateKeyHandle);
61 };
62
40 HASH_HashType WebCryptoAlgorithmToNSSHashType( 63 HASH_HashType WebCryptoAlgorithmToNSSHashType(
41 const WebKit::WebCryptoAlgorithm& algorithm) { 64 const WebKit::WebCryptoAlgorithm& algorithm) {
42 switch (algorithm.id()) { 65 switch (algorithm.id()) {
43 case WebKit::WebCryptoAlgorithmIdSha1: 66 case WebKit::WebCryptoAlgorithmIdSha1:
44 return HASH_AlgSHA1; 67 return HASH_AlgSHA1;
45 case WebKit::WebCryptoAlgorithmIdSha224: 68 case WebKit::WebCryptoAlgorithmIdSha224:
46 return HASH_AlgSHA224; 69 return HASH_AlgSHA224;
47 case WebKit::WebCryptoAlgorithmIdSha256: 70 case WebKit::WebCryptoAlgorithmIdSha256:
48 return HASH_AlgSHA256; 71 return HASH_AlgSHA256;
49 case WebKit::WebCryptoAlgorithmIdSha384: 72 case WebKit::WebCryptoAlgorithmIdSha384:
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
95 crypto::ScopedSECItem param(PK11_ParamFromIV(CKM_AES_CBC_PAD, &iv_item)); 118 crypto::ScopedSECItem param(PK11_ParamFromIV(CKM_AES_CBC_PAD, &iv_item));
96 if (!param) 119 if (!param)
97 return false; 120 return false;
98 121
99 crypto::ScopedPK11Context context(PK11_CreateContextBySymKey( 122 crypto::ScopedPK11Context context(PK11_CreateContextBySymKey(
100 CKM_AES_CBC_PAD, operation, sym_key->key(), param.get())); 123 CKM_AES_CBC_PAD, operation, sym_key->key(), param.get()));
101 124
102 if (!context.get()) 125 if (!context.get())
103 return false; 126 return false;
104 127
105 // Oddly PK11_CipherOp takes input and output lenths as "int" rather than 128 // Oddly PK11_CipherOp takes input and output lengths as "int" rather than
106 // "unsigned". Do some checks now to avoid integer overflowing. 129 // "unsigned". Do some checks now to avoid integer overflowing.
107 if (data_size >= INT_MAX - AES_BLOCK_SIZE) { 130 if (data_size >= INT_MAX - AES_BLOCK_SIZE) {
108 // TODO(eroman): Handle this by chunking the input fed into NSS. Right now 131 // TODO(eroman): Handle this by chunking the input fed into NSS. Right now
109 // it doesn't make much difference since the one-shot API would end up 132 // it doesn't make much difference since the one-shot API would end up
110 // blowing out the memory and crashing anyway. However a newer version of 133 // blowing out the memory and crashing anyway. However a newer version of
111 // the spec allows for a sequence<CryptoData> so this will be relevant. 134 // the spec allows for a sequence<CryptoData> so this will be relevant.
112 return false; 135 return false;
113 } 136 }
114 137
115 // PK11_CipherOp does an invalid memory access when given empty decryption 138 // PK11_CipherOp does an invalid memory access when given empty decryption
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
186 switch (params->hash().id()) { 209 switch (params->hash().id()) {
187 case WebKit::WebCryptoAlgorithmIdSha1: 210 case WebKit::WebCryptoAlgorithmIdSha1:
188 return 512; 211 return 512;
189 case WebKit::WebCryptoAlgorithmIdSha256: 212 case WebKit::WebCryptoAlgorithmIdSha256:
190 return 512; 213 return 512;
191 default: 214 default:
192 return 0; 215 return 0;
193 } 216 }
194 } 217 }
195 218
219 // Converts a (big-endian) WebCrypto BigInteger, with or without leading zeros,
220 // to unsigned long.
221 bool BigIntegerToLong(const uint8* data,
222 unsigned data_size,
223 unsigned long* result) {
224 // TODO(padolph): Is it correct to say that empty data is an error, or does it
225 // mean value 0? See https://www.w3.org/Bugs/Public/show_bug.cgi?id=23655
226 if (data_size == 0)
227 return false;
228
229 *result = 0;
230 for (size_t i = 0; i < data_size; ++i) {
231 size_t reverse_i = data_size - i - 1;
232
233 if (reverse_i >= sizeof(unsigned long) && data[i])
234 return false; // Too large for a long.
235
236 *result |= data[i] << 8 * reverse_i;
237 }
238 return true;
239 }
240
196 } // namespace 241 } // namespace
197 242
198 void WebCryptoImpl::Init() { 243 void WebCryptoImpl::Init() {
199 crypto::EnsureNSSInit(); 244 crypto::EnsureNSSInit();
200 } 245 }
201 246
202 bool WebCryptoImpl::EncryptInternal( 247 bool WebCryptoImpl::EncryptInternal(
203 const WebKit::WebCryptoAlgorithm& algorithm, 248 const WebKit::WebCryptoAlgorithm& algorithm,
204 const WebKit::WebCryptoKey& key, 249 const WebKit::WebCryptoKey& key,
205 const unsigned char* data, 250 const unsigned char* data,
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
317 if (!pk11_key) { 362 if (!pk11_key) {
318 return false; 363 return false;
319 } 364 }
320 365
321 *key = WebKit::WebCryptoKey::create( 366 *key = WebKit::WebCryptoKey::create(
322 new SymKeyHandle(pk11_key.Pass()), 367 new SymKeyHandle(pk11_key.Pass()),
323 key_type, extractable, algorithm, usage_mask); 368 key_type, extractable, algorithm, usage_mask);
324 return true; 369 return true;
325 } 370 }
326 371
372 bool WebCryptoImpl::GenerateKeyPairInternal(
373 const WebKit::WebCryptoAlgorithm& algorithm,
374 bool extractable,
375 WebKit::WebCryptoKeyUsageMask usage_mask,
376 WebKit::WebCryptoKey* public_key,
377 WebKit::WebCryptoKey* private_key) {
378
379 // TODO(padolph): Handle other asymmetric algorithm key generation.
380 switch (algorithm.id()) {
381 case WebKit::WebCryptoAlgorithmIdRsaEsPkcs1v1_5:
382 case WebKit::WebCryptoAlgorithmIdRsaOaep:
383 case WebKit::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: {
384 const WebKit::WebCryptoRsaKeyGenParams* const params =
385 algorithm.rsaKeyGenParams();
386 DCHECK(params);
387
388 crypto::ScopedPK11Slot slot(PK11_GetInternalKeySlot());
389 unsigned long public_exponent;
390 if (!slot || !params->modulusLength() ||
391 !BigIntegerToLong(params->publicExponent().data(),
392 params->publicExponent().size(),
393 &public_exponent) ||
394 !public_exponent) {
395 return false;
396 }
397
398 PK11RSAGenParams rsa_gen_params;
399 rsa_gen_params.keySizeInBits = params->modulusLength();
400 rsa_gen_params.pe = public_exponent;
401
402 // Flags are verified at the Blink layer; here the flags are set to all
403 // possible operations for the given key type.
404 CK_FLAGS operation_flags;
405 switch (algorithm.id()) {
406 case WebKit::WebCryptoAlgorithmIdRsaEsPkcs1v1_5:
407 case WebKit::WebCryptoAlgorithmIdRsaOaep:
408 operation_flags = CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP;
409 break;
410 case WebKit::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5:
411 operation_flags = CKF_SIGN | CKF_VERIFY;
412 break;
413 default:
414 NOTREACHED();
415 return false;
416 }
417 const CK_FLAGS operation_flags_mask = CKF_ENCRYPT | CKF_DECRYPT |
418 CKF_SIGN | CKF_VERIFY | CKF_WRAP |
419 CKF_UNWRAP;
420 const PK11AttrFlags attribute_flags = 0; // Default all PK11_ATTR_ flags.
421
422 // Note: NSS does not generate an sec_public_key if the call below fails,
423 // so there is no danger of a leaked sec_public_key.
424 SECKEYPublicKey* sec_public_key;
425 crypto::ScopedSECKEYPrivateKey scoped_sec_private_key(
426 PK11_GenerateKeyPairWithOpFlags(slot.get(),
427 CKM_RSA_PKCS_KEY_PAIR_GEN,
428 &rsa_gen_params,
429 &sec_public_key,
430 attribute_flags,
431 operation_flags,
432 operation_flags_mask,
433 NULL));
434 if (!private_key) {
435 return false;
436 }
437
438 // The 'extractable' input parameter applies to the private key here.
439 // Make the public key always extractable.
eroman 2013/10/31 22:18:36 I don't see anything about this in the spec. My i
Ryan Sleevi 2013/10/31 22:23:20 File a spec bug. Current spec indicates both keys
eroman 2013/10/31 22:30:07 Done: https://www.w3.org/Bugs/Public/show_bug.cgi?
padolph 2013/11/01 20:35:31 Done.
440 *public_key = WebKit::WebCryptoKey::create(
441 new PublicKeyHandle(
442 crypto::ScopedSECKEYPublicKey(sec_public_key).Pass()),
eroman 2013/10/31 22:18:36 Is the .Pass() needed ?
padolph 2013/11/01 20:35:31 No. Done.
443 WebKit::WebCryptoKeyTypePublic,
444 true,
445 algorithm,
446 usage_mask);
447 *private_key = WebKit::WebCryptoKey::create(
448 new PrivateKeyHandle(scoped_sec_private_key.Pass()),
449 WebKit::WebCryptoKeyTypePrivate,
450 extractable,
451 algorithm,
452 usage_mask);
453
454 return true;
455 }
456 default:
457 return false;
458 }
459 }
327 460
328 bool WebCryptoImpl::ImportKeyInternal( 461 bool WebCryptoImpl::ImportKeyInternal(
329 WebKit::WebCryptoKeyFormat format, 462 WebKit::WebCryptoKeyFormat format,
330 const unsigned char* key_data, 463 const unsigned char* key_data,
331 unsigned key_data_size, 464 unsigned key_data_size,
332 const WebKit::WebCryptoAlgorithm& algorithm_or_null, 465 const WebKit::WebCryptoAlgorithm& algorithm_or_null,
333 bool extractable, 466 bool extractable,
334 WebKit::WebCryptoKeyUsageMask usage_mask, 467 WebKit::WebCryptoKeyUsageMask usage_mask,
335 WebKit::WebCryptoKey* key) { 468 WebKit::WebCryptoKey* key) {
336 // TODO(eroman): Currently expects algorithm to always be specified, as it is 469 // TODO(eroman): Currently expects algorithm to always be specified, as it is
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after
506 break; 639 break;
507 } 640 }
508 default: 641 default:
509 return false; 642 return false;
510 } 643 }
511 644
512 return true; 645 return true;
513 } 646 }
514 647
515 } // namespace content 648 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698