1 // Copyright 2015 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
7 #pragma allow_unsafe_buffers
8 #endif
9
10 #include "crypto/nss_key_util.h"
11
12 #include <cryptohi.h>
13 #include <keyhi.h>
14 #include <pk11pub.h>
15 #include <secmod.h>
16 #include <stdint.h>
17
18 #include <memory>
19 #include <vector>
20
21 #include "base/logging.h"
22 #include "crypto/nss_util.h"
23 #include "crypto/nss_util_internal.h"
24
25 namespace crypto {
26
MakeNssIdFromPublicKey(SECKEYPublicKey * public_key)27 crypto::ScopedSECItem MakeNssIdFromPublicKey(SECKEYPublicKey* public_key) {
28 CHECK(public_key);
29
30 // See pk11_MakeIDFromPublicKey from NSS. For now, only RSA and EC public_keys
31 // are supported.
32 if (SECKEY_GetPublicKeyType(public_key) == rsaKey) {
33 return crypto::ScopedSECItem(
34 PK11_MakeIDFromPubKey(&public_key->u.rsa.modulus));
35 }
36 if (SECKEY_GetPublicKeyType(public_key) == ecKey) {
37 return crypto::ScopedSECItem(
38 PK11_MakeIDFromPubKey(&public_key->u.ec.publicValue));
39 }
40 return nullptr;
41 }
42
MakeNssIdFromSpki(base::span<const uint8_t> input)43 ScopedSECItem MakeNssIdFromSpki(base::span<const uint8_t> input) {
44 ScopedCERTSubjectPublicKeyInfo spki = DecodeSubjectPublicKeyInfoNSS(input);
45 if (!spki) {
46 return nullptr;
47 }
48
49 ScopedSECKEYPublicKey public_key(SECKEY_ExtractPublicKey(spki.get()));
50 if (!public_key) {
51 return nullptr;
52 }
53
54 return MakeNssIdFromPublicKey(public_key.get());
55 }
56
GenerateRSAKeyPairNSS(PK11SlotInfo * slot,uint16_t num_bits,bool permanent,ScopedSECKEYPublicKey * public_key,ScopedSECKEYPrivateKey * private_key)57 bool GenerateRSAKeyPairNSS(PK11SlotInfo* slot,
58 uint16_t num_bits,
59 bool permanent,
60 ScopedSECKEYPublicKey* public_key,
61 ScopedSECKEYPrivateKey* private_key) {
62 DCHECK(slot);
63
64 PK11RSAGenParams param;
65 param.keySizeInBits = num_bits;
66 param.pe = 65537L;
67 SECKEYPublicKey* public_key_raw = nullptr;
68 private_key->reset(PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN,
69 ¶m, &public_key_raw, permanent,
70 permanent /* sensitive */, nullptr));
71 if (!*private_key) {
72 return false;
73 }
74
75 public_key->reset(public_key_raw);
76 return true;
77 }
78
GenerateECKeyPairNSS(PK11SlotInfo * slot,const SECOidTag named_curve,bool permanent,ScopedSECKEYPublicKey * public_key,ScopedSECKEYPrivateKey * private_key)79 bool GenerateECKeyPairNSS(PK11SlotInfo* slot,
80 const SECOidTag named_curve,
81 bool permanent,
82 ScopedSECKEYPublicKey* public_key,
83 ScopedSECKEYPrivateKey* private_key) {
84 DCHECK(slot);
85
86 if (named_curve != SEC_OID_ANSIX962_EC_PRIME256V1) {
87 LOG(ERROR) << "SECOidTag: " << named_curve
88 << " is not supported. Only SEC_OID_ANSIX962_EC_PRIME256V1 is "
89 "supported for elliptic curve key pair generation.";
90 return false;
91 }
92
93 SECOidData* oid_data = SECOID_FindOIDByTag(named_curve);
94 if (!oid_data) {
95 LOG(ERROR) << "SECOID_FindOIDByTag: " << PORT_GetError();
96 return false;
97 }
98
99 std::vector<uint8_t> parameters_buf(2 + oid_data->oid.len);
100 SECKEYECParams ec_parameters = {siDEROID, parameters_buf.data(),
101 static_cast<unsigned>(parameters_buf.size())};
102
103 ec_parameters.data[0] = SEC_ASN1_OBJECT_ID;
104 ec_parameters.data[1] = oid_data->oid.len;
105 memcpy(ec_parameters.data + 2, oid_data->oid.data, oid_data->oid.len);
106 SECKEYPublicKey* public_key_raw = nullptr;
107 private_key->reset(PK11_GenerateKeyPair(slot, CKM_EC_KEY_PAIR_GEN,
108 &ec_parameters, &public_key_raw,
109 permanent, permanent, nullptr));
110 if (!*private_key) {
111 return false;
112 }
113
114 public_key->reset(public_key_raw);
115 return true;
116 }
117
ImportNSSKeyFromPrivateKeyInfo(PK11SlotInfo * slot,base::span<const uint8_t> input,bool permanent)118 ScopedSECKEYPrivateKey ImportNSSKeyFromPrivateKeyInfo(
119 PK11SlotInfo* slot,
120 base::span<const uint8_t> input,
121 bool permanent) {
122 DCHECK(slot);
123
124 ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
125 DCHECK(arena);
126
127 // Excess data is illegal, but NSS silently accepts it, so first ensure that
128 // |input| consists of a single ASN.1 element.
129 SECItem input_item;
130 input_item.data = const_cast<unsigned char*>(input.data());
131 input_item.len = input.size();
132 SECItem der_private_key_info;
133 SECStatus rv =
134 SEC_QuickDERDecodeItem(arena.get(), &der_private_key_info,
135 SEC_ASN1_GET(SEC_AnyTemplate), &input_item);
136 if (rv != SECSuccess) {
137 return nullptr;
138 }
139
140 // Allow the private key to be used for key unwrapping, data decryption,
141 // and signature generation.
142 const unsigned int key_usage =
143 KU_KEY_ENCIPHERMENT | KU_DATA_ENCIPHERMENT | KU_DIGITAL_SIGNATURE;
144 SECKEYPrivateKey* key_raw = nullptr;
145 rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(
146 slot, &der_private_key_info, nullptr, nullptr, permanent,
147 permanent /* sensitive */, key_usage, &key_raw, nullptr);
148 if (rv != SECSuccess) {
149 return nullptr;
150 }
151 return ScopedSECKEYPrivateKey(key_raw);
152 }
153
FindNSSKeyFromPublicKeyInfo(base::span<const uint8_t> input)154 ScopedSECKEYPrivateKey FindNSSKeyFromPublicKeyInfo(
155 base::span<const uint8_t> input) {
156 EnsureNSSInit();
157
158 ScopedSECItem cka_id(MakeNssIdFromSpki(input));
159 if (!cka_id) {
160 return nullptr;
161 }
162
163 // Search all slots in all modules for the key with the given ID.
164 AutoSECMODListReadLock auto_lock;
165 const SECMODModuleList* head = SECMOD_GetDefaultModuleList();
166 for (const SECMODModuleList* item = head; item != nullptr;
167 item = item->next) {
168 int slot_count = item->module->loaded ? item->module->slotCount : 0;
169 for (int i = 0; i < slot_count; i++) {
170 // Look for the key in slot |i|.
171 ScopedSECKEYPrivateKey key(
172 PK11_FindKeyByKeyID(item->module->slots[i], cka_id.get(), nullptr));
173 if (key) {
174 return key;
175 }
176 }
177 }
178
179 // The key wasn't found in any module.
180 return nullptr;
181 }
182
FindNSSKeyFromPublicKeyInfoInSlot(base::span<const uint8_t> input,PK11SlotInfo * slot)183 ScopedSECKEYPrivateKey FindNSSKeyFromPublicKeyInfoInSlot(
184 base::span<const uint8_t> input,
185 PK11SlotInfo* slot) {
186 DCHECK(slot);
187
188 ScopedSECItem cka_id(MakeNssIdFromSpki(input));
189 if (!cka_id) {
190 return nullptr;
191 }
192
193 return ScopedSECKEYPrivateKey(
194 PK11_FindKeyByKeyID(slot, cka_id.get(), nullptr));
195 }
196
DecodeSubjectPublicKeyInfoNSS(base::span<const uint8_t> input)197 ScopedCERTSubjectPublicKeyInfo DecodeSubjectPublicKeyInfoNSS(
198 base::span<const uint8_t> input) {
199 // First, decode and save the public key.
200 SECItem key_der;
201 key_der.type = siBuffer;
202 key_der.data = const_cast<unsigned char*>(input.data());
203 key_der.len = input.size();
204
205 ScopedCERTSubjectPublicKeyInfo spki(
206 SECKEY_DecodeDERSubjectPublicKeyInfo(&key_der));
207 return spki;
208 }
209
210 } // namespace crypto
211