blob: ab948b672d5960727421368364be66cfa74ee740 [file] [log] [blame]
davidben85bad9e2015-05-11 20:20:101// 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>
rsleevia3ad8d02016-06-07 18:22:3310#include <secmod.h>
avidd373b8b2015-12-21 21:34:4311#include <stdint.h>
davidben85bad9e2015-05-11 20:20:1012
thakisd1a18472016-04-08 22:30:4113#include <memory>
14
davidben85bad9e2015-05-11 20:20:1015#include "base/logging.h"
davidben85bad9e2015-05-11 20:20:1016#include "crypto/nss_util.h"
davidben85bad9e2015-05-11 20:20:1017#include "crypto/nss_util_internal.h"
davidben85bad9e2015-05-11 20:20:1018
19namespace crypto {
20
21namespace {
22
davidben85bad9e2015-05-11 20:20:1023struct PublicKeyInfoDeleter {
24 inline void operator()(CERTSubjectPublicKeyInfo* spki) {
25 SECKEY_DestroySubjectPublicKeyInfo(spki);
26 }
27};
28
thakisd1a18472016-04-08 22:30:4129typedef std::unique_ptr<CERTSubjectPublicKeyInfo, PublicKeyInfoDeleter>
davidben85bad9e2015-05-11 20:20:1030 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.
Omar Morsi7294a252020-03-03 10:23:3434ScopedSECItem MakeIDFromSPKI(base::span<const uint8_t> input) {
davidben85bad9e2015-05-11 20:20:1035 // First, decode and save the public key.
36 SECItem key_der;
37 key_der.type = siBuffer;
davidben4507eaa2015-11-19 19:07:0638 key_der.data = const_cast<unsigned char*>(input.data());
davidben85bad9e2015-05-11 20:20:1039 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
Omar Morsi7294a252020-03-03 10:23:3449 // See pk11_MakeIDFromPublicKey from NSS. For now, only RSA and EC keys are
davidben85bad9e2015-05-11 20:20:1050 // supported.
Omar Morsi7294a252020-03-03 10:23:3451 if (SECKEY_GetPublicKeyType(result.get()) == rsaKey)
52 return ScopedSECItem(PK11_MakeIDFromPubKey(&result->u.rsa.modulus));
53 if (SECKEY_GetPublicKeyType(result.get()) == ecKey)
54 return ScopedSECItem(PK11_MakeIDFromPubKey(&result->u.ec.publicValue));
55 return nullptr;
davidben85bad9e2015-05-11 20:20:1056}
57
davidben85bad9e2015-05-11 20:20:1058} // namespace
59
60bool GenerateRSAKeyPairNSS(PK11SlotInfo* slot,
61 uint16_t num_bits,
62 bool permanent,
63 ScopedSECKEYPublicKey* public_key,
64 ScopedSECKEYPrivateKey* private_key) {
65 DCHECK(slot);
66
67 PK11RSAGenParams param;
68 param.keySizeInBits = num_bits;
69 param.pe = 65537L;
70 SECKEYPublicKey* public_key_raw = nullptr;
71 private_key->reset(PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN,
72 &param, &public_key_raw, permanent,
73 permanent /* sensitive */, nullptr));
74 if (!*private_key)
75 return false;
76
77 public_key->reset(public_key_raw);
78 return true;
79}
80
Omar Morsi7294a252020-03-03 10:23:3481bool GenerateECKeyPairNSS(PK11SlotInfo* slot,
82 const SECOidTag named_curve,
83 bool permanent,
84 ScopedSECKEYPublicKey* public_key,
85 ScopedSECKEYPrivateKey* private_key) {
86 DCHECK(slot);
87
88 if (named_curve != SEC_OID_ANSIX962_EC_PRIME256V1) {
89 LOG(ERROR) << "SECOidTag: " << named_curve
90 << " is not supported. Only SEC_OID_ANSIX962_EC_PRIME256V1 is "
91 "supported for elliptic curve key pair generation.";
92 return false;
93 }
94
95 SECOidData* oid_data = SECOID_FindOIDByTag(named_curve);
96 if (!oid_data) {
97 LOG(ERROR) << "SECOID_FindOIDByTag: " << PORT_GetError();
98 return false;
99 }
100
101 std::vector<uint8_t> parameters_buf(2 + oid_data->oid.len);
102 SECKEYECParams ec_parameters = {siDEROID, parameters_buf.data(),
103 static_cast<unsigned>(parameters_buf.size())};
104
105 ec_parameters.data[0] = SEC_ASN1_OBJECT_ID;
106 ec_parameters.data[1] = oid_data->oid.len;
107 memcpy(ec_parameters.data + 2, oid_data->oid.data, oid_data->oid.len);
108 SECKEYPublicKey* public_key_raw = nullptr;
109 private_key->reset(PK11_GenerateKeyPair(slot, CKM_EC_KEY_PAIR_GEN,
110 &ec_parameters, &public_key_raw,
111 permanent, permanent, nullptr));
112 if (!*private_key)
113 return false;
114
115 public_key->reset(public_key_raw);
116 return true;
117}
118
davidben85bad9e2015-05-11 20:20:10119ScopedSECKEYPrivateKey ImportNSSKeyFromPrivateKeyInfo(
120 PK11SlotInfo* slot,
121 const std::vector<uint8_t>& input,
122 bool permanent) {
123 DCHECK(slot);
124
125 ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
126 DCHECK(arena);
127
128 // Excess data is illegal, but NSS silently accepts it, so first ensure that
129 // |input| consists of a single ASN.1 element.
130 SECItem input_item;
davidben4507eaa2015-11-19 19:07:06131 input_item.data = const_cast<unsigned char*>(input.data());
davidben85bad9e2015-05-11 20:20:10132 input_item.len = input.size();
133 SECItem der_private_key_info;
134 SECStatus rv =
135 SEC_QuickDERDecodeItem(arena.get(), &der_private_key_info,
136 SEC_ASN1_GET(SEC_AnyTemplate), &input_item);
137 if (rv != SECSuccess)
138 return nullptr;
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 return ScopedSECKEYPrivateKey(key_raw);
151}
152
davidben85bad9e2015-05-11 20:20:10153ScopedSECKEYPrivateKey FindNSSKeyFromPublicKeyInfo(
Omar Morsi7294a252020-03-03 10:23:34154 base::span<const uint8_t> input) {
davidben85bad9e2015-05-11 20:20:10155 EnsureNSSInit();
156
157 ScopedSECItem cka_id(MakeIDFromSPKI(input));
158 if (!cka_id)
159 return nullptr;
160
161 // Search all slots in all modules for the key with the given ID.
162 AutoSECMODListReadLock auto_lock;
163 const SECMODModuleList* head = SECMOD_GetDefaultModuleList();
164 for (const SECMODModuleList* item = head; item != nullptr;
165 item = item->next) {
166 int slot_count = item->module->loaded ? item->module->slotCount : 0;
167 for (int i = 0; i < slot_count; i++) {
168 // Look for the key in slot |i|.
169 ScopedSECKEYPrivateKey key(
170 PK11_FindKeyByKeyID(item->module->slots[i], cka_id.get(), nullptr));
171 if (key)
dchenge48600452015-12-28 02:24:50172 return key;
davidben85bad9e2015-05-11 20:20:10173 }
174 }
175
176 // The key wasn't found in any module.
177 return nullptr;
178}
179
180ScopedSECKEYPrivateKey FindNSSKeyFromPublicKeyInfoInSlot(
Omar Morsi7294a252020-03-03 10:23:34181 base::span<const uint8_t> input,
davidben85bad9e2015-05-11 20:20:10182 PK11SlotInfo* slot) {
183 DCHECK(slot);
184
185 ScopedSECItem cka_id(MakeIDFromSPKI(input));
186 if (!cka_id)
187 return nullptr;
188
189 return ScopedSECKEYPrivateKey(
190 PK11_FindKeyByKeyID(slot, cka_id.get(), nullptr));
191}
192
davidben85bad9e2015-05-11 20:20:10193} // namespace crypto