Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/renderer/webcrypto/webcrypto_impl.h" | 5 #include "content/renderer/webcrypto/webcrypto_impl.h" |
| 6 | 6 |
| 7 #include <cryptohi.h> | 7 #include <cryptohi.h> |
| 8 #include <pk11pub.h> | 8 #include <pk11pub.h> |
| 9 #include <sechash.h> | 9 #include <sechash.h> |
| 10 | 10 |
| (...skipping 306 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 317 NULL)); | 317 NULL)); |
| 318 if (!pk11_sym_key.get()) { | 318 if (!pk11_sym_key.get()) { |
| 319 return false; | 319 return false; |
| 320 } | 320 } |
| 321 | 321 |
| 322 *key = blink::WebCryptoKey::create(new SymKeyHandle(pk11_sym_key.Pass()), | 322 *key = blink::WebCryptoKey::create(new SymKeyHandle(pk11_sym_key.Pass()), |
| 323 type, extractable, algorithm, usage_mask); | 323 type, extractable, algorithm, usage_mask); |
| 324 return true; | 324 return true; |
| 325 } | 325 } |
| 326 | 326 |
| 327 typedef scoped_ptr_malloc< | 327 typedef scoped_ptr<CERTSubjectPublicKeyInfo, |
| 328 CERTSubjectPublicKeyInfo, | 328 crypto::NSSDestroyer<CERTSubjectPublicKeyInfo, |
| 329 crypto::NSSDestroyer<CERTSubjectPublicKeyInfo, | 329 SECKEY_DestroySubjectPublicKeyInfo> > |
| 330 SECKEY_DestroySubjectPublicKeyInfo> > | |
| 331 ScopedCERTSubjectPublicKeyInfo; | 330 ScopedCERTSubjectPublicKeyInfo; |
| 332 | 331 |
| 332 // Validates an NSS KeyType against a WebCrypto algorithm. Some NSS KeyTypes | |
| 333 // contain enough information to fabricate a Web Crypto algorithm, which is | |
| 334 // returned if the input algorithm isNull(). This function indicates failure by | |
| 335 // returning a Null algorithm. | |
| 336 blink::WebCryptoAlgorithm ResolveNssKeyTypeWithInputAlgorithm( | |
| 337 KeyType key_type, | |
| 338 const blink::WebCryptoAlgorithm& algorithm_or_null) { | |
| 339 switch (key_type) { | |
| 340 case rsaKey: | |
| 341 // NSS's rsaKey KeyType maps to keys with SEC_OID_PKCS1_RSA_ENCRYPTION and | |
| 342 // according to RFC 4055 this can be used for both encryption and | |
|
Ryan Sleevi
2013/11/25 06:59:44
Note the existence of http://tools.ietf.org/html/r
padolph
2013/11/25 23:02:58
Done.
| |
| 343 // signatures. However, this is not specific enough to build a compatible | |
| 344 // Web Crypto algorithm, since in Web Crypto RSA encryption and signature | |
|
Ryan Sleevi
2013/11/25 06:59:44
"since in Web Crypto" -> "since in Web Crypto,"
padolph
2013/11/25 23:02:58
Done.
| |
| 345 // algorithms are distinct. So if the input algorithm isNull() here, we | |
| 346 // have to fail. | |
| 347 if (!algorithm_or_null.isNull() && IsAlgorithmRsa(algorithm_or_null)) | |
| 348 return algorithm_or_null; | |
| 349 break; | |
| 350 case dsaKey: | |
| 351 case ecKey: | |
| 352 case rsaPssKey: | |
| 353 case rsaOaepKey: | |
| 354 // TODO(padolph): Handle other key types. | |
| 355 break; | |
| 356 default: | |
| 357 break; | |
| 358 } | |
| 359 return blink::WebCryptoAlgorithm::createNull(); | |
| 360 } | |
| 361 | |
| 333 bool ImportKeyInternalSpki( | 362 bool ImportKeyInternalSpki( |
| 334 const unsigned char* key_data, | 363 const unsigned char* key_data, |
| 335 unsigned key_data_size, | 364 unsigned key_data_size, |
| 336 const blink::WebCryptoAlgorithm& algorithm_or_null, | 365 const blink::WebCryptoAlgorithm& algorithm_or_null, |
| 337 bool extractable, | 366 bool extractable, |
| 338 blink::WebCryptoKeyUsageMask usage_mask, | 367 blink::WebCryptoKeyUsageMask usage_mask, |
| 339 blink::WebCryptoKey* key) { | 368 blink::WebCryptoKey* key) { |
| 340 | 369 |
| 341 DCHECK(key); | 370 DCHECK(key); |
| 342 | 371 |
| 343 if (!key_data_size) | 372 if (!key_data_size) |
| 344 return false; | 373 return false; |
| 345 | |
| 346 DCHECK(key_data); | 374 DCHECK(key_data); |
| 347 | 375 |
| 348 // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 Subject | 376 // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 Subject |
| 349 // Public Key Info. Decode this to a CERTSubjectPublicKeyInfo. | 377 // Public Key Info. Decode this to a CERTSubjectPublicKeyInfo. |
| 350 SECItem spki_item = { | 378 SECItem spki_item = {siBuffer, const_cast<uint8*>(key_data), key_data_size}; |
| 351 siBuffer, | |
| 352 const_cast<uint8*>(key_data), | |
| 353 key_data_size | |
| 354 }; | |
| 355 const ScopedCERTSubjectPublicKeyInfo spki( | 379 const ScopedCERTSubjectPublicKeyInfo spki( |
| 356 SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item)); | 380 SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item)); |
| 357 if (!spki) | 381 if (!spki) |
| 358 return false; | 382 return false; |
| 359 | 383 |
| 360 crypto::ScopedSECKEYPublicKey sec_public_key( | 384 crypto::ScopedSECKEYPublicKey sec_public_key( |
| 361 SECKEY_ExtractPublicKey(spki.get())); | 385 SECKEY_ExtractPublicKey(spki.get())); |
| 362 if (!sec_public_key) | 386 if (!sec_public_key) |
| 363 return false; | 387 return false; |
| 364 | 388 |
| 365 const KeyType sec_key_type = SECKEY_GetPublicKeyType(sec_public_key.get()); | 389 const KeyType sec_key_type = SECKEY_GetPublicKeyType(sec_public_key.get()); |
| 366 | |
| 367 // Validate the sec_key_type against the input algorithm. Some NSS KeyType's | |
| 368 // contain enough information to fabricate a Web Crypto Algorithm, which will | |
| 369 // be used if the input algorithm isNull(). Others like 'rsaKey' do not (see | |
| 370 // below). | |
| 371 blink::WebCryptoAlgorithm algorithm = | 390 blink::WebCryptoAlgorithm algorithm = |
| 372 blink::WebCryptoAlgorithm::createNull(); | 391 ResolveNssKeyTypeWithInputAlgorithm(sec_key_type, algorithm_or_null); |
| 373 switch (sec_key_type) { | 392 if (algorithm.isNull()) |
| 374 case rsaKey: | 393 return false; |
| 375 // NSS's rsaKey KeyType maps to keys with SEC_OID_PKCS1_RSA_ENCRYPTION and | |
| 376 // according to RFC 4055 this can be used for both encryption and | |
| 377 // signatures. However, this is not specific enough to build a compatible | |
| 378 // Web Crypto algorithm, since in Web Crypto RSA encryption and signature | |
| 379 // algorithms are distinct. So if the input algorithm isNull() here, we | |
| 380 // have to fail. | |
| 381 if (algorithm_or_null.isNull() || !IsAlgorithmRsa(algorithm_or_null)) | |
| 382 return false; | |
| 383 algorithm = algorithm_or_null; | |
| 384 break; | |
| 385 case dsaKey: | |
| 386 case ecKey: | |
| 387 case rsaPssKey: | |
| 388 case rsaOaepKey: | |
| 389 // TODO(padolph): Handle other key types. | |
| 390 return false; | |
| 391 default: | |
| 392 return false; | |
| 393 } | |
| 394 | 394 |
| 395 *key = blink::WebCryptoKey::create( | 395 *key = blink::WebCryptoKey::create( |
| 396 new PublicKeyHandle(sec_public_key.Pass()), | 396 new PublicKeyHandle(sec_public_key.Pass()), |
| 397 blink::WebCryptoKeyTypePublic, | 397 blink::WebCryptoKeyTypePublic, |
| 398 extractable, | 398 extractable, |
| 399 algorithm, | 399 algorithm, |
| 400 usage_mask); | 400 usage_mask); |
| 401 | 401 |
| 402 return true; | 402 return true; |
| 403 } | 403 } |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 422 | 422 |
| 423 DCHECK(spki_der->data); | 423 DCHECK(spki_der->data); |
| 424 DCHECK(spki_der->len); | 424 DCHECK(spki_der->len); |
| 425 | 425 |
| 426 *buffer = blink::WebArrayBuffer::create(spki_der->len, 1); | 426 *buffer = blink::WebArrayBuffer::create(spki_der->len, 1); |
| 427 memcpy(buffer->data(), spki_der->data, spki_der->len); | 427 memcpy(buffer->data(), spki_der->data, spki_der->len); |
| 428 | 428 |
| 429 return true; | 429 return true; |
| 430 } | 430 } |
| 431 | 431 |
| 432 bool ImportKeyInternalPkcs8( | |
| 433 const unsigned char* key_data, | |
| 434 unsigned key_data_size, | |
| 435 const blink::WebCryptoAlgorithm& algorithm_or_null, | |
| 436 bool extractable, | |
| 437 blink::WebCryptoKeyUsageMask usage_mask, | |
| 438 blink::WebCryptoKey* key) { | |
| 439 | |
| 440 DCHECK(key); | |
| 441 | |
| 442 if (!key_data_size) | |
| 443 return false; | |
| 444 DCHECK(key_data); | |
| 445 | |
| 446 // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 PKCS#8 | |
| 447 // private key info object. | |
| 448 SECItem pki_der = {siBuffer, const_cast<uint8*>(key_data), key_data_size}; | |
| 449 | |
| 450 crypto::ScopedPK11Slot slot(PK11_GetInternalKeySlot()); | |
|
Ryan Sleevi
2013/11/25 06:59:44
This should be PK11_GetInternalSlot, not PK11_GetI
padolph
2013/11/25 23:02:58
Done.
| |
| 451 if (!slot) | |
| 452 return false; | |
| 453 | |
| 454 SECKEYPrivateKey* seckey_private_key = NULL; | |
| 455 // TODO(padolph): Verify correct values of isPerm, isPrivate, and usage below. | |
|
Ryan Sleevi
2013/11/25 06:59:44
isPerm/isPrivate is correct. Usage is (probably) w
padolph
2013/11/25 23:02:58
Thanks.
For usage, there are two cases to conside
eroman
2013/11/26 03:40:28
Setting usage to 0 seems like the right approach t
padolph
2013/11/27 03:35:34
Thanks for the guidance. I'll use KU_ALL because i
| |
| 456 if (PK11_ImportDERPrivateKeyInfoAndReturnKey( | |
| 457 slot.get(), | |
|
Ryan Sleevi
2013/11/25 06:59:44
These should all be indented an additional 4 space
padolph
2013/11/25 23:02:58
Done.
| |
| 458 &pki_der, | |
| 459 NULL, | |
| 460 NULL, | |
| 461 false, // isPerm | |
| 462 false, // isPrivate | |
| 463 0, // usage | |
| 464 &seckey_private_key, | |
| 465 NULL) != SECSuccess) { | |
| 466 return false; | |
| 467 } | |
| 468 DCHECK(seckey_private_key); | |
| 469 crypto::ScopedSECKEYPrivateKey private_key(seckey_private_key); | |
| 470 | |
| 471 const KeyType sec_key_type = SECKEY_GetPrivateKeyType(private_key.get()); | |
| 472 blink::WebCryptoAlgorithm algorithm = | |
| 473 ResolveNssKeyTypeWithInputAlgorithm(sec_key_type, algorithm_or_null); | |
| 474 if (algorithm.isNull()) | |
| 475 return false; | |
| 476 | |
| 477 *key = blink::WebCryptoKey::create( | |
| 478 new PrivateKeyHandle(private_key.Pass()), | |
| 479 blink::WebCryptoKeyTypePrivate, | |
| 480 extractable, | |
| 481 algorithm, | |
| 482 usage_mask); | |
| 483 | |
| 484 return true; | |
| 485 } | |
| 486 | |
| 432 } // namespace | 487 } // namespace |
| 433 | 488 |
| 434 void WebCryptoImpl::Init() { | 489 void WebCryptoImpl::Init() { |
| 435 crypto::EnsureNSSInit(); | 490 crypto::EnsureNSSInit(); |
| 436 } | 491 } |
| 437 | 492 |
| 438 bool WebCryptoImpl::EncryptInternal( | 493 bool WebCryptoImpl::EncryptInternal( |
| 439 const blink::WebCryptoAlgorithm& algorithm, | 494 const blink::WebCryptoAlgorithm& algorithm, |
| 440 const blink::WebCryptoKey& key, | 495 const blink::WebCryptoKey& key, |
| 441 const unsigned char* data, | 496 const unsigned char* data, |
| (...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 673 usage_mask, | 728 usage_mask, |
| 674 key); | 729 key); |
| 675 case blink::WebCryptoKeyFormatSpki: | 730 case blink::WebCryptoKeyFormatSpki: |
| 676 return ImportKeyInternalSpki(key_data, | 731 return ImportKeyInternalSpki(key_data, |
| 677 key_data_size, | 732 key_data_size, |
| 678 algorithm_or_null, | 733 algorithm_or_null, |
| 679 extractable, | 734 extractable, |
| 680 usage_mask, | 735 usage_mask, |
| 681 key); | 736 key); |
| 682 case blink::WebCryptoKeyFormatPkcs8: | 737 case blink::WebCryptoKeyFormatPkcs8: |
| 683 // TODO(padolph): Handle PKCS#8 private key import | 738 return ImportKeyInternalPkcs8(key_data, |
| 684 return false; | 739 key_data_size, |
| 740 algorithm_or_null, | |
| 741 extractable, | |
| 742 usage_mask, | |
| 743 key); | |
| 685 default: | 744 default: |
| 745 // NOTE: blink::WebCryptoKeyFormatJwk is handled one level above. | |
| 686 return false; | 746 return false; |
| 687 } | 747 } |
| 688 } | 748 } |
| 689 | 749 |
| 690 bool WebCryptoImpl::ExportKeyInternal( | 750 bool WebCryptoImpl::ExportKeyInternal( |
| 691 blink::WebCryptoKeyFormat format, | 751 blink::WebCryptoKeyFormat format, |
| 692 const blink::WebCryptoKey& key, | 752 const blink::WebCryptoKey& key, |
| 693 blink::WebArrayBuffer* buffer) { | 753 blink::WebArrayBuffer* buffer) { |
| 694 switch (format) { | 754 switch (format) { |
| 695 case blink::WebCryptoKeyFormatRaw: | 755 case blink::WebCryptoKeyFormatRaw: |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 796 break; | 856 break; |
| 797 } | 857 } |
| 798 default: | 858 default: |
| 799 return false; | 859 return false; |
| 800 } | 860 } |
| 801 | 861 |
| 802 return true; | 862 return true; |
| 803 } | 863 } |
| 804 | 864 |
| 805 } // namespace content | 865 } // namespace content |
| OLD | NEW |