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