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 <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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |