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

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

Issue 155623005: Refactor to share more code between OpenSSL and NSS implementations. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Change header guard Created 6 years, 10 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 2013 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 "content/renderer/webcrypto/webcrypto_impl.h"
6
7 #include <cryptohi.h>
8 #include <pk11pub.h>
9 #include <sechash.h>
10
11 #include <vector>
12
13 #include "base/lazy_instance.h"
14 #include "base/logging.h"
15 #include "content/renderer/webcrypto/webcrypto_util.h"
16 #include "crypto/nss_util.h"
17 #include "crypto/scoped_nss_types.h"
18 #include "crypto/secure_util.h"
19 #include "third_party/WebKit/public/platform/WebArrayBuffer.h"
20 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
21 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
22
23 #if defined(USE_NSS)
24 #include <dlfcn.h>
25 #endif
26
27 // At the time of this writing:
28 // * Windows and Mac builds ship with their own copy of NSS (3.15+)
29 // * Linux builds use the system's libnss, which is 3.14 on Debian (but 3.15+
30 // on other distros).
31 //
32 // Since NSS provides AES-GCM support starting in version 3.15, it may be
33 // unavailable for Linux Chrome users.
34 //
35 // * !defined(CKM_AES_GCM)
36 //
37 // This means that at build time, the NSS header pkcs11t.h is older than
38 // 3.15. However at runtime support may be present.
39 //
40 // * !defined(USE_NSS)
41 //
42 // This means that Chrome is being built with an embedded copy of NSS,
43 // which can be assumed to be >= 3.15. On the other hand if USE_NSS is
44 // defined, it also implies running on Linux.
45 //
46 // TODO(eroman): Simplify this once 3.15+ is required by Linux builds.
47 #if !defined(CKM_AES_GCM)
48 #define CKM_AES_GCM 0x00001087
49
50 struct CK_GCM_PARAMS {
51 CK_BYTE_PTR pIv;
52 CK_ULONG ulIvLen;
53 CK_BYTE_PTR pAAD;
54 CK_ULONG ulAADLen;
55 CK_ULONG ulTagBits;
56 };
57 #endif // !defined(CKM_AES_GCM)
58
59 // Signature for PK11_Encrypt and PK11_Decrypt.
60 typedef SECStatus
61 (*PK11_EncryptDecryptFunction)(
62 PK11SymKey*, CK_MECHANISM_TYPE, SECItem*,
63 unsigned char*, unsigned int*, unsigned int,
64 const unsigned char*, unsigned int);
65
66 // Singleton to abstract away dynamically loading libnss3.so
67 class AesGcmSupport {
68 public:
69 bool IsSupported() const {
70 return pk11_encrypt_func_ && pk11_decrypt_func_;
71 }
72
73 // Returns NULL if unsupported.
74 PK11_EncryptDecryptFunction pk11_encrypt_func() const {
75 return pk11_encrypt_func_;
76 }
77
78 // Returns NULL if unsupported.
79 PK11_EncryptDecryptFunction pk11_decrypt_func() const {
80 return pk11_decrypt_func_;
81 }
82
83 private:
84 friend struct base::DefaultLazyInstanceTraits<AesGcmSupport>;
85
86 AesGcmSupport() {
87 #if !defined(USE_NSS)
88 // Using a bundled version of NSS that is guaranteed to have this symbol.
89 pk11_encrypt_func_ = PK11_Encrypt;
90 pk11_decrypt_func_ = PK11_Decrypt;
91 #else
92 // Using system NSS libraries and PCKS #11 modules, which may not have the
93 // necessary function (PK11_Encrypt) or mechanism support (CKM_AES_GCM).
94
95 // If PK11_Encrypt() was successfully resolved, then NSS will support
96 // AES-GCM directly. This was introduced in NSS 3.15.
97 pk11_encrypt_func_ =
98 reinterpret_cast<PK11_EncryptDecryptFunction>(
99 dlsym(RTLD_DEFAULT, "PK11_Encrypt"));
100 pk11_decrypt_func_ =
101 reinterpret_cast<PK11_EncryptDecryptFunction>(
102 dlsym(RTLD_DEFAULT, "PK11_Decrypt"));
103 #endif
104 }
105
106 PK11_EncryptDecryptFunction pk11_encrypt_func_;
107 PK11_EncryptDecryptFunction pk11_decrypt_func_;
108 };
109
110 base::LazyInstance<AesGcmSupport>::Leaky g_aes_gcm_support =
111 LAZY_INSTANCE_INITIALIZER;
112
113 namespace content {
114
115 using webcrypto::Status;
116
117 namespace {
118
119 class SymKeyHandle : public blink::WebCryptoKeyHandle {
120 public:
121 explicit SymKeyHandle(crypto::ScopedPK11SymKey key) : key_(key.Pass()) {}
122
123 PK11SymKey* key() { return key_.get(); }
124
125 private:
126 crypto::ScopedPK11SymKey key_;
127
128 DISALLOW_COPY_AND_ASSIGN(SymKeyHandle);
129 };
130
131 class PublicKeyHandle : public blink::WebCryptoKeyHandle {
132 public:
133 explicit PublicKeyHandle(crypto::ScopedSECKEYPublicKey key)
134 : key_(key.Pass()) {}
135
136 SECKEYPublicKey* key() { return key_.get(); }
137
138 private:
139 crypto::ScopedSECKEYPublicKey key_;
140
141 DISALLOW_COPY_AND_ASSIGN(PublicKeyHandle);
142 };
143
144 class PrivateKeyHandle : public blink::WebCryptoKeyHandle {
145 public:
146 explicit PrivateKeyHandle(crypto::ScopedSECKEYPrivateKey key)
147 : key_(key.Pass()) {}
148
149 SECKEYPrivateKey* key() { return key_.get(); }
150
151 private:
152 crypto::ScopedSECKEYPrivateKey key_;
153
154 DISALLOW_COPY_AND_ASSIGN(PrivateKeyHandle);
155 };
156
157 HASH_HashType WebCryptoAlgorithmToNSSHashType(
158 const blink::WebCryptoAlgorithm& algorithm) {
159 switch (algorithm.id()) {
160 case blink::WebCryptoAlgorithmIdSha1:
161 return HASH_AlgSHA1;
162 case blink::WebCryptoAlgorithmIdSha224:
163 return HASH_AlgSHA224;
164 case blink::WebCryptoAlgorithmIdSha256:
165 return HASH_AlgSHA256;
166 case blink::WebCryptoAlgorithmIdSha384:
167 return HASH_AlgSHA384;
168 case blink::WebCryptoAlgorithmIdSha512:
169 return HASH_AlgSHA512;
170 default:
171 // Not a digest algorithm.
172 return HASH_AlgNULL;
173 }
174 }
175
176 CK_MECHANISM_TYPE WebCryptoHashToHMACMechanism(
177 const blink::WebCryptoAlgorithm& algorithm) {
178 switch (algorithm.id()) {
179 case blink::WebCryptoAlgorithmIdSha1:
180 return CKM_SHA_1_HMAC;
181 case blink::WebCryptoAlgorithmIdSha224:
182 return CKM_SHA224_HMAC;
183 case blink::WebCryptoAlgorithmIdSha256:
184 return CKM_SHA256_HMAC;
185 case blink::WebCryptoAlgorithmIdSha384:
186 return CKM_SHA384_HMAC;
187 case blink::WebCryptoAlgorithmIdSha512:
188 return CKM_SHA512_HMAC;
189 default:
190 // Not a supported algorithm.
191 return CKM_INVALID_MECHANISM;
192 }
193 }
194
195 Status AesCbcEncryptDecrypt(
196 CK_ATTRIBUTE_TYPE operation,
197 const blink::WebCryptoAlgorithm& algorithm,
198 const blink::WebCryptoKey& key,
199 const unsigned char* data,
200 unsigned int data_size,
201 blink::WebArrayBuffer* buffer) {
202 DCHECK_EQ(blink::WebCryptoAlgorithmIdAesCbc, algorithm.id());
203 DCHECK_EQ(algorithm.id(), key.algorithm().id());
204 DCHECK_EQ(blink::WebCryptoKeyTypeSecret, key.type());
205 DCHECK(operation == CKA_ENCRYPT || operation == CKA_DECRYPT);
206
207 SymKeyHandle* sym_key = reinterpret_cast<SymKeyHandle*>(key.handle());
208
209 const blink::WebCryptoAesCbcParams* params = algorithm.aesCbcParams();
210 if (params->iv().size() != AES_BLOCK_SIZE)
211 return Status::ErrorIncorrectSizeAesCbcIv();
212
213 SECItem iv_item;
214 iv_item.type = siBuffer;
215 iv_item.data = const_cast<unsigned char*>(params->iv().data());
216 iv_item.len = params->iv().size();
217
218 crypto::ScopedSECItem param(PK11_ParamFromIV(CKM_AES_CBC_PAD, &iv_item));
219 if (!param)
220 return Status::Error();
221
222 crypto::ScopedPK11Context context(PK11_CreateContextBySymKey(
223 CKM_AES_CBC_PAD, operation, sym_key->key(), param.get()));
224
225 if (!context.get())
226 return Status::Error();
227
228 // Oddly PK11_CipherOp takes input and output lengths as "int" rather than
229 // "unsigned int". Do some checks now to avoid integer overflowing.
230 if (data_size >= INT_MAX - AES_BLOCK_SIZE) {
231 // TODO(eroman): Handle this by chunking the input fed into NSS. Right now
232 // it doesn't make much difference since the one-shot API would end up
233 // blowing out the memory and crashing anyway.
234 return Status::ErrorDataTooLarge();
235 }
236
237 // PK11_CipherOp does an invalid memory access when given empty decryption
238 // input, or input which is not a multiple of the block size. See also
239 // https://bugzilla.mozilla.com/show_bug.cgi?id=921687.
240 if (operation == CKA_DECRYPT &&
241 (data_size == 0 || (data_size % AES_BLOCK_SIZE != 0))) {
242 return Status::Error();
243 }
244
245 // TODO(eroman): Refine the output buffer size. It can be computed exactly for
246 // encryption, and can be smaller for decryption.
247 unsigned int output_max_len = data_size + AES_BLOCK_SIZE;
248 CHECK_GT(output_max_len, data_size);
249
250 *buffer = blink::WebArrayBuffer::create(output_max_len, 1);
251
252 unsigned char* buffer_data = reinterpret_cast<unsigned char*>(buffer->data());
253
254 int output_len;
255 if (SECSuccess != PK11_CipherOp(context.get(),
256 buffer_data,
257 &output_len,
258 buffer->byteLength(),
259 data,
260 data_size)) {
261 return Status::Error();
262 }
263
264 unsigned int final_output_chunk_len;
265 if (SECSuccess != PK11_DigestFinal(context.get(),
266 buffer_data + output_len,
267 &final_output_chunk_len,
268 output_max_len - output_len)) {
269 return Status::Error();
270 }
271
272 webcrypto::ShrinkBuffer(buffer, final_output_chunk_len + output_len);
273 return Status::Success();
274 }
275
276 // Helper to either encrypt or decrypt for AES-GCM. The result of encryption is
277 // the concatenation of the ciphertext and the authentication tag. Similarly,
278 // this is the expectation for the input to decryption.
279 Status AesGcmEncryptDecrypt(
280 bool encrypt,
281 const blink::WebCryptoAlgorithm& algorithm,
282 const blink::WebCryptoKey& key,
283 const unsigned char* data,
284 unsigned int data_size,
285 blink::WebArrayBuffer* buffer) {
286 DCHECK_EQ(blink::WebCryptoAlgorithmIdAesGcm, algorithm.id());
287 DCHECK_EQ(algorithm.id(), key.algorithm().id());
288 DCHECK_EQ(blink::WebCryptoKeyTypeSecret, key.type());
289
290 if (!g_aes_gcm_support.Get().IsSupported())
291 return Status::ErrorUnsupported();
292
293 SymKeyHandle* sym_key = reinterpret_cast<SymKeyHandle*>(key.handle());
294
295 const blink::WebCryptoAesGcmParams* params = algorithm.aesGcmParams();
296 if (!params)
297 return Status::ErrorUnexpected();
298
299 // TODO(eroman): The spec doesn't define the default value. Assume 128 for now
300 // since that is the maximum tag length:
301 // http://www.w3.org/2012/webcrypto/track/issues/46
302 unsigned int tag_length_bits = 128;
303 if (params->hasTagLengthBits())
304 tag_length_bits = params->optionalTagLengthBits();
305
306 if (tag_length_bits > 128 || (tag_length_bits % 8) != 0)
307 return Status::ErrorInvalidAesGcmTagLength();
308
309 unsigned int tag_length_bytes = tag_length_bits / 8;
310
311 CK_GCM_PARAMS gcm_params = {0};
312 gcm_params.pIv =
313 const_cast<unsigned char*>(algorithm.aesGcmParams()->iv().data());
314 gcm_params.ulIvLen = algorithm.aesGcmParams()->iv().size();
315
316 gcm_params.pAAD =
317 const_cast<unsigned char*>(params->optionalAdditionalData().data());
318 gcm_params.ulAADLen = params->optionalAdditionalData().size();
319
320 gcm_params.ulTagBits = tag_length_bits;
321
322 SECItem param;
323 param.type = siBuffer;
324 param.data = reinterpret_cast<unsigned char*>(&gcm_params);
325 param.len = sizeof(gcm_params);
326
327 unsigned int buffer_size = 0;
328
329 // Calculate the output buffer size.
330 if (encrypt) {
331 // TODO(eroman): This is ugly, abstract away the safe integer arithmetic.
332 if (data_size > (UINT_MAX - tag_length_bytes))
333 return Status::ErrorDataTooLarge();
334 buffer_size = data_size + tag_length_bytes;
335 } else {
336 // TODO(eroman): In theory the buffer allocated for the plain text should be
337 // sized as |data_size - tag_length_bytes|.
338 //
339 // However NSS has a bug whereby it will fail if the output buffer size is
340 // not at least as large as the ciphertext:
341 //
342 // https://bugzilla.mozilla.org/show_bug.cgi?id=%20853674
343 //
344 // From the analysis of that bug it looks like it might be safe to pass a
345 // correctly sized buffer but lie about its size. Since resizing the
346 // WebCryptoArrayBuffer is expensive that hack may be worth looking into.
347 buffer_size = data_size;
348 }
349
350 *buffer = blink::WebArrayBuffer::create(buffer_size, 1);
351 unsigned char* buffer_data = reinterpret_cast<unsigned char*>(buffer->data());
352
353 PK11_EncryptDecryptFunction func =
354 encrypt ? g_aes_gcm_support.Get().pk11_encrypt_func() :
355 g_aes_gcm_support.Get().pk11_decrypt_func();
356
357 unsigned int output_len = 0;
358 SECStatus result = func(sym_key->key(), CKM_AES_GCM, &param,
359 buffer_data, &output_len, buffer->byteLength(),
360 data, data_size);
361
362 if (result != SECSuccess)
363 return Status::Error();
364
365 // Unfortunately the buffer needs to be shrunk for decryption (see the NSS bug
366 // above).
367 webcrypto::ShrinkBuffer(buffer, output_len);
368
369 return Status::Success();
370 }
371
372 CK_MECHANISM_TYPE WebCryptoAlgorithmToGenMechanism(
373 const blink::WebCryptoAlgorithm& algorithm) {
374 switch (algorithm.id()) {
375 case blink::WebCryptoAlgorithmIdAesCbc:
376 case blink::WebCryptoAlgorithmIdAesGcm:
377 case blink::WebCryptoAlgorithmIdAesKw:
378 return CKM_AES_KEY_GEN;
379 case blink::WebCryptoAlgorithmIdHmac:
380 return WebCryptoHashToHMACMechanism(algorithm.hmacKeyParams()->hash());
381 default:
382 return CKM_INVALID_MECHANISM;
383 }
384 }
385
386 // Converts a (big-endian) WebCrypto BigInteger, with or without leading zeros,
387 // to unsigned long.
388 bool BigIntegerToLong(const uint8* data,
389 unsigned int data_size,
390 unsigned long* result) {
391 // TODO(padolph): Is it correct to say that empty data is an error, or does it
392 // mean value 0? See https://www.w3.org/Bugs/Public/show_bug.cgi?id=23655
393 if (data_size == 0)
394 return false;
395
396 *result = 0;
397 for (size_t i = 0; i < data_size; ++i) {
398 size_t reverse_i = data_size - i - 1;
399
400 if (reverse_i >= sizeof(unsigned long) && data[i])
401 return false; // Too large for a long.
402
403 *result |= data[i] << 8 * reverse_i;
404 }
405 return true;
406 }
407
408 bool IsAlgorithmRsa(const blink::WebCryptoAlgorithm& algorithm) {
409 return algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 ||
410 algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep ||
411 algorithm.id() == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5;
412 }
413
414 Status ImportKeyInternalRaw(
415 const unsigned char* key_data,
416 unsigned int key_data_size,
417 const blink::WebCryptoAlgorithm& algorithm,
418 bool extractable,
419 blink::WebCryptoKeyUsageMask usage_mask,
420 blink::WebCryptoKey* key) {
421
422 DCHECK(!algorithm.isNull());
423
424 blink::WebCryptoKeyType type;
425 switch (algorithm.id()) {
426 case blink::WebCryptoAlgorithmIdHmac:
427 case blink::WebCryptoAlgorithmIdAesCbc:
428 case blink::WebCryptoAlgorithmIdAesKw:
429 case blink::WebCryptoAlgorithmIdAesGcm:
430 type = blink::WebCryptoKeyTypeSecret;
431 break;
432 // TODO(bryaneyler): Support more key types.
433 default:
434 return Status::ErrorUnsupported();
435 }
436
437 // TODO(bryaneyler): Need to split handling for symmetric and asymmetric keys.
438 // Currently only supporting symmetric.
439 CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
440 // Flags are verified at the Blink layer; here the flags are set to all
441 // possible operations for this key type.
442 CK_FLAGS flags = 0;
443
444 switch (algorithm.id()) {
445 case blink::WebCryptoAlgorithmIdHmac: {
446 const blink::WebCryptoHmacParams* params = algorithm.hmacParams();
447 if (!params)
448 return Status::ErrorUnexpected();
449
450 mechanism = WebCryptoHashToHMACMechanism(params->hash());
451 if (mechanism == CKM_INVALID_MECHANISM)
452 return Status::ErrorUnsupported();
453
454 flags |= CKF_SIGN | CKF_VERIFY;
455
456 break;
457 }
458 case blink::WebCryptoAlgorithmIdAesCbc: {
459 mechanism = CKM_AES_CBC;
460 flags |= CKF_ENCRYPT | CKF_DECRYPT;
461 break;
462 }
463 case blink::WebCryptoAlgorithmIdAesKw: {
464 mechanism = CKM_NSS_AES_KEY_WRAP;
465 flags |= CKF_WRAP | CKF_WRAP;
466 break;
467 }
468 case blink::WebCryptoAlgorithmIdAesGcm: {
469 if (!g_aes_gcm_support.Get().IsSupported())
470 return Status::ErrorUnsupported();
471 mechanism = CKM_AES_GCM;
472 flags |= CKF_ENCRYPT | CKF_DECRYPT;
473 break;
474 }
475 default:
476 return Status::ErrorUnsupported();
477 }
478
479 DCHECK_NE(CKM_INVALID_MECHANISM, mechanism);
480 DCHECK_NE(0ul, flags);
481
482 SECItem key_item = {
483 siBuffer,
484 const_cast<unsigned char*>(key_data),
485 key_data_size
486 };
487
488 crypto::ScopedPK11Slot slot(PK11_GetInternalSlot());
489 crypto::ScopedPK11SymKey pk11_sym_key(
490 PK11_ImportSymKeyWithFlags(slot.get(),
491 mechanism,
492 PK11_OriginUnwrap,
493 CKA_FLAGS_ONLY,
494 &key_item,
495 flags,
496 false,
497 NULL));
498 if (!pk11_sym_key.get())
499 return Status::Error();
500
501 *key = blink::WebCryptoKey::create(new SymKeyHandle(pk11_sym_key.Pass()),
502 type, extractable, algorithm, usage_mask);
503 return Status::Success();
504 }
505
506 Status ExportKeyInternalRaw(
507 const blink::WebCryptoKey& key,
508 blink::WebArrayBuffer* buffer) {
509
510 DCHECK(key.handle());
511 DCHECK(buffer);
512
513 if (!key.extractable())
514 return Status::ErrorKeyNotExtractable();
515 if (key.type() != blink::WebCryptoKeyTypeSecret)
516 return Status::ErrorUnexpectedKeyType();
517
518 SymKeyHandle* sym_key = reinterpret_cast<SymKeyHandle*>(key.handle());
519
520 if (PK11_ExtractKeyValue(sym_key->key()) != SECSuccess)
521 return Status::Error();
522
523 const SECItem* key_data = PK11_GetKeyData(sym_key->key());
524 if (!key_data)
525 return Status::Error();
526
527 *buffer = webcrypto::CreateArrayBuffer(key_data->data, key_data->len);
528
529 return Status::Success();
530 }
531
532 typedef scoped_ptr<CERTSubjectPublicKeyInfo,
533 crypto::NSSDestroyer<CERTSubjectPublicKeyInfo,
534 SECKEY_DestroySubjectPublicKeyInfo> >
535 ScopedCERTSubjectPublicKeyInfo;
536
537 // Validates an NSS KeyType against a WebCrypto algorithm. Some NSS KeyTypes
538 // contain enough information to fabricate a Web Crypto algorithm, which is
539 // returned if the input algorithm isNull(). This function indicates failure by
540 // returning a Null algorithm.
541 blink::WebCryptoAlgorithm ResolveNssKeyTypeWithInputAlgorithm(
542 KeyType key_type,
543 const blink::WebCryptoAlgorithm& algorithm_or_null) {
544 switch (key_type) {
545 case rsaKey:
546 // NSS's rsaKey KeyType maps to keys with SEC_OID_PKCS1_RSA_ENCRYPTION and
547 // according to RFCs 4055/5756 this can be used for both encryption and
548 // signatures. However, this is not specific enough to build a compatible
549 // Web Crypto algorithm, since in Web Crypto, RSA encryption and signature
550 // algorithms are distinct. So if the input algorithm isNull() here, we
551 // have to fail.
552 if (!algorithm_or_null.isNull() && IsAlgorithmRsa(algorithm_or_null))
553 return algorithm_or_null;
554 break;
555 case dsaKey:
556 case ecKey:
557 case rsaPssKey:
558 case rsaOaepKey:
559 // TODO(padolph): Handle other key types.
560 break;
561 default:
562 break;
563 }
564 return blink::WebCryptoAlgorithm::createNull();
565 }
566
567 Status ImportKeyInternalSpki(
568 const unsigned char* key_data,
569 unsigned int key_data_size,
570 const blink::WebCryptoAlgorithm& algorithm_or_null,
571 bool extractable,
572 blink::WebCryptoKeyUsageMask usage_mask,
573 blink::WebCryptoKey* key) {
574
575 DCHECK(key);
576
577 if (!key_data_size)
578 return Status::ErrorImportEmptyKeyData();
579 DCHECK(key_data);
580
581 // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 Subject
582 // Public Key Info. Decode this to a CERTSubjectPublicKeyInfo.
583 SECItem spki_item = {siBuffer, const_cast<uint8*>(key_data), key_data_size};
584 const ScopedCERTSubjectPublicKeyInfo spki(
585 SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item));
586 if (!spki)
587 return Status::Error();
588
589 crypto::ScopedSECKEYPublicKey sec_public_key(
590 SECKEY_ExtractPublicKey(spki.get()));
591 if (!sec_public_key)
592 return Status::Error();
593
594 const KeyType sec_key_type = SECKEY_GetPublicKeyType(sec_public_key.get());
595 blink::WebCryptoAlgorithm algorithm =
596 ResolveNssKeyTypeWithInputAlgorithm(sec_key_type, algorithm_or_null);
597 if (algorithm.isNull())
598 return Status::Error();
599
600 *key = blink::WebCryptoKey::create(
601 new PublicKeyHandle(sec_public_key.Pass()),
602 blink::WebCryptoKeyTypePublic,
603 extractable,
604 algorithm,
605 usage_mask);
606
607 return Status::Success();
608 }
609
610 Status ExportKeyInternalSpki(
611 const blink::WebCryptoKey& key,
612 blink::WebArrayBuffer* buffer) {
613
614 DCHECK(key.handle());
615 DCHECK(buffer);
616
617 if (!key.extractable())
618 return Status::ErrorKeyNotExtractable();
619 if (key.type() != blink::WebCryptoKeyTypePublic)
620 return Status::ErrorUnexpectedKeyType();
621
622 PublicKeyHandle* const pub_key =
623 reinterpret_cast<PublicKeyHandle*>(key.handle());
624
625 const crypto::ScopedSECItem spki_der(
626 SECKEY_EncodeDERSubjectPublicKeyInfo(pub_key->key()));
627 if (!spki_der)
628 return Status::Error();
629
630 DCHECK(spki_der->data);
631 DCHECK(spki_der->len);
632
633 *buffer = webcrypto::CreateArrayBuffer(spki_der->data, spki_der->len);
634
635 return Status::Success();
636 }
637
638 Status ImportKeyInternalPkcs8(
639 const unsigned char* key_data,
640 unsigned int key_data_size,
641 const blink::WebCryptoAlgorithm& algorithm_or_null,
642 bool extractable,
643 blink::WebCryptoKeyUsageMask usage_mask,
644 blink::WebCryptoKey* key) {
645
646 DCHECK(key);
647
648 if (!key_data_size)
649 return Status::ErrorImportEmptyKeyData();
650 DCHECK(key_data);
651
652 // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 PKCS#8
653 // private key info object.
654 SECItem pki_der = {siBuffer, const_cast<uint8*>(key_data), key_data_size};
655
656 SECKEYPrivateKey* seckey_private_key = NULL;
657 crypto::ScopedPK11Slot slot(PK11_GetInternalSlot());
658 if (PK11_ImportDERPrivateKeyInfoAndReturnKey(
659 slot.get(),
660 &pki_der,
661 NULL, // nickname
662 NULL, // publicValue
663 false, // isPerm
664 false, // isPrivate
665 KU_ALL, // usage
666 &seckey_private_key,
667 NULL) != SECSuccess) {
668 return Status::Error();
669 }
670 DCHECK(seckey_private_key);
671 crypto::ScopedSECKEYPrivateKey private_key(seckey_private_key);
672
673 const KeyType sec_key_type = SECKEY_GetPrivateKeyType(private_key.get());
674 blink::WebCryptoAlgorithm algorithm =
675 ResolveNssKeyTypeWithInputAlgorithm(sec_key_type, algorithm_or_null);
676 if (algorithm.isNull())
677 return Status::Error();
678
679 *key = blink::WebCryptoKey::create(
680 new PrivateKeyHandle(private_key.Pass()),
681 blink::WebCryptoKeyTypePrivate,
682 extractable,
683 algorithm,
684 usage_mask);
685
686 return Status::Success();
687 }
688
689 // -----------------------------------
690 // Hmac
691 // -----------------------------------
692
693 Status SignHmac(
694 const blink::WebCryptoAlgorithm& algorithm,
695 const blink::WebCryptoKey& key,
696 const unsigned char* data,
697 unsigned int data_size,
698 blink::WebArrayBuffer* buffer) {
699 DCHECK_EQ(blink::WebCryptoAlgorithmIdHmac, algorithm.id());
700
701 const blink::WebCryptoHmacParams* params = algorithm.hmacParams();
702 if (!params)
703 return Status::ErrorUnexpected();
704
705 SymKeyHandle* sym_key = reinterpret_cast<SymKeyHandle*>(key.handle());
706
707 DCHECK_EQ(PK11_GetMechanism(sym_key->key()),
708 WebCryptoHashToHMACMechanism(params->hash()));
709
710 SECItem param_item = { siBuffer, NULL, 0 };
711 SECItem data_item = {
712 siBuffer,
713 const_cast<unsigned char*>(data),
714 data_size
715 };
716 // First call is to figure out the length.
717 SECItem signature_item = { siBuffer, NULL, 0 };
718
719 if (PK11_SignWithSymKey(sym_key->key(),
720 PK11_GetMechanism(sym_key->key()),
721 &param_item,
722 &signature_item,
723 &data_item) != SECSuccess) {
724 return Status::Error();
725 }
726
727 DCHECK_NE(0u, signature_item.len);
728
729 *buffer = blink::WebArrayBuffer::create(signature_item.len, 1);
730 signature_item.data = reinterpret_cast<unsigned char*>(buffer->data());
731
732 if (PK11_SignWithSymKey(sym_key->key(),
733 PK11_GetMechanism(sym_key->key()),
734 &param_item,
735 &signature_item,
736 &data_item) != SECSuccess) {
737 return Status::Error();
738 }
739
740 DCHECK_EQ(buffer->byteLength(), signature_item.len);
741 return Status::Success();
742 }
743
744 Status VerifyHmac(
745 const blink::WebCryptoAlgorithm& algorithm,
746 const blink::WebCryptoKey& key,
747 const unsigned char* signature,
748 unsigned int signature_size,
749 const unsigned char* data,
750 unsigned int data_size,
751 bool* signature_match) {
752 DCHECK_EQ(blink::WebCryptoAlgorithmIdHmac, algorithm.id());
753
754 blink::WebArrayBuffer result;
755 Status status = SignHmac(algorithm, key, data, data_size, &result);
756 if (status.IsError())
757 return status;
758
759 // Handling of truncated signatures is underspecified in the WebCrypto
760 // spec, so here we fail verification if a truncated signature is being
761 // verified.
762 // See https://www.w3.org/Bugs/Public/show_bug.cgi?id=23097
763 *signature_match =
764 result.byteLength() == signature_size &&
765 crypto::SecureMemEqual(result.data(), signature, signature_size);
766
767 return Status::Success();
768 }
769
770 // -----------------------------------
771 // RsaEsPkcs1v1_5
772 // -----------------------------------
773
774 Status EncryptRsaEsPkcs1v1_5(
775 const blink::WebCryptoAlgorithm& algorithm,
776 const blink::WebCryptoKey& key,
777 const unsigned char* data,
778 unsigned int data_size,
779 blink::WebArrayBuffer* buffer) {
780 DCHECK_EQ(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, algorithm.id());
781
782 // RSAES encryption does not support empty input
783 if (!data_size)
784 return Status::Error();
785 DCHECK(data);
786
787 if (key.type() != blink::WebCryptoKeyTypePublic)
788 return Status::ErrorUnexpectedKeyType();
789
790 PublicKeyHandle* const public_key =
791 reinterpret_cast<PublicKeyHandle*>(key.handle());
792
793 const unsigned int encrypted_length_bytes =
794 SECKEY_PublicKeyStrength(public_key->key());
795
796 // RSAES can operate on messages up to a length of k - 11, where k is the
797 // octet length of the RSA modulus.
798 if (encrypted_length_bytes < 11 || encrypted_length_bytes - 11 < data_size)
799 return Status::ErrorDataTooLarge();
800
801 *buffer = blink::WebArrayBuffer::create(encrypted_length_bytes, 1);
802 unsigned char* const buffer_data =
803 reinterpret_cast<unsigned char*>(buffer->data());
804
805 if (PK11_PubEncryptPKCS1(public_key->key(),
806 buffer_data,
807 const_cast<unsigned char*>(data),
808 data_size,
809 NULL) != SECSuccess) {
810 return Status::Error();
811 }
812 return Status::Success();
813 }
814
815 Status DecryptRsaEsPkcs1v1_5(
816 const blink::WebCryptoAlgorithm& algorithm,
817 const blink::WebCryptoKey& key,
818 const unsigned char* data,
819 unsigned int data_size,
820 blink::WebArrayBuffer* buffer) {
821 DCHECK_EQ(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, algorithm.id());
822
823 // RSAES decryption does not support empty input
824 if (!data_size)
825 return Status::Error();
826 DCHECK(data);
827
828 if (key.type() != blink::WebCryptoKeyTypePrivate)
829 return Status::ErrorUnexpectedKeyType();
830
831 PrivateKeyHandle* const private_key =
832 reinterpret_cast<PrivateKeyHandle*>(key.handle());
833
834 const int modulus_length_bytes =
835 PK11_GetPrivateModulusLen(private_key->key());
836 if (modulus_length_bytes <= 0)
837 return Status::ErrorUnexpected();
838 const unsigned int max_output_length_bytes = modulus_length_bytes;
839
840 *buffer = blink::WebArrayBuffer::create(max_output_length_bytes, 1);
841 unsigned char* const buffer_data =
842 reinterpret_cast<unsigned char*>(buffer->data());
843
844 unsigned int output_length_bytes = 0;
845 if (PK11_PrivDecryptPKCS1(private_key->key(),
846 buffer_data,
847 &output_length_bytes,
848 max_output_length_bytes,
849 const_cast<unsigned char*>(data),
850 data_size) != SECSuccess) {
851 return Status::Error();
852 }
853 DCHECK_LE(output_length_bytes, max_output_length_bytes);
854 webcrypto::ShrinkBuffer(buffer, output_length_bytes);
855 return Status::Success();
856 }
857
858 // -----------------------------------
859 // RsaSsaPkcs1v1_5
860 // -----------------------------------
861
862 Status SignRsaSsaPkcs1v1_5(
863 const blink::WebCryptoAlgorithm& algorithm,
864 const blink::WebCryptoKey& key,
865 const unsigned char* data,
866 unsigned int data_size,
867 blink::WebArrayBuffer* buffer) {
868 DCHECK_EQ(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, algorithm.id());
869
870 if (key.type() != blink::WebCryptoKeyTypePrivate)
871 return Status::ErrorUnexpectedKeyType();
872
873 if (webcrypto::GetInnerHashAlgorithm(algorithm).isNull())
874 return Status::ErrorUnexpected();
875
876 PrivateKeyHandle* const private_key =
877 reinterpret_cast<PrivateKeyHandle*>(key.handle());
878 DCHECK(private_key);
879 DCHECK(private_key->key());
880
881 // Pick the NSS signing algorithm by combining RSA-SSA (RSA PKCS1) and the
882 // inner hash of the input Web Crypto algorithm.
883 SECOidTag sign_alg_tag;
884 switch (webcrypto::GetInnerHashAlgorithm(algorithm).id()) {
885 case blink::WebCryptoAlgorithmIdSha1:
886 sign_alg_tag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
887 break;
888 case blink::WebCryptoAlgorithmIdSha224:
889 sign_alg_tag = SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION;
890 break;
891 case blink::WebCryptoAlgorithmIdSha256:
892 sign_alg_tag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION;
893 break;
894 case blink::WebCryptoAlgorithmIdSha384:
895 sign_alg_tag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION;
896 break;
897 case blink::WebCryptoAlgorithmIdSha512:
898 sign_alg_tag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION;
899 break;
900 default:
901 return Status::ErrorUnsupported();
902 }
903
904 crypto::ScopedSECItem signature_item(SECITEM_AllocItem(NULL, NULL, 0));
905 if (SEC_SignData(signature_item.get(),
906 data,
907 data_size,
908 private_key->key(),
909 sign_alg_tag) != SECSuccess) {
910 return Status::Error();
911 }
912
913 *buffer = webcrypto::CreateArrayBuffer(signature_item->data,
914 signature_item->len);
915 return Status::Success();
916 }
917
918 Status VerifyRsaSsaPkcs1v1_5(
919 const blink::WebCryptoAlgorithm& algorithm,
920 const blink::WebCryptoKey& key,
921 const unsigned char* signature,
922 unsigned int signature_size,
923 const unsigned char* data,
924 unsigned int data_size,
925 bool* signature_match) {
926 DCHECK_EQ(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, algorithm.id());
927
928 if (key.type() != blink::WebCryptoKeyTypePublic)
929 return Status::ErrorUnexpectedKeyType();
930
931 PublicKeyHandle* const public_key =
932 reinterpret_cast<PublicKeyHandle*>(key.handle());
933 DCHECK(public_key);
934 DCHECK(public_key->key());
935
936 const SECItem signature_item = {
937 siBuffer,
938 const_cast<unsigned char*>(signature),
939 signature_size
940 };
941
942 SECOidTag hash_alg_tag;
943 switch (webcrypto::GetInnerHashAlgorithm(algorithm).id()) {
944 case blink::WebCryptoAlgorithmIdSha1:
945 hash_alg_tag = SEC_OID_SHA1;
946 break;
947 case blink::WebCryptoAlgorithmIdSha224:
948 hash_alg_tag = SEC_OID_SHA224;
949 break;
950 case blink::WebCryptoAlgorithmIdSha256:
951 hash_alg_tag = SEC_OID_SHA256;
952 break;
953 case blink::WebCryptoAlgorithmIdSha384:
954 hash_alg_tag = SEC_OID_SHA384;
955 break;
956 case blink::WebCryptoAlgorithmIdSha512:
957 hash_alg_tag = SEC_OID_SHA512;
958 break;
959 default:
960 return Status::ErrorUnsupported();
961 }
962
963 *signature_match =
964 SECSuccess == VFY_VerifyDataDirect(data,
965 data_size,
966 public_key->key(),
967 &signature_item,
968 SEC_OID_PKCS1_RSA_ENCRYPTION,
969 hash_alg_tag,
970 NULL,
971 NULL);
972 return Status::Success();
973 }
974
975 // -----------------------------------
976 // Key generation
977 // -----------------------------------
978
979 Status GenerateRsaKeyPair(
980 const blink::WebCryptoAlgorithm& algorithm,
981 bool extractable,
982 blink::WebCryptoKeyUsageMask usage_mask,
983 blink::WebCryptoKey* public_key,
984 blink::WebCryptoKey* private_key) {
985 const blink::WebCryptoRsaKeyGenParams* const params =
986 algorithm.rsaKeyGenParams();
987 DCHECK(params);
988
989 crypto::ScopedPK11Slot slot(PK11_GetInternalKeySlot());
990 if (!slot)
991 return Status::Error();
992
993 unsigned long public_exponent;
994 if (!params->modulusLengthBits())
995 return Status::ErrorGenerateRsaZeroModulus();
996
997 if (!BigIntegerToLong(params->publicExponent().data(),
998 params->publicExponent().size(),
999 &public_exponent) || !public_exponent) {
1000 return Status::ErrorGenerateKeyPublicExponent();
1001 }
1002
1003 PK11RSAGenParams rsa_gen_params;
1004 rsa_gen_params.keySizeInBits = params->modulusLengthBits();
1005 rsa_gen_params.pe = public_exponent;
1006
1007 // Flags are verified at the Blink layer; here the flags are set to all
1008 // possible operations for the given key type.
1009 CK_FLAGS operation_flags;
1010 switch (algorithm.id()) {
1011 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5:
1012 case blink::WebCryptoAlgorithmIdRsaOaep:
1013 operation_flags = CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP;
1014 break;
1015 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5:
1016 operation_flags = CKF_SIGN | CKF_VERIFY;
1017 break;
1018 default:
1019 NOTREACHED();
1020 return Status::ErrorUnexpected();
1021 }
1022 const CK_FLAGS operation_flags_mask = CKF_ENCRYPT | CKF_DECRYPT |
1023 CKF_SIGN | CKF_VERIFY | CKF_WRAP |
1024 CKF_UNWRAP;
1025 const PK11AttrFlags attribute_flags = 0; // Default all PK11_ATTR_ flags.
1026
1027 // Note: NSS does not generate an sec_public_key if the call below fails,
1028 // so there is no danger of a leaked sec_public_key.
1029 SECKEYPublicKey* sec_public_key;
1030 crypto::ScopedSECKEYPrivateKey scoped_sec_private_key(
1031 PK11_GenerateKeyPairWithOpFlags(slot.get(),
1032 CKM_RSA_PKCS_KEY_PAIR_GEN,
1033 &rsa_gen_params,
1034 &sec_public_key,
1035 attribute_flags,
1036 operation_flags,
1037 operation_flags_mask,
1038 NULL));
1039 if (!private_key)
1040 return Status::Error();
1041
1042 *public_key = blink::WebCryptoKey::create(
1043 new PublicKeyHandle(crypto::ScopedSECKEYPublicKey(sec_public_key)),
1044 blink::WebCryptoKeyTypePublic,
1045 true,
1046 algorithm,
1047 usage_mask);
1048 *private_key = blink::WebCryptoKey::create(
1049 new PrivateKeyHandle(scoped_sec_private_key.Pass()),
1050 blink::WebCryptoKeyTypePrivate,
1051 extractable,
1052 algorithm,
1053 usage_mask);
1054
1055 return Status::Success();
1056 }
1057
1058 // Get the secret key length in bytes from generation parameters. This resolves
1059 // any defaults.
1060 Status GetGenerateSecretKeyLength(const blink::WebCryptoAlgorithm& algorithm,
1061 unsigned int* keylen_bytes) {
1062 *keylen_bytes = 0;
1063
1064 switch (algorithm.id()) {
1065 case blink::WebCryptoAlgorithmIdAesCbc:
1066 case blink::WebCryptoAlgorithmIdAesGcm:
1067 case blink::WebCryptoAlgorithmIdAesKw: {
1068 const blink::WebCryptoAesKeyGenParams* params =
1069 algorithm.aesKeyGenParams();
1070 DCHECK(params);
1071 // Ensure the key length is a multiple of 8 bits. Let NSS verify further
1072 // algorithm-specific length restrictions.
1073 if (params->lengthBits() % 8)
1074 return Status::ErrorGenerateKeyLength();
1075 *keylen_bytes = params->lengthBits() / 8;
1076 break;
1077 }
1078 case blink::WebCryptoAlgorithmIdHmac: {
1079 const blink::WebCryptoHmacKeyParams* params = algorithm.hmacKeyParams();
1080 DCHECK(params);
1081 if (params->hasLengthBytes())
1082 *keylen_bytes = params->optionalLengthBytes();
1083 else
1084 *keylen_bytes = webcrypto::ShaBlockSizeBytes(params->hash().id());
1085 break;
1086 }
1087
1088 default:
1089 return Status::ErrorUnsupported();
1090 }
1091
1092 if (*keylen_bytes == 0)
1093 return Status::ErrorGenerateKeyLength();
1094
1095 return Status::Success();
1096 }
1097
1098 } // namespace
1099
1100 void WebCryptoImpl::Init() {
1101 crypto::EnsureNSSInit();
1102 }
1103
1104 Status WebCryptoImpl::EncryptInternal(
1105 const blink::WebCryptoAlgorithm& algorithm,
1106 const blink::WebCryptoKey& key,
1107 const unsigned char* data,
1108 unsigned int data_size,
1109 blink::WebArrayBuffer* buffer) {
1110
1111 DCHECK_EQ(algorithm.id(), key.algorithm().id());
1112 DCHECK(key.handle());
1113 DCHECK(buffer);
1114
1115 switch (algorithm.id()) {
1116 case blink::WebCryptoAlgorithmIdAesCbc:
1117 return AesCbcEncryptDecrypt(
1118 CKA_ENCRYPT, algorithm, key, data, data_size, buffer);
1119 case blink::WebCryptoAlgorithmIdAesGcm:
1120 return AesGcmEncryptDecrypt(
1121 true, algorithm, key, data, data_size, buffer);
1122 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5:
1123 return EncryptRsaEsPkcs1v1_5(algorithm, key, data, data_size, buffer);
1124 default:
1125 return Status::ErrorUnsupported();
1126 }
1127 }
1128
1129 Status WebCryptoImpl::DecryptInternal(
1130 const blink::WebCryptoAlgorithm& algorithm,
1131 const blink::WebCryptoKey& key,
1132 const unsigned char* data,
1133 unsigned int data_size,
1134 blink::WebArrayBuffer* buffer) {
1135
1136 DCHECK_EQ(algorithm.id(), key.algorithm().id());
1137 DCHECK(key.handle());
1138 DCHECK(buffer);
1139
1140 switch (algorithm.id()) {
1141 case blink::WebCryptoAlgorithmIdAesCbc:
1142 return AesCbcEncryptDecrypt(
1143 CKA_DECRYPT, algorithm, key, data, data_size, buffer);
1144 case blink::WebCryptoAlgorithmIdAesGcm:
1145 return AesGcmEncryptDecrypt(
1146 false, algorithm, key, data, data_size, buffer);
1147 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5:
1148 return DecryptRsaEsPkcs1v1_5(algorithm, key, data, data_size, buffer);
1149 default:
1150 return Status::ErrorUnsupported();
1151 }
1152 }
1153
1154 Status WebCryptoImpl::DigestInternal(
1155 const blink::WebCryptoAlgorithm& algorithm,
1156 const unsigned char* data,
1157 unsigned int data_size,
1158 blink::WebArrayBuffer* buffer) {
1159 HASH_HashType hash_type = WebCryptoAlgorithmToNSSHashType(algorithm);
1160 if (hash_type == HASH_AlgNULL)
1161 return Status::ErrorUnsupported();
1162
1163 HASHContext* context = HASH_Create(hash_type);
1164 if (!context)
1165 return Status::Error();
1166
1167 HASH_Begin(context);
1168
1169 HASH_Update(context, data, data_size);
1170
1171 unsigned int hash_result_length = HASH_ResultLenContext(context);
1172 DCHECK_LE(hash_result_length, static_cast<size_t>(HASH_LENGTH_MAX));
1173
1174 *buffer = blink::WebArrayBuffer::create(hash_result_length, 1);
1175
1176 unsigned char* digest = reinterpret_cast<unsigned char*>(buffer->data());
1177
1178 unsigned int result_length = 0;
1179 HASH_End(context, digest, &result_length, hash_result_length);
1180
1181 HASH_Destroy(context);
1182
1183 if (result_length != hash_result_length)
1184 return Status::ErrorUnexpected();
1185 return Status::Success();
1186 }
1187
1188 Status WebCryptoImpl::GenerateSecretKeyInternal(
1189 const blink::WebCryptoAlgorithm& algorithm,
1190 bool extractable,
1191 blink::WebCryptoKeyUsageMask usage_mask,
1192 blink::WebCryptoKey* key) {
1193
1194 CK_MECHANISM_TYPE mech = WebCryptoAlgorithmToGenMechanism(algorithm);
1195 blink::WebCryptoKeyType key_type = blink::WebCryptoKeyTypeSecret;
1196
1197 if (mech == CKM_INVALID_MECHANISM)
1198 return Status::ErrorUnsupported();
1199
1200 unsigned int keylen_bytes = 0;
1201 Status status = GetGenerateSecretKeyLength(algorithm, &keylen_bytes);
1202 if (status.IsError())
1203 return status;
1204
1205 crypto::ScopedPK11Slot slot(PK11_GetInternalKeySlot());
1206 if (!slot)
1207 return Status::Error();
1208
1209 crypto::ScopedPK11SymKey pk11_key(
1210 PK11_KeyGen(slot.get(), mech, NULL, keylen_bytes, NULL));
1211
1212 if (!pk11_key)
1213 return Status::Error();
1214
1215 *key = blink::WebCryptoKey::create(
1216 new SymKeyHandle(pk11_key.Pass()),
1217 key_type, extractable, algorithm, usage_mask);
1218 return Status::Success();
1219 }
1220
1221 Status WebCryptoImpl::GenerateKeyPairInternal(
1222 const blink::WebCryptoAlgorithm& algorithm,
1223 bool extractable,
1224 blink::WebCryptoKeyUsageMask usage_mask,
1225 blink::WebCryptoKey* public_key,
1226 blink::WebCryptoKey* private_key) {
1227
1228 // TODO(padolph): Handle other asymmetric algorithm key generation.
1229 switch (algorithm.id()) {
1230 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5:
1231 case blink::WebCryptoAlgorithmIdRsaOaep:
1232 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5:
1233 return GenerateRsaKeyPair(algorithm, extractable, usage_mask,
1234 public_key, private_key);
1235 default:
1236 return Status::ErrorUnsupported();
1237 }
1238 }
1239
1240 Status WebCryptoImpl::ImportKeyInternal(
1241 blink::WebCryptoKeyFormat format,
1242 const unsigned char* key_data,
1243 unsigned int key_data_size,
1244 const blink::WebCryptoAlgorithm& algorithm_or_null,
1245 bool extractable,
1246 blink::WebCryptoKeyUsageMask usage_mask,
1247 blink::WebCryptoKey* key) {
1248
1249 switch (format) {
1250 case blink::WebCryptoKeyFormatRaw:
1251 // A 'raw'-formatted key import requires an input algorithm.
1252 if (algorithm_or_null.isNull())
1253 return Status::ErrorMissingAlgorithmImportRawKey();
1254 return ImportKeyInternalRaw(key_data,
1255 key_data_size,
1256 algorithm_or_null,
1257 extractable,
1258 usage_mask,
1259 key);
1260 case blink::WebCryptoKeyFormatSpki:
1261 return ImportKeyInternalSpki(key_data,
1262 key_data_size,
1263 algorithm_or_null,
1264 extractable,
1265 usage_mask,
1266 key);
1267 case blink::WebCryptoKeyFormatPkcs8:
1268 return ImportKeyInternalPkcs8(key_data,
1269 key_data_size,
1270 algorithm_or_null,
1271 extractable,
1272 usage_mask,
1273 key);
1274 default:
1275 // NOTE: blink::WebCryptoKeyFormatJwk is handled one level above.
1276 return Status::ErrorUnsupported();
1277 }
1278 }
1279
1280 Status WebCryptoImpl::ExportKeyInternal(
1281 blink::WebCryptoKeyFormat format,
1282 const blink::WebCryptoKey& key,
1283 blink::WebArrayBuffer* buffer) {
1284 switch (format) {
1285 case blink::WebCryptoKeyFormatRaw:
1286 return ExportKeyInternalRaw(key, buffer);
1287 case blink::WebCryptoKeyFormatSpki:
1288 return ExportKeyInternalSpki(key, buffer);
1289 case blink::WebCryptoKeyFormatPkcs8:
1290 // TODO(padolph): Implement pkcs8 export
1291 return Status::ErrorUnsupported();
1292 default:
1293 return Status::ErrorUnsupported();
1294 }
1295 }
1296
1297 Status WebCryptoImpl::SignInternal(
1298 const blink::WebCryptoAlgorithm& algorithm,
1299 const blink::WebCryptoKey& key,
1300 const unsigned char* data,
1301 unsigned int data_size,
1302 blink::WebArrayBuffer* buffer) {
1303
1304 // Note: It is not an error to sign empty data.
1305
1306 DCHECK(buffer);
1307 DCHECK_NE(0, key.usages() & blink::WebCryptoKeyUsageSign);
1308
1309 switch (algorithm.id()) {
1310 case blink::WebCryptoAlgorithmIdHmac:
1311 return SignHmac(algorithm, key, data, data_size, buffer);
1312 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5:
1313 return SignRsaSsaPkcs1v1_5(algorithm, key, data, data_size, buffer);
1314 default:
1315 return Status::ErrorUnsupported();
1316 }
1317 }
1318
1319 Status WebCryptoImpl::VerifySignatureInternal(
1320 const blink::WebCryptoAlgorithm& algorithm,
1321 const blink::WebCryptoKey& key,
1322 const unsigned char* signature,
1323 unsigned int signature_size,
1324 const unsigned char* data,
1325 unsigned int data_size,
1326 bool* signature_match) {
1327
1328 if (!signature_size) {
1329 // None of the algorithms generate valid zero-length signatures so this
1330 // will necessarily fail verification. Early return to protect
1331 // implementations from dealing with a NULL signature pointer.
1332 *signature_match = false;
1333 return Status::Success();
1334 }
1335
1336 DCHECK(signature);
1337
1338 switch (algorithm.id()) {
1339 case blink::WebCryptoAlgorithmIdHmac:
1340 return VerifyHmac(algorithm, key, signature, signature_size,
1341 data, data_size, signature_match);
1342 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5:
1343 return VerifyRsaSsaPkcs1v1_5(algorithm, key, signature, signature_size,
1344 data, data_size, signature_match);
1345 default:
1346 return Status::ErrorUnsupported();
1347 }
1348 }
1349
1350 Status WebCryptoImpl::ImportRsaPublicKeyInternal(
1351 const unsigned char* modulus_data,
1352 unsigned int modulus_size,
1353 const unsigned char* exponent_data,
1354 unsigned int exponent_size,
1355 const blink::WebCryptoAlgorithm& algorithm,
1356 bool extractable,
1357 blink::WebCryptoKeyUsageMask usage_mask,
1358 blink::WebCryptoKey* key) {
1359
1360 if (!modulus_size)
1361 return Status::ErrorImportRsaEmptyModulus();
1362
1363 if (!exponent_size)
1364 return Status::ErrorImportRsaEmptyExponent();
1365
1366 DCHECK(modulus_data);
1367 DCHECK(exponent_data);
1368
1369 // NSS does not provide a way to create an RSA public key directly from the
1370 // modulus and exponent values, but it can import an DER-encoded ASN.1 blob
1371 // with these values and create the public key from that. The code below
1372 // follows the recommendation described in
1373 // https://developer.mozilla.org/en-US/docs/NSS/NSS_Tech_Notes/nss_tech_note7
1374
1375 // Pack the input values into a struct compatible with NSS ASN.1 encoding, and
1376 // set up an ASN.1 encoder template for it.
1377 struct RsaPublicKeyData {
1378 SECItem modulus;
1379 SECItem exponent;
1380 };
1381 const RsaPublicKeyData pubkey_in = {
1382 {siUnsignedInteger, const_cast<unsigned char*>(modulus_data),
1383 modulus_size},
1384 {siUnsignedInteger, const_cast<unsigned char*>(exponent_data),
1385 exponent_size}};
1386 const SEC_ASN1Template rsa_public_key_template[] = {
1387 {SEC_ASN1_SEQUENCE, 0, NULL, sizeof(RsaPublicKeyData)},
1388 {SEC_ASN1_INTEGER, offsetof(RsaPublicKeyData, modulus), },
1389 {SEC_ASN1_INTEGER, offsetof(RsaPublicKeyData, exponent), },
1390 {0, }};
1391
1392 // DER-encode the public key.
1393 crypto::ScopedSECItem pubkey_der(SEC_ASN1EncodeItem(
1394 NULL, NULL, &pubkey_in, rsa_public_key_template));
1395 if (!pubkey_der)
1396 return Status::Error();
1397
1398 // Import the DER-encoded public key to create an RSA SECKEYPublicKey.
1399 crypto::ScopedSECKEYPublicKey pubkey(
1400 SECKEY_ImportDERPublicKey(pubkey_der.get(), CKK_RSA));
1401 if (!pubkey)
1402 return Status::Error();
1403
1404 *key = blink::WebCryptoKey::create(new PublicKeyHandle(pubkey.Pass()),
1405 blink::WebCryptoKeyTypePublic,
1406 extractable,
1407 algorithm,
1408 usage_mask);
1409 return Status::Success();
1410 }
1411
1412 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/webcrypto/webcrypto_impl.cc ('k') | content/renderer/webcrypto/webcrypto_impl_openssl.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698