You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
155 lines
4.6 KiB
155 lines
4.6 KiB
// 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 <secmod.h>
|
|
#include <stdint.h>
|
|
|
|
#include <memory>
|
|
|
|
#include "base/logging.h"
|
|
#include "crypto/nss_util.h"
|
|
#include "crypto/nss_util_internal.h"
|
|
|
|
namespace crypto {
|
|
|
|
namespace {
|
|
|
|
struct PublicKeyInfoDeleter {
|
|
inline void operator()(CERTSubjectPublicKeyInfo* spki) {
|
|
SECKEY_DestroySubjectPublicKeyInfo(spki);
|
|
}
|
|
};
|
|
|
|
typedef std::unique_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.data());
|
|
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. For now, only RSA keys are
|
|
// supported.
|
|
if (SECKEY_GetPublicKeyType(result.get()) != rsaKey)
|
|
return nullptr;
|
|
|
|
return ScopedSECItem(PK11_MakeIDFromPubKey(&result->u.rsa.modulus));
|
|
}
|
|
|
|
} // namespace
|
|
|
|
bool GenerateRSAKeyPairNSS(PK11SlotInfo* slot,
|
|
uint16_t num_bits,
|
|
bool permanent,
|
|
ScopedSECKEYPublicKey* public_key,
|
|
ScopedSECKEYPrivateKey* private_key) {
|
|
DCHECK(slot);
|
|
|
|
PK11RSAGenParams param;
|
|
param.keySizeInBits = num_bits;
|
|
param.pe = 65537L;
|
|
SECKEYPublicKey* public_key_raw = nullptr;
|
|
private_key->reset(PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN,
|
|
¶m, &public_key_raw, permanent,
|
|
permanent /* sensitive */, nullptr));
|
|
if (!*private_key)
|
|
return false;
|
|
|
|
public_key->reset(public_key_raw);
|
|
return true;
|
|
}
|
|
|
|
ScopedSECKEYPrivateKey ImportNSSKeyFromPrivateKeyInfo(
|
|
PK11SlotInfo* slot,
|
|
const std::vector<uint8_t>& input,
|
|
bool permanent) {
|
|
DCHECK(slot);
|
|
|
|
ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
|
|
DCHECK(arena);
|
|
|
|
// 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.data());
|
|
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 = nullptr;
|
|
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);
|
|
}
|
|
|
|
ScopedSECKEYPrivateKey FindNSSKeyFromPublicKeyInfo(
|
|
const std::vector<uint8_t>& input) {
|
|
EnsureNSSInit();
|
|
|
|
ScopedSECItem cka_id(MakeIDFromSPKI(input));
|
|
if (!cka_id)
|
|
return nullptr;
|
|
|
|
// Search all slots in all modules for the key with the given ID.
|
|
AutoSECMODListReadLock auto_lock;
|
|
const SECMODModuleList* head = SECMOD_GetDefaultModuleList();
|
|
for (const 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;
|
|
}
|
|
}
|
|
|
|
// The key wasn't found in any module.
|
|
return nullptr;
|
|
}
|
|
|
|
ScopedSECKEYPrivateKey FindNSSKeyFromPublicKeyInfoInSlot(
|
|
const std::vector<uint8_t>& input,
|
|
PK11SlotInfo* slot) {
|
|
DCHECK(slot);
|
|
|
|
ScopedSECItem cka_id(MakeIDFromSPKI(input));
|
|
if (!cka_id)
|
|
return nullptr;
|
|
|
|
return ScopedSECKEYPrivateKey(
|
|
PK11_FindKeyByKeyID(slot, cka_id.get(), nullptr));
|
|
}
|
|
|
|
} // namespace crypto
|