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