// Copyright 2015 The Chromium Authors // 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 #include #include #include #include #include #include "base/logging.h" #include "crypto/nss_util.h" #include "crypto/nss_util_internal.h" namespace crypto { namespace { // Decodes |input| as a SubjectPublicKeyInfo and returns a SECItem containing // the CKA_ID of that public key or nullptr on error. ScopedSECItem MakeIDFromSPKI(base::span input) { ScopedCERTSubjectPublicKeyInfo spki = DecodeSubjectPublicKeyInfoNSS(input); if (!spki) return nullptr; ScopedSECKEYPublicKey result(SECKEY_ExtractPublicKey(spki.get())); if (!result) return nullptr; // See pk11_MakeIDFromPublicKey from NSS. For now, only RSA and EC keys are // supported. if (SECKEY_GetPublicKeyType(result.get()) == rsaKey) return ScopedSECItem(PK11_MakeIDFromPubKey(&result->u.rsa.modulus)); if (SECKEY_GetPublicKeyType(result.get()) == ecKey) return ScopedSECItem(PK11_MakeIDFromPubKey(&result->u.ec.publicValue)); return nullptr; } } // 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; } bool GenerateECKeyPairNSS(PK11SlotInfo* slot, const SECOidTag named_curve, bool permanent, ScopedSECKEYPublicKey* public_key, ScopedSECKEYPrivateKey* private_key) { DCHECK(slot); if (named_curve != SEC_OID_ANSIX962_EC_PRIME256V1) { LOG(ERROR) << "SECOidTag: " << named_curve << " is not supported. Only SEC_OID_ANSIX962_EC_PRIME256V1 is " "supported for elliptic curve key pair generation."; return false; } SECOidData* oid_data = SECOID_FindOIDByTag(named_curve); if (!oid_data) { LOG(ERROR) << "SECOID_FindOIDByTag: " << PORT_GetError(); return false; } std::vector parameters_buf(2 + oid_data->oid.len); SECKEYECParams ec_parameters = {siDEROID, parameters_buf.data(), static_cast(parameters_buf.size())}; ec_parameters.data[0] = SEC_ASN1_OBJECT_ID; ec_parameters.data[1] = oid_data->oid.len; memcpy(ec_parameters.data + 2, oid_data->oid.data, oid_data->oid.len); SECKEYPublicKey* public_key_raw = nullptr; private_key->reset(PK11_GenerateKeyPair(slot, CKM_EC_KEY_PAIR_GEN, &ec_parameters, &public_key_raw, permanent, permanent, nullptr)); if (!*private_key) return false; public_key->reset(public_key_raw); return true; } ScopedSECKEYPrivateKey ImportNSSKeyFromPrivateKeyInfo( PK11SlotInfo* slot, const std::vector& 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(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( base::span 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( base::span input, PK11SlotInfo* slot) { DCHECK(slot); ScopedSECItem cka_id(MakeIDFromSPKI(input)); if (!cka_id) return nullptr; return ScopedSECKEYPrivateKey( PK11_FindKeyByKeyID(slot, cka_id.get(), nullptr)); } ScopedCERTSubjectPublicKeyInfo DecodeSubjectPublicKeyInfoNSS( base::span input) { // First, decode and save the public key. SECItem key_der; key_der.type = siBuffer; key_der.data = const_cast(input.data()); key_der.len = input.size(); ScopedCERTSubjectPublicKeyInfo spki( SECKEY_DecodeDERSubjectPublicKeyInfo(&key_der)); return spki; } } // namespace crypto