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

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: Remove static 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/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
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
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
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
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