75a73d8b3d06d086e9dc3726f2598e6a1aa4af2c
[platform/framework/web/crosswalk.git] / src / content / child / webcrypto / platform_crypto_nss.cc
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/child/webcrypto/platform_crypto.h"
6
7 #include <cryptohi.h>
8 #include <pk11pub.h>
9 #include <secerr.h>
10 #include <sechash.h>
11
12 #include <vector>
13
14 #include "base/lazy_instance.h"
15 #include "base/logging.h"
16 #include "content/child/webcrypto/crypto_data.h"
17 #include "content/child/webcrypto/status.h"
18 #include "content/child/webcrypto/webcrypto_util.h"
19 #include "crypto/nss_util.h"
20 #include "crypto/scoped_nss_types.h"
21 #include "third_party/WebKit/public/platform/WebArrayBuffer.h"
22 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
23 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
24 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
25
26 #if defined(USE_NSS)
27 #include <dlfcn.h>
28 #include <secoid.h>
29 #endif
30
31 // At the time of this writing:
32 //   * Windows and Mac builds ship with their own copy of NSS (3.15+)
33 //   * Linux builds use the system's libnss, which is 3.14 on Debian (but 3.15+
34 //     on other distros).
35 //
36 // Since NSS provides AES-GCM support starting in version 3.15, it may be
37 // unavailable for Linux Chrome users.
38 //
39 //  * !defined(CKM_AES_GCM)
40 //
41 //      This means that at build time, the NSS header pkcs11t.h is older than
42 //      3.15. However at runtime support may be present.
43 //
44 //  * !defined(USE_NSS)
45 //
46 //      This means that Chrome is being built with an embedded copy of NSS,
47 //      which can be assumed to be >= 3.15. On the other hand if USE_NSS is
48 //      defined, it also implies running on Linux.
49 //
50 // TODO(eroman): Simplify this once 3.15+ is required by Linux builds.
51 #if !defined(CKM_AES_GCM)
52 #define CKM_AES_GCM 0x00001087
53
54 struct CK_GCM_PARAMS {
55   CK_BYTE_PTR pIv;
56   CK_ULONG ulIvLen;
57   CK_BYTE_PTR pAAD;
58   CK_ULONG ulAADLen;
59   CK_ULONG ulTagBits;
60 };
61 #endif  // !defined(CKM_AES_GCM)
62
63 // Signature for PK11_Encrypt and PK11_Decrypt.
64 typedef SECStatus (*PK11_EncryptDecryptFunction)(PK11SymKey*,
65                                                  CK_MECHANISM_TYPE,
66                                                  SECItem*,
67                                                  unsigned char*,
68                                                  unsigned int*,
69                                                  unsigned int,
70                                                  const unsigned char*,
71                                                  unsigned int);
72
73 // Singleton to abstract away dynamically loading libnss3.so
74 class AesGcmSupport {
75  public:
76   bool IsSupported() const { return pk11_encrypt_func_ && pk11_decrypt_func_; }
77
78   // Returns NULL if unsupported.
79   PK11_EncryptDecryptFunction pk11_encrypt_func() const {
80     return pk11_encrypt_func_;
81   }
82
83   // Returns NULL if unsupported.
84   PK11_EncryptDecryptFunction pk11_decrypt_func() const {
85     return pk11_decrypt_func_;
86   }
87
88  private:
89   friend struct base::DefaultLazyInstanceTraits<AesGcmSupport>;
90
91   AesGcmSupport() {
92 #if !defined(USE_NSS)
93     // Using a bundled version of NSS that is guaranteed to have this symbol.
94     pk11_encrypt_func_ = PK11_Encrypt;
95     pk11_decrypt_func_ = PK11_Decrypt;
96 #else
97     // Using system NSS libraries and PCKS #11 modules, which may not have the
98     // necessary function (PK11_Encrypt) or mechanism support (CKM_AES_GCM).
99
100     // If PK11_Encrypt() was successfully resolved, then NSS will support
101     // AES-GCM directly. This was introduced in NSS 3.15.
102     pk11_encrypt_func_ = reinterpret_cast<PK11_EncryptDecryptFunction>(
103         dlsym(RTLD_DEFAULT, "PK11_Encrypt"));
104     pk11_decrypt_func_ = reinterpret_cast<PK11_EncryptDecryptFunction>(
105         dlsym(RTLD_DEFAULT, "PK11_Decrypt"));
106 #endif
107   }
108
109   PK11_EncryptDecryptFunction pk11_encrypt_func_;
110   PK11_EncryptDecryptFunction pk11_decrypt_func_;
111 };
112
113 base::LazyInstance<AesGcmSupport>::Leaky g_aes_gcm_support =
114     LAZY_INSTANCE_INITIALIZER;
115
116 namespace content {
117
118 namespace webcrypto {
119
120 namespace platform {
121
122 class SymKey : public Key {
123  public:
124   explicit SymKey(crypto::ScopedPK11SymKey key) : key_(key.Pass()) {}
125
126   PK11SymKey* key() { return key_.get(); }
127
128   virtual SymKey* AsSymKey() OVERRIDE { return this; }
129   virtual PublicKey* AsPublicKey() OVERRIDE { return NULL; }
130   virtual PrivateKey* AsPrivateKey() OVERRIDE { return NULL; }
131
132  private:
133   crypto::ScopedPK11SymKey key_;
134
135   DISALLOW_COPY_AND_ASSIGN(SymKey);
136 };
137
138 class PublicKey : public Key {
139  public:
140   explicit PublicKey(crypto::ScopedSECKEYPublicKey key) : key_(key.Pass()) {}
141
142   SECKEYPublicKey* key() { return key_.get(); }
143
144   virtual SymKey* AsSymKey() OVERRIDE { return NULL; }
145   virtual PublicKey* AsPublicKey() OVERRIDE { return this; }
146   virtual PrivateKey* AsPrivateKey() OVERRIDE { return NULL; }
147
148  private:
149   crypto::ScopedSECKEYPublicKey key_;
150
151   DISALLOW_COPY_AND_ASSIGN(PublicKey);
152 };
153
154 class PrivateKey : public Key {
155  public:
156   explicit PrivateKey(crypto::ScopedSECKEYPrivateKey key) : key_(key.Pass()) {}
157
158   SECKEYPrivateKey* key() { return key_.get(); }
159
160   virtual SymKey* AsSymKey() OVERRIDE { return NULL; }
161   virtual PublicKey* AsPublicKey() OVERRIDE { return NULL; }
162   virtual PrivateKey* AsPrivateKey() OVERRIDE { return this; }
163
164  private:
165   crypto::ScopedSECKEYPrivateKey key_;
166
167   DISALLOW_COPY_AND_ASSIGN(PrivateKey);
168 };
169
170 namespace {
171
172 // Creates a SECItem for the data in |buffer|. This does NOT make a copy, so
173 // |buffer| should outlive the SECItem.
174 SECItem MakeSECItemForBuffer(const CryptoData& buffer) {
175   SECItem item = {
176       siBuffer,
177       // NSS requires non-const data even though it is just for input.
178       const_cast<unsigned char*>(buffer.bytes()), buffer.byte_length()};
179   return item;
180 }
181
182 HASH_HashType WebCryptoAlgorithmToNSSHashType(
183     blink::WebCryptoAlgorithmId algorithm) {
184   switch (algorithm) {
185     case blink::WebCryptoAlgorithmIdSha1:
186       return HASH_AlgSHA1;
187     case blink::WebCryptoAlgorithmIdSha256:
188       return HASH_AlgSHA256;
189     case blink::WebCryptoAlgorithmIdSha384:
190       return HASH_AlgSHA384;
191     case blink::WebCryptoAlgorithmIdSha512:
192       return HASH_AlgSHA512;
193     default:
194       // Not a digest algorithm.
195       return HASH_AlgNULL;
196   }
197 }
198
199 CK_MECHANISM_TYPE WebCryptoHashToHMACMechanism(
200     const blink::WebCryptoAlgorithm& algorithm) {
201   switch (algorithm.id()) {
202     case blink::WebCryptoAlgorithmIdSha1:
203       return CKM_SHA_1_HMAC;
204     case blink::WebCryptoAlgorithmIdSha256:
205       return CKM_SHA256_HMAC;
206     case blink::WebCryptoAlgorithmIdSha384:
207       return CKM_SHA384_HMAC;
208     case blink::WebCryptoAlgorithmIdSha512:
209       return CKM_SHA512_HMAC;
210     default:
211       // Not a supported algorithm.
212       return CKM_INVALID_MECHANISM;
213   }
214 }
215
216 Status AesCbcEncryptDecrypt(EncryptOrDecrypt mode,
217                             SymKey* key,
218                             const CryptoData& iv,
219                             const CryptoData& data,
220                             blink::WebArrayBuffer* buffer) {
221   CK_ATTRIBUTE_TYPE operation = (mode == ENCRYPT) ? CKA_ENCRYPT : CKA_DECRYPT;
222
223   SECItem iv_item = MakeSECItemForBuffer(iv);
224
225   crypto::ScopedSECItem param(PK11_ParamFromIV(CKM_AES_CBC_PAD, &iv_item));
226   if (!param)
227     return Status::Error();
228
229   crypto::ScopedPK11Context context(PK11_CreateContextBySymKey(
230       CKM_AES_CBC_PAD, operation, key->key(), param.get()));
231
232   if (!context.get())
233     return Status::Error();
234
235   // Oddly PK11_CipherOp takes input and output lengths as "int" rather than
236   // "unsigned int". Do some checks now to avoid integer overflowing.
237   if (data.byte_length() >= INT_MAX - AES_BLOCK_SIZE) {
238     // TODO(eroman): Handle this by chunking the input fed into NSS. Right now
239     // it doesn't make much difference since the one-shot API would end up
240     // blowing out the memory and crashing anyway.
241     return Status::ErrorDataTooLarge();
242   }
243
244   // PK11_CipherOp does an invalid memory access when given empty decryption
245   // input, or input which is not a multiple of the block size. See also
246   // https://bugzilla.mozilla.com/show_bug.cgi?id=921687.
247   if (operation == CKA_DECRYPT &&
248       (data.byte_length() == 0 || (data.byte_length() % AES_BLOCK_SIZE != 0))) {
249     return Status::Error();
250   }
251
252   // TODO(eroman): Refine the output buffer size. It can be computed exactly for
253   //               encryption, and can be smaller for decryption.
254   unsigned int output_max_len = data.byte_length() + AES_BLOCK_SIZE;
255   CHECK_GT(output_max_len, data.byte_length());
256
257   *buffer = blink::WebArrayBuffer::create(output_max_len, 1);
258
259   unsigned char* buffer_data = reinterpret_cast<unsigned char*>(buffer->data());
260
261   int output_len;
262   if (SECSuccess != PK11_CipherOp(context.get(),
263                                   buffer_data,
264                                   &output_len,
265                                   buffer->byteLength(),
266                                   data.bytes(),
267                                   data.byte_length())) {
268     return Status::Error();
269   }
270
271   unsigned int final_output_chunk_len;
272   if (SECSuccess != PK11_DigestFinal(context.get(),
273                                      buffer_data + output_len,
274                                      &final_output_chunk_len,
275                                      output_max_len - output_len)) {
276     return Status::Error();
277   }
278
279   ShrinkBuffer(buffer, final_output_chunk_len + output_len);
280   return Status::Success();
281 }
282
283 // Helper to either encrypt or decrypt for AES-GCM. The result of encryption is
284 // the concatenation of the ciphertext and the authentication tag. Similarly,
285 // this is the expectation for the input to decryption.
286 Status AesGcmEncryptDecrypt(EncryptOrDecrypt mode,
287                             SymKey* key,
288                             const CryptoData& data,
289                             const CryptoData& iv,
290                             const CryptoData& additional_data,
291                             unsigned int tag_length_bits,
292                             blink::WebArrayBuffer* buffer) {
293   if (!g_aes_gcm_support.Get().IsSupported())
294     return Status::ErrorUnsupported();
295
296   unsigned int tag_length_bytes = tag_length_bits / 8;
297
298   CK_GCM_PARAMS gcm_params = {0};
299   gcm_params.pIv = const_cast<unsigned char*>(iv.bytes());
300   gcm_params.ulIvLen = iv.byte_length();
301
302   gcm_params.pAAD = const_cast<unsigned char*>(additional_data.bytes());
303   gcm_params.ulAADLen = additional_data.byte_length();
304
305   gcm_params.ulTagBits = tag_length_bits;
306
307   SECItem param;
308   param.type = siBuffer;
309   param.data = reinterpret_cast<unsigned char*>(&gcm_params);
310   param.len = sizeof(gcm_params);
311
312   unsigned int buffer_size = 0;
313
314   // Calculate the output buffer size.
315   if (mode == ENCRYPT) {
316     // TODO(eroman): This is ugly, abstract away the safe integer arithmetic.
317     if (data.byte_length() > (UINT_MAX - tag_length_bytes))
318       return Status::ErrorDataTooLarge();
319     buffer_size = data.byte_length() + tag_length_bytes;
320   } else {
321     // TODO(eroman): In theory the buffer allocated for the plain text should be
322     // sized as |data.byte_length() - tag_length_bytes|.
323     //
324     // However NSS has a bug whereby it will fail if the output buffer size is
325     // not at least as large as the ciphertext:
326     //
327     // https://bugzilla.mozilla.org/show_bug.cgi?id=%20853674
328     //
329     // From the analysis of that bug it looks like it might be safe to pass a
330     // correctly sized buffer but lie about its size. Since resizing the
331     // WebCryptoArrayBuffer is expensive that hack may be worth looking into.
332     buffer_size = data.byte_length();
333   }
334
335   *buffer = blink::WebArrayBuffer::create(buffer_size, 1);
336   unsigned char* buffer_data = reinterpret_cast<unsigned char*>(buffer->data());
337
338   PK11_EncryptDecryptFunction func =
339       (mode == ENCRYPT) ? g_aes_gcm_support.Get().pk11_encrypt_func()
340                         : g_aes_gcm_support.Get().pk11_decrypt_func();
341
342   unsigned int output_len = 0;
343   SECStatus result = func(key->key(),
344                           CKM_AES_GCM,
345                           &param,
346                           buffer_data,
347                           &output_len,
348                           buffer->byteLength(),
349                           data.bytes(),
350                           data.byte_length());
351
352   if (result != SECSuccess)
353     return Status::Error();
354
355   // Unfortunately the buffer needs to be shrunk for decryption (see the NSS bug
356   // above).
357   ShrinkBuffer(buffer, output_len);
358
359   return Status::Success();
360 }
361
362 CK_MECHANISM_TYPE WebCryptoAlgorithmToGenMechanism(
363     const blink::WebCryptoAlgorithm& algorithm) {
364   switch (algorithm.id()) {
365     case blink::WebCryptoAlgorithmIdAesCbc:
366     case blink::WebCryptoAlgorithmIdAesGcm:
367     case blink::WebCryptoAlgorithmIdAesKw:
368       return CKM_AES_KEY_GEN;
369     case blink::WebCryptoAlgorithmIdHmac:
370       return WebCryptoHashToHMACMechanism(algorithm.hmacKeyGenParams()->hash());
371     default:
372       return CKM_INVALID_MECHANISM;
373   }
374 }
375
376 // Converts a (big-endian) WebCrypto BigInteger, with or without leading zeros,
377 // to unsigned long.
378 bool BigIntegerToLong(const uint8* data,
379                       unsigned int data_size,
380                       unsigned long* result) {
381   // TODO(padolph): Is it correct to say that empty data is an error, or does it
382   // mean value 0? See https://www.w3.org/Bugs/Public/show_bug.cgi?id=23655
383   if (data_size == 0)
384     return false;
385
386   *result = 0;
387   for (size_t i = 0; i < data_size; ++i) {
388     size_t reverse_i = data_size - i - 1;
389
390     if (reverse_i >= sizeof(unsigned long) && data[i])
391       return false;  // Too large for a long.
392
393     *result |= data[i] << 8 * reverse_i;
394   }
395   return true;
396 }
397
398 bool IsAlgorithmRsa(const blink::WebCryptoAlgorithm& algorithm) {
399   return algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 ||
400          algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep ||
401          algorithm.id() == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5;
402 }
403
404 bool CreatePublicKeyAlgorithm(const blink::WebCryptoAlgorithm& algorithm,
405                               SECKEYPublicKey* key,
406                               blink::WebCryptoKeyAlgorithm* key_algorithm) {
407   // TODO(eroman): What about other key types rsaPss, rsaOaep.
408   if (!key || key->keyType != rsaKey)
409     return false;
410
411   unsigned int modulus_length_bits = SECKEY_PublicKeyStrength(key) * 8;
412   CryptoData public_exponent(key->u.rsa.publicExponent.data,
413                              key->u.rsa.publicExponent.len);
414
415   switch (algorithm.paramsType()) {
416     case blink::WebCryptoAlgorithmParamsTypeRsaHashedImportParams:
417     case blink::WebCryptoAlgorithmParamsTypeRsaHashedKeyGenParams:
418       *key_algorithm = blink::WebCryptoKeyAlgorithm::createRsaHashed(
419           algorithm.id(),
420           modulus_length_bits,
421           public_exponent.bytes(),
422           public_exponent.byte_length(),
423           GetInnerHashAlgorithm(algorithm).id());
424       return true;
425     case blink::WebCryptoAlgorithmParamsTypeRsaKeyGenParams:
426     case blink::WebCryptoAlgorithmParamsTypeNone:
427       *key_algorithm = blink::WebCryptoKeyAlgorithm::createRsa(
428           algorithm.id(),
429           modulus_length_bits,
430           public_exponent.bytes(),
431           public_exponent.byte_length());
432       return true;
433     default:
434       return false;
435   }
436 }
437
438 bool CreatePrivateKeyAlgorithm(const blink::WebCryptoAlgorithm& algorithm,
439                                SECKEYPrivateKey* key,
440                                blink::WebCryptoKeyAlgorithm* key_algorithm) {
441   crypto::ScopedSECKEYPublicKey public_key(SECKEY_ConvertToPublicKey(key));
442   return CreatePublicKeyAlgorithm(algorithm, public_key.get(), key_algorithm);
443 }
444
445 // The Default IV for AES-KW. See http://www.ietf.org/rfc/rfc3394.txt
446 // Section 2.2.3.1.
447 // TODO(padolph): Move to common place to be shared with OpenSSL implementation.
448 const unsigned char kAesIv[] = {0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6};
449
450 // Sets NSS CK_MECHANISM_TYPE and CK_FLAGS corresponding to the input Web Crypto
451 // algorithm ID.
452 Status WebCryptoAlgorithmToNssMechFlags(
453     const blink::WebCryptoAlgorithm& algorithm,
454     CK_MECHANISM_TYPE* mechanism,
455     CK_FLAGS* flags) {
456   // Flags are verified at the Blink layer; here the flags are set to all
457   // possible operations of a key for the input algorithm type.
458   switch (algorithm.id()) {
459     case blink::WebCryptoAlgorithmIdHmac: {
460       const blink::WebCryptoAlgorithm hash = GetInnerHashAlgorithm(algorithm);
461       *mechanism = WebCryptoHashToHMACMechanism(hash);
462       if (*mechanism == CKM_INVALID_MECHANISM)
463         return Status::ErrorUnsupported();
464       *flags = CKF_SIGN | CKF_VERIFY;
465       break;
466     }
467     case blink::WebCryptoAlgorithmIdAesCbc: {
468       *mechanism = CKM_AES_CBC;
469       *flags = CKF_ENCRYPT | CKF_DECRYPT;
470       break;
471     }
472     case blink::WebCryptoAlgorithmIdAesKw: {
473       *mechanism = CKM_NSS_AES_KEY_WRAP;
474       *flags = CKF_WRAP | CKF_WRAP;
475       break;
476     }
477     case blink::WebCryptoAlgorithmIdAesGcm: {
478       if (!g_aes_gcm_support.Get().IsSupported())
479         return Status::ErrorUnsupported();
480       *mechanism = CKM_AES_GCM;
481       *flags = CKF_ENCRYPT | CKF_DECRYPT;
482       break;
483     }
484     default:
485       return Status::ErrorUnsupported();
486   }
487   return Status::Success();
488 }
489
490 Status DoUnwrapSymKeyAesKw(const CryptoData& wrapped_key_data,
491                            SymKey* wrapping_key,
492                            CK_MECHANISM_TYPE mechanism,
493                            CK_FLAGS flags,
494                            crypto::ScopedPK11SymKey* unwrapped_key) {
495   DCHECK_GE(wrapped_key_data.byte_length(), 24u);
496   DCHECK_EQ(wrapped_key_data.byte_length() % 8, 0u);
497
498   SECItem iv_item = MakeSECItemForBuffer(CryptoData(kAesIv, sizeof(kAesIv)));
499   crypto::ScopedSECItem param_item(
500       PK11_ParamFromIV(CKM_NSS_AES_KEY_WRAP, &iv_item));
501   if (!param_item)
502     return Status::ErrorUnexpected();
503
504   SECItem cipher_text = MakeSECItemForBuffer(wrapped_key_data);
505
506   // The plaintext length is always 64 bits less than the data size.
507   const unsigned int plaintext_length = wrapped_key_data.byte_length() - 8;
508
509 #if defined(USE_NSS)
510   // Part of workaround for
511   // https://bugzilla.mozilla.org/show_bug.cgi?id=981170. See the explanation
512   // later in this function.
513   PORT_SetError(0);
514 #endif
515
516   crypto::ScopedPK11SymKey new_key(PK11_UnwrapSymKey(wrapping_key->key(),
517                                                      CKM_NSS_AES_KEY_WRAP,
518                                                      param_item.get(),
519                                                      &cipher_text,
520                                                      mechanism,
521                                                      flags,
522                                                      plaintext_length));
523   // TODO(padolph): Use NSS PORT_GetError() and friends to report a more
524   // accurate error, providing if doesn't leak any information to web pages
525   // about other web crypto users, key details, etc.
526   if (!new_key)
527     return Status::Error();
528
529 #if defined(USE_NSS)
530   // Workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=981170
531   // which was fixed in NSS 3.16.0.
532   // If unwrap fails, NSS nevertheless returns a valid-looking PK11SymKey,
533   // with a reasonable length but with key data pointing to uninitialized
534   // memory.
535   // To understand this workaround see the fix for 981170:
536   // https://hg.mozilla.org/projects/nss/rev/753bb69e543c
537   if (!NSS_VersionCheck("3.16") && PORT_GetError() == SEC_ERROR_BAD_DATA)
538     return Status::Error();
539 #endif
540
541   *unwrapped_key = new_key.Pass();
542   return Status::Success();
543 }
544
545 void CopySECItemToVector(const SECItem& item, std::vector<uint8>* out) {
546   out->assign(item.data, item.data + item.len);
547 }
548
549 // The system NSS library doesn't have the new PK11_ExportDERPrivateKeyInfo
550 // function yet (https://bugzilla.mozilla.org/show_bug.cgi?id=519255). So we
551 // provide a fallback implementation.
552 #if defined(USE_NSS)
553 // From PKCS#1 [http://tools.ietf.org/html/rfc3447]:
554 //
555 //    RSAPrivateKey ::= SEQUENCE {
556 //      version           Version,
557 //      modulus           INTEGER,  -- n
558 //      publicExponent    INTEGER,  -- e
559 //      privateExponent   INTEGER,  -- d
560 //      prime1            INTEGER,  -- p
561 //      prime2            INTEGER,  -- q
562 //      exponent1         INTEGER,  -- d mod (p-1)
563 //      exponent2         INTEGER,  -- d mod (q-1)
564 //      coefficient       INTEGER,  -- (inverse of q) mod p
565 //      otherPrimeInfos   OtherPrimeInfos OPTIONAL
566 //    }
567 //
568 // Note that otherPrimeInfos is only applicable for version=1. Since NSS
569 // doesn't use multi-prime can safely use version=0.
570 struct RSAPrivateKey {
571   SECItem version;
572   SECItem modulus;
573   SECItem public_exponent;
574   SECItem private_exponent;
575   SECItem prime1;
576   SECItem prime2;
577   SECItem exponent1;
578   SECItem exponent2;
579   SECItem coefficient;
580 };
581
582 const SEC_ASN1Template RSAPrivateKeyTemplate[] = {
583     {SEC_ASN1_SEQUENCE, 0, NULL, sizeof(RSAPrivateKey)},
584     {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, version)},
585     {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, modulus)},
586     {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, public_exponent)},
587     {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, private_exponent)},
588     {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, prime1)},
589     {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, prime2)},
590     {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, exponent1)},
591     {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, exponent2)},
592     {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, coefficient)},
593     {0}};
594
595 // On success |value| will be filled with data which must be freed by
596 // SECITEM_FreeItem(value, PR_FALSE);
597 bool ReadUint(SECKEYPrivateKey* key,
598               CK_ATTRIBUTE_TYPE attribute,
599               SECItem* value) {
600   SECStatus rv = PK11_ReadRawAttribute(PK11_TypePrivKey, key, attribute, value);
601
602   // PK11_ReadRawAttribute() returns items of type siBuffer. However in order
603   // for the ASN.1 encoding to be correct, the items must be of type
604   // siUnsignedInteger.
605   value->type = siUnsignedInteger;
606
607   return rv == SECSuccess;
608 }
609
610 // Fills |out| with the RSA private key properties. Returns true on success.
611 // Regardless of the return value, the caller must invoke FreeRSAPrivateKey()
612 // to free up any allocated memory.
613 //
614 // The passed in RSAPrivateKey must be zero-initialized.
615 bool InitRSAPrivateKey(SECKEYPrivateKey* key, RSAPrivateKey* out) {
616   if (key->keyType != rsaKey)
617     return false;
618
619   // Everything should be zero-ed out. These are just some spot checks.
620   DCHECK(!out->version.data);
621   DCHECK(!out->version.len);
622   DCHECK(!out->modulus.data);
623   DCHECK(!out->modulus.len);
624
625   // Always use version=0 since not using multi-prime.
626   if (!SEC_ASN1EncodeInteger(NULL, &out->version, 0))
627     return false;
628
629   if (!ReadUint(key, CKA_MODULUS, &out->modulus))
630     return false;
631   if (!ReadUint(key, CKA_PUBLIC_EXPONENT, &out->public_exponent))
632     return false;
633   if (!ReadUint(key, CKA_PRIVATE_EXPONENT, &out->private_exponent))
634     return false;
635   if (!ReadUint(key, CKA_PRIME_1, &out->prime1))
636     return false;
637   if (!ReadUint(key, CKA_PRIME_2, &out->prime2))
638     return false;
639   if (!ReadUint(key, CKA_EXPONENT_1, &out->exponent1))
640     return false;
641   if (!ReadUint(key, CKA_EXPONENT_2, &out->exponent2))
642     return false;
643   if (!ReadUint(key, CKA_COEFFICIENT, &out->coefficient))
644     return false;
645
646   return true;
647 }
648
649 struct FreeRsaPrivateKey {
650   void operator()(RSAPrivateKey* out) {
651     SECITEM_FreeItem(&out->version, PR_FALSE);
652     SECITEM_FreeItem(&out->modulus, PR_FALSE);
653     SECITEM_FreeItem(&out->public_exponent, PR_FALSE);
654     SECITEM_FreeItem(&out->private_exponent, PR_FALSE);
655     SECITEM_FreeItem(&out->prime1, PR_FALSE);
656     SECITEM_FreeItem(&out->prime2, PR_FALSE);
657     SECITEM_FreeItem(&out->exponent1, PR_FALSE);
658     SECITEM_FreeItem(&out->exponent2, PR_FALSE);
659     SECITEM_FreeItem(&out->coefficient, PR_FALSE);
660   }
661 };
662 #endif  // defined(USE_NSS)
663
664 }  // namespace
665
666 Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm,
667                     const CryptoData& key_data,
668                     bool extractable,
669                     blink::WebCryptoKeyUsageMask usage_mask,
670                     blink::WebCryptoKey* key) {
671
672   DCHECK(!algorithm.isNull());
673
674   CK_MECHANISM_TYPE mechanism;
675   CK_FLAGS flags;
676   Status status =
677       WebCryptoAlgorithmToNssMechFlags(algorithm, &mechanism, &flags);
678   if (status.IsError())
679     return status;
680
681   SECItem key_item = MakeSECItemForBuffer(key_data);
682
683   crypto::ScopedPK11Slot slot(PK11_GetInternalSlot());
684   crypto::ScopedPK11SymKey pk11_sym_key(
685       PK11_ImportSymKeyWithFlags(slot.get(),
686                                  mechanism,
687                                  PK11_OriginUnwrap,
688                                  CKA_FLAGS_ONLY,
689                                  &key_item,
690                                  flags,
691                                  false,
692                                  NULL));
693   if (!pk11_sym_key.get())
694     return Status::Error();
695
696   blink::WebCryptoKeyAlgorithm key_algorithm;
697   if (!CreateSecretKeyAlgorithm(
698           algorithm, key_data.byte_length(), &key_algorithm))
699     return Status::ErrorUnexpected();
700
701   *key = blink::WebCryptoKey::create(new SymKey(pk11_sym_key.Pass()),
702                                      blink::WebCryptoKeyTypeSecret,
703                                      extractable,
704                                      key_algorithm,
705                                      usage_mask);
706   return Status::Success();
707 }
708
709 Status ExportKeyRaw(SymKey* key, blink::WebArrayBuffer* buffer) {
710   if (PK11_ExtractKeyValue(key->key()) != SECSuccess)
711     return Status::Error();
712
713   const SECItem* key_data = PK11_GetKeyData(key->key());
714   if (!key_data)
715     return Status::Error();
716
717   *buffer = CreateArrayBuffer(key_data->data, key_data->len);
718
719   return Status::Success();
720 }
721
722 namespace {
723
724 typedef scoped_ptr<CERTSubjectPublicKeyInfo,
725                    crypto::NSSDestroyer<CERTSubjectPublicKeyInfo,
726                                         SECKEY_DestroySubjectPublicKeyInfo> >
727     ScopedCERTSubjectPublicKeyInfo;
728
729 // Validates an NSS KeyType against a WebCrypto import algorithm.
730 bool ValidateNssKeyTypeAgainstInputAlgorithm(
731     KeyType key_type,
732     const blink::WebCryptoAlgorithm& algorithm) {
733   switch (key_type) {
734     case rsaKey:
735       return IsAlgorithmRsa(algorithm);
736     case dsaKey:
737     case ecKey:
738     case rsaPssKey:
739     case rsaOaepKey:
740       // TODO(padolph): Handle other key types.
741       break;
742     default:
743       break;
744   }
745   return false;
746 }
747
748 }  // namespace
749
750 Status ImportKeySpki(const blink::WebCryptoAlgorithm& algorithm,
751                      const CryptoData& key_data,
752                      bool extractable,
753                      blink::WebCryptoKeyUsageMask usage_mask,
754                      blink::WebCryptoKey* key) {
755
756   DCHECK(key);
757
758   if (!key_data.byte_length())
759     return Status::ErrorImportEmptyKeyData();
760   DCHECK(key_data.bytes());
761
762   // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 Subject
763   // Public Key Info. Decode this to a CERTSubjectPublicKeyInfo.
764   SECItem spki_item = MakeSECItemForBuffer(key_data);
765   const ScopedCERTSubjectPublicKeyInfo spki(
766       SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item));
767   if (!spki)
768     return Status::Error();
769
770   crypto::ScopedSECKEYPublicKey sec_public_key(
771       SECKEY_ExtractPublicKey(spki.get()));
772   if (!sec_public_key)
773     return Status::Error();
774
775   const KeyType sec_key_type = SECKEY_GetPublicKeyType(sec_public_key.get());
776   if (!ValidateNssKeyTypeAgainstInputAlgorithm(sec_key_type, algorithm))
777     return Status::Error();
778
779   blink::WebCryptoKeyAlgorithm key_algorithm;
780   if (!CreatePublicKeyAlgorithm(
781           algorithm, sec_public_key.get(), &key_algorithm))
782     return Status::ErrorUnexpected();
783
784   *key = blink::WebCryptoKey::create(new PublicKey(sec_public_key.Pass()),
785                                      blink::WebCryptoKeyTypePublic,
786                                      extractable,
787                                      key_algorithm,
788                                      usage_mask);
789
790   return Status::Success();
791 }
792
793 Status ExportKeySpki(PublicKey* key, blink::WebArrayBuffer* buffer) {
794   const crypto::ScopedSECItem spki_der(
795       SECKEY_EncodeDERSubjectPublicKeyInfo(key->key()));
796   if (!spki_der)
797     return Status::Error();
798
799   DCHECK(spki_der->data);
800   DCHECK(spki_der->len);
801
802   *buffer = CreateArrayBuffer(spki_der->data, spki_der->len);
803
804   return Status::Success();
805 }
806
807 Status ExportRsaPublicKey(PublicKey* key,
808                           std::vector<uint8>* modulus,
809                           std::vector<uint8>* public_exponent) {
810   DCHECK(key);
811   DCHECK(key->key());
812   if (key->key()->keyType != rsaKey)
813     return Status::ErrorUnsupported();
814   CopySECItemToVector(key->key()->u.rsa.modulus, modulus);
815   CopySECItemToVector(key->key()->u.rsa.publicExponent, public_exponent);
816   if (modulus->empty() || public_exponent->empty())
817     return Status::ErrorUnexpected();
818   return Status::Success();
819 }
820
821 Status ExportKeyPkcs8(PrivateKey* key,
822                       const blink::WebCryptoKeyAlgorithm& key_algorithm,
823                       blink::WebArrayBuffer* buffer) {
824   // TODO(eroman): Support other RSA key types as they are added to Blink.
825   if (key_algorithm.id() != blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 &&
826       key_algorithm.id() != blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5)
827     return Status::ErrorUnsupported();
828
829 #if defined(USE_NSS)
830   // PK11_ExportDERPrivateKeyInfo isn't available. Use our fallback code.
831   const SECOidTag algorithm = SEC_OID_PKCS1_RSA_ENCRYPTION;
832   const int kPrivateKeyInfoVersion = 0;
833
834   SECKEYPrivateKeyInfo private_key_info = {};
835   RSAPrivateKey rsa_private_key = {};
836   scoped_ptr<RSAPrivateKey, FreeRsaPrivateKey> free_private_key(
837       &rsa_private_key);
838
839   if (!InitRSAPrivateKey(key->key(), &rsa_private_key))
840     return Status::Error();
841
842   crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
843   if (!arena.get())
844     return Status::Error();
845
846   if (!SEC_ASN1EncodeItem(arena.get(),
847                           &private_key_info.privateKey,
848                           &rsa_private_key,
849                           RSAPrivateKeyTemplate))
850     return Status::Error();
851
852   if (SECSuccess !=
853       SECOID_SetAlgorithmID(
854           arena.get(), &private_key_info.algorithm, algorithm, NULL))
855     return Status::Error();
856
857   if (!SEC_ASN1EncodeInteger(
858           arena.get(), &private_key_info.version, kPrivateKeyInfoVersion))
859     return Status::Error();
860
861   crypto::ScopedSECItem encoded_key(
862       SEC_ASN1EncodeItem(NULL,
863                          NULL,
864                          &private_key_info,
865                          SEC_ASN1_GET(SECKEY_PrivateKeyInfoTemplate)));
866 #else  // defined(USE_NSS)
867   crypto::ScopedSECItem encoded_key(
868       PK11_ExportDERPrivateKeyInfo(key->key(), NULL));
869 #endif  // defined(USE_NSS)
870
871   if (!encoded_key.get())
872     return Status::Error();
873
874   *buffer = CreateArrayBuffer(encoded_key->data, encoded_key->len);
875   return Status::Success();
876 }
877
878 Status ImportKeyPkcs8(const blink::WebCryptoAlgorithm& algorithm,
879                       const CryptoData& key_data,
880                       bool extractable,
881                       blink::WebCryptoKeyUsageMask usage_mask,
882                       blink::WebCryptoKey* key) {
883
884   DCHECK(key);
885
886   if (!key_data.byte_length())
887     return Status::ErrorImportEmptyKeyData();
888   DCHECK(key_data.bytes());
889
890   // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 PKCS#8
891   // private key info object.
892   SECItem pki_der = MakeSECItemForBuffer(key_data);
893
894   SECKEYPrivateKey* seckey_private_key = NULL;
895   crypto::ScopedPK11Slot slot(PK11_GetInternalSlot());
896   if (PK11_ImportDERPrivateKeyInfoAndReturnKey(slot.get(),
897                                                &pki_der,
898                                                NULL,    // nickname
899                                                NULL,    // publicValue
900                                                false,   // isPerm
901                                                false,   // isPrivate
902                                                KU_ALL,  // usage
903                                                &seckey_private_key,
904                                                NULL) != SECSuccess) {
905     return Status::Error();
906   }
907   DCHECK(seckey_private_key);
908   crypto::ScopedSECKEYPrivateKey private_key(seckey_private_key);
909
910   const KeyType sec_key_type = SECKEY_GetPrivateKeyType(private_key.get());
911   if (!ValidateNssKeyTypeAgainstInputAlgorithm(sec_key_type, algorithm))
912     return Status::Error();
913
914   blink::WebCryptoKeyAlgorithm key_algorithm;
915   if (!CreatePrivateKeyAlgorithm(algorithm, private_key.get(), &key_algorithm))
916     return Status::ErrorUnexpected();
917
918   *key = blink::WebCryptoKey::create(new PrivateKey(private_key.Pass()),
919                                      blink::WebCryptoKeyTypePrivate,
920                                      extractable,
921                                      key_algorithm,
922                                      usage_mask);
923
924   return Status::Success();
925 }
926
927 // -----------------------------------
928 // Hmac
929 // -----------------------------------
930
931 Status SignHmac(SymKey* key,
932                 const blink::WebCryptoAlgorithm& hash,
933                 const CryptoData& data,
934                 blink::WebArrayBuffer* buffer) {
935   DCHECK_EQ(PK11_GetMechanism(key->key()), WebCryptoHashToHMACMechanism(hash));
936
937   SECItem param_item = {siBuffer, NULL, 0};
938   SECItem data_item = MakeSECItemForBuffer(data);
939   // First call is to figure out the length.
940   SECItem signature_item = {siBuffer, NULL, 0};
941
942   if (PK11_SignWithSymKey(key->key(),
943                           PK11_GetMechanism(key->key()),
944                           &param_item,
945                           &signature_item,
946                           &data_item) != SECSuccess) {
947     return Status::Error();
948   }
949
950   DCHECK_NE(0u, signature_item.len);
951
952   *buffer = blink::WebArrayBuffer::create(signature_item.len, 1);
953   signature_item.data = reinterpret_cast<unsigned char*>(buffer->data());
954
955   if (PK11_SignWithSymKey(key->key(),
956                           PK11_GetMechanism(key->key()),
957                           &param_item,
958                           &signature_item,
959                           &data_item) != SECSuccess) {
960     return Status::Error();
961   }
962
963   DCHECK_EQ(buffer->byteLength(), signature_item.len);
964   return Status::Success();
965 }
966
967 // -----------------------------------
968 // RsaEsPkcs1v1_5
969 // -----------------------------------
970
971 Status EncryptRsaEsPkcs1v1_5(PublicKey* key,
972                              const CryptoData& data,
973                              blink::WebArrayBuffer* buffer) {
974   const unsigned int encrypted_length_bytes =
975       SECKEY_PublicKeyStrength(key->key());
976
977   // RSAES can operate on messages up to a length of k - 11, where k is the
978   // octet length of the RSA modulus.
979   if (encrypted_length_bytes < 11 ||
980       encrypted_length_bytes - 11 < data.byte_length())
981     return Status::ErrorDataTooLarge();
982
983   *buffer = blink::WebArrayBuffer::create(encrypted_length_bytes, 1);
984   unsigned char* const buffer_data =
985       reinterpret_cast<unsigned char*>(buffer->data());
986
987   if (PK11_PubEncryptPKCS1(key->key(),
988                            buffer_data,
989                            const_cast<unsigned char*>(data.bytes()),
990                            data.byte_length(),
991                            NULL) != SECSuccess) {
992     return Status::Error();
993   }
994   return Status::Success();
995 }
996
997 Status DecryptRsaEsPkcs1v1_5(PrivateKey* key,
998                              const CryptoData& data,
999                              blink::WebArrayBuffer* buffer) {
1000   const int modulus_length_bytes = PK11_GetPrivateModulusLen(key->key());
1001   if (modulus_length_bytes <= 0)
1002     return Status::ErrorUnexpected();
1003   const unsigned int max_output_length_bytes = modulus_length_bytes;
1004
1005   *buffer = blink::WebArrayBuffer::create(max_output_length_bytes, 1);
1006   unsigned char* const buffer_data =
1007       reinterpret_cast<unsigned char*>(buffer->data());
1008
1009   unsigned int output_length_bytes = 0;
1010   if (PK11_PrivDecryptPKCS1(key->key(),
1011                             buffer_data,
1012                             &output_length_bytes,
1013                             max_output_length_bytes,
1014                             const_cast<unsigned char*>(data.bytes()),
1015                             data.byte_length()) != SECSuccess) {
1016     return Status::Error();
1017   }
1018   DCHECK_LE(output_length_bytes, max_output_length_bytes);
1019   ShrinkBuffer(buffer, output_length_bytes);
1020   return Status::Success();
1021 }
1022
1023 // -----------------------------------
1024 // RsaSsaPkcs1v1_5
1025 // -----------------------------------
1026
1027 Status SignRsaSsaPkcs1v1_5(PrivateKey* key,
1028                            const blink::WebCryptoAlgorithm& hash,
1029                            const CryptoData& data,
1030                            blink::WebArrayBuffer* buffer) {
1031   // Pick the NSS signing algorithm by combining RSA-SSA (RSA PKCS1) and the
1032   // inner hash of the input Web Crypto algorithm.
1033   SECOidTag sign_alg_tag;
1034   switch (hash.id()) {
1035     case blink::WebCryptoAlgorithmIdSha1:
1036       sign_alg_tag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
1037       break;
1038     case blink::WebCryptoAlgorithmIdSha256:
1039       sign_alg_tag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION;
1040       break;
1041     case blink::WebCryptoAlgorithmIdSha384:
1042       sign_alg_tag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION;
1043       break;
1044     case blink::WebCryptoAlgorithmIdSha512:
1045       sign_alg_tag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION;
1046       break;
1047     default:
1048       return Status::ErrorUnsupported();
1049   }
1050
1051   crypto::ScopedSECItem signature_item(SECITEM_AllocItem(NULL, NULL, 0));
1052   if (SEC_SignData(signature_item.get(),
1053                    data.bytes(),
1054                    data.byte_length(),
1055                    key->key(),
1056                    sign_alg_tag) != SECSuccess) {
1057     return Status::Error();
1058   }
1059
1060   *buffer = CreateArrayBuffer(signature_item->data, signature_item->len);
1061   return Status::Success();
1062 }
1063
1064 Status VerifyRsaSsaPkcs1v1_5(PublicKey* key,
1065                              const blink::WebCryptoAlgorithm& hash,
1066                              const CryptoData& signature,
1067                              const CryptoData& data,
1068                              bool* signature_match) {
1069   const SECItem signature_item = MakeSECItemForBuffer(signature);
1070
1071   SECOidTag hash_alg_tag;
1072   switch (hash.id()) {
1073     case blink::WebCryptoAlgorithmIdSha1:
1074       hash_alg_tag = SEC_OID_SHA1;
1075       break;
1076     case blink::WebCryptoAlgorithmIdSha256:
1077       hash_alg_tag = SEC_OID_SHA256;
1078       break;
1079     case blink::WebCryptoAlgorithmIdSha384:
1080       hash_alg_tag = SEC_OID_SHA384;
1081       break;
1082     case blink::WebCryptoAlgorithmIdSha512:
1083       hash_alg_tag = SEC_OID_SHA512;
1084       break;
1085     default:
1086       return Status::ErrorUnsupported();
1087   }
1088
1089   *signature_match =
1090       SECSuccess == VFY_VerifyDataDirect(data.bytes(),
1091                                          data.byte_length(),
1092                                          key->key(),
1093                                          &signature_item,
1094                                          SEC_OID_PKCS1_RSA_ENCRYPTION,
1095                                          hash_alg_tag,
1096                                          NULL,
1097                                          NULL);
1098   return Status::Success();
1099 }
1100
1101 Status EncryptDecryptAesCbc(EncryptOrDecrypt mode,
1102                             SymKey* key,
1103                             const CryptoData& data,
1104                             const CryptoData& iv,
1105                             blink::WebArrayBuffer* buffer) {
1106   // TODO(eroman): Inline.
1107   return AesCbcEncryptDecrypt(mode, key, iv, data, buffer);
1108 }
1109
1110 Status EncryptDecryptAesGcm(EncryptOrDecrypt mode,
1111                             SymKey* key,
1112                             const CryptoData& data,
1113                             const CryptoData& iv,
1114                             const CryptoData& additional_data,
1115                             unsigned int tag_length_bits,
1116                             blink::WebArrayBuffer* buffer) {
1117   // TODO(eroman): Inline.
1118   return AesGcmEncryptDecrypt(
1119       mode, key, data, iv, additional_data, tag_length_bits, buffer);
1120 }
1121
1122 // -----------------------------------
1123 // Key generation
1124 // -----------------------------------
1125
1126 Status GenerateRsaKeyPair(const blink::WebCryptoAlgorithm& algorithm,
1127                           bool extractable,
1128                           blink::WebCryptoKeyUsageMask usage_mask,
1129                           unsigned int modulus_length_bits,
1130                           const CryptoData& public_exponent,
1131                           const blink::WebCryptoAlgorithm& hash_or_null,
1132                           blink::WebCryptoKey* public_key,
1133                           blink::WebCryptoKey* private_key) {
1134   crypto::ScopedPK11Slot slot(PK11_GetInternalKeySlot());
1135   if (!slot)
1136     return Status::Error();
1137
1138   unsigned long public_exponent_long;
1139   if (!BigIntegerToLong(public_exponent.bytes(),
1140                         public_exponent.byte_length(),
1141                         &public_exponent_long) ||
1142       !public_exponent_long) {
1143     return Status::ErrorGenerateKeyPublicExponent();
1144   }
1145
1146   PK11RSAGenParams rsa_gen_params;
1147   rsa_gen_params.keySizeInBits = modulus_length_bits;
1148   rsa_gen_params.pe = public_exponent_long;
1149
1150   // Flags are verified at the Blink layer; here the flags are set to all
1151   // possible operations for the given key type.
1152   CK_FLAGS operation_flags;
1153   switch (algorithm.id()) {
1154     case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5:
1155     case blink::WebCryptoAlgorithmIdRsaOaep:
1156       operation_flags = CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP;
1157       break;
1158     case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5:
1159       operation_flags = CKF_SIGN | CKF_VERIFY;
1160       break;
1161     default:
1162       NOTREACHED();
1163       return Status::ErrorUnexpected();
1164   }
1165   const CK_FLAGS operation_flags_mask =
1166       CKF_ENCRYPT | CKF_DECRYPT | CKF_SIGN | CKF_VERIFY | CKF_WRAP | CKF_UNWRAP;
1167
1168   // The private key must be marked as insensitive and extractable, otherwise it
1169   // cannot later be exported in unencrypted form or structured-cloned.
1170   const PK11AttrFlags attribute_flags =
1171       PK11_ATTR_INSENSITIVE | PK11_ATTR_EXTRACTABLE;
1172
1173   // Note: NSS does not generate an sec_public_key if the call below fails,
1174   // so there is no danger of a leaked sec_public_key.
1175   SECKEYPublicKey* sec_public_key;
1176   crypto::ScopedSECKEYPrivateKey scoped_sec_private_key(
1177       PK11_GenerateKeyPairWithOpFlags(slot.get(),
1178                                       CKM_RSA_PKCS_KEY_PAIR_GEN,
1179                                       &rsa_gen_params,
1180                                       &sec_public_key,
1181                                       attribute_flags,
1182                                       operation_flags,
1183                                       operation_flags_mask,
1184                                       NULL));
1185   if (!private_key)
1186     return Status::Error();
1187
1188   blink::WebCryptoKeyAlgorithm key_algorithm;
1189   if (!CreatePublicKeyAlgorithm(algorithm, sec_public_key, &key_algorithm))
1190     return Status::ErrorUnexpected();
1191
1192   *public_key = blink::WebCryptoKey::create(
1193       new PublicKey(crypto::ScopedSECKEYPublicKey(sec_public_key)),
1194       blink::WebCryptoKeyTypePublic,
1195       true,
1196       key_algorithm,
1197       usage_mask);
1198   *private_key =
1199       blink::WebCryptoKey::create(new PrivateKey(scoped_sec_private_key.Pass()),
1200                                   blink::WebCryptoKeyTypePrivate,
1201                                   extractable,
1202                                   key_algorithm,
1203                                   usage_mask);
1204
1205   return Status::Success();
1206 }
1207
1208 void Init() { crypto::EnsureNSSInit(); }
1209
1210 Status DigestSha(blink::WebCryptoAlgorithmId algorithm,
1211                  const CryptoData& data,
1212                  blink::WebArrayBuffer* buffer) {
1213   HASH_HashType hash_type = WebCryptoAlgorithmToNSSHashType(algorithm);
1214   if (hash_type == HASH_AlgNULL)
1215     return Status::ErrorUnsupported();
1216
1217   HASHContext* context = HASH_Create(hash_type);
1218   if (!context)
1219     return Status::Error();
1220
1221   HASH_Begin(context);
1222
1223   HASH_Update(context, data.bytes(), data.byte_length());
1224
1225   unsigned int hash_result_length = HASH_ResultLenContext(context);
1226   DCHECK_LE(hash_result_length, static_cast<size_t>(HASH_LENGTH_MAX));
1227
1228   *buffer = blink::WebArrayBuffer::create(hash_result_length, 1);
1229
1230   unsigned char* digest = reinterpret_cast<unsigned char*>(buffer->data());
1231
1232   unsigned int result_length = 0;
1233   HASH_End(context, digest, &result_length, hash_result_length);
1234
1235   HASH_Destroy(context);
1236
1237   if (result_length != hash_result_length)
1238     return Status::ErrorUnexpected();
1239   return Status::Success();
1240 }
1241
1242 Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm,
1243                          bool extractable,
1244                          blink::WebCryptoKeyUsageMask usage_mask,
1245                          unsigned keylen_bytes,
1246                          blink::WebCryptoKey* key) {
1247   CK_MECHANISM_TYPE mech = WebCryptoAlgorithmToGenMechanism(algorithm);
1248   blink::WebCryptoKeyType key_type = blink::WebCryptoKeyTypeSecret;
1249
1250   if (mech == CKM_INVALID_MECHANISM)
1251     return Status::ErrorUnsupported();
1252
1253   crypto::ScopedPK11Slot slot(PK11_GetInternalKeySlot());
1254   if (!slot)
1255     return Status::Error();
1256
1257   crypto::ScopedPK11SymKey pk11_key(
1258       PK11_KeyGen(slot.get(), mech, NULL, keylen_bytes, NULL));
1259
1260   if (!pk11_key)
1261     return Status::Error();
1262
1263   blink::WebCryptoKeyAlgorithm key_algorithm;
1264   if (!CreateSecretKeyAlgorithm(algorithm, keylen_bytes, &key_algorithm))
1265     return Status::ErrorUnexpected();
1266
1267   *key = blink::WebCryptoKey::create(new SymKey(pk11_key.Pass()),
1268                                      key_type,
1269                                      extractable,
1270                                      key_algorithm,
1271                                      usage_mask);
1272   return Status::Success();
1273 }
1274
1275 Status ImportRsaPublicKey(const blink::WebCryptoAlgorithm& algorithm,
1276                           bool extractable,
1277                           blink::WebCryptoKeyUsageMask usage_mask,
1278                           const CryptoData& modulus_data,
1279                           const CryptoData& exponent_data,
1280                           blink::WebCryptoKey* key) {
1281
1282   if (!modulus_data.byte_length())
1283     return Status::ErrorImportRsaEmptyModulus();
1284
1285   if (!exponent_data.byte_length())
1286     return Status::ErrorImportRsaEmptyExponent();
1287
1288   DCHECK(modulus_data.bytes());
1289   DCHECK(exponent_data.bytes());
1290
1291   // NSS does not provide a way to create an RSA public key directly from the
1292   // modulus and exponent values, but it can import an DER-encoded ASN.1 blob
1293   // with these values and create the public key from that. The code below
1294   // follows the recommendation described in
1295   // https://developer.mozilla.org/en-US/docs/NSS/NSS_Tech_Notes/nss_tech_note7
1296
1297   // Pack the input values into a struct compatible with NSS ASN.1 encoding, and
1298   // set up an ASN.1 encoder template for it.
1299   struct RsaPublicKeyData {
1300     SECItem modulus;
1301     SECItem exponent;
1302   };
1303   const RsaPublicKeyData pubkey_in = {
1304       {siUnsignedInteger, const_cast<unsigned char*>(modulus_data.bytes()),
1305        modulus_data.byte_length()},
1306       {siUnsignedInteger, const_cast<unsigned char*>(exponent_data.bytes()),
1307        exponent_data.byte_length()}};
1308   const SEC_ASN1Template rsa_public_key_template[] = {
1309       {SEC_ASN1_SEQUENCE, 0, NULL, sizeof(RsaPublicKeyData)},
1310       {SEC_ASN1_INTEGER, offsetof(RsaPublicKeyData, modulus), },
1311       {SEC_ASN1_INTEGER, offsetof(RsaPublicKeyData, exponent), },
1312       {0, }};
1313
1314   // DER-encode the public key.
1315   crypto::ScopedSECItem pubkey_der(
1316       SEC_ASN1EncodeItem(NULL, NULL, &pubkey_in, rsa_public_key_template));
1317   if (!pubkey_der)
1318     return Status::Error();
1319
1320   // Import the DER-encoded public key to create an RSA SECKEYPublicKey.
1321   crypto::ScopedSECKEYPublicKey pubkey(
1322       SECKEY_ImportDERPublicKey(pubkey_der.get(), CKK_RSA));
1323   if (!pubkey)
1324     return Status::Error();
1325
1326   blink::WebCryptoKeyAlgorithm key_algorithm;
1327   if (!CreatePublicKeyAlgorithm(algorithm, pubkey.get(), &key_algorithm))
1328     return Status::ErrorUnexpected();
1329
1330   *key = blink::WebCryptoKey::create(new PublicKey(pubkey.Pass()),
1331                                      blink::WebCryptoKeyTypePublic,
1332                                      extractable,
1333                                      key_algorithm,
1334                                      usage_mask);
1335   return Status::Success();
1336 }
1337
1338 Status WrapSymKeyAesKw(SymKey* wrapping_key,
1339                        SymKey* key,
1340                        blink::WebArrayBuffer* buffer) {
1341   // The data size must be at least 16 bytes and a multiple of 8 bytes.
1342   // RFC 3394 does not specify a maximum allowed data length, but since only
1343   // keys are being wrapped in this application (which are small), a reasonable
1344   // max limit is whatever will fit into an unsigned. For the max size test,
1345   // note that AES Key Wrap always adds 8 bytes to the input data size.
1346   const unsigned int input_length = PK11_GetKeyLength(key->key());
1347   if (input_length < 16)
1348     return Status::ErrorDataTooSmall();
1349   if (input_length > UINT_MAX - 8)
1350     return Status::ErrorDataTooLarge();
1351   if (input_length % 8)
1352     return Status::ErrorInvalidAesKwDataLength();
1353
1354   SECItem iv_item = MakeSECItemForBuffer(CryptoData(kAesIv, sizeof(kAesIv)));
1355   crypto::ScopedSECItem param_item(
1356       PK11_ParamFromIV(CKM_NSS_AES_KEY_WRAP, &iv_item));
1357   if (!param_item)
1358     return Status::ErrorUnexpected();
1359
1360   const unsigned int output_length = input_length + 8;
1361   *buffer = blink::WebArrayBuffer::create(output_length, 1);
1362   SECItem wrapped_key_item = MakeSECItemForBuffer(CryptoData(*buffer));
1363
1364   if (SECSuccess != PK11_WrapSymKey(CKM_NSS_AES_KEY_WRAP,
1365                                     param_item.get(),
1366                                     wrapping_key->key(),
1367                                     key->key(),
1368                                     &wrapped_key_item)) {
1369     return Status::Error();
1370   }
1371   if (output_length != wrapped_key_item.len)
1372     return Status::ErrorUnexpected();
1373
1374   return Status::Success();
1375 }
1376
1377 Status UnwrapSymKeyAesKw(const CryptoData& wrapped_key_data,
1378                          SymKey* wrapping_key,
1379                          const blink::WebCryptoAlgorithm& algorithm,
1380                          bool extractable,
1381                          blink::WebCryptoKeyUsageMask usage_mask,
1382                          blink::WebCryptoKey* key) {
1383   // Determine the proper NSS key properties from the input algorithm.
1384   CK_MECHANISM_TYPE mechanism;
1385   CK_FLAGS flags;
1386   Status status =
1387       WebCryptoAlgorithmToNssMechFlags(algorithm, &mechanism, &flags);
1388   if (status.IsError())
1389     return status;
1390
1391   crypto::ScopedPK11SymKey unwrapped_key;
1392   status = DoUnwrapSymKeyAesKw(
1393       wrapped_key_data, wrapping_key, mechanism, flags, &unwrapped_key);
1394   if (status.IsError())
1395     return status;
1396
1397   blink::WebCryptoKeyAlgorithm key_algorithm;
1398   if (!CreateSecretKeyAlgorithm(
1399           algorithm, PK11_GetKeyLength(unwrapped_key.get()), &key_algorithm))
1400     return Status::ErrorUnexpected();
1401
1402   *key = blink::WebCryptoKey::create(new SymKey(unwrapped_key.Pass()),
1403                                      blink::WebCryptoKeyTypeSecret,
1404                                      extractable,
1405                                      key_algorithm,
1406                                      usage_mask);
1407   return Status::Success();
1408 }
1409
1410 Status DecryptAesKw(SymKey* wrapping_key,
1411                     const CryptoData& data,
1412                     blink::WebArrayBuffer* buffer) {
1413   // Due to limitations in the NSS API for the AES-KW algorithm, |data| must be
1414   // temporarily viewed as a symmetric key to be unwrapped (decrypted).
1415   crypto::ScopedPK11SymKey decrypted;
1416   Status status = DoUnwrapSymKeyAesKw(
1417       data, wrapping_key, CKK_GENERIC_SECRET, CKA_ENCRYPT, &decrypted);
1418   if (status.IsError())
1419     return status;
1420
1421   // Once the decrypt is complete, extract the resultant raw bytes from NSS and
1422   // return them to the caller.
1423   if (PK11_ExtractKeyValue(decrypted.get()) != SECSuccess)
1424     return Status::Error();
1425   const SECItem* const key_data = PK11_GetKeyData(decrypted.get());
1426   if (!key_data)
1427     return Status::Error();
1428   *buffer = webcrypto::CreateArrayBuffer(key_data->data, key_data->len);
1429
1430   return Status::Success();
1431 }
1432
1433 Status WrapSymKeyRsaEs(PublicKey* wrapping_key,
1434                        SymKey* key,
1435                        blink::WebArrayBuffer* buffer) {
1436   // Check the raw length of the key to be wrapped against the max size allowed
1437   // by the RSA wrapping key. With PKCS#1 v1.5 padding used in this function,
1438   // the maximum data length that can be encrypted is the wrapping_key's modulus
1439   // byte length minus eleven bytes.
1440   const unsigned int input_length_bytes = PK11_GetKeyLength(key->key());
1441   const unsigned int modulus_length_bytes =
1442       SECKEY_PublicKeyStrength(wrapping_key->key());
1443   if (modulus_length_bytes < 11 ||
1444       modulus_length_bytes - 11 < input_length_bytes)
1445     return Status::ErrorDataTooLarge();
1446
1447   *buffer = blink::WebArrayBuffer::create(modulus_length_bytes, 1);
1448   SECItem wrapped_key_item = MakeSECItemForBuffer(CryptoData(*buffer));
1449
1450   if (SECSuccess !=
1451       PK11_PubWrapSymKey(
1452           CKM_RSA_PKCS, wrapping_key->key(), key->key(), &wrapped_key_item)) {
1453     return Status::Error();
1454   }
1455   if (wrapped_key_item.len != modulus_length_bytes)
1456     return Status::ErrorUnexpected();
1457
1458   return Status::Success();
1459 }
1460
1461 Status UnwrapSymKeyRsaEs(const CryptoData& wrapped_key_data,
1462                          PrivateKey* wrapping_key,
1463                          const blink::WebCryptoAlgorithm& algorithm,
1464                          bool extractable,
1465                          blink::WebCryptoKeyUsageMask usage_mask,
1466                          blink::WebCryptoKey* key) {
1467
1468   // Verify wrapped_key_data size does not exceed the modulus of the RSA key.
1469   const int modulus_length_bytes =
1470       PK11_GetPrivateModulusLen(wrapping_key->key());
1471   if (modulus_length_bytes <= 0)
1472     return Status::ErrorUnexpected();
1473   if (wrapped_key_data.byte_length() >
1474       static_cast<unsigned int>(modulus_length_bytes))
1475     return Status::ErrorDataTooLarge();
1476
1477   // Determine the proper NSS key properties from the input algorithm.
1478   CK_MECHANISM_TYPE mechanism;
1479   CK_FLAGS flags;
1480   Status status =
1481       WebCryptoAlgorithmToNssMechFlags(algorithm, &mechanism, &flags);
1482   if (status.IsError())
1483     return status;
1484
1485   SECItem wrapped_key_item = MakeSECItemForBuffer(wrapped_key_data);
1486
1487   crypto::ScopedPK11SymKey unwrapped_key(
1488       PK11_PubUnwrapSymKeyWithFlagsPerm(wrapping_key->key(),
1489                                         &wrapped_key_item,
1490                                         mechanism,
1491                                         CKA_DECRYPT,
1492                                         0,
1493                                         flags,
1494                                         false));
1495   if (!unwrapped_key)
1496     return Status::Error();
1497
1498   const unsigned int key_length = PK11_GetKeyLength(unwrapped_key.get());
1499
1500   blink::WebCryptoKeyAlgorithm key_algorithm;
1501   if (!CreateSecretKeyAlgorithm(algorithm, key_length, &key_algorithm))
1502     return Status::ErrorUnexpected();
1503
1504   *key = blink::WebCryptoKey::create(new SymKey(unwrapped_key.Pass()),
1505                                      blink::WebCryptoKeyTypeSecret,
1506                                      extractable,
1507                                      key_algorithm,
1508                                      usage_mask);
1509   return Status::Success();
1510 }
1511
1512 }  // namespace platform
1513
1514 }  // namespace webcrypto
1515
1516 }  // namespace content