Index: crypto/nss_key_util.cc |
diff --git a/crypto/nss_key_util.cc b/crypto/nss_key_util.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..08912c55615ff29b146a4080b2a5153079dd9ddc |
--- /dev/null |
+++ b/crypto/nss_key_util.cc |
@@ -0,0 +1,169 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "crypto/nss_key_util.h" |
+ |
+#include <cryptohi.h> |
+#include <keyhi.h> |
+#include <pk11pub.h> |
+ |
+#include "base/logging.h" |
+#include "crypto/nss_util.h" |
+ |
+#if defined(USE_NSS_CERTS) |
+#include <secmod.h> |
+#include "crypto/nss_util_internal.h" |
+#endif |
+ |
+namespace crypto { |
+ |
+namespace { |
+ |
+#if defined(USE_NSS_CERTS) |
+ |
+struct PublicKeyInfoDeleter { |
+ inline void operator()(CERTSubjectPublicKeyInfo* spki) { |
+ SECKEY_DestroySubjectPublicKeyInfo(spki); |
+ } |
+}; |
+ |
+typedef scoped_ptr<CERTSubjectPublicKeyInfo, PublicKeyInfoDeleter> |
+ ScopedPublicKeyInfo; |
+ |
+// Decodes |input| as a SubjectPublicKeyInfo and returns a SECItem containing |
+// the CKA_ID of that public key or nullptr on error. |
+ScopedSECItem MakeIDFromSPKI(const std::vector<uint8_t> input) { |
+ // First, decode and save the public key. |
+ SECItem key_der; |
+ key_der.type = siBuffer; |
+ key_der.data = const_cast<unsigned char*>(&input[0]); |
pneubeck (no reviews)
2015/04/28 09:56:26
note that this fails if size is null.
probably (de
davidben
2015/04/28 16:27:46
Done.
|
+ key_der.len = input.size(); |
+ |
+ ScopedPublicKeyInfo spki(SECKEY_DecodeDERSubjectPublicKeyInfo(&key_der)); |
+ if (!spki) |
+ return nullptr; |
+ |
+ ScopedSECKEYPublicKey result(SECKEY_ExtractPublicKey(spki.get())); |
+ if (!result) |
+ return nullptr; |
+ |
+ // See pk11_MakeIDFromPublicKey from NSS. |
+ SECItem* pub_key_index; |
+ switch (SECKEY_GetPublicKeyType(result.get())) { |
+ case rsaKey: |
+ pub_key_index = &result->u.rsa.modulus; |
+ break; |
+ default: |
+ // Unsupported key type. |
+ return nullptr; |
+ } |
+ |
+ return ScopedSECItem(PK11_MakeIDFromPubKey(pub_key_index)); |
pneubeck (no reviews)
2015/04/28 09:56:26
you could move this to line 55 and remove the temp
davidben
2015/04/28 16:27:45
Done.
|
+} |
+ |
+#endif // defined(USE_NSS_CERTS) |
+ |
+} // namespace |
+ |
+bool GenerateRSAKeyPairNSS(PK11SlotInfo* slot, |
pneubeck (no reviews)
2015/04/28 09:56:26
it's unclear (or at least subtle) how PK11_Generat
davidben
2015/04/28 16:27:46
NSS generally checks for NULL inputs (and does her
pneubeck (no reviews)
2015/04/28 16:40:27
That's right. Usually we drop a DCHECK if we are c
|
+ uint16_t num_bits, |
+ bool permanent, |
+ ScopedSECKEYPublicKey* out_public_key, |
+ ScopedSECKEYPrivateKey* out_private_key) { |
+ PK11RSAGenParams param; |
+ param.keySizeInBits = num_bits; |
+ param.pe = 65537L; |
+ SECKEYPublicKey* public_key_raw; |
pneubeck (no reviews)
2015/04/28 09:56:27
should be intialized to nulltpr.
davidben
2015/04/28 16:27:46
Done.
|
+ ScopedSECKEYPrivateKey private_key(PK11_GenerateKeyPair( |
pneubeck (no reviews)
2015/04/28 09:56:26
could directly assign to out_private_key
and renam
davidben
2015/04/28 16:27:45
I prefer explicitly annotating output parameters i
|
+ slot, CKM_RSA_PKCS_KEY_PAIR_GEN, ¶m, &public_key_raw, permanent, |
+ permanent /* sensitive */, nullptr)); |
+ if (!private_key) |
+ return false; |
+ |
+ out_public_key->reset(public_key_raw); |
+ *out_private_key = private_key.Pass(); |
+ return true; |
+} |
+ |
+ScopedSECKEYPrivateKey ImportNSSKeyFromPrivateKeyInfo( |
pneubeck (no reviews)
2015/04/28 09:56:26
i think this function did an EnsureNSSInit before
davidben
2015/04/28 16:27:46
I didn't put in EnsureNSSInit for functions that t
pneubeck (no reviews)
2015/04/28 16:40:27
Acknowledged.
|
+ PK11SlotInfo* slot, |
pneubeck (no reviews)
2015/04/28 09:56:26
ditto, add check for slot
davidben
2015/04/28 16:27:46
Added DCHECK.
|
+ const std::vector<uint8_t>& input, |
+ bool permanent) { |
+ ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); |
+ if (!arena) { |
+ NOTREACHED(); |
pneubeck (no reviews)
2015/04/28 09:56:26
these NOTREACHED (which equals a DCHECK) + return
davidben
2015/04/28 16:27:45
This came from the old code. Invariant is really n
|
+ return nullptr; |
+ } |
+ |
+ // Excess data is illegal, but NSS silently accepts it, so first ensure that |
+ // |input| consists of a single ASN.1 element. |
+ SECItem input_item; |
+ input_item.data = const_cast<unsigned char*>(&input.front()); |
pneubeck (no reviews)
2015/04/28 09:56:26
ditto, fails if input is empty.
davidben
2015/04/28 16:27:46
Done.
|
+ input_item.len = input.size(); |
+ SECItem der_private_key_info; |
+ SECStatus rv = |
+ SEC_QuickDERDecodeItem(arena.get(), &der_private_key_info, |
+ SEC_ASN1_GET(SEC_AnyTemplate), &input_item); |
+ if (rv != SECSuccess) |
+ return nullptr; |
+ |
+ // Allow the private key to be used for key unwrapping, data decryption, |
+ // and signature generation. |
+ const unsigned int key_usage = |
+ KU_KEY_ENCIPHERMENT | KU_DATA_ENCIPHERMENT | KU_DIGITAL_SIGNATURE; |
+ SECKEYPrivateKey* key_raw; |
pneubeck (no reviews)
2015/04/28 09:56:26
should be initialized to nullptr.
davidben
2015/04/28 16:27:45
Done.
|
+ rv = PK11_ImportDERPrivateKeyInfoAndReturnKey( |
+ slot, &der_private_key_info, nullptr, nullptr, permanent, |
+ permanent /* sensitive */, key_usage, &key_raw, nullptr); |
+ if (rv != SECSuccess) |
+ return nullptr; |
+ return ScopedSECKEYPrivateKey(key_raw); |
+} |
+ |
+#if defined(USE_NSS_CERTS) |
+ |
+ScopedSECKEYPrivateKey FindNSSKeyFromPublicKeyInfo( |
+ const std::vector<uint8_t>& input) { |
+ EnsureNSSInit(); |
+ |
+ ScopedSECItem cka_id(MakeIDFromSPKI(input)); |
+ if (!cka_id) { |
+ NOTREACHED(); |
pneubeck (no reviews)
2015/04/28 09:56:26
ditto, wrong NOTREACHED
davidben
2015/04/28 16:27:45
Removed the NOTREACHED. I probably got it from the
|
+ return nullptr; |
+ } |
+ |
+ // Search all slots in all modules for the key with the given ID. |
+ AutoSECMODListReadLock auto_lock; |
+ SECMODModuleList* head = SECMOD_GetDefaultModuleList(); |
pneubeck (no reviews)
2015/04/28 09:56:26
+ const
davidben
2015/04/28 16:27:45
Done.
|
+ for (SECMODModuleList* item = head; item != nullptr; item = item->next) { |
+ int slot_count = item->module->loaded ? item->module->slotCount : 0; |
pneubeck (no reviews)
2015/04/28 09:56:26
+ const
davidben
2015/04/28 16:27:46
I'm assume this meant to be the previous line? Don
pneubeck (no reviews)
2015/04/28 16:40:27
then both lines ;-)
davidben
2015/04/29 21:51:32
Do you mean the local variable? I didn't think we
pneubeck (no reviews)
2015/04/30 07:45:55
Yes.
|
+ for (int i = 0; i < slot_count; i++) { |
+ // Look for the key in slot |i|. |
+ ScopedSECKEYPrivateKey key( |
+ PK11_FindKeyByKeyID(item->module->slots[i], cka_id.get(), nullptr)); |
+ if (key) |
+ return key.Pass(); |
+ } |
+ } |
+ |
+ // The key wasn't found in any module. |
+ return nullptr; |
+} |
+ |
+ScopedSECKEYPrivateKey FindNSSKeyFromPublicKeyInfoInSlot( |
pneubeck (no reviews)
2015/04/28 09:56:26
i think this function did an EnsureNSSInit before
davidben
2015/04/28 16:27:46
Ditto about slot parameter.
|
+ const std::vector<uint8_t>& input, |
+ PK11SlotInfo* slot) { |
pneubeck (no reviews)
2015/04/28 09:56:26
ditto, add check for slot
davidben
2015/04/28 16:27:45
Done.
|
+ ScopedSECItem cka_id(MakeIDFromSPKI(input)); |
+ if (!cka_id) { |
+ NOTREACHED(); |
pneubeck (no reviews)
2015/04/28 09:56:26
ditto, wrong NOTREACHED
davidben
2015/04/28 16:27:45
Done.
|
+ return nullptr; |
+ } |
+ |
+ return ScopedSECKEYPrivateKey( |
+ PK11_FindKeyByKeyID(slot, cka_id.get(), nullptr)); |
+} |
+ |
+#endif // defined(USE_NSS_CERTS) |
+ |
+} // namespace crypto |