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.
5 #include "content/child/webcrypto/nss/rsa_key_nss.h"
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"
24 bool CreatePublicKeyAlgorithm(const blink::WebCryptoAlgorithm& algorithm,
26 blink::WebCryptoKeyAlgorithm* key_algorithm) {
27 // TODO(eroman): What about other key types rsaPss, rsaOaep.
28 if (!key || key->keyType != rsaKey)
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);
35 switch (algorithm.paramsType()) {
36 case blink::WebCryptoAlgorithmParamsTypeRsaHashedImportParams:
37 case blink::WebCryptoAlgorithmParamsTypeRsaHashedKeyGenParams:
38 *key_algorithm = blink::WebCryptoKeyAlgorithm::createRsaHashed(
41 public_exponent.bytes(),
42 public_exponent.byte_length(),
43 GetInnerHashAlgorithm(algorithm).id());
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);
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");
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();
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();
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();
89 return ErrorRsaKeyImportNotSupported();
92 Status NssSupportsRsaKeyImport() {
93 return Status::Success();
97 bool CreateRsaHashedPublicKeyAlgorithm(
98 const blink::WebCryptoAlgorithm& algorithm,
100 blink::WebCryptoKeyAlgorithm* key_algorithm) {
101 // TODO(eroman): What about other key types rsaPss, rsaOaep.
102 if (!key || key->keyType != rsaKey)
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);
109 switch (algorithm.paramsType()) {
110 case blink::WebCryptoAlgorithmParamsTypeRsaHashedImportParams:
111 case blink::WebCryptoAlgorithmParamsTypeRsaHashedKeyGenParams:
112 *key_algorithm = blink::WebCryptoKeyAlgorithm::createRsaHashed(
115 public_exponent.bytes(),
116 public_exponent.byte_length(),
117 GetInnerHashAlgorithm(algorithm).id());
124 bool CreateRsaHashedPrivateKeyAlgorithm(
125 const blink::WebCryptoAlgorithm& algorithm,
126 SECKEYPrivateKey* key,
127 blink::WebCryptoKeyAlgorithm* key_algorithm) {
128 crypto::ScopedSECKEYPublicKey public_key(SECKEY_ConvertToPublicKey(key));
131 return CreateRsaHashedPublicKeyAlgorithm(
132 algorithm, public_key.get(), key_algorithm);
135 // From PKCS#1 [http://tools.ietf.org/html/rfc3447]:
137 // RSAPrivateKey ::= SEQUENCE {
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
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 {
155 SECItem public_exponent;
156 SECItem private_exponent;
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.
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)},
180 #endif // defined(USE_NSS)
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,
187 SECStatus rv = PK11_ReadRawAttribute(PK11_TypePrivKey, key, attribute, value);
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;
194 return rv == SECSuccess;
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.
201 // The passed in RSAPrivateKey must be zero-initialized.
202 bool InitRSAPrivateKey(SECKEYPrivateKey* key, RSAPrivateKey* out) {
203 if (key->keyType != rsaKey)
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);
212 // Always use version=0 since not using multi-prime.
213 if (!SEC_ASN1EncodeInteger(NULL, &out->version, 0))
216 if (!ReadUint(key, CKA_MODULUS, &out->modulus))
218 if (!ReadUint(key, CKA_PUBLIC_EXPONENT, &out->public_exponent))
220 if (!ReadUint(key, CKA_PRIVATE_EXPONENT, &out->private_exponent))
222 if (!ReadUint(key, CKA_PRIME_1, &out->prime1))
224 if (!ReadUint(key, CKA_PRIME_2, &out->prime2))
226 if (!ReadUint(key, CKA_EXPONENT_1, &out->exponent1))
228 if (!ReadUint(key, CKA_EXPONENT_2, &out->exponent2))
230 if (!ReadUint(key, CKA_COEFFICIENT, &out->coefficient))
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);
250 typedef scoped_ptr<CERTSubjectPublicKeyInfo,
251 crypto::NSSDestroyer<CERTSubjectPublicKeyInfo,
252 SECKEY_DestroySubjectPublicKeyInfo> >
253 ScopedCERTSubjectPublicKeyInfo;
255 struct DestroyGenericObject {
256 void operator()(PK11GenericObject* o) const {
258 PK11_DestroyGenericObject(o);
262 typedef scoped_ptr<PK11GenericObject, DestroyGenericObject>
263 ScopedPK11GenericObject;
265 // Helper to add an attribute to a template.
266 void AddAttribute(CK_ATTRIBUTE_TYPE type,
268 unsigned long length,
269 std::vector<CK_ATTRIBUTE>* templ) {
270 CK_ATTRIBUTE attribute = {type, value, length};
271 templ->push_back(attribute);
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()),
279 templ->push_back(attribute);
282 void AddAttribute(CK_ATTRIBUTE_TYPE type,
283 const std::string& data,
284 std::vector<CK_ATTRIBUTE>* templ) {
285 AddAttribute(type, CryptoData(data), templ);
288 Status ExportKeyPkcs8Nss(SECKEYPrivateKey* key, std::vector<uint8_t>* buffer) {
289 if (key->keyType != rsaKey)
290 return Status::ErrorUnsupported();
292 // TODO(rsleevi): Implement OAEP support according to the spec.
295 // PK11_ExportDERPrivateKeyInfo isn't available. Use our fallback code.
296 const SECOidTag algorithm = SEC_OID_PKCS1_RSA_ENCRYPTION;
297 const int kPrivateKeyInfoVersion = 0;
299 SECKEYPrivateKeyInfo private_key_info = {};
300 RSAPrivateKey rsa_private_key = {};
301 scoped_ptr<RSAPrivateKey, FreeRsaPrivateKey> free_private_key(
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();
309 crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
311 return Status::OperationError();
313 if (!SEC_ASN1EncodeItem(arena.get(),
314 &private_key_info.privateKey,
316 RSAPrivateKeyTemplate))
317 return Status::OperationError();
320 SECOID_SetAlgorithmID(
321 arena.get(), &private_key_info.algorithm, algorithm, NULL))
322 return Status::OperationError();
324 if (!SEC_ASN1EncodeInteger(
325 arena.get(), &private_key_info.version, kPrivateKeyInfoVersion))
326 return Status::OperationError();
328 crypto::ScopedSECItem encoded_key(
329 SEC_ASN1EncodeItem(NULL,
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)
337 if (!encoded_key.get())
338 return Status::OperationError();
340 buffer->assign(encoded_key->data, encoded_key->data + encoded_key->len);
341 return Status::Success();
344 Status ImportRsaPrivateKey(const blink::WebCryptoAlgorithm& algorithm,
346 blink::WebCryptoKeyUsageMask usage_mask,
347 const JwkRsaInfo& params,
348 blink::WebCryptoKey* key) {
349 Status status = NssSupportsRsaKeyImport();
350 if (status.IsError())
353 CK_OBJECT_CLASS obj_class = CKO_PRIVATE_KEY;
354 CK_KEY_TYPE key_type = CKK_RSA;
355 CK_BBOOL ck_false = CK_FALSE;
357 std::vector<CK_ATTRIBUTE> key_template;
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);
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);
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.
374 // For consistency with other NSS key creation methods, set the CKA_ID to
375 // PK11_MakeIDFromPubKey(). There are some problems with
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
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
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));
398 CKA_ID, CryptoData(object_id->data, object_id->len), &key_template);
400 // Optional properties by JWA, however guaranteed to be present by Chromium's
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);
408 crypto::ScopedPK11Slot slot(PK11_GetInternalSlot());
410 ScopedPK11GenericObject key_object(PK11_CreateGenericObject(
411 slot.get(), &key_template[0], key_template.size(), PR_FALSE));
414 return Status::OperationError();
416 crypto::ScopedSECKEYPrivateKey private_key_tmp(
417 PK11_FindKeyByKeyID(slot.get(), object_id.get(), NULL));
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()));
425 return Status::OperationError();
427 blink::WebCryptoKeyAlgorithm key_algorithm;
428 if (!CreatePrivateKeyAlgorithm(algorithm, private_key.get(), &key_algorithm))
429 return Status::ErrorUnexpected();
431 std::vector<uint8_t> pkcs8_data;
432 status = ExportKeyPkcs8Nss(private_key.get(), &pkcs8_data);
433 if (status.IsError())
436 scoped_ptr<PrivateKeyNss> key_handle(
437 new PrivateKeyNss(private_key.Pass(), CryptoData(pkcs8_data)));
439 *key = blink::WebCryptoKey::create(key_handle.release(),
440 blink::WebCryptoKeyTypePrivate,
444 return Status::Success();
447 Status ExportKeySpkiNss(SECKEYPublicKey* key, std::vector<uint8_t>* buffer) {
448 const crypto::ScopedSECItem spki_der(
449 SECKEY_EncodeDERSubjectPublicKeyInfo(key));
451 return Status::OperationError();
453 buffer->assign(spki_der->data, spki_der->data + spki_der->len);
454 return Status::Success();
457 Status ImportRsaPublicKey(const blink::WebCryptoAlgorithm& algorithm,
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();
466 if (!exponent_data.byte_length())
467 return Status::ErrorImportRsaEmptyExponent();
469 DCHECK(modulus_data.bytes());
470 DCHECK(exponent_data.bytes());
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
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 {
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)},
492 SEC_ASN1_INTEGER, offsetof(RsaPublicKeyData, modulus),
495 SEC_ASN1_INTEGER, offsetof(RsaPublicKeyData, exponent),
501 // DER-encode the public key.
502 crypto::ScopedSECItem pubkey_der(
503 SEC_ASN1EncodeItem(NULL, NULL, &pubkey_in, rsa_public_key_template));
505 return Status::OperationError();
507 // Import the DER-encoded public key to create an RSA SECKEYPublicKey.
508 crypto::ScopedSECKEYPublicKey pubkey(
509 SECKEY_ImportDERPublicKey(pubkey_der.get(), CKK_RSA));
511 return Status::OperationError();
513 blink::WebCryptoKeyAlgorithm key_algorithm;
514 if (!CreatePublicKeyAlgorithm(algorithm, pubkey.get(), &key_algorithm))
515 return Status::ErrorUnexpected();
517 std::vector<uint8_t> spki_data;
518 Status status = ExportKeySpkiNss(pubkey.get(), &spki_data);
519 if (status.IsError())
522 scoped_ptr<PublicKeyNss> key_handle(
523 new PublicKeyNss(pubkey.Pass(), CryptoData(spki_data)));
525 *key = blink::WebCryptoKey::create(key_handle.release(),
526 blink::WebCryptoKeyTypePublic,
530 return Status::Success();
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())
544 *public_usage_mask = combined_usage_mask & all_public_key_usages_;
545 *private_usage_mask = combined_usage_mask & all_private_key_usages_;
547 return Status::Success();
550 Status RsaHashedAlgorithm::GenerateKeyPair(
551 const blink::WebCryptoAlgorithm& algorithm,
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(),
561 &modulus_length_bits);
562 if (status.IsError())
565 crypto::ScopedPK11Slot slot(PK11_GetInternalKeySlot());
567 return Status::OperationError();
569 PK11RSAGenParams rsa_gen_params;
570 rsa_gen_params.keySizeInBits = modulus_length_bits;
571 rsa_gen_params.pe = public_exponent;
573 const CK_FLAGS operation_flags_mask =
574 CKF_ENCRYPT | CKF_DECRYPT | CKF_SIGN | CKF_VERIFY | CKF_WRAP | CKF_UNWRAP;
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;
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,
591 operation_flags_mask,
593 if (!scoped_sec_private_key)
594 return Status::OperationError();
596 blink::WebCryptoKeyAlgorithm key_algorithm;
597 if (!CreatePublicKeyAlgorithm(algorithm, sec_public_key, &key_algorithm))
598 return Status::ErrorUnexpected();
600 std::vector<uint8_t> spki_data;
601 status = ExportKeySpkiNss(sec_public_key, &spki_data);
602 if (status.IsError())
605 scoped_ptr<PublicKeyNss> public_key_handle(new PublicKeyNss(
606 crypto::ScopedSECKEYPublicKey(sec_public_key), CryptoData(spki_data)));
608 std::vector<uint8_t> pkcs8_data;
609 status = ExportKeyPkcs8Nss(scoped_sec_private_key.get(), &pkcs8_data);
610 if (status.IsError())
613 scoped_ptr<PrivateKeyNss> private_key_handle(
614 new PrivateKeyNss(scoped_sec_private_key.Pass(), CryptoData(pkcs8_data)));
616 *public_key = blink::WebCryptoKey::create(public_key_handle.release(),
617 blink::WebCryptoKeyTypePublic,
621 *private_key = blink::WebCryptoKey::create(private_key_handle.release(),
622 blink::WebCryptoKeyTypePrivate,
627 return Status::Success();
630 Status RsaHashedAlgorithm::VerifyKeyUsagesBeforeImportKey(
631 blink::WebCryptoKeyFormat format,
632 blink::WebCryptoKeyUsageMask usage_mask) const {
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);
642 return Status::ErrorUnsupportedImportKeyFormat();
646 Status RsaHashedAlgorithm::ImportKeyPkcs8(
647 const CryptoData& key_data,
648 const blink::WebCryptoAlgorithm& algorithm,
650 blink::WebCryptoKeyUsageMask usage_mask,
651 blink::WebCryptoKey* key) const {
652 Status status = NssSupportsRsaKeyImport();
653 if (status.IsError())
656 if (!key_data.byte_length())
657 return Status::ErrorImportEmptyKeyData();
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);
663 SECKEYPrivateKey* seckey_private_key = NULL;
664 crypto::ScopedPK11Slot slot(PK11_GetInternalSlot());
665 if (PK11_ImportDERPrivateKeyInfoAndReturnKey(slot.get(),
673 NULL) != SECSuccess) {
674 return Status::DataError();
676 DCHECK(seckey_private_key);
677 crypto::ScopedSECKEYPrivateKey private_key(seckey_private_key);
679 const KeyType sec_key_type = SECKEY_GetPrivateKeyType(private_key.get());
680 if (sec_key_type != rsaKey)
681 return Status::DataError();
683 blink::WebCryptoKeyAlgorithm key_algorithm;
684 if (!CreateRsaHashedPrivateKeyAlgorithm(
685 algorithm, private_key.get(), &key_algorithm))
686 return Status::ErrorUnexpected();
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())
694 scoped_ptr<PrivateKeyNss> key_handle(
695 new PrivateKeyNss(private_key.Pass(), CryptoData(pkcs8_data)));
697 *key = blink::WebCryptoKey::create(key_handle.release(),
698 blink::WebCryptoKeyTypePrivate,
703 return Status::Success();
706 Status RsaHashedAlgorithm::ImportKeySpki(
707 const CryptoData& key_data,
708 const blink::WebCryptoAlgorithm& algorithm,
710 blink::WebCryptoKeyUsageMask usage_mask,
711 blink::WebCryptoKey* key) const {
712 Status status = NssSupportsRsaKeyImport();
713 if (status.IsError())
716 if (!key_data.byte_length())
717 return Status::ErrorImportEmptyKeyData();
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));
725 return Status::DataError();
727 crypto::ScopedSECKEYPublicKey sec_public_key(
728 SECKEY_ExtractPublicKey(spki.get()));
730 return Status::DataError();
732 const KeyType sec_key_type = SECKEY_GetPublicKeyType(sec_public_key.get());
733 if (sec_key_type != rsaKey)
734 return Status::DataError();
736 blink::WebCryptoKeyAlgorithm key_algorithm;
737 if (!CreateRsaHashedPublicKeyAlgorithm(
738 algorithm, sec_public_key.get(), &key_algorithm))
739 return Status::ErrorUnexpected();
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())
747 scoped_ptr<PublicKeyNss> key_handle(
748 new PublicKeyNss(sec_public_key.Pass(), CryptoData(spki_data)));
750 *key = blink::WebCryptoKey::create(key_handle.release(),
751 blink::WebCryptoKeyTypePublic,
756 return Status::Success();
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();
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();
775 Status RsaHashedAlgorithm::ImportKeyJwk(
776 const CryptoData& key_data,
777 const blink::WebCryptoAlgorithm& algorithm,
779 blink::WebCryptoKeyUsageMask usage_mask,
780 blink::WebCryptoKey* key) const {
781 const char* jwk_algorithm =
782 GetJwkAlgorithm(algorithm.rsaHashedImportParams()->hash().id());
785 return Status::ErrorUnexpected();
789 ReadRsaKeyJwk(key_data, jwk_algorithm, extractable, usage_mask, &jwk);
790 if (status.IsError())
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_,
797 if (status.IsError())
798 return Status::ErrorCreateKeyBadUsages();
800 return jwk.is_private_key
801 ? ImportRsaPrivateKey(algorithm, extractable, usage_mask, jwk, key)
802 : ImportRsaPublicKey(algorithm,
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());
816 return Status::ErrorUnexpected();
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();
824 WriteRsaPublicKeyJwk(SECItemToCryptoData(nss_key->u.rsa.modulus),
825 SECItemToCryptoData(nss_key->u.rsa.publicExponent),
831 return Status::Success();
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);
839 if (!InitRSAPrivateKey(nss_key, &key_props))
840 return Status::OperationError();
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),
855 return Status::Success();
858 return Status::ErrorUnexpected();
862 } // namespace webcrypto
864 } // namespace content