blob: 083a4374aa9b11d509e230fd4e91a49608c0bd54 [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:1023// Decodes |input| as a SubjectPublicKeyInfo and returns a SECItem containing
24// the CKA_ID of that public key or nullptr on error.
Omar Morsi7294a252020-03-03 10:23:3425ScopedSECItem MakeIDFromSPKI(base::span<const uint8_t> input) {
Pavol Marko701cae52020-05-14 00:17:0326 ScopedCERTSubjectPublicKeyInfo spki = DecodeSubjectPublicKeyInfoNSS(input);
davidben85bad9e2015-05-11 20:20:1027 if (!spki)
28 return nullptr;
29
30 ScopedSECKEYPublicKey result(SECKEY_ExtractPublicKey(spki.get()));
31 if (!result)
32 return nullptr;
33
Omar Morsi7294a252020-03-03 10:23:3434 // See pk11_MakeIDFromPublicKey from NSS. For now, only RSA and EC keys are
davidben85bad9e2015-05-11 20:20:1035 // supported.
Omar Morsi7294a252020-03-03 10:23:3436 if (SECKEY_GetPublicKeyType(result.get()) == rsaKey)
37 return ScopedSECItem(PK11_MakeIDFromPubKey(&result->u.rsa.modulus));
38 if (SECKEY_GetPublicKeyType(result.get()) == ecKey)
39 return ScopedSECItem(PK11_MakeIDFromPubKey(&result->u.ec.publicValue));
40 return nullptr;
davidben85bad9e2015-05-11 20:20:1041}
42
davidben85bad9e2015-05-11 20:20:1043} // namespace
44
45bool GenerateRSAKeyPairNSS(PK11SlotInfo* slot,
46 uint16_t num_bits,
47 bool permanent,
48 ScopedSECKEYPublicKey* public_key,
49 ScopedSECKEYPrivateKey* private_key) {
50 DCHECK(slot);
51
52 PK11RSAGenParams param;
53 param.keySizeInBits = num_bits;
54 param.pe = 65537L;
55 SECKEYPublicKey* public_key_raw = nullptr;
56 private_key->reset(PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN,
57 &param, &public_key_raw, permanent,
58 permanent /* sensitive */, nullptr));
59 if (!*private_key)
60 return false;
61
62 public_key->reset(public_key_raw);
63 return true;
64}
65
Omar Morsi7294a252020-03-03 10:23:3466bool GenerateECKeyPairNSS(PK11SlotInfo* slot,
67 const SECOidTag named_curve,
68 bool permanent,
69 ScopedSECKEYPublicKey* public_key,
70 ScopedSECKEYPrivateKey* private_key) {
71 DCHECK(slot);
72
73 if (named_curve != SEC_OID_ANSIX962_EC_PRIME256V1) {
74 LOG(ERROR) << "SECOidTag: " << named_curve
75 << " is not supported. Only SEC_OID_ANSIX962_EC_PRIME256V1 is "
76 "supported for elliptic curve key pair generation.";
77 return false;
78 }
79
80 SECOidData* oid_data = SECOID_FindOIDByTag(named_curve);
81 if (!oid_data) {
82 LOG(ERROR) << "SECOID_FindOIDByTag: " << PORT_GetError();
83 return false;
84 }
85
86 std::vector<uint8_t> parameters_buf(2 + oid_data->oid.len);
87 SECKEYECParams ec_parameters = {siDEROID, parameters_buf.data(),
88 static_cast<unsigned>(parameters_buf.size())};
89
90 ec_parameters.data[0] = SEC_ASN1_OBJECT_ID;
91 ec_parameters.data[1] = oid_data->oid.len;
92 memcpy(ec_parameters.data + 2, oid_data->oid.data, oid_data->oid.len);
93 SECKEYPublicKey* public_key_raw = nullptr;
94 private_key->reset(PK11_GenerateKeyPair(slot, CKM_EC_KEY_PAIR_GEN,
95 &ec_parameters, &public_key_raw,
96 permanent, permanent, nullptr));
97 if (!*private_key)
98 return false;
99
100 public_key->reset(public_key_raw);
101 return true;
102}
103
davidben85bad9e2015-05-11 20:20:10104ScopedSECKEYPrivateKey ImportNSSKeyFromPrivateKeyInfo(
105 PK11SlotInfo* slot,
106 const std::vector<uint8_t>& input,
107 bool permanent) {
108 DCHECK(slot);
109
110 ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
111 DCHECK(arena);
112
113 // Excess data is illegal, but NSS silently accepts it, so first ensure that
114 // |input| consists of a single ASN.1 element.
115 SECItem input_item;
davidben4507eaa2015-11-19 19:07:06116 input_item.data = const_cast<unsigned char*>(input.data());
davidben85bad9e2015-05-11 20:20:10117 input_item.len = input.size();
118 SECItem der_private_key_info;
119 SECStatus rv =
120 SEC_QuickDERDecodeItem(arena.get(), &der_private_key_info,
121 SEC_ASN1_GET(SEC_AnyTemplate), &input_item);
122 if (rv != SECSuccess)
123 return nullptr;
124
125 // Allow the private key to be used for key unwrapping, data decryption,
126 // and signature generation.
127 const unsigned int key_usage =
128 KU_KEY_ENCIPHERMENT | KU_DATA_ENCIPHERMENT | KU_DIGITAL_SIGNATURE;
129 SECKEYPrivateKey* key_raw = nullptr;
130 rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(
131 slot, &der_private_key_info, nullptr, nullptr, permanent,
132 permanent /* sensitive */, key_usage, &key_raw, nullptr);
133 if (rv != SECSuccess)
134 return nullptr;
135 return ScopedSECKEYPrivateKey(key_raw);
136}
137
davidben85bad9e2015-05-11 20:20:10138ScopedSECKEYPrivateKey FindNSSKeyFromPublicKeyInfo(
Omar Morsi7294a252020-03-03 10:23:34139 base::span<const uint8_t> input) {
davidben85bad9e2015-05-11 20:20:10140 EnsureNSSInit();
141
142 ScopedSECItem cka_id(MakeIDFromSPKI(input));
143 if (!cka_id)
144 return nullptr;
145
146 // Search all slots in all modules for the key with the given ID.
147 AutoSECMODListReadLock auto_lock;
148 const SECMODModuleList* head = SECMOD_GetDefaultModuleList();
149 for (const SECMODModuleList* item = head; item != nullptr;
150 item = item->next) {
151 int slot_count = item->module->loaded ? item->module->slotCount : 0;
152 for (int i = 0; i < slot_count; i++) {
153 // Look for the key in slot |i|.
154 ScopedSECKEYPrivateKey key(
155 PK11_FindKeyByKeyID(item->module->slots[i], cka_id.get(), nullptr));
156 if (key)
dchenge48600452015-12-28 02:24:50157 return key;
davidben85bad9e2015-05-11 20:20:10158 }
159 }
160
161 // The key wasn't found in any module.
162 return nullptr;
163}
164
165ScopedSECKEYPrivateKey FindNSSKeyFromPublicKeyInfoInSlot(
Omar Morsi7294a252020-03-03 10:23:34166 base::span<const uint8_t> input,
davidben85bad9e2015-05-11 20:20:10167 PK11SlotInfo* slot) {
168 DCHECK(slot);
169
170 ScopedSECItem cka_id(MakeIDFromSPKI(input));
171 if (!cka_id)
172 return nullptr;
173
174 return ScopedSECKEYPrivateKey(
175 PK11_FindKeyByKeyID(slot, cka_id.get(), nullptr));
176}
177
Pavol Marko701cae52020-05-14 00:17:03178ScopedCERTSubjectPublicKeyInfo DecodeSubjectPublicKeyInfoNSS(
179 base::span<const uint8_t> input) {
180 // First, decode and save the public key.
181 SECItem key_der;
182 key_der.type = siBuffer;
183 key_der.data = const_cast<unsigned char*>(input.data());
184 key_der.len = input.size();
185
186 ScopedCERTSubjectPublicKeyInfo spki(
187 SECKEY_DecodeDERSubjectPublicKeyInfo(&key_der));
188 return spki;
189}
190
davidben85bad9e2015-05-11 20:20:10191} // namespace crypto