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

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

Issue 203753009: [webcrypto] Add PKCS#8 export for RSA private keys for NSS. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 6 years, 9 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 <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/status.h" 17 #include "content/child/webcrypto/status.h"
17 #include "content/child/webcrypto/webcrypto_util.h" 18 #include "content/child/webcrypto/webcrypto_util.h"
18 #include "crypto/nss_util.h" 19 #include "crypto/nss_util.h"
19 #include "crypto/scoped_nss_types.h" 20 #include "crypto/scoped_nss_types.h"
(...skipping 525 matching lines...) Expand 10 before | Expand all | Expand 10 after
545 wrapped_key_item.len) != 0) { 546 wrapped_key_item.len) != 0) {
546 return Status::Error(); 547 return Status::Error();
547 } 548 }
548 // ------- End NSS bug workaround 549 // ------- End NSS bug workaround
549 #endif 550 #endif
550 551
551 *unwrapped_key = new_key.Pass(); 552 *unwrapped_key = new_key.Pass();
552 return Status::Success(); 553 return Status::Success();
553 } 554 }
554 555
556 // From PKCS#1 [http://tools.ietf.org/html/rfc3447]:
557 //
558 // RSAPrivateKey ::= SEQUENCE {
559 // version Version,
560 // modulus INTEGER, -- n
561 // publicExponent INTEGER, -- e
562 // privateExponent INTEGER, -- d
563 // prime1 INTEGER, -- p
564 // prime2 INTEGER, -- q
565 // exponent1 INTEGER, -- d mod (p-1)
566 // exponent2 INTEGER, -- d mod (q-1)
567 // coefficient INTEGER, -- (inverse of q) mod p
568 // otherPrimeInfos OtherPrimeInfos OPTIONAL
569 // }
570 //
571 // Note that otherPrimeInfos is only applicable for version=1. Since NSS
572 // doesn't use multi-prime can safely use version=0.
573 struct RSAPrivateKey {
574 SECItem version;
575 SECItem modulus;
576 SECItem public_exponent;
577 SECItem private_exponent;
578 SECItem prime1;
579 SECItem prime2;
580 SECItem exponent1;
581 SECItem exponent2;
582 SECItem coefficient;
583 };
584
585 const SEC_ASN1Template RSAPrivateKeyTemplate[] = {
586 {SEC_ASN1_SEQUENCE, 0, NULL, sizeof(RSAPrivateKey)},
587 {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, version)},
588 {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, modulus)},
589 {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, public_exponent)},
590 {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, private_exponent)},
591 {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, prime1)},
592 {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, prime2)},
593 {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, exponent1)},
594 {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, exponent2)},
595 {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, coefficient)},
596 {0}};
597
598 // On success |value| will be filled with data which must be freed by
599 // SECITEM_FreeItem(value, PR_FALSE);
600 bool ReadUint(SECKEYPrivateKey* key,
601 CK_ATTRIBUTE_TYPE attribute,
602 SECItem* value) {
603 SECStatus rv = PK11_ReadRawAttribute(PK11_TypePrivKey, key, attribute, value);
604
605 // PK11_ReadRawAttribute() returns items of type siBuffer. However in order
606 // for the ASN.1 encoding to be correct, the items must be of type
607 // siUnsignedInteger.
608 value->type = siUnsignedInteger;
609
610 return rv == SECSuccess;
611 }
612
613 // Fills |out| with the RSA private key properties. Returns true on success.
614 // Regardless of the return value, the caller must invoke FreeRSAPrivateKey()
615 // to free up any allocated memory.
616 //
617 // The passed in RSAPrivateKey must be zero-initialized.
618 bool InitRSAPrivateKey(SECKEYPrivateKey* key, RSAPrivateKey* out) {
619 if (key->keyType != rsaKey)
620 return false;
621
622 // Everything should be zero-ed out. These are just some spot checks.
623 DCHECK(!out->version.data);
624 DCHECK(!out->version.len);
625 DCHECK(!out->modulus.data);
626 DCHECK(!out->modulus.len);
627
628 // Always use version=0 since not using multi-prime.
629 if (!SEC_ASN1EncodeInteger(NULL, &out->version, 0))
630 return false;
631
632 if (!ReadUint(key, CKA_MODULUS, &out->modulus))
633 return false;
634 if (!ReadUint(key, CKA_PUBLIC_EXPONENT, &out->public_exponent))
635 return false;
636 if (!ReadUint(key, CKA_PRIVATE_EXPONENT, &out->private_exponent))
637 return false;
638 if (!ReadUint(key, CKA_PRIME_1, &out->prime1))
639 return false;
640 if (!ReadUint(key, CKA_PRIME_2, &out->prime2))
641 return false;
642 if (!ReadUint(key, CKA_EXPONENT_1, &out->exponent1))
643 return false;
644 if (!ReadUint(key, CKA_EXPONENT_2, &out->exponent2))
645 return false;
646 if (!ReadUint(key, CKA_COEFFICIENT, &out->coefficient))
647 return false;
648
649 return true;
650 }
651
652 struct FreeRsaPrivateKey {
653 void operator()(RSAPrivateKey* out) {
654 SECITEM_FreeItem(&out->version, PR_FALSE);
655 SECITEM_FreeItem(&out->modulus, PR_FALSE);
656 SECITEM_FreeItem(&out->public_exponent, PR_FALSE);
657 SECITEM_FreeItem(&out->private_exponent, PR_FALSE);
658 SECITEM_FreeItem(&out->prime1, PR_FALSE);
659 SECITEM_FreeItem(&out->prime2, PR_FALSE);
660 SECITEM_FreeItem(&out->exponent1, PR_FALSE);
661 SECITEM_FreeItem(&out->exponent2, PR_FALSE);
662 SECITEM_FreeItem(&out->coefficient, PR_FALSE);
663 }
664 };
665
555 } // namespace 666 } // namespace
556 667
557 Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm, 668 Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm,
558 const CryptoData& key_data, 669 const CryptoData& key_data,
559 bool extractable, 670 bool extractable,
560 blink::WebCryptoKeyUsageMask usage_mask, 671 blink::WebCryptoKeyUsageMask usage_mask,
561 blink::WebCryptoKey* key) { 672 blink::WebCryptoKey* key) {
562 673
563 DCHECK(!algorithm.isNull()); 674 DCHECK(!algorithm.isNull());
564 675
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
688 return Status::Error(); 799 return Status::Error();
689 800
690 DCHECK(spki_der->data); 801 DCHECK(spki_der->data);
691 DCHECK(spki_der->len); 802 DCHECK(spki_der->len);
692 803
693 *buffer = CreateArrayBuffer(spki_der->data, spki_der->len); 804 *buffer = CreateArrayBuffer(spki_der->data, spki_der->len);
694 805
695 return Status::Success(); 806 return Status::Success();
696 } 807 }
697 808
809 Status ExportKeyPkcs8(PrivateKey* key,
810 const blink::WebCryptoKeyAlgorithm& key_algorithm,
811 blink::WebArrayBuffer* buffer) {
812 // TODO(eroman): Support other RSA key types as they are added to Blink.
813 if (key_algorithm.id() != blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 &&
814 key_algorithm.id() != blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5)
815 return Status::ErrorUnsupported();
816
817 const SECOidTag algorithm = SEC_OID_PKCS1_RSA_ENCRYPTION;
818 const int kPrivateKeyInfoVersion = 0;
819
820 SECKEYPrivateKeyInfo private_key_info = {};
821 RSAPrivateKey rsa_private_key = {};
822 scoped_ptr<RSAPrivateKey, FreeRsaPrivateKey> free_private_key(
823 &rsa_private_key);
824
825 if (!InitRSAPrivateKey(key->key(), &rsa_private_key))
826 return Status::Error();
827
828 crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
829 if (!arena.get())
830 return Status::Error();
831
832 if (!SEC_ASN1EncodeItem(arena.get(),
833 &private_key_info.privateKey,
834 &rsa_private_key,
835 RSAPrivateKeyTemplate))
836 return Status::Error();
837
838 if (SECSuccess !=
839 SECOID_SetAlgorithmID(
840 arena.get(), &private_key_info.algorithm, algorithm, NULL))
841 return Status::Error();
842
843 if (!SEC_ASN1EncodeInteger(
844 arena.get(), &private_key_info.version, kPrivateKeyInfoVersion))
845 return Status::Error();
846
847 crypto::ScopedSECItem encoded_key(
848 SEC_ASN1EncodeItem(NULL,
849 NULL,
850 &private_key_info,
851 SEC_ASN1_GET(SECKEY_PrivateKeyInfoTemplate)));
852
853 if (!encoded_key.get())
854 return Status::Error();
855
856 *buffer = CreateArrayBuffer(encoded_key->data, encoded_key->len);
857 return Status::Success();
858 }
859
698 Status ImportKeyPkcs8(const blink::WebCryptoAlgorithm& algorithm, 860 Status ImportKeyPkcs8(const blink::WebCryptoAlgorithm& algorithm,
699 const CryptoData& key_data, 861 const CryptoData& key_data,
700 bool extractable, 862 bool extractable,
701 blink::WebCryptoKeyUsageMask usage_mask, 863 blink::WebCryptoKeyUsageMask usage_mask,
702 blink::WebCryptoKey* key) { 864 blink::WebCryptoKey* key) {
703 865
704 DCHECK(key); 866 DCHECK(key);
705 867
706 if (!key_data.byte_length()) 868 if (!key_data.byte_length())
707 return Status::ErrorImportEmptyKeyData(); 869 return Status::ErrorImportEmptyKeyData();
(...skipping 615 matching lines...) Expand 10 before | Expand all | Expand 10 after
1323 key_algorithm, 1485 key_algorithm,
1324 usage_mask); 1486 usage_mask);
1325 return Status::Success(); 1487 return Status::Success();
1326 } 1488 }
1327 1489
1328 } // namespace platform 1490 } // namespace platform
1329 1491
1330 } // namespace webcrypto 1492 } // namespace webcrypto
1331 1493
1332 } // namespace content 1494 } // namespace content
OLDNEW
« no previous file with comments | « content/child/webcrypto/platform_crypto.h ('k') | content/child/webcrypto/platform_crypto_openssl.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698