nss_key_util.cc revision 24854748fba09df2a29f0d08d558c3acea70e7a1
1// Copyright 2015 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "crypto/nss_key_util.h" 6 7#include <cryptohi.h> 8#include <keyhi.h> 9#include <pk11pub.h> 10#include <stdint.h> 11 12#include "base/logging.h" 13#include "crypto/nss_util.h" 14 15#if defined(USE_NSS_CERTS) 16#include <secmod.h> 17#include "crypto/nss_util_internal.h" 18#endif 19 20namespace crypto { 21 22namespace { 23 24#if defined(USE_NSS_CERTS) 25 26struct PublicKeyInfoDeleter { 27 inline void operator()(CERTSubjectPublicKeyInfo* spki) { 28 SECKEY_DestroySubjectPublicKeyInfo(spki); 29 } 30}; 31 32typedef scoped_ptr<CERTSubjectPublicKeyInfo, PublicKeyInfoDeleter> 33 ScopedPublicKeyInfo; 34 35// Decodes |input| as a SubjectPublicKeyInfo and returns a SECItem containing 36// the CKA_ID of that public key or nullptr on error. 37ScopedSECItem MakeIDFromSPKI(const std::vector<uint8_t>& input) { 38 // First, decode and save the public key. 39 SECItem key_der; 40 key_der.type = siBuffer; 41 key_der.data = const_cast<unsigned char*>(input.data()); 42 key_der.len = input.size(); 43 44 ScopedPublicKeyInfo spki(SECKEY_DecodeDERSubjectPublicKeyInfo(&key_der)); 45 if (!spki) 46 return nullptr; 47 48 ScopedSECKEYPublicKey result(SECKEY_ExtractPublicKey(spki.get())); 49 if (!result) 50 return nullptr; 51 52 // See pk11_MakeIDFromPublicKey from NSS. For now, only RSA keys are 53 // supported. 54 if (SECKEY_GetPublicKeyType(result.get()) != rsaKey) 55 return nullptr; 56 57 return ScopedSECItem(PK11_MakeIDFromPubKey(&result->u.rsa.modulus)); 58} 59 60#endif // defined(USE_NSS_CERTS) 61 62} // namespace 63 64bool GenerateRSAKeyPairNSS(PK11SlotInfo* slot, 65 uint16_t num_bits, 66 bool permanent, 67 ScopedSECKEYPublicKey* public_key, 68 ScopedSECKEYPrivateKey* private_key) { 69 DCHECK(slot); 70 71 PK11RSAGenParams param; 72 param.keySizeInBits = num_bits; 73 param.pe = 65537L; 74 SECKEYPublicKey* public_key_raw = nullptr; 75 private_key->reset(PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN, 76 ¶m, &public_key_raw, permanent, 77 permanent /* sensitive */, nullptr)); 78 if (!*private_key) 79 return false; 80 81 public_key->reset(public_key_raw); 82 return true; 83} 84 85ScopedSECKEYPrivateKey ImportNSSKeyFromPrivateKeyInfo( 86 PK11SlotInfo* slot, 87 const std::vector<uint8_t>& input, 88 bool permanent) { 89 DCHECK(slot); 90 91 ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); 92 DCHECK(arena); 93 94 // Excess data is illegal, but NSS silently accepts it, so first ensure that 95 // |input| consists of a single ASN.1 element. 96 SECItem input_item; 97 input_item.data = const_cast<unsigned char*>(input.data()); 98 input_item.len = input.size(); 99 SECItem der_private_key_info; 100 SECStatus rv = 101 SEC_QuickDERDecodeItem(arena.get(), &der_private_key_info, 102 SEC_ASN1_GET(SEC_AnyTemplate), &input_item); 103 if (rv != SECSuccess) 104 return nullptr; 105 106 // Allow the private key to be used for key unwrapping, data decryption, 107 // and signature generation. 108 const unsigned int key_usage = 109 KU_KEY_ENCIPHERMENT | KU_DATA_ENCIPHERMENT | KU_DIGITAL_SIGNATURE; 110 SECKEYPrivateKey* key_raw = nullptr; 111 rv = PK11_ImportDERPrivateKeyInfoAndReturnKey( 112 slot, &der_private_key_info, nullptr, nullptr, permanent, 113 permanent /* sensitive */, key_usage, &key_raw, nullptr); 114 if (rv != SECSuccess) 115 return nullptr; 116 return ScopedSECKEYPrivateKey(key_raw); 117} 118 119#if defined(USE_NSS_CERTS) 120 121ScopedSECKEYPrivateKey FindNSSKeyFromPublicKeyInfo( 122 const std::vector<uint8_t>& input) { 123 EnsureNSSInit(); 124 125 ScopedSECItem cka_id(MakeIDFromSPKI(input)); 126 if (!cka_id) 127 return nullptr; 128 129 // Search all slots in all modules for the key with the given ID. 130 AutoSECMODListReadLock auto_lock; 131 const SECMODModuleList* head = SECMOD_GetDefaultModuleList(); 132 for (const SECMODModuleList* item = head; item != nullptr; 133 item = item->next) { 134 int slot_count = item->module->loaded ? item->module->slotCount : 0; 135 for (int i = 0; i < slot_count; i++) { 136 // Look for the key in slot |i|. 137 ScopedSECKEYPrivateKey key( 138 PK11_FindKeyByKeyID(item->module->slots[i], cka_id.get(), nullptr)); 139 if (key) 140 return key; 141 } 142 } 143 144 // The key wasn't found in any module. 145 return nullptr; 146} 147 148ScopedSECKEYPrivateKey FindNSSKeyFromPublicKeyInfoInSlot( 149 const std::vector<uint8_t>& input, 150 PK11SlotInfo* slot) { 151 DCHECK(slot); 152 153 ScopedSECItem cka_id(MakeIDFromSPKI(input)); 154 if (!cka_id) 155 return nullptr; 156 157 return ScopedSECKEYPrivateKey( 158 PK11_FindKeyByKeyID(slot, cka_id.get(), nullptr)); 159} 160 161#endif // defined(USE_NSS_CERTS) 162 163} // namespace crypto 164