Chromium Code Reviews| 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..1deda4f9461a1d4c40c6d45e53b1aaac5f977f9d |
| --- /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 null on error. |
|
Ryan Sleevi
2015/04/27 19:11:27
s/null/nullptr/ (or NULL)
davidben
2015/04/27 19:53:44
Done.
|
| +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]); |
| + 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)); |
| +} |
| + |
| +#endif // defined(USE_NSS_CERTS) |
| + |
| +} // namespace |
| + |
| +bool GenerateRSAKeyPairNSS(PK11SlotInfo* slot, |
| + 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; |
| + ScopedSECKEYPrivateKey private_key(PK11_GenerateKeyPair( |
| + 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( |
| + PK11SlotInfo* slot, |
| + const std::vector<uint8_t>& input, |
| + bool permanent) { |
| + ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); |
| + if (!arena) { |
| + NOTREACHED(); |
| + 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()); |
| + 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; |
| + 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(); |
| + return nullptr; |
| + } |
| + |
| + // Search all slots in all modules for the key with the given ID. |
| + AutoSECMODListReadLock auto_lock; |
| + SECMODModuleList* head = SECMOD_GetDefaultModuleList(); |
| + for (SECMODModuleList* item = head; item != nullptr; item = item->next) { |
| + int slot_count = item->module->loaded ? item->module->slotCount : 0; |
| + 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( |
| + const std::vector<uint8_t>& input, |
| + PK11SlotInfo* slot) { |
| + ScopedSECItem cka_id(MakeIDFromSPKI(input)); |
| + if (!cka_id.get()) { |
|
Ryan Sleevi
2015/04/27 19:11:27
s/.get()//
davidben
2015/04/27 19:53:44
Done.
|
| + NOTREACHED(); |
| + return nullptr; |
| + } |
| + |
| + return ScopedSECKEYPrivateKey( |
| + PK11_FindKeyByKeyID(slot, cka_id.get(), nullptr)); |
| +} |
| + |
| +#endif // defined(USE_NSS_CERTS) |
| + |
| +} // namespace crypto |