Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / content / child / webcrypto / nss / rsa_key_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/nss/rsa_key_nss.h"
6
7 #include "base/logging.h"
8 #include "content/child/webcrypto/crypto_data.h"
9 #include "content/child/webcrypto/jwk.h"
10 #include "content/child/webcrypto/nss/key_nss.h"
11 #include "content/child/webcrypto/nss/util_nss.h"
12 #include "content/child/webcrypto/status.h"
13 #include "content/child/webcrypto/webcrypto_util.h"
14 #include "crypto/scoped_nss_types.h"
15 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
16 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
17
18 namespace content {
19
20 namespace webcrypto {
21
22 namespace {
23
24 bool CreatePublicKeyAlgorithm(const blink::WebCryptoAlgorithm& algorithm,
25                               SECKEYPublicKey* key,
26                               blink::WebCryptoKeyAlgorithm* key_algorithm) {
27   // TODO(eroman): What about other key types rsaPss, rsaOaep.
28   if (!key || key->keyType != rsaKey)
29     return false;
30
31   unsigned int modulus_length_bits = SECKEY_PublicKeyStrength(key) * 8;
32   CryptoData public_exponent(key->u.rsa.publicExponent.data,
33                              key->u.rsa.publicExponent.len);
34
35   switch (algorithm.paramsType()) {
36     case blink::WebCryptoAlgorithmParamsTypeRsaHashedImportParams:
37     case blink::WebCryptoAlgorithmParamsTypeRsaHashedKeyGenParams:
38       *key_algorithm = blink::WebCryptoKeyAlgorithm::createRsaHashed(
39           algorithm.id(),
40           modulus_length_bits,
41           public_exponent.bytes(),
42           public_exponent.byte_length(),
43           GetInnerHashAlgorithm(algorithm).id());
44       return true;
45     default:
46       return false;
47   }
48 }
49
50 bool CreatePrivateKeyAlgorithm(const blink::WebCryptoAlgorithm& algorithm,
51                                SECKEYPrivateKey* key,
52                                blink::WebCryptoKeyAlgorithm* key_algorithm) {
53   crypto::ScopedSECKEYPublicKey public_key(SECKEY_ConvertToPublicKey(key));
54   return CreatePublicKeyAlgorithm(algorithm, public_key.get(), key_algorithm);
55 }
56
57 #if defined(USE_NSS) && !defined(OS_CHROMEOS)
58 Status ErrorRsaKeyImportNotSupported() {
59   return Status::ErrorUnsupported(
60       "NSS version must be at least 3.16.2 for RSA key import. See "
61       "http://crbug.com/380424");
62 }
63
64 // Prior to NSS 3.16.2 RSA key parameters were not validated. This is
65 // a security problem for RSA private key import from JWK which uses a
66 // CKA_ID based on the public modulus to retrieve the private key.
67 Status NssSupportsRsaKeyImport() {
68   if (!NSS_VersionCheck("3.16.2"))
69     return ErrorRsaKeyImportNotSupported();
70
71   // Also ensure that the version of Softoken is 3.16.2 or later.
72   crypto::ScopedPK11Slot slot(PK11_GetInternalSlot());
73   CK_SLOT_INFO info = {};
74   if (PK11_GetSlotInfo(slot.get(), &info) != SECSuccess)
75     return ErrorRsaKeyImportNotSupported();
76
77   // CK_SLOT_INFO.hardwareVersion contains the major.minor
78   // version info for Softoken in the corresponding .major/.minor
79   // fields, and .firmwareVersion contains the patch.build
80   // version info (in the .major/.minor fields)
81   if ((info.hardwareVersion.major > 3) ||
82       (info.hardwareVersion.major == 3 &&
83        (info.hardwareVersion.minor > 16 ||
84         (info.hardwareVersion.minor == 16 &&
85          info.firmwareVersion.major >= 2)))) {
86     return Status::Success();
87   }
88
89   return ErrorRsaKeyImportNotSupported();
90 }
91 #else
92 Status NssSupportsRsaKeyImport() {
93   return Status::Success();
94 }
95 #endif
96
97 bool CreateRsaHashedPublicKeyAlgorithm(
98     const blink::WebCryptoAlgorithm& algorithm,
99     SECKEYPublicKey* key,
100     blink::WebCryptoKeyAlgorithm* key_algorithm) {
101   // TODO(eroman): What about other key types rsaPss, rsaOaep.
102   if (!key || key->keyType != rsaKey)
103     return false;
104
105   unsigned int modulus_length_bits = SECKEY_PublicKeyStrength(key) * 8;
106   CryptoData public_exponent(key->u.rsa.publicExponent.data,
107                              key->u.rsa.publicExponent.len);
108
109   switch (algorithm.paramsType()) {
110     case blink::WebCryptoAlgorithmParamsTypeRsaHashedImportParams:
111     case blink::WebCryptoAlgorithmParamsTypeRsaHashedKeyGenParams:
112       *key_algorithm = blink::WebCryptoKeyAlgorithm::createRsaHashed(
113           algorithm.id(),
114           modulus_length_bits,
115           public_exponent.bytes(),
116           public_exponent.byte_length(),
117           GetInnerHashAlgorithm(algorithm).id());
118       return true;
119     default:
120       return false;
121   }
122 }
123
124 bool CreateRsaHashedPrivateKeyAlgorithm(
125     const blink::WebCryptoAlgorithm& algorithm,
126     SECKEYPrivateKey* key,
127     blink::WebCryptoKeyAlgorithm* key_algorithm) {
128   crypto::ScopedSECKEYPublicKey public_key(SECKEY_ConvertToPublicKey(key));
129   if (!public_key)
130     return false;
131   return CreateRsaHashedPublicKeyAlgorithm(
132       algorithm, public_key.get(), key_algorithm);
133 }
134
135 // From PKCS#1 [http://tools.ietf.org/html/rfc3447]:
136 //
137 //    RSAPrivateKey ::= SEQUENCE {
138 //      version           Version,
139 //      modulus           INTEGER,  -- n
140 //      publicExponent    INTEGER,  -- e
141 //      privateExponent   INTEGER,  -- d
142 //      prime1            INTEGER,  -- p
143 //      prime2            INTEGER,  -- q
144 //      exponent1         INTEGER,  -- d mod (p-1)
145 //      exponent2         INTEGER,  -- d mod (q-1)
146 //      coefficient       INTEGER,  -- (inverse of q) mod p
147 //      otherPrimeInfos   OtherPrimeInfos OPTIONAL
148 //    }
149 //
150 // Note that otherPrimeInfos is only applicable for version=1. Since NSS
151 // doesn't use multi-prime can safely use version=0.
152 struct RSAPrivateKey {
153   SECItem version;
154   SECItem modulus;
155   SECItem public_exponent;
156   SECItem private_exponent;
157   SECItem prime1;
158   SECItem prime2;
159   SECItem exponent1;
160   SECItem exponent2;
161   SECItem coefficient;
162 };
163
164 // The system NSS library doesn't have the new PK11_ExportDERPrivateKeyInfo
165 // function yet (https://bugzilla.mozilla.org/show_bug.cgi?id=519255). So we
166 // provide a fallback implementation.
167 #if defined(USE_NSS)
168 const SEC_ASN1Template RSAPrivateKeyTemplate[] = {
169     {SEC_ASN1_SEQUENCE, 0, NULL, sizeof(RSAPrivateKey)},
170     {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, version)},
171     {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, modulus)},
172     {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, public_exponent)},
173     {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, private_exponent)},
174     {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, prime1)},
175     {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, prime2)},
176     {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, exponent1)},
177     {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, exponent2)},
178     {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, coefficient)},
179     {0}};
180 #endif  // defined(USE_NSS)
181
182 // On success |value| will be filled with data which must be freed by
183 // SECITEM_FreeItem(value, PR_FALSE);
184 bool ReadUint(SECKEYPrivateKey* key,
185               CK_ATTRIBUTE_TYPE attribute,
186               SECItem* value) {
187   SECStatus rv = PK11_ReadRawAttribute(PK11_TypePrivKey, key, attribute, value);
188
189   // PK11_ReadRawAttribute() returns items of type siBuffer. However in order
190   // for the ASN.1 encoding to be correct, the items must be of type
191   // siUnsignedInteger.
192   value->type = siUnsignedInteger;
193
194   return rv == SECSuccess;
195 }
196
197 // Fills |out| with the RSA private key properties. Returns true on success.
198 // Regardless of the return value, the caller must invoke FreeRSAPrivateKey()
199 // to free up any allocated memory.
200 //
201 // The passed in RSAPrivateKey must be zero-initialized.
202 bool InitRSAPrivateKey(SECKEYPrivateKey* key, RSAPrivateKey* out) {
203   if (key->keyType != rsaKey)
204     return false;
205
206   // Everything should be zero-ed out. These are just some spot checks.
207   DCHECK(!out->version.data);
208   DCHECK(!out->version.len);
209   DCHECK(!out->modulus.data);
210   DCHECK(!out->modulus.len);
211
212   // Always use version=0 since not using multi-prime.
213   if (!SEC_ASN1EncodeInteger(NULL, &out->version, 0))
214     return false;
215
216   if (!ReadUint(key, CKA_MODULUS, &out->modulus))
217     return false;
218   if (!ReadUint(key, CKA_PUBLIC_EXPONENT, &out->public_exponent))
219     return false;
220   if (!ReadUint(key, CKA_PRIVATE_EXPONENT, &out->private_exponent))
221     return false;
222   if (!ReadUint(key, CKA_PRIME_1, &out->prime1))
223     return false;
224   if (!ReadUint(key, CKA_PRIME_2, &out->prime2))
225     return false;
226   if (!ReadUint(key, CKA_EXPONENT_1, &out->exponent1))
227     return false;
228   if (!ReadUint(key, CKA_EXPONENT_2, &out->exponent2))
229     return false;
230   if (!ReadUint(key, CKA_COEFFICIENT, &out->coefficient))
231     return false;
232
233   return true;
234 }
235
236 struct FreeRsaPrivateKey {
237   void operator()(RSAPrivateKey* out) {
238     SECITEM_FreeItem(&out->version, PR_FALSE);
239     SECITEM_FreeItem(&out->modulus, PR_FALSE);
240     SECITEM_FreeItem(&out->public_exponent, PR_FALSE);
241     SECITEM_FreeItem(&out->private_exponent, PR_FALSE);
242     SECITEM_FreeItem(&out->prime1, PR_FALSE);
243     SECITEM_FreeItem(&out->prime2, PR_FALSE);
244     SECITEM_FreeItem(&out->exponent1, PR_FALSE);
245     SECITEM_FreeItem(&out->exponent2, PR_FALSE);
246     SECITEM_FreeItem(&out->coefficient, PR_FALSE);
247   }
248 };
249
250 typedef scoped_ptr<CERTSubjectPublicKeyInfo,
251                    crypto::NSSDestroyer<CERTSubjectPublicKeyInfo,
252                                         SECKEY_DestroySubjectPublicKeyInfo> >
253     ScopedCERTSubjectPublicKeyInfo;
254
255 struct DestroyGenericObject {
256   void operator()(PK11GenericObject* o) const {
257     if (o)
258       PK11_DestroyGenericObject(o);
259   }
260 };
261
262 typedef scoped_ptr<PK11GenericObject, DestroyGenericObject>
263     ScopedPK11GenericObject;
264
265 // Helper to add an attribute to a template.
266 void AddAttribute(CK_ATTRIBUTE_TYPE type,
267                   void* value,
268                   unsigned long length,
269                   std::vector<CK_ATTRIBUTE>* templ) {
270   CK_ATTRIBUTE attribute = {type, value, length};
271   templ->push_back(attribute);
272 }
273
274 void AddAttribute(CK_ATTRIBUTE_TYPE type,
275                   const CryptoData& data,
276                   std::vector<CK_ATTRIBUTE>* templ) {
277   CK_ATTRIBUTE attribute = {type, const_cast<unsigned char*>(data.bytes()),
278                             data.byte_length()};
279   templ->push_back(attribute);
280 }
281
282 void AddAttribute(CK_ATTRIBUTE_TYPE type,
283                   const std::string& data,
284                   std::vector<CK_ATTRIBUTE>* templ) {
285   AddAttribute(type, CryptoData(data), templ);
286 }
287
288 Status ExportKeyPkcs8Nss(SECKEYPrivateKey* key, std::vector<uint8_t>* buffer) {
289   if (key->keyType != rsaKey)
290     return Status::ErrorUnsupported();
291
292 // TODO(rsleevi): Implement OAEP support according to the spec.
293
294 #if defined(USE_NSS)
295   // PK11_ExportDERPrivateKeyInfo isn't available. Use our fallback code.
296   const SECOidTag algorithm = SEC_OID_PKCS1_RSA_ENCRYPTION;
297   const int kPrivateKeyInfoVersion = 0;
298
299   SECKEYPrivateKeyInfo private_key_info = {};
300   RSAPrivateKey rsa_private_key = {};
301   scoped_ptr<RSAPrivateKey, FreeRsaPrivateKey> free_private_key(
302       &rsa_private_key);
303
304   // http://crbug.com/366427: the spec does not define any other failures for
305   // exporting, so none of the subsequent errors are spec compliant.
306   if (!InitRSAPrivateKey(key, &rsa_private_key))
307     return Status::OperationError();
308
309   crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
310   if (!arena.get())
311     return Status::OperationError();
312
313   if (!SEC_ASN1EncodeItem(arena.get(),
314                           &private_key_info.privateKey,
315                           &rsa_private_key,
316                           RSAPrivateKeyTemplate))
317     return Status::OperationError();
318
319   if (SECSuccess !=
320       SECOID_SetAlgorithmID(
321           arena.get(), &private_key_info.algorithm, algorithm, NULL))
322     return Status::OperationError();
323
324   if (!SEC_ASN1EncodeInteger(
325           arena.get(), &private_key_info.version, kPrivateKeyInfoVersion))
326     return Status::OperationError();
327
328   crypto::ScopedSECItem encoded_key(
329       SEC_ASN1EncodeItem(NULL,
330                          NULL,
331                          &private_key_info,
332                          SEC_ASN1_GET(SECKEY_PrivateKeyInfoTemplate)));
333 #else   // defined(USE_NSS)
334   crypto::ScopedSECItem encoded_key(PK11_ExportDERPrivateKeyInfo(key, NULL));
335 #endif  // defined(USE_NSS)
336
337   if (!encoded_key.get())
338     return Status::OperationError();
339
340   buffer->assign(encoded_key->data, encoded_key->data + encoded_key->len);
341   return Status::Success();
342 }
343
344 Status ImportRsaPrivateKey(const blink::WebCryptoAlgorithm& algorithm,
345                            bool extractable,
346                            blink::WebCryptoKeyUsageMask usage_mask,
347                            const JwkRsaInfo& params,
348                            blink::WebCryptoKey* key) {
349   Status status = NssSupportsRsaKeyImport();
350   if (status.IsError())
351     return status;
352
353   CK_OBJECT_CLASS obj_class = CKO_PRIVATE_KEY;
354   CK_KEY_TYPE key_type = CKK_RSA;
355   CK_BBOOL ck_false = CK_FALSE;
356
357   std::vector<CK_ATTRIBUTE> key_template;
358
359   AddAttribute(CKA_CLASS, &obj_class, sizeof(obj_class), &key_template);
360   AddAttribute(CKA_KEY_TYPE, &key_type, sizeof(key_type), &key_template);
361   AddAttribute(CKA_TOKEN, &ck_false, sizeof(ck_false), &key_template);
362   AddAttribute(CKA_SENSITIVE, &ck_false, sizeof(ck_false), &key_template);
363   AddAttribute(CKA_PRIVATE, &ck_false, sizeof(ck_false), &key_template);
364
365   // Required properties by JWA.
366   AddAttribute(CKA_MODULUS, params.n, &key_template);
367   AddAttribute(CKA_PUBLIC_EXPONENT, params.e, &key_template);
368   AddAttribute(CKA_PRIVATE_EXPONENT, params.d, &key_template);
369
370   // Manufacture a CKA_ID so the created key can be retrieved later as a
371   // SECKEYPrivateKey using FindKeyByKeyID(). Unfortunately there isn't a more
372   // direct way to do this in NSS.
373   //
374   // For consistency with other NSS key creation methods, set the CKA_ID to
375   // PK11_MakeIDFromPubKey(). There are some problems with
376   // this approach:
377   //
378   //  (1) Prior to NSS 3.16.2, there is no parameter validation when creating
379   //      private keys. It is therefore possible to construct a key using the
380   //      known public modulus, and where all the other parameters are bogus.
381   //      FindKeyByKeyID() returns the first key matching the ID. So this would
382   //      effectively allow an attacker to retrieve a private key of their
383   //      choice.
384   //
385   //  (2) The ID space is shared by different key types. So theoretically
386   //      possible to retrieve a key of the wrong type which has a matching
387   //      CKA_ID. In practice I am told this is not likely except for small key
388   //      sizes, since would require constructing keys with the same public
389   //      data.
390   //
391   //  (3) FindKeyByKeyID() doesn't necessarily return the object that was just
392   //      created by CreateGenericObject. If the pre-existing key was
393   //      provisioned with flags incompatible with WebCrypto (for instance
394   //      marked sensitive) then this will break things.
395   SECItem modulus_item = MakeSECItemForBuffer(CryptoData(params.n));
396   crypto::ScopedSECItem object_id(PK11_MakeIDFromPubKey(&modulus_item));
397   AddAttribute(
398       CKA_ID, CryptoData(object_id->data, object_id->len), &key_template);
399
400   // Optional properties by JWA, however guaranteed to be present by Chromium's
401   // implementation.
402   AddAttribute(CKA_PRIME_1, params.p, &key_template);
403   AddAttribute(CKA_PRIME_2, params.q, &key_template);
404   AddAttribute(CKA_EXPONENT_1, params.dp, &key_template);
405   AddAttribute(CKA_EXPONENT_2, params.dq, &key_template);
406   AddAttribute(CKA_COEFFICIENT, params.qi, &key_template);
407
408   crypto::ScopedPK11Slot slot(PK11_GetInternalSlot());
409
410   ScopedPK11GenericObject key_object(PK11_CreateGenericObject(
411       slot.get(), &key_template[0], key_template.size(), PR_FALSE));
412
413   if (!key_object)
414     return Status::OperationError();
415
416   crypto::ScopedSECKEYPrivateKey private_key_tmp(
417       PK11_FindKeyByKeyID(slot.get(), object_id.get(), NULL));
418
419   // PK11_FindKeyByKeyID() may return a handle to an existing key, rather than
420   // the object created by PK11_CreateGenericObject().
421   crypto::ScopedSECKEYPrivateKey private_key(
422       SECKEY_CopyPrivateKey(private_key_tmp.get()));
423
424   if (!private_key)
425     return Status::OperationError();
426
427   blink::WebCryptoKeyAlgorithm key_algorithm;
428   if (!CreatePrivateKeyAlgorithm(algorithm, private_key.get(), &key_algorithm))
429     return Status::ErrorUnexpected();
430
431   std::vector<uint8_t> pkcs8_data;
432   status = ExportKeyPkcs8Nss(private_key.get(), &pkcs8_data);
433   if (status.IsError())
434     return status;
435
436   scoped_ptr<PrivateKeyNss> key_handle(
437       new PrivateKeyNss(private_key.Pass(), CryptoData(pkcs8_data)));
438
439   *key = blink::WebCryptoKey::create(key_handle.release(),
440                                      blink::WebCryptoKeyTypePrivate,
441                                      extractable,
442                                      key_algorithm,
443                                      usage_mask);
444   return Status::Success();
445 }
446
447 Status ExportKeySpkiNss(SECKEYPublicKey* key, std::vector<uint8_t>* buffer) {
448   const crypto::ScopedSECItem spki_der(
449       SECKEY_EncodeDERSubjectPublicKeyInfo(key));
450   if (!spki_der)
451     return Status::OperationError();
452
453   buffer->assign(spki_der->data, spki_der->data + spki_der->len);
454   return Status::Success();
455 }
456
457 Status ImportRsaPublicKey(const blink::WebCryptoAlgorithm& algorithm,
458                           bool extractable,
459                           blink::WebCryptoKeyUsageMask usage_mask,
460                           const CryptoData& modulus_data,
461                           const CryptoData& exponent_data,
462                           blink::WebCryptoKey* key) {
463   if (!modulus_data.byte_length())
464     return Status::ErrorImportRsaEmptyModulus();
465
466   if (!exponent_data.byte_length())
467     return Status::ErrorImportRsaEmptyExponent();
468
469   DCHECK(modulus_data.bytes());
470   DCHECK(exponent_data.bytes());
471
472   // NSS does not provide a way to create an RSA public key directly from the
473   // modulus and exponent values, but it can import an DER-encoded ASN.1 blob
474   // with these values and create the public key from that. The code below
475   // follows the recommendation described in
476   // https://developer.mozilla.org/en-US/docs/NSS/NSS_Tech_Notes/nss_tech_note7
477
478   // Pack the input values into a struct compatible with NSS ASN.1 encoding, and
479   // set up an ASN.1 encoder template for it.
480   struct RsaPublicKeyData {
481     SECItem modulus;
482     SECItem exponent;
483   };
484   const RsaPublicKeyData pubkey_in = {
485       {siUnsignedInteger, const_cast<unsigned char*>(modulus_data.bytes()),
486        modulus_data.byte_length()},
487       {siUnsignedInteger, const_cast<unsigned char*>(exponent_data.bytes()),
488        exponent_data.byte_length()}};
489   const SEC_ASN1Template rsa_public_key_template[] = {
490       {SEC_ASN1_SEQUENCE, 0, NULL, sizeof(RsaPublicKeyData)},
491       {
492        SEC_ASN1_INTEGER, offsetof(RsaPublicKeyData, modulus),
493       },
494       {
495        SEC_ASN1_INTEGER, offsetof(RsaPublicKeyData, exponent),
496       },
497       {
498        0,
499       }};
500
501   // DER-encode the public key.
502   crypto::ScopedSECItem pubkey_der(
503       SEC_ASN1EncodeItem(NULL, NULL, &pubkey_in, rsa_public_key_template));
504   if (!pubkey_der)
505     return Status::OperationError();
506
507   // Import the DER-encoded public key to create an RSA SECKEYPublicKey.
508   crypto::ScopedSECKEYPublicKey pubkey(
509       SECKEY_ImportDERPublicKey(pubkey_der.get(), CKK_RSA));
510   if (!pubkey)
511     return Status::OperationError();
512
513   blink::WebCryptoKeyAlgorithm key_algorithm;
514   if (!CreatePublicKeyAlgorithm(algorithm, pubkey.get(), &key_algorithm))
515     return Status::ErrorUnexpected();
516
517   std::vector<uint8_t> spki_data;
518   Status status = ExportKeySpkiNss(pubkey.get(), &spki_data);
519   if (status.IsError())
520     return status;
521
522   scoped_ptr<PublicKeyNss> key_handle(
523       new PublicKeyNss(pubkey.Pass(), CryptoData(spki_data)));
524
525   *key = blink::WebCryptoKey::create(key_handle.release(),
526                                      blink::WebCryptoKeyTypePublic,
527                                      extractable,
528                                      key_algorithm,
529                                      usage_mask);
530   return Status::Success();
531 }
532
533 }  // namespace
534
535 Status RsaHashedAlgorithm::VerifyKeyUsagesBeforeGenerateKeyPair(
536     blink::WebCryptoKeyUsageMask combined_usage_mask,
537     blink::WebCryptoKeyUsageMask* public_usage_mask,
538     blink::WebCryptoKeyUsageMask* private_usage_mask) const {
539   Status status = CheckKeyCreationUsages(
540       all_public_key_usages_ | all_private_key_usages_, combined_usage_mask);
541   if (status.IsError())
542     return status;
543
544   *public_usage_mask = combined_usage_mask & all_public_key_usages_;
545   *private_usage_mask = combined_usage_mask & all_private_key_usages_;
546
547   return Status::Success();
548 }
549
550 Status RsaHashedAlgorithm::GenerateKeyPair(
551     const blink::WebCryptoAlgorithm& algorithm,
552     bool extractable,
553     blink::WebCryptoKeyUsageMask public_usage_mask,
554     blink::WebCryptoKeyUsageMask private_usage_mask,
555     blink::WebCryptoKey* public_key,
556     blink::WebCryptoKey* private_key) const {
557   unsigned int public_exponent = 0;
558   unsigned int modulus_length_bits = 0;
559   Status status = GetRsaKeyGenParameters(algorithm.rsaHashedKeyGenParams(),
560                                          &public_exponent,
561                                          &modulus_length_bits);
562   if (status.IsError())
563     return status;
564
565   crypto::ScopedPK11Slot slot(PK11_GetInternalKeySlot());
566   if (!slot)
567     return Status::OperationError();
568
569   PK11RSAGenParams rsa_gen_params;
570   rsa_gen_params.keySizeInBits = modulus_length_bits;
571   rsa_gen_params.pe = public_exponent;
572
573   const CK_FLAGS operation_flags_mask =
574       CKF_ENCRYPT | CKF_DECRYPT | CKF_SIGN | CKF_VERIFY | CKF_WRAP | CKF_UNWRAP;
575
576   // The private key must be marked as insensitive and extractable, otherwise it
577   // cannot later be exported in unencrypted form or structured-cloned.
578   const PK11AttrFlags attribute_flags =
579       PK11_ATTR_INSENSITIVE | PK11_ATTR_EXTRACTABLE;
580
581   // Note: NSS does not generate an sec_public_key if the call below fails,
582   // so there is no danger of a leaked sec_public_key.
583   SECKEYPublicKey* sec_public_key;
584   crypto::ScopedSECKEYPrivateKey scoped_sec_private_key(
585       PK11_GenerateKeyPairWithOpFlags(slot.get(),
586                                       CKM_RSA_PKCS_KEY_PAIR_GEN,
587                                       &rsa_gen_params,
588                                       &sec_public_key,
589                                       attribute_flags,
590                                       generate_flags_,
591                                       operation_flags_mask,
592                                       NULL));
593   if (!scoped_sec_private_key)
594     return Status::OperationError();
595
596   blink::WebCryptoKeyAlgorithm key_algorithm;
597   if (!CreatePublicKeyAlgorithm(algorithm, sec_public_key, &key_algorithm))
598     return Status::ErrorUnexpected();
599
600   std::vector<uint8_t> spki_data;
601   status = ExportKeySpkiNss(sec_public_key, &spki_data);
602   if (status.IsError())
603     return status;
604
605   scoped_ptr<PublicKeyNss> public_key_handle(new PublicKeyNss(
606       crypto::ScopedSECKEYPublicKey(sec_public_key), CryptoData(spki_data)));
607
608   std::vector<uint8_t> pkcs8_data;
609   status = ExportKeyPkcs8Nss(scoped_sec_private_key.get(), &pkcs8_data);
610   if (status.IsError())
611     return status;
612
613   scoped_ptr<PrivateKeyNss> private_key_handle(
614       new PrivateKeyNss(scoped_sec_private_key.Pass(), CryptoData(pkcs8_data)));
615
616   *public_key = blink::WebCryptoKey::create(public_key_handle.release(),
617                                             blink::WebCryptoKeyTypePublic,
618                                             true,
619                                             key_algorithm,
620                                             public_usage_mask);
621   *private_key = blink::WebCryptoKey::create(private_key_handle.release(),
622                                              blink::WebCryptoKeyTypePrivate,
623                                              extractable,
624                                              key_algorithm,
625                                              private_usage_mask);
626
627   return Status::Success();
628 }
629
630 Status RsaHashedAlgorithm::VerifyKeyUsagesBeforeImportKey(
631     blink::WebCryptoKeyFormat format,
632     blink::WebCryptoKeyUsageMask usage_mask) const {
633   switch (format) {
634     case blink::WebCryptoKeyFormatSpki:
635       return CheckKeyCreationUsages(all_public_key_usages_, usage_mask);
636     case blink::WebCryptoKeyFormatPkcs8:
637       return CheckKeyCreationUsages(all_private_key_usages_, usage_mask);
638     case blink::WebCryptoKeyFormatJwk:
639       return CheckKeyCreationUsages(
640           all_public_key_usages_ | all_private_key_usages_, usage_mask);
641     default:
642       return Status::ErrorUnsupportedImportKeyFormat();
643   }
644 }
645
646 Status RsaHashedAlgorithm::ImportKeyPkcs8(
647     const CryptoData& key_data,
648     const blink::WebCryptoAlgorithm& algorithm,
649     bool extractable,
650     blink::WebCryptoKeyUsageMask usage_mask,
651     blink::WebCryptoKey* key) const {
652   Status status = NssSupportsRsaKeyImport();
653   if (status.IsError())
654     return status;
655
656   if (!key_data.byte_length())
657     return Status::ErrorImportEmptyKeyData();
658
659   // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 PKCS#8
660   // private key info object.
661   SECItem pki_der = MakeSECItemForBuffer(key_data);
662
663   SECKEYPrivateKey* seckey_private_key = NULL;
664   crypto::ScopedPK11Slot slot(PK11_GetInternalSlot());
665   if (PK11_ImportDERPrivateKeyInfoAndReturnKey(slot.get(),
666                                                &pki_der,
667                                                NULL,    // nickname
668                                                NULL,    // publicValue
669                                                false,   // isPerm
670                                                false,   // isPrivate
671                                                KU_ALL,  // usage
672                                                &seckey_private_key,
673                                                NULL) != SECSuccess) {
674     return Status::DataError();
675   }
676   DCHECK(seckey_private_key);
677   crypto::ScopedSECKEYPrivateKey private_key(seckey_private_key);
678
679   const KeyType sec_key_type = SECKEY_GetPrivateKeyType(private_key.get());
680   if (sec_key_type != rsaKey)
681     return Status::DataError();
682
683   blink::WebCryptoKeyAlgorithm key_algorithm;
684   if (!CreateRsaHashedPrivateKeyAlgorithm(
685           algorithm, private_key.get(), &key_algorithm))
686     return Status::ErrorUnexpected();
687
688   // TODO(eroman): This is probably going to be the same as the input.
689   std::vector<uint8_t> pkcs8_data;
690   status = ExportKeyPkcs8Nss(private_key.get(), &pkcs8_data);
691   if (status.IsError())
692     return status;
693
694   scoped_ptr<PrivateKeyNss> key_handle(
695       new PrivateKeyNss(private_key.Pass(), CryptoData(pkcs8_data)));
696
697   *key = blink::WebCryptoKey::create(key_handle.release(),
698                                      blink::WebCryptoKeyTypePrivate,
699                                      extractable,
700                                      key_algorithm,
701                                      usage_mask);
702
703   return Status::Success();
704 }
705
706 Status RsaHashedAlgorithm::ImportKeySpki(
707     const CryptoData& key_data,
708     const blink::WebCryptoAlgorithm& algorithm,
709     bool extractable,
710     blink::WebCryptoKeyUsageMask usage_mask,
711     blink::WebCryptoKey* key) const {
712   Status status = NssSupportsRsaKeyImport();
713   if (status.IsError())
714     return status;
715
716   if (!key_data.byte_length())
717     return Status::ErrorImportEmptyKeyData();
718
719   // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 Subject
720   // Public Key Info. Decode this to a CERTSubjectPublicKeyInfo.
721   SECItem spki_item = MakeSECItemForBuffer(key_data);
722   const ScopedCERTSubjectPublicKeyInfo spki(
723       SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item));
724   if (!spki)
725     return Status::DataError();
726
727   crypto::ScopedSECKEYPublicKey sec_public_key(
728       SECKEY_ExtractPublicKey(spki.get()));
729   if (!sec_public_key)
730     return Status::DataError();
731
732   const KeyType sec_key_type = SECKEY_GetPublicKeyType(sec_public_key.get());
733   if (sec_key_type != rsaKey)
734     return Status::DataError();
735
736   blink::WebCryptoKeyAlgorithm key_algorithm;
737   if (!CreateRsaHashedPublicKeyAlgorithm(
738           algorithm, sec_public_key.get(), &key_algorithm))
739     return Status::ErrorUnexpected();
740
741   // TODO(eroman): This is probably going to be the same as the input.
742   std::vector<uint8_t> spki_data;
743   status = ExportKeySpkiNss(sec_public_key.get(), &spki_data);
744   if (status.IsError())
745     return status;
746
747   scoped_ptr<PublicKeyNss> key_handle(
748       new PublicKeyNss(sec_public_key.Pass(), CryptoData(spki_data)));
749
750   *key = blink::WebCryptoKey::create(key_handle.release(),
751                                      blink::WebCryptoKeyTypePublic,
752                                      extractable,
753                                      key_algorithm,
754                                      usage_mask);
755
756   return Status::Success();
757 }
758
759 Status RsaHashedAlgorithm::ExportKeyPkcs8(const blink::WebCryptoKey& key,
760                                           std::vector<uint8_t>* buffer) const {
761   if (key.type() != blink::WebCryptoKeyTypePrivate)
762     return Status::ErrorUnexpectedKeyType();
763   *buffer = PrivateKeyNss::Cast(key)->pkcs8_data();
764   return Status::Success();
765 }
766
767 Status RsaHashedAlgorithm::ExportKeySpki(const blink::WebCryptoKey& key,
768                                          std::vector<uint8_t>* buffer) const {
769   if (key.type() != blink::WebCryptoKeyTypePublic)
770     return Status::ErrorUnexpectedKeyType();
771   *buffer = PublicKeyNss::Cast(key)->spki_data();
772   return Status::Success();
773 }
774
775 Status RsaHashedAlgorithm::ImportKeyJwk(
776     const CryptoData& key_data,
777     const blink::WebCryptoAlgorithm& algorithm,
778     bool extractable,
779     blink::WebCryptoKeyUsageMask usage_mask,
780     blink::WebCryptoKey* key) const {
781   const char* jwk_algorithm =
782       GetJwkAlgorithm(algorithm.rsaHashedImportParams()->hash().id());
783
784   if (!jwk_algorithm)
785     return Status::ErrorUnexpected();
786
787   JwkRsaInfo jwk;
788   Status status =
789       ReadRsaKeyJwk(key_data, jwk_algorithm, extractable, usage_mask, &jwk);
790   if (status.IsError())
791     return status;
792
793   // Once the key type is known, verify the usages.
794   status = CheckKeyCreationUsages(
795       jwk.is_private_key ? all_private_key_usages_ : all_public_key_usages_,
796       usage_mask);
797   if (status.IsError())
798     return Status::ErrorCreateKeyBadUsages();
799
800   return jwk.is_private_key
801              ? ImportRsaPrivateKey(algorithm, extractable, usage_mask, jwk, key)
802              : ImportRsaPublicKey(algorithm,
803                                   extractable,
804                                   usage_mask,
805                                   CryptoData(jwk.n),
806                                   CryptoData(jwk.e),
807                                   key);
808 }
809
810 Status RsaHashedAlgorithm::ExportKeyJwk(const blink::WebCryptoKey& key,
811                                         std::vector<uint8_t>* buffer) const {
812   const char* jwk_algorithm =
813       GetJwkAlgorithm(key.algorithm().rsaHashedParams()->hash().id());
814
815   if (!jwk_algorithm)
816     return Status::ErrorUnexpected();
817
818   switch (key.type()) {
819     case blink::WebCryptoKeyTypePublic: {
820       SECKEYPublicKey* nss_key = PublicKeyNss::Cast(key)->key();
821       if (nss_key->keyType != rsaKey)
822         return Status::ErrorUnsupported();
823
824       WriteRsaPublicKeyJwk(SECItemToCryptoData(nss_key->u.rsa.modulus),
825                            SECItemToCryptoData(nss_key->u.rsa.publicExponent),
826                            jwk_algorithm,
827                            key.extractable(),
828                            key.usages(),
829                            buffer);
830
831       return Status::Success();
832     }
833
834     case blink::WebCryptoKeyTypePrivate: {
835       SECKEYPrivateKey* nss_key = PrivateKeyNss::Cast(key)->key();
836       RSAPrivateKey key_props = {};
837       scoped_ptr<RSAPrivateKey, FreeRsaPrivateKey> free_private_key(&key_props);
838
839       if (!InitRSAPrivateKey(nss_key, &key_props))
840         return Status::OperationError();
841
842       WriteRsaPrivateKeyJwk(SECItemToCryptoData(key_props.modulus),
843                             SECItemToCryptoData(key_props.public_exponent),
844                             SECItemToCryptoData(key_props.private_exponent),
845                             SECItemToCryptoData(key_props.prime1),
846                             SECItemToCryptoData(key_props.prime2),
847                             SECItemToCryptoData(key_props.exponent1),
848                             SECItemToCryptoData(key_props.exponent2),
849                             SECItemToCryptoData(key_props.coefficient),
850                             jwk_algorithm,
851                             key.extractable(),
852                             key.usages(),
853                             buffer);
854
855       return Status::Success();
856     }
857     default:
858       return Status::ErrorUnexpected();
859   }
860 }
861
862 }  // namespace webcrypto
863
864 }  // namespace content