Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / content / renderer / webcrypto / webcrypto_impl_nss.cc
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