Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 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/child/webcrypto/platform_crypto.h" | 5 #include "content/child/webcrypto/platform_crypto.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 #include <secoid.h> | |
| 10 | 11 |
| 11 #include <vector> | 12 #include <vector> |
| 12 | 13 |
| 13 #include "base/lazy_instance.h" | 14 #include "base/lazy_instance.h" |
| 14 #include "base/logging.h" | 15 #include "base/logging.h" |
| 15 #include "content/child/webcrypto/crypto_data.h" | 16 #include "content/child/webcrypto/crypto_data.h" |
| 16 #include "content/child/webcrypto/webcrypto_util.h" | 17 #include "content/child/webcrypto/webcrypto_util.h" |
| 17 #include "crypto/nss_util.h" | 18 #include "crypto/nss_util.h" |
| 18 #include "crypto/scoped_nss_types.h" | 19 #include "crypto/scoped_nss_types.h" |
| 19 #include "third_party/WebKit/public/platform/WebArrayBuffer.h" | 20 #include "third_party/WebKit/public/platform/WebArrayBuffer.h" |
| (...skipping 524 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 544 wrapped_key_item.len) != 0) { | 545 wrapped_key_item.len) != 0) { |
| 545 return Status::Error(); | 546 return Status::Error(); |
| 546 } | 547 } |
| 547 // ------- End NSS bug workaround | 548 // ------- End NSS bug workaround |
| 548 #endif | 549 #endif |
| 549 | 550 |
| 550 *unwrapped_key = new_key.Pass(); | 551 *unwrapped_key = new_key.Pass(); |
| 551 return Status::Success(); | 552 return Status::Success(); |
| 552 } | 553 } |
| 553 | 554 |
| 555 // From PKCS#1 [http://tools.ietf.org/html/rfc3447]: | |
| 556 // | |
| 557 // RSAPrivateKey ::= SEQUENCE { | |
| 558 // version Version, | |
| 559 // modulus INTEGER, -- n | |
| 560 // publicExponent INTEGER, -- e | |
| 561 // privateExponent INTEGER, -- d | |
| 562 // prime1 INTEGER, -- p | |
| 563 // prime2 INTEGER, -- q | |
| 564 // exponent1 INTEGER, -- d mod (p-1) | |
| 565 // exponent2 INTEGER, -- d mod (q-1) | |
| 566 // coefficient INTEGER, -- (inverse of q) mod p | |
| 567 // otherPrimeInfos OtherPrimeInfos OPTIONAL | |
| 568 // } | |
| 569 // | |
| 570 // Note that otherPrimeInfos is only applicable for version=1. Since NSS | |
| 571 // doesn't use multi-prime can safely use version=0. | |
| 572 struct RSAPrivateKey { | |
| 573 SECItem version; | |
| 574 SECItem modulus; | |
| 575 SECItem public_exponent; | |
| 576 SECItem private_exponent; | |
| 577 SECItem prime1; | |
| 578 SECItem prime2; | |
| 579 SECItem exponent1; | |
| 580 SECItem exponent2; | |
| 581 SECItem coefficient; | |
| 582 }; | |
| 583 | |
| 584 const SEC_ASN1Template RSAPrivateKeyTemplate[] = { | |
| 585 {SEC_ASN1_SEQUENCE, 0, NULL, sizeof(RSAPrivateKey)}, | |
| 586 {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, version)}, | |
| 587 {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, modulus)}, | |
| 588 {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, public_exponent)}, | |
| 589 {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, private_exponent)}, | |
| 590 {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, prime1)}, | |
| 591 {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, prime2)}, | |
| 592 {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, exponent1)}, | |
| 593 {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, exponent2)}, | |
| 594 {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, coefficient)}, | |
| 595 {0}}; | |
|
wtc
2014/03/19 23:49:40
Nit: indent the inners by two, not four.
Nit: put
eroman
2014/03/19 23:55:17
We have decided to use clang-format exclusively fo
| |
| 596 | |
| 597 // On success |value| will be filled with data which must be freed by | |
| 598 // SECITEM_FreeItem(value, PR_FALSE); | |
| 599 bool ReadUint(SECKEYPrivateKey* key, | |
| 600 CK_ATTRIBUTE_TYPE attribute, | |
| 601 SECItem* value) { | |
| 602 SECStatus rv = PK11_ReadRawAttribute(PK11_TypePrivKey, key, attribute, value); | |
| 603 | |
| 604 // PK11_ReadRawAttribute() returns items of type siBuffer. However in order | |
| 605 // for the ASN.1 encoding to be correct, the items must be of type | |
| 606 // siUnsignedInteger. | |
| 607 value->type = siUnsignedInteger; | |
| 608 | |
| 609 return rv == SECSuccess; | |
| 610 } | |
| 611 | |
| 612 // Fills |out| with the RSA private key properties. Returns true on success. | |
| 613 // Regardless of the return value, the caller must invoke FreeRSAPrivateKey() | |
| 614 // to free up any allocated memory. | |
| 615 // | |
| 616 // The passed in RSAPrivateKey must be zero-initialized. | |
| 617 bool InitRSAPrivateKey(SECKEYPrivateKey* key, RSAPrivateKey* out) { | |
| 618 if (key->keyType != rsaKey) | |
| 619 return false; | |
| 620 | |
| 621 // Everything should be zero-ed out. These are just some spot checks. | |
| 622 DCHECK(!out->version.data); | |
| 623 DCHECK(!out->version.len); | |
| 624 DCHECK(!out->modulus.data); | |
| 625 DCHECK(!out->modulus.len); | |
| 626 | |
| 627 // Always use version=0 since not using multi-prime. | |
| 628 if (!SEC_ASN1EncodeInteger(NULL, &out->version, 0)) | |
| 629 return false; | |
| 630 | |
| 631 if (!ReadUint(key, CKA_MODULUS, &out->modulus)) | |
| 632 return false; | |
| 633 if (!ReadUint(key, CKA_PUBLIC_EXPONENT, &out->public_exponent)) | |
| 634 return false; | |
| 635 if (!ReadUint(key, CKA_PRIVATE_EXPONENT, &out->private_exponent)) | |
| 636 return false; | |
| 637 if (!ReadUint(key, CKA_PRIME_1, &out->prime1)) | |
| 638 return false; | |
| 639 if (!ReadUint(key, CKA_PRIME_2, &out->prime2)) | |
| 640 return false; | |
| 641 if (!ReadUint(key, CKA_EXPONENT_1, &out->exponent1)) | |
| 642 return false; | |
| 643 if (!ReadUint(key, CKA_EXPONENT_2, &out->exponent2)) | |
| 644 return false; | |
| 645 if (!ReadUint(key, CKA_COEFFICIENT, &out->coefficient)) | |
| 646 return false; | |
| 647 | |
| 648 return true; | |
| 649 } | |
| 650 | |
| 651 struct FreeRsaPrivateKey { | |
| 652 void operator()(RSAPrivateKey* out) { | |
| 653 SECITEM_FreeItem(&out->version, PR_FALSE); | |
| 654 SECITEM_FreeItem(&out->modulus, PR_FALSE); | |
| 655 SECITEM_FreeItem(&out->public_exponent, PR_FALSE); | |
| 656 SECITEM_FreeItem(&out->private_exponent, PR_FALSE); | |
| 657 SECITEM_FreeItem(&out->prime1, PR_FALSE); | |
| 658 SECITEM_FreeItem(&out->prime2, PR_FALSE); | |
| 659 SECITEM_FreeItem(&out->exponent1, PR_FALSE); | |
| 660 SECITEM_FreeItem(&out->exponent2, PR_FALSE); | |
| 661 SECITEM_FreeItem(&out->coefficient, PR_FALSE); | |
| 662 } | |
| 663 }; | |
| 664 | |
| 554 } // namespace | 665 } // namespace |
| 555 | 666 |
| 556 Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm, | 667 Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm, |
| 557 const CryptoData& key_data, | 668 const CryptoData& key_data, |
| 558 bool extractable, | 669 bool extractable, |
| 559 blink::WebCryptoKeyUsageMask usage_mask, | 670 blink::WebCryptoKeyUsageMask usage_mask, |
| 560 blink::WebCryptoKey* key) { | 671 blink::WebCryptoKey* key) { |
| 561 | 672 |
| 562 DCHECK(!algorithm.isNull()); | 673 DCHECK(!algorithm.isNull()); |
| 563 | 674 |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 700 return Status::Error(); | 811 return Status::Error(); |
| 701 | 812 |
| 702 DCHECK(spki_der->data); | 813 DCHECK(spki_der->data); |
| 703 DCHECK(spki_der->len); | 814 DCHECK(spki_der->len); |
| 704 | 815 |
| 705 *buffer = CreateArrayBuffer(spki_der->data, spki_der->len); | 816 *buffer = CreateArrayBuffer(spki_der->data, spki_der->len); |
| 706 | 817 |
| 707 return Status::Success(); | 818 return Status::Success(); |
| 708 } | 819 } |
| 709 | 820 |
| 821 Status ExportKeyPkcs8(PrivateKey* key, | |
| 822 const blink::WebCryptoKeyAlgorithm& key_algorithm, | |
| 823 blink::WebArrayBuffer* buffer) { | |
| 824 // TODO(eroman): Support other RSA key types as they are added to blink. | |
| 825 if (key_algorithm.id() != blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 && | |
| 826 key_algorithm.id() != blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5) | |
| 827 return Status::ErrorUnsupported(); | |
| 828 | |
| 829 const SECOidTag algorithm = SEC_OID_PKCS1_RSA_ENCRYPTION; | |
|
wtc
2014/03/19 23:49:40
Ryan: the NSS function PK11_ExportDERPrivateKeyInf
| |
| 830 const int kPrivateKeyInfoVersion = 0; | |
| 831 | |
| 832 SECKEYPrivateKeyInfo private_key_info = {}; | |
| 833 RSAPrivateKey rsa_private_key = {}; | |
| 834 scoped_ptr<RSAPrivateKey, FreeRsaPrivateKey> free_private_key( | |
| 835 &rsa_private_key); | |
| 836 | |
| 837 if (!InitRSAPrivateKey(key->key(), &rsa_private_key)) | |
| 838 return Status::Error(); | |
| 839 | |
| 840 crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); | |
| 841 if (!arena.get()) | |
| 842 return Status::Error(); | |
| 843 | |
| 844 if (!SEC_ASN1EncodeItem(arena.get(), | |
| 845 &private_key_info.privateKey, | |
| 846 &rsa_private_key, | |
| 847 RSAPrivateKeyTemplate)) | |
| 848 return Status::Error(); | |
| 849 | |
| 850 if (SECSuccess != | |
| 851 SECOID_SetAlgorithmID( | |
| 852 arena.get(), &private_key_info.algorithm, algorithm, NULL)) | |
| 853 return Status::Error(); | |
| 854 | |
| 855 if (!SEC_ASN1EncodeInteger( | |
| 856 arena.get(), &private_key_info.version, kPrivateKeyInfoVersion)) | |
| 857 return Status::Error(); | |
| 858 | |
| 859 crypto::ScopedSECItem encodedKey( | |
|
wtc
2014/03/19 23:49:40
Nit: this variable should be named "encoded_key".
eroman
2014/03/19 23:55:17
Done
| |
| 860 SEC_ASN1EncodeItem(NULL, | |
| 861 NULL, | |
| 862 &private_key_info, | |
| 863 SEC_ASN1_GET(SECKEY_PrivateKeyInfoTemplate))); | |
| 864 | |
| 865 if (!encodedKey.get()) | |
| 866 return Status::Error(); | |
| 867 | |
| 868 *buffer = CreateArrayBuffer(encodedKey->data, encodedKey->len); | |
| 869 return Status::Success(); | |
| 870 } | |
| 871 | |
| 710 Status ImportKeyPkcs8(const blink::WebCryptoAlgorithm& algorithm_or_null, | 872 Status ImportKeyPkcs8(const blink::WebCryptoAlgorithm& algorithm_or_null, |
| 711 const CryptoData& key_data, | 873 const CryptoData& key_data, |
| 712 bool extractable, | 874 bool extractable, |
| 713 blink::WebCryptoKeyUsageMask usage_mask, | 875 blink::WebCryptoKeyUsageMask usage_mask, |
| 714 blink::WebCryptoKey* key) { | 876 blink::WebCryptoKey* key) { |
| 715 | 877 |
| 716 DCHECK(key); | 878 DCHECK(key); |
| 717 | 879 |
| 718 if (!key_data.byte_length()) | 880 if (!key_data.byte_length()) |
| 719 return Status::ErrorImportEmptyKeyData(); | 881 return Status::ErrorImportEmptyKeyData(); |
| (...skipping 617 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1337 key_algorithm, | 1499 key_algorithm, |
| 1338 usage_mask); | 1500 usage_mask); |
| 1339 return Status::Success(); | 1501 return Status::Success(); |
| 1340 } | 1502 } |
| 1341 | 1503 |
| 1342 } // namespace platform | 1504 } // namespace platform |
| 1343 | 1505 |
| 1344 } // namespace webcrypto | 1506 } // namespace webcrypto |
| 1345 | 1507 |
| 1346 } // namespace content | 1508 } // namespace content |
| OLD | NEW |