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

Side by Side Diff: content/child/webcrypto/platform_crypto_nss.cc

Issue 287133004: [webcrypto] Add JWK import/export of RSA private keys (NSS). (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Add JWK private key import as well. Created 6 years, 7 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
OLDNEW
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 <secerr.h> 9 #include <secerr.h>
10 #include <sechash.h> 10 #include <sechash.h>
(...skipping 578 matching lines...) Expand 10 before | Expand all | Expand 10 after
589 #endif 589 #endif
590 590
591 *unwrapped_key = new_key.Pass(); 591 *unwrapped_key = new_key.Pass();
592 return Status::Success(); 592 return Status::Success();
593 } 593 }
594 594
595 void CopySECItemToVector(const SECItem& item, std::vector<uint8>* out) { 595 void CopySECItemToVector(const SECItem& item, std::vector<uint8>* out) {
596 out->assign(item.data, item.data + item.len); 596 out->assign(item.data, item.data + item.len);
597 } 597 }
598 598
599 // The system NSS library doesn't have the new PK11_ExportDERPrivateKeyInfo
600 // function yet (https://bugzilla.mozilla.org/show_bug.cgi?id=519255). So we
601 // provide a fallback implementation.
602 #if defined(USE_NSS)
603 // From PKCS#1 [http://tools.ietf.org/html/rfc3447]: 599 // From PKCS#1 [http://tools.ietf.org/html/rfc3447]:
604 // 600 //
605 // RSAPrivateKey ::= SEQUENCE { 601 // RSAPrivateKey ::= SEQUENCE {
606 // version Version, 602 // version Version,
607 // modulus INTEGER, -- n 603 // modulus INTEGER, -- n
608 // publicExponent INTEGER, -- e 604 // publicExponent INTEGER, -- e
609 // privateExponent INTEGER, -- d 605 // privateExponent INTEGER, -- d
610 // prime1 INTEGER, -- p 606 // prime1 INTEGER, -- p
611 // prime2 INTEGER, -- q 607 // prime2 INTEGER, -- q
612 // exponent1 INTEGER, -- d mod (p-1) 608 // exponent1 INTEGER, -- d mod (p-1)
613 // exponent2 INTEGER, -- d mod (q-1) 609 // exponent2 INTEGER, -- d mod (q-1)
614 // coefficient INTEGER, -- (inverse of q) mod p 610 // coefficient INTEGER, -- (inverse of q) mod p
615 // otherPrimeInfos OtherPrimeInfos OPTIONAL 611 // otherPrimeInfos OtherPrimeInfos OPTIONAL
616 // } 612 // }
617 // 613 //
618 // Note that otherPrimeInfos is only applicable for version=1. Since NSS 614 // Note that otherPrimeInfos is only applicable for version=1. Since NSS
619 // doesn't use multi-prime can safely use version=0. 615 // doesn't use multi-prime can safely use version=0.
620 struct RSAPrivateKey { 616 struct RSAPrivateKey {
621 SECItem version; 617 SECItem version;
622 SECItem modulus; 618 SECItem modulus;
623 SECItem public_exponent; 619 SECItem public_exponent;
624 SECItem private_exponent; 620 SECItem private_exponent;
625 SECItem prime1; 621 SECItem prime1;
626 SECItem prime2; 622 SECItem prime2;
627 SECItem exponent1; 623 SECItem exponent1;
628 SECItem exponent2; 624 SECItem exponent2;
629 SECItem coefficient; 625 SECItem coefficient;
630 }; 626 };
631 627
628 // The system NSS library doesn't have the new PK11_ExportDERPrivateKeyInfo
629 // function yet (https://bugzilla.mozilla.org/show_bug.cgi?id=519255). So we
630 // provide a fallback implementation.
631 #if defined(USE_NSS)
Ryan Sleevi 2014/05/19 00:10:34 I would prefer a runtime check, rather than the ha
eroman 2014/05/19 18:51:09 Can you explain a bit more? This ifdef is guardin
Ryan Sleevi 2014/05/19 18:59:27 Ah, right, missed that bit. No, this is fine.
632 const SEC_ASN1Template RSAPrivateKeyTemplate[] = { 632 const SEC_ASN1Template RSAPrivateKeyTemplate[] = {
633 {SEC_ASN1_SEQUENCE, 0, NULL, sizeof(RSAPrivateKey)}, 633 {SEC_ASN1_SEQUENCE, 0, NULL, sizeof(RSAPrivateKey)},
634 {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, version)}, 634 {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, version)},
635 {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, modulus)}, 635 {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, modulus)},
636 {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, public_exponent)}, 636 {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, public_exponent)},
637 {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, private_exponent)}, 637 {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, private_exponent)},
638 {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, prime1)}, 638 {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, prime1)},
639 {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, prime2)}, 639 {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, prime2)},
640 {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, exponent1)}, 640 {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, exponent1)},
641 {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, exponent2)}, 641 {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, exponent2)},
642 {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, coefficient)}, 642 {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, coefficient)},
643 {0}}; 643 {0}};
644 #endif // defined(USE_NSS)
644 645
645 // On success |value| will be filled with data which must be freed by 646 // On success |value| will be filled with data which must be freed by
646 // SECITEM_FreeItem(value, PR_FALSE); 647 // SECITEM_FreeItem(value, PR_FALSE);
647 bool ReadUint(SECKEYPrivateKey* key, 648 bool ReadUint(SECKEYPrivateKey* key,
648 CK_ATTRIBUTE_TYPE attribute, 649 CK_ATTRIBUTE_TYPE attribute,
649 SECItem* value) { 650 SECItem* value) {
650 SECStatus rv = PK11_ReadRawAttribute(PK11_TypePrivKey, key, attribute, value); 651 SECStatus rv = PK11_ReadRawAttribute(PK11_TypePrivKey, key, attribute, value);
651 652
652 // PK11_ReadRawAttribute() returns items of type siBuffer. However in order 653 // PK11_ReadRawAttribute() returns items of type siBuffer. However in order
653 // for the ASN.1 encoding to be correct, the items must be of type 654 // for the ASN.1 encoding to be correct, the items must be of type
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
702 SECITEM_FreeItem(&out->modulus, PR_FALSE); 703 SECITEM_FreeItem(&out->modulus, PR_FALSE);
703 SECITEM_FreeItem(&out->public_exponent, PR_FALSE); 704 SECITEM_FreeItem(&out->public_exponent, PR_FALSE);
704 SECITEM_FreeItem(&out->private_exponent, PR_FALSE); 705 SECITEM_FreeItem(&out->private_exponent, PR_FALSE);
705 SECITEM_FreeItem(&out->prime1, PR_FALSE); 706 SECITEM_FreeItem(&out->prime1, PR_FALSE);
706 SECITEM_FreeItem(&out->prime2, PR_FALSE); 707 SECITEM_FreeItem(&out->prime2, PR_FALSE);
707 SECITEM_FreeItem(&out->exponent1, PR_FALSE); 708 SECITEM_FreeItem(&out->exponent1, PR_FALSE);
708 SECITEM_FreeItem(&out->exponent2, PR_FALSE); 709 SECITEM_FreeItem(&out->exponent2, PR_FALSE);
709 SECITEM_FreeItem(&out->coefficient, PR_FALSE); 710 SECITEM_FreeItem(&out->coefficient, PR_FALSE);
710 } 711 }
711 }; 712 };
712 #endif // defined(USE_NSS)
713 713
714 } // namespace 714 } // namespace
715 715
716 class DigestorNSS : public blink::WebCryptoDigestor { 716 class DigestorNSS : public blink::WebCryptoDigestor {
717 public: 717 public:
718 explicit DigestorNSS(blink::WebCryptoAlgorithmId algorithm_id) 718 explicit DigestorNSS(blink::WebCryptoAlgorithmId algorithm_id)
719 : hash_context_(NULL), algorithm_id_(algorithm_id) {} 719 : hash_context_(NULL), algorithm_id_(algorithm_id) {}
720 720
721 virtual ~DigestorNSS() { 721 virtual ~DigestorNSS() {
722 if (!hash_context_) 722 if (!hash_context_)
(...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after
961 DCHECK(key->key()); 961 DCHECK(key->key());
962 if (key->key()->keyType != rsaKey) 962 if (key->key()->keyType != rsaKey)
963 return Status::ErrorUnsupported(); 963 return Status::ErrorUnsupported();
964 CopySECItemToVector(key->key()->u.rsa.modulus, modulus); 964 CopySECItemToVector(key->key()->u.rsa.modulus, modulus);
965 CopySECItemToVector(key->key()->u.rsa.publicExponent, public_exponent); 965 CopySECItemToVector(key->key()->u.rsa.publicExponent, public_exponent);
966 if (modulus->empty() || public_exponent->empty()) 966 if (modulus->empty() || public_exponent->empty())
967 return Status::ErrorUnexpected(); 967 return Status::ErrorUnexpected();
968 return Status::Success(); 968 return Status::Success();
969 } 969 }
970 970
971 void AssignVectorFromSecItem(const SECItem& item, std::vector<uint8>* output) {
972 output->assign(item.data, item.data + item.len);
973 }
974
975 Status ExportRsaPrivateKey(PrivateKey* key,
976 std::vector<uint8>* modulus,
977 std::vector<uint8>* public_exponent,
978 std::vector<uint8>* private_exponent,
979 std::vector<uint8>* prime1,
980 std::vector<uint8>* prime2,
981 std::vector<uint8>* exponent1,
982 std::vector<uint8>* exponent2,
983 std::vector<uint8>* coefficient) {
984 RSAPrivateKey key_props = {};
985 scoped_ptr<RSAPrivateKey, FreeRsaPrivateKey> free_private_key(&key_props);
986
987 if (!InitRSAPrivateKey(key->key(), &key_props))
988 return Status::OperationError();
989
990 AssignVectorFromSecItem(key_props.modulus, modulus);
991 AssignVectorFromSecItem(key_props.public_exponent, public_exponent);
992 AssignVectorFromSecItem(key_props.private_exponent, private_exponent);
993 AssignVectorFromSecItem(key_props.prime1, prime1);
994 AssignVectorFromSecItem(key_props.prime2, prime2);
995 AssignVectorFromSecItem(key_props.exponent1, exponent1);
996 AssignVectorFromSecItem(key_props.exponent2, exponent2);
997 AssignVectorFromSecItem(key_props.coefficient, coefficient);
998
999 return Status::Success();
1000 }
1001
971 Status ExportKeyPkcs8(PrivateKey* key, 1002 Status ExportKeyPkcs8(PrivateKey* key,
972 const blink::WebCryptoKeyAlgorithm& key_algorithm, 1003 const blink::WebCryptoKeyAlgorithm& key_algorithm,
973 std::vector<uint8>* buffer) { 1004 std::vector<uint8>* buffer) {
974 // TODO(eroman): Support other RSA key types as they are added to Blink. 1005 // TODO(eroman): Support other RSA key types as they are added to Blink.
975 if (key_algorithm.id() != blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 && 1006 if (key_algorithm.id() != blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 &&
976 key_algorithm.id() != blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5) 1007 key_algorithm.id() != blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5)
977 return Status::ErrorUnsupported(); 1008 return Status::ErrorUnsupported();
978 1009
979 #if defined(USE_NSS) 1010 #if defined(USE_NSS)
980 // PK11_ExportDERPrivateKeyInfo isn't available. Use our fallback code. 1011 // PK11_ExportDERPrivateKeyInfo isn't available. Use our fallback code.
(...skipping 506 matching lines...) Expand 10 before | Expand all | Expand 10 after
1487 return status; 1518 return status;
1488 1519
1489 *key = blink::WebCryptoKey::create(key_handle.release(), 1520 *key = blink::WebCryptoKey::create(key_handle.release(),
1490 blink::WebCryptoKeyTypePublic, 1521 blink::WebCryptoKeyTypePublic,
1491 extractable, 1522 extractable,
1492 key_algorithm, 1523 key_algorithm,
1493 usage_mask); 1524 usage_mask);
1494 return Status::Success(); 1525 return Status::Success();
1495 } 1526 }
1496 1527
1528 struct DestroyGenericObject {
1529 void operator()(PK11GenericObject* o) const {
1530 if (o)
1531 PK11_DestroyGenericObject(o);
1532 }
1533 };
1534
1535 typedef scoped_ptr<PK11GenericObject, DestroyGenericObject>
1536 ScopedPK11GenericObject;
1537
1538 // Helper to add an attribute to a template.
1539 void AddAttribute(CK_ATTRIBUTE_TYPE type,
1540 void* value,
1541 unsigned long length,
1542 std::vector<CK_ATTRIBUTE>* templ) {
1543 CK_ATTRIBUTE attribute = {type, value, length};
1544 templ->push_back(attribute);
1545 }
1546
1547 // Helper to optionally add an attribute to a template, based on |has_data|.
1548 void AddOptionalAttribute(CK_ATTRIBUTE_TYPE type,
1549 bool has_data,
1550 const CryptoData& data,
1551 std::vector<CK_ATTRIBUTE>* templ) {
1552 if (has_data) {
Ryan Sleevi 2014/05/19 00:10:34 Two thoughts: 1) Short-circuit the error control:
eroman 2014/05/19 18:51:09 I considered this initially, but wasn't sure about
Ryan Sleevi 2014/05/19 18:58:35 This is not correct. It's a valid JWK to have thes
1553 CK_ATTRIBUTE attribute = {type, const_cast<unsigned char*>(data.bytes()),
1554 data.byte_length()};
1555 templ->push_back(attribute);
1556 }
1557 }
1558
1559 Status ImportRsaPrivateKey(const blink::WebCryptoAlgorithm& algorithm,
1560 bool extractable,
1561 blink::WebCryptoKeyUsageMask usage_mask,
1562 const CryptoData& modulus,
1563 const CryptoData& public_exponent,
1564 const CryptoData& private_exponent,
1565 bool has_prime1,
1566 const CryptoData& prime1,
1567 bool has_prime2,
1568 const CryptoData& prime2,
1569 bool has_exponent1,
1570 const CryptoData& exponent1,
1571 bool has_exponent2,
1572 const CryptoData& exponent2,
1573 bool has_coefficient,
1574 const CryptoData& coefficient,
1575 blink::WebCryptoKey* key) {
1576 CK_OBJECT_CLASS obj_class = CKO_PRIVATE_KEY;
1577 CK_KEY_TYPE key_type = CKK_RSA;
1578 CK_BBOOL ck_false = CK_FALSE;
1579
1580 std::vector<CK_ATTRIBUTE> key_template;
1581
1582 AddAttribute(CKA_CLASS, &obj_class, sizeof(obj_class), &key_template);
1583 AddAttribute(CKA_KEY_TYPE, &key_type, sizeof(key_type), &key_template);
1584 AddAttribute(CKA_TOKEN, &ck_false, sizeof(ck_false), &key_template);
1585 AddAttribute(CKA_SENSITIVE, &ck_false, sizeof(ck_false), &key_template);
1586 AddAttribute(CKA_PRIVATE, &ck_false, sizeof(ck_false), &key_template);
1587
1588 // Required properties.
1589 AddOptionalAttribute(CKA_MODULUS, true, modulus, &key_template);
1590 AddOptionalAttribute(
1591 CKA_PUBLIC_EXPONENT, true, public_exponent, &key_template);
1592 AddOptionalAttribute(
1593 CKA_PRIVATE_EXPONENT, true, private_exponent, &key_template);
1594
1595 // Optional properties.
1596 AddOptionalAttribute(CKA_PRIME_1, has_prime1, prime1, &key_template);
1597 AddOptionalAttribute(CKA_PRIME_2, has_prime2, prime2, &key_template);
1598 AddOptionalAttribute(CKA_EXPONENT_1, has_exponent1, exponent1, &key_template);
1599 AddOptionalAttribute(CKA_EXPONENT_2, has_exponent2, exponent2, &key_template);
1600 AddOptionalAttribute(
1601 CKA_COEFFICIENT, has_coefficient, coefficient, &key_template);
1602
1603 crypto::ScopedPK11Slot slot(PK11_GetInternalSlot());
1604
1605 ScopedPK11GenericObject key_object(PK11_CreateGenericObject(
1606 slot.get(), &key_template[0], key_template.size(), PR_FALSE));
1607
1608 if (!key_object)
1609 return Status::OperationError();
1610
1611 SECItem object_id = {};
1612 if (PK11_ReadRawAttribute(
1613 PK11_TypeGeneric, key_object.get(), CKA_ID, &object_id) != SECSuccess)
Ryan Sleevi 2014/05/19 00:10:34 Should document that this isn't guaranteed to be s
eroman 2014/05/19 18:51:09 Done, added comment.
1614 return Status::OperationError();
1615
1616 crypto::ScopedSECKEYPrivateKey private_key(
1617 PK11_FindKeyByKeyID(slot.get(), &object_id, NULL));
1618 if (!private_key)
1619 return Status::OperationError();
1620
1621 blink::WebCryptoKeyAlgorithm key_algorithm;
1622 if (!CreatePrivateKeyAlgorithm(algorithm, private_key.get(), &key_algorithm))
1623 return Status::ErrorUnexpected();
1624
1625 scoped_ptr<PrivateKey> key_handle;
1626 Status status =
1627 PrivateKey::Create(private_key.Pass(), key_algorithm, &key_handle);
1628 if (status.IsError())
1629 return status;
1630
1631 *key = blink::WebCryptoKey::create(key_handle.release(),
1632 blink::WebCryptoKeyTypePrivate,
1633 extractable,
1634 key_algorithm,
1635 usage_mask);
1636 return Status::Success();
1637 }
1638
1497 Status WrapSymKeyAesKw(SymKey* key, 1639 Status WrapSymKeyAesKw(SymKey* key,
1498 SymKey* wrapping_key, 1640 SymKey* wrapping_key,
1499 std::vector<uint8>* buffer) { 1641 std::vector<uint8>* buffer) {
1500 // The data size must be at least 16 bytes and a multiple of 8 bytes. 1642 // The data size must be at least 16 bytes and a multiple of 8 bytes.
1501 // RFC 3394 does not specify a maximum allowed data length, but since only 1643 // RFC 3394 does not specify a maximum allowed data length, but since only
1502 // keys are being wrapped in this application (which are small), a reasonable 1644 // keys are being wrapped in this application (which are small), a reasonable
1503 // max limit is whatever will fit into an unsigned. For the max size test, 1645 // max limit is whatever will fit into an unsigned. For the max size test,
1504 // note that AES Key Wrap always adds 8 bytes to the input data size. 1646 // note that AES Key Wrap always adds 8 bytes to the input data size.
1505 const unsigned int input_length = PK11_GetKeyLength(key->key()); 1647 const unsigned int input_length = PK11_GetKeyLength(key->key());
1506 if (input_length < 16) 1648 if (input_length < 16)
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after
1675 key_algorithm, 1817 key_algorithm,
1676 usage_mask); 1818 usage_mask);
1677 return Status::Success(); 1819 return Status::Success();
1678 } 1820 }
1679 1821
1680 } // namespace platform 1822 } // namespace platform
1681 1823
1682 } // namespace webcrypto 1824 } // namespace webcrypto
1683 1825
1684 } // namespace content 1826 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698