Open NaCl IRT file only once at startup
[chromium-blink-merge.git] / crypto / rsa_private_key_nss.cc
blobcd1f9203f3517b1cbe4451ab9700803d52c055fd
1 // Copyright (c) 2011 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.
5 #include "crypto/rsa_private_key.h"
7 #include <cryptohi.h>
8 #include <keyhi.h>
9 #include <pk11pub.h>
10 #include <secmod.h>
12 #include <list>
14 #include "base/debug/leak_annotations.h"
15 #include "base/logging.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "base/string_util.h"
18 #include "crypto/nss_util.h"
19 #include "crypto/nss_util_internal.h"
20 #include "crypto/scoped_nss_types.h"
22 // TODO(rafaelw): Consider refactoring common functions and definitions from
23 // rsa_private_key_win.cc or using NSS's ASN.1 encoder.
24 namespace {
26 static bool ReadAttribute(SECKEYPrivateKey* key,
27 CK_ATTRIBUTE_TYPE type,
28 std::vector<uint8>* output) {
29 SECItem item;
30 SECStatus rv;
31 rv = PK11_ReadRawAttribute(PK11_TypePrivKey, key, type, &item);
32 if (rv != SECSuccess) {
33 NOTREACHED();
34 return false;
37 output->assign(item.data, item.data + item.len);
38 SECITEM_FreeItem(&item, PR_FALSE);
39 return true;
42 } // namespace
44 namespace crypto {
46 RSAPrivateKey::~RSAPrivateKey() {
47 if (key_)
48 SECKEY_DestroyPrivateKey(key_);
49 if (public_key_)
50 SECKEY_DestroyPublicKey(public_key_);
53 // static
54 RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) {
55 return CreateWithParams(num_bits,
56 PR_FALSE /* not permanent */,
57 PR_FALSE /* not sensitive */);
60 // static
61 RSAPrivateKey* RSAPrivateKey::CreateSensitive(uint16 num_bits) {
62 return CreateWithParams(num_bits,
63 PR_TRUE /* permanent */,
64 PR_TRUE /* sensitive */);
67 // static
68 RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo(
69 const std::vector<uint8>& input) {
70 return CreateFromPrivateKeyInfoWithParams(input,
71 PR_FALSE /* not permanent */,
72 PR_FALSE /* not sensitive */);
75 // static
76 RSAPrivateKey* RSAPrivateKey::CreateSensitiveFromPrivateKeyInfo(
77 const std::vector<uint8>& input) {
78 return CreateFromPrivateKeyInfoWithParams(input,
79 PR_TRUE /* permanent */,
80 PR_TRUE /* sensitive */);
83 // static
84 RSAPrivateKey* RSAPrivateKey::FindFromPublicKeyInfo(
85 const std::vector<uint8>& input) {
86 EnsureNSSInit();
88 scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
90 // First, decode and save the public key.
91 SECItem key_der;
92 key_der.type = siBuffer;
93 key_der.data = const_cast<unsigned char*>(&input[0]);
94 key_der.len = input.size();
96 CERTSubjectPublicKeyInfo* spki =
97 SECKEY_DecodeDERSubjectPublicKeyInfo(&key_der);
98 if (!spki) {
99 NOTREACHED();
100 return NULL;
103 result->public_key_ = SECKEY_ExtractPublicKey(spki);
104 SECKEY_DestroySubjectPublicKeyInfo(spki);
105 if (!result->public_key_) {
106 NOTREACHED();
107 return NULL;
110 // Make sure the key is an RSA key. If not, that's an error
111 if (result->public_key_->keyType != rsaKey) {
112 NOTREACHED();
113 return NULL;
116 ScopedSECItem ck_id(
117 PK11_MakeIDFromPubKey(&(result->public_key_->u.rsa.modulus)));
118 if (!ck_id.get()) {
119 NOTREACHED();
120 return NULL;
123 // Search all slots in all modules for the key with the given ID.
124 AutoSECMODListReadLock auto_lock;
125 SECMODModuleList* head = SECMOD_GetDefaultModuleList();
126 for (SECMODModuleList* item = head; item != NULL; item = item->next) {
127 int slot_count = item->module->loaded ? item->module->slotCount : 0;
128 for (int i = 0; i < slot_count; i++) {
129 // Finally...Look for the key!
130 result->key_ = PK11_FindKeyByKeyID(item->module->slots[i],
131 ck_id.get(), NULL);
132 if (result->key_)
133 return result.release();
137 // We didn't find the key.
138 return NULL;
142 bool RSAPrivateKey::ExportPrivateKey(std::vector<uint8>* output) {
143 PrivateKeyInfoCodec private_key_info(true);
145 // Manually read the component attributes of the private key and build up
146 // the PrivateKeyInfo.
147 if (!ReadAttribute(key_, CKA_MODULUS, private_key_info.modulus()) ||
148 !ReadAttribute(key_, CKA_PUBLIC_EXPONENT,
149 private_key_info.public_exponent()) ||
150 !ReadAttribute(key_, CKA_PRIVATE_EXPONENT,
151 private_key_info.private_exponent()) ||
152 !ReadAttribute(key_, CKA_PRIME_1, private_key_info.prime1()) ||
153 !ReadAttribute(key_, CKA_PRIME_2, private_key_info.prime2()) ||
154 !ReadAttribute(key_, CKA_EXPONENT_1, private_key_info.exponent1()) ||
155 !ReadAttribute(key_, CKA_EXPONENT_2, private_key_info.exponent2()) ||
156 !ReadAttribute(key_, CKA_COEFFICIENT, private_key_info.coefficient())) {
157 NOTREACHED();
158 return false;
161 return private_key_info.Export(output);
164 bool RSAPrivateKey::ExportPublicKey(std::vector<uint8>* output) {
165 ScopedSECItem der_pubkey(SECKEY_EncodeDERSubjectPublicKeyInfo(public_key_));
166 if (!der_pubkey.get()) {
167 NOTREACHED();
168 return false;
171 output->assign(der_pubkey->data, der_pubkey->data + der_pubkey->len);
172 return true;
175 RSAPrivateKey::RSAPrivateKey() : key_(NULL), public_key_(NULL) {
176 EnsureNSSInit();
179 // static
180 RSAPrivateKey* RSAPrivateKey::CreateWithParams(uint16 num_bits,
181 bool permanent,
182 bool sensitive) {
183 EnsureNSSInit();
185 scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
187 ScopedPK11Slot slot(GetPrivateNSSKeySlot());
188 if (!slot.get())
189 return NULL;
191 PK11RSAGenParams param;
192 param.keySizeInBits = num_bits;
193 param.pe = 65537L;
194 result->key_ = PK11_GenerateKeyPair(slot.get(),
195 CKM_RSA_PKCS_KEY_PAIR_GEN,
196 &param,
197 &result->public_key_,
198 permanent,
199 sensitive,
200 NULL);
201 if (!result->key_)
202 return NULL;
204 return result.release();
207 // static
208 RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfoWithParams(
209 const std::vector<uint8>& input, bool permanent, bool sensitive) {
210 // This method currently leaks some memory.
211 // See http://crbug.com/34742.
212 ANNOTATE_SCOPED_MEMORY_LEAK;
213 EnsureNSSInit();
215 scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
217 ScopedPK11Slot slot(GetPrivateNSSKeySlot());
218 if (!slot.get())
219 return NULL;
221 SECItem der_private_key_info;
222 der_private_key_info.data = const_cast<unsigned char*>(&input.front());
223 der_private_key_info.len = input.size();
224 // Allow the private key to be used for key unwrapping, data decryption,
225 // and signature generation.
226 const unsigned int key_usage = KU_KEY_ENCIPHERMENT | KU_DATA_ENCIPHERMENT |
227 KU_DIGITAL_SIGNATURE;
228 SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(
229 slot.get(), &der_private_key_info, NULL, NULL, permanent, sensitive,
230 key_usage, &result->key_, NULL);
231 if (rv != SECSuccess) {
232 NOTREACHED();
233 return NULL;
236 result->public_key_ = SECKEY_ConvertToPublicKey(result->key_);
237 if (!result->public_key_) {
238 NOTREACHED();
239 return NULL;
242 return result.release();
245 } // namespace crypto