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

Side by Side Diff: content/child/webcrypto/nss/rsa_key_nss.cc

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

Powered by Google App Engine
This is Rietveld 408576698