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 
20 namespace crypto {
21 
22 namespace {
23 
24 #if defined(USE_NSS_CERTS)
25 
26 struct PublicKeyInfoDeleter {
operator ()crypto::__anone823ca920111::PublicKeyInfoDeleter27   inline void operator()(CERTSubjectPublicKeyInfo* spki) {
28     SECKEY_DestroySubjectPublicKeyInfo(spki);
29   }
30 };
31 
32 typedef 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.
MakeIDFromSPKI(const std::vector<uint8_t> & input)37 ScopedSECItem 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 
GenerateRSAKeyPairNSS(PK11SlotInfo * slot,uint16_t num_bits,bool permanent,ScopedSECKEYPublicKey * public_key,ScopedSECKEYPrivateKey * private_key)64 bool 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                                           &param, &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 
ImportNSSKeyFromPrivateKeyInfo(PK11SlotInfo * slot,const std::vector<uint8_t> & input,bool permanent)85 ScopedSECKEYPrivateKey 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 
FindNSSKeyFromPublicKeyInfo(const std::vector<uint8_t> & input)121 ScopedSECKEYPrivateKey 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 
FindNSSKeyFromPublicKeyInfoInSlot(const std::vector<uint8_t> & input,PK11SlotInfo * slot)148 ScopedSECKEYPrivateKey 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