xref: /aosp_15_r20/external/libchrome/crypto/nss_key_util.cc (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
1*635a8641SAndroid Build Coastguard Worker // Copyright 2015 The Chromium Authors. All rights reserved.
2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file.
4*635a8641SAndroid Build Coastguard Worker 
5*635a8641SAndroid Build Coastguard Worker #include "crypto/nss_key_util.h"
6*635a8641SAndroid Build Coastguard Worker 
7*635a8641SAndroid Build Coastguard Worker #include <cryptohi.h>
8*635a8641SAndroid Build Coastguard Worker #include <keyhi.h>
9*635a8641SAndroid Build Coastguard Worker #include <pk11pub.h>
10*635a8641SAndroid Build Coastguard Worker #include <secmod.h>
11*635a8641SAndroid Build Coastguard Worker #include <stdint.h>
12*635a8641SAndroid Build Coastguard Worker 
13*635a8641SAndroid Build Coastguard Worker #include <memory>
14*635a8641SAndroid Build Coastguard Worker 
15*635a8641SAndroid Build Coastguard Worker #include "base/logging.h"
16*635a8641SAndroid Build Coastguard Worker #include "crypto/nss_util.h"
17*635a8641SAndroid Build Coastguard Worker #include "crypto/nss_util_internal.h"
18*635a8641SAndroid Build Coastguard Worker 
19*635a8641SAndroid Build Coastguard Worker namespace crypto {
20*635a8641SAndroid Build Coastguard Worker 
21*635a8641SAndroid Build Coastguard Worker namespace {
22*635a8641SAndroid Build Coastguard Worker 
23*635a8641SAndroid Build Coastguard Worker struct PublicKeyInfoDeleter {
operator ()crypto::__anonb64bfa880111::PublicKeyInfoDeleter24*635a8641SAndroid Build Coastguard Worker   inline void operator()(CERTSubjectPublicKeyInfo* spki) {
25*635a8641SAndroid Build Coastguard Worker     SECKEY_DestroySubjectPublicKeyInfo(spki);
26*635a8641SAndroid Build Coastguard Worker   }
27*635a8641SAndroid Build Coastguard Worker };
28*635a8641SAndroid Build Coastguard Worker 
29*635a8641SAndroid Build Coastguard Worker typedef std::unique_ptr<CERTSubjectPublicKeyInfo, PublicKeyInfoDeleter>
30*635a8641SAndroid Build Coastguard Worker     ScopedPublicKeyInfo;
31*635a8641SAndroid Build Coastguard Worker 
32*635a8641SAndroid Build Coastguard Worker // Decodes |input| as a SubjectPublicKeyInfo and returns a SECItem containing
33*635a8641SAndroid Build Coastguard Worker // the CKA_ID of that public key or nullptr on error.
MakeIDFromSPKI(const std::vector<uint8_t> & input)34*635a8641SAndroid Build Coastguard Worker ScopedSECItem MakeIDFromSPKI(const std::vector<uint8_t>& input) {
35*635a8641SAndroid Build Coastguard Worker   // First, decode and save the public key.
36*635a8641SAndroid Build Coastguard Worker   SECItem key_der;
37*635a8641SAndroid Build Coastguard Worker   key_der.type = siBuffer;
38*635a8641SAndroid Build Coastguard Worker   key_der.data = const_cast<unsigned char*>(input.data());
39*635a8641SAndroid Build Coastguard Worker   key_der.len = input.size();
40*635a8641SAndroid Build Coastguard Worker 
41*635a8641SAndroid Build Coastguard Worker   ScopedPublicKeyInfo spki(SECKEY_DecodeDERSubjectPublicKeyInfo(&key_der));
42*635a8641SAndroid Build Coastguard Worker   if (!spki)
43*635a8641SAndroid Build Coastguard Worker     return nullptr;
44*635a8641SAndroid Build Coastguard Worker 
45*635a8641SAndroid Build Coastguard Worker   ScopedSECKEYPublicKey result(SECKEY_ExtractPublicKey(spki.get()));
46*635a8641SAndroid Build Coastguard Worker   if (!result)
47*635a8641SAndroid Build Coastguard Worker     return nullptr;
48*635a8641SAndroid Build Coastguard Worker 
49*635a8641SAndroid Build Coastguard Worker   // See pk11_MakeIDFromPublicKey from NSS. For now, only RSA keys are
50*635a8641SAndroid Build Coastguard Worker   // supported.
51*635a8641SAndroid Build Coastguard Worker   if (SECKEY_GetPublicKeyType(result.get()) != rsaKey)
52*635a8641SAndroid Build Coastguard Worker     return nullptr;
53*635a8641SAndroid Build Coastguard Worker 
54*635a8641SAndroid Build Coastguard Worker   return ScopedSECItem(PK11_MakeIDFromPubKey(&result->u.rsa.modulus));
55*635a8641SAndroid Build Coastguard Worker }
56*635a8641SAndroid Build Coastguard Worker 
57*635a8641SAndroid Build Coastguard Worker }  // namespace
58*635a8641SAndroid Build Coastguard Worker 
GenerateRSAKeyPairNSS(PK11SlotInfo * slot,uint16_t num_bits,bool permanent,ScopedSECKEYPublicKey * public_key,ScopedSECKEYPrivateKey * private_key)59*635a8641SAndroid Build Coastguard Worker bool GenerateRSAKeyPairNSS(PK11SlotInfo* slot,
60*635a8641SAndroid Build Coastguard Worker                            uint16_t num_bits,
61*635a8641SAndroid Build Coastguard Worker                            bool permanent,
62*635a8641SAndroid Build Coastguard Worker                            ScopedSECKEYPublicKey* public_key,
63*635a8641SAndroid Build Coastguard Worker                            ScopedSECKEYPrivateKey* private_key) {
64*635a8641SAndroid Build Coastguard Worker   DCHECK(slot);
65*635a8641SAndroid Build Coastguard Worker 
66*635a8641SAndroid Build Coastguard Worker   PK11RSAGenParams param;
67*635a8641SAndroid Build Coastguard Worker   param.keySizeInBits = num_bits;
68*635a8641SAndroid Build Coastguard Worker   param.pe = 65537L;
69*635a8641SAndroid Build Coastguard Worker   SECKEYPublicKey* public_key_raw = nullptr;
70*635a8641SAndroid Build Coastguard Worker   private_key->reset(PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN,
71*635a8641SAndroid Build Coastguard Worker                                           &param, &public_key_raw, permanent,
72*635a8641SAndroid Build Coastguard Worker                                           permanent /* sensitive */, nullptr));
73*635a8641SAndroid Build Coastguard Worker   if (!*private_key)
74*635a8641SAndroid Build Coastguard Worker     return false;
75*635a8641SAndroid Build Coastguard Worker 
76*635a8641SAndroid Build Coastguard Worker   public_key->reset(public_key_raw);
77*635a8641SAndroid Build Coastguard Worker   return true;
78*635a8641SAndroid Build Coastguard Worker }
79*635a8641SAndroid Build Coastguard Worker 
ImportNSSKeyFromPrivateKeyInfo(PK11SlotInfo * slot,const std::vector<uint8_t> & input,bool permanent)80*635a8641SAndroid Build Coastguard Worker ScopedSECKEYPrivateKey ImportNSSKeyFromPrivateKeyInfo(
81*635a8641SAndroid Build Coastguard Worker     PK11SlotInfo* slot,
82*635a8641SAndroid Build Coastguard Worker     const std::vector<uint8_t>& input,
83*635a8641SAndroid Build Coastguard Worker     bool permanent) {
84*635a8641SAndroid Build Coastguard Worker   DCHECK(slot);
85*635a8641SAndroid Build Coastguard Worker 
86*635a8641SAndroid Build Coastguard Worker   ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
87*635a8641SAndroid Build Coastguard Worker   DCHECK(arena);
88*635a8641SAndroid Build Coastguard Worker 
89*635a8641SAndroid Build Coastguard Worker   // Excess data is illegal, but NSS silently accepts it, so first ensure that
90*635a8641SAndroid Build Coastguard Worker   // |input| consists of a single ASN.1 element.
91*635a8641SAndroid Build Coastguard Worker   SECItem input_item;
92*635a8641SAndroid Build Coastguard Worker   input_item.data = const_cast<unsigned char*>(input.data());
93*635a8641SAndroid Build Coastguard Worker   input_item.len = input.size();
94*635a8641SAndroid Build Coastguard Worker   SECItem der_private_key_info;
95*635a8641SAndroid Build Coastguard Worker   SECStatus rv =
96*635a8641SAndroid Build Coastguard Worker       SEC_QuickDERDecodeItem(arena.get(), &der_private_key_info,
97*635a8641SAndroid Build Coastguard Worker                              SEC_ASN1_GET(SEC_AnyTemplate), &input_item);
98*635a8641SAndroid Build Coastguard Worker   if (rv != SECSuccess)
99*635a8641SAndroid Build Coastguard Worker     return nullptr;
100*635a8641SAndroid Build Coastguard Worker 
101*635a8641SAndroid Build Coastguard Worker   // Allow the private key to be used for key unwrapping, data decryption,
102*635a8641SAndroid Build Coastguard Worker   // and signature generation.
103*635a8641SAndroid Build Coastguard Worker   const unsigned int key_usage =
104*635a8641SAndroid Build Coastguard Worker       KU_KEY_ENCIPHERMENT | KU_DATA_ENCIPHERMENT | KU_DIGITAL_SIGNATURE;
105*635a8641SAndroid Build Coastguard Worker   SECKEYPrivateKey* key_raw = nullptr;
106*635a8641SAndroid Build Coastguard Worker   rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(
107*635a8641SAndroid Build Coastguard Worker       slot, &der_private_key_info, nullptr, nullptr, permanent,
108*635a8641SAndroid Build Coastguard Worker       permanent /* sensitive */, key_usage, &key_raw, nullptr);
109*635a8641SAndroid Build Coastguard Worker   if (rv != SECSuccess)
110*635a8641SAndroid Build Coastguard Worker     return nullptr;
111*635a8641SAndroid Build Coastguard Worker   return ScopedSECKEYPrivateKey(key_raw);
112*635a8641SAndroid Build Coastguard Worker }
113*635a8641SAndroid Build Coastguard Worker 
FindNSSKeyFromPublicKeyInfo(const std::vector<uint8_t> & input)114*635a8641SAndroid Build Coastguard Worker ScopedSECKEYPrivateKey FindNSSKeyFromPublicKeyInfo(
115*635a8641SAndroid Build Coastguard Worker     const std::vector<uint8_t>& input) {
116*635a8641SAndroid Build Coastguard Worker   EnsureNSSInit();
117*635a8641SAndroid Build Coastguard Worker 
118*635a8641SAndroid Build Coastguard Worker   ScopedSECItem cka_id(MakeIDFromSPKI(input));
119*635a8641SAndroid Build Coastguard Worker   if (!cka_id)
120*635a8641SAndroid Build Coastguard Worker     return nullptr;
121*635a8641SAndroid Build Coastguard Worker 
122*635a8641SAndroid Build Coastguard Worker   // Search all slots in all modules for the key with the given ID.
123*635a8641SAndroid Build Coastguard Worker   AutoSECMODListReadLock auto_lock;
124*635a8641SAndroid Build Coastguard Worker   const SECMODModuleList* head = SECMOD_GetDefaultModuleList();
125*635a8641SAndroid Build Coastguard Worker   for (const SECMODModuleList* item = head; item != nullptr;
126*635a8641SAndroid Build Coastguard Worker        item = item->next) {
127*635a8641SAndroid Build Coastguard Worker     int slot_count = item->module->loaded ? item->module->slotCount : 0;
128*635a8641SAndroid Build Coastguard Worker     for (int i = 0; i < slot_count; i++) {
129*635a8641SAndroid Build Coastguard Worker       // Look for the key in slot |i|.
130*635a8641SAndroid Build Coastguard Worker       ScopedSECKEYPrivateKey key(
131*635a8641SAndroid Build Coastguard Worker           PK11_FindKeyByKeyID(item->module->slots[i], cka_id.get(), nullptr));
132*635a8641SAndroid Build Coastguard Worker       if (key)
133*635a8641SAndroid Build Coastguard Worker         return key;
134*635a8641SAndroid Build Coastguard Worker     }
135*635a8641SAndroid Build Coastguard Worker   }
136*635a8641SAndroid Build Coastguard Worker 
137*635a8641SAndroid Build Coastguard Worker   // The key wasn't found in any module.
138*635a8641SAndroid Build Coastguard Worker   return nullptr;
139*635a8641SAndroid Build Coastguard Worker }
140*635a8641SAndroid Build Coastguard Worker 
FindNSSKeyFromPublicKeyInfoInSlot(const std::vector<uint8_t> & input,PK11SlotInfo * slot)141*635a8641SAndroid Build Coastguard Worker ScopedSECKEYPrivateKey FindNSSKeyFromPublicKeyInfoInSlot(
142*635a8641SAndroid Build Coastguard Worker     const std::vector<uint8_t>& input,
143*635a8641SAndroid Build Coastguard Worker     PK11SlotInfo* slot) {
144*635a8641SAndroid Build Coastguard Worker   DCHECK(slot);
145*635a8641SAndroid Build Coastguard Worker 
146*635a8641SAndroid Build Coastguard Worker   ScopedSECItem cka_id(MakeIDFromSPKI(input));
147*635a8641SAndroid Build Coastguard Worker   if (!cka_id)
148*635a8641SAndroid Build Coastguard Worker     return nullptr;
149*635a8641SAndroid Build Coastguard Worker 
150*635a8641SAndroid Build Coastguard Worker   return ScopedSECKEYPrivateKey(
151*635a8641SAndroid Build Coastguard Worker       PK11_FindKeyByKeyID(slot, cka_id.get(), nullptr));
152*635a8641SAndroid Build Coastguard Worker }
153*635a8641SAndroid Build Coastguard Worker 
154*635a8641SAndroid Build Coastguard Worker }  // namespace crypto
155