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 |