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