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