Updating trunk VERSION from 874.0 to 875.0
[chromium-blink-merge.git] / crypto / rsa_private_key_nss.cc
blob0d79dbe84661831740ef43cdd66bf72696f26685
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 for (size_t i = 0; i < der_pubkey->len; ++i)
172 output->push_back(der_pubkey->data[i]);
174 return true;
177 RSAPrivateKey::RSAPrivateKey() : key_(NULL), public_key_(NULL) {
178 EnsureNSSInit();
181 // static
182 RSAPrivateKey* RSAPrivateKey::CreateWithParams(uint16 num_bits,
183 bool permanent,
184 bool sensitive) {
185 EnsureNSSInit();
187 scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
189 ScopedPK11Slot slot(GetPrivateNSSKeySlot());
190 if (!slot.get())
191 return NULL;
193 PK11RSAGenParams param;
194 param.keySizeInBits = num_bits;
195 param.pe = 65537L;
196 result->key_ = PK11_GenerateKeyPair(slot.get(),
197 CKM_RSA_PKCS_KEY_PAIR_GEN,
198 &param,
199 &result->public_key_,
200 permanent,
201 sensitive,
202 NULL);
203 if (!result->key_)
204 return NULL;
206 return result.release();
209 // static
210 RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfoWithParams(
211 const std::vector<uint8>& input, bool permanent, bool sensitive) {
212 // This method currently leaks some memory.
213 // See http://crbug.com/34742.
214 ANNOTATE_SCOPED_MEMORY_LEAK;
215 EnsureNSSInit();
217 scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
219 ScopedPK11Slot slot(GetPrivateNSSKeySlot());
220 if (!slot.get())
221 return NULL;
223 SECItem der_private_key_info;
224 der_private_key_info.data = const_cast<unsigned char*>(&input.front());
225 der_private_key_info.len = input.size();
226 // Allow the private key to be used for key unwrapping, data decryption,
227 // and signature generation.
228 const unsigned int key_usage = KU_KEY_ENCIPHERMENT | KU_DATA_ENCIPHERMENT |
229 KU_DIGITAL_SIGNATURE;
230 SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(
231 slot.get(), &der_private_key_info, NULL, NULL, permanent, sensitive,
232 key_usage, &result->key_, NULL);
233 if (rv != SECSuccess) {
234 NOTREACHED();
235 return NULL;
238 result->public_key_ = SECKEY_ConvertToPublicKey(result->key_);
239 if (!result->public_key_) {
240 NOTREACHED();
241 return NULL;
244 return result.release();
247 } // namespace crypto