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