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