• 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 #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                                           &param, &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