The download arrow is not vertically centered and needs to be shifted down by 2 pt.
[chromium-blink-merge.git] / crypto / rsa_private_key_nss.cc
blob3b8bd4489a2446265d54cebe845b5fe1947ffc29
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;
141 RSAPrivateKey* RSAPrivateKey::Copy() const {
142 RSAPrivateKey* copy = new RSAPrivateKey();
143 copy->key_ = SECKEY_CopyPrivateKey(key_);
144 copy->public_key_ = SECKEY_CopyPublicKey(public_key_);
145 return copy;
148 bool RSAPrivateKey::ExportPrivateKey(std::vector<uint8>* output) const {
149 PrivateKeyInfoCodec private_key_info(true);
151 // Manually read the component attributes of the private key and build up
152 // the PrivateKeyInfo.
153 if (!ReadAttribute(key_, CKA_MODULUS, private_key_info.modulus()) ||
154 !ReadAttribute(key_, CKA_PUBLIC_EXPONENT,
155 private_key_info.public_exponent()) ||
156 !ReadAttribute(key_, CKA_PRIVATE_EXPONENT,
157 private_key_info.private_exponent()) ||
158 !ReadAttribute(key_, CKA_PRIME_1, private_key_info.prime1()) ||
159 !ReadAttribute(key_, CKA_PRIME_2, private_key_info.prime2()) ||
160 !ReadAttribute(key_, CKA_EXPONENT_1, private_key_info.exponent1()) ||
161 !ReadAttribute(key_, CKA_EXPONENT_2, private_key_info.exponent2()) ||
162 !ReadAttribute(key_, CKA_COEFFICIENT, private_key_info.coefficient())) {
163 NOTREACHED();
164 return false;
167 return private_key_info.Export(output);
170 bool RSAPrivateKey::ExportPublicKey(std::vector<uint8>* output) const {
171 ScopedSECItem der_pubkey(SECKEY_EncodeDERSubjectPublicKeyInfo(public_key_));
172 if (!der_pubkey.get()) {
173 NOTREACHED();
174 return false;
177 output->assign(der_pubkey->data, der_pubkey->data + der_pubkey->len);
178 return true;
181 RSAPrivateKey::RSAPrivateKey() : key_(NULL), public_key_(NULL) {
182 EnsureNSSInit();
185 // static
186 RSAPrivateKey* RSAPrivateKey::CreateWithParams(uint16 num_bits,
187 bool permanent,
188 bool sensitive) {
189 EnsureNSSInit();
191 scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
193 ScopedPK11Slot slot(GetPrivateNSSKeySlot());
194 if (!slot.get())
195 return NULL;
197 PK11RSAGenParams param;
198 param.keySizeInBits = num_bits;
199 param.pe = 65537L;
200 result->key_ = PK11_GenerateKeyPair(slot.get(),
201 CKM_RSA_PKCS_KEY_PAIR_GEN,
202 &param,
203 &result->public_key_,
204 permanent,
205 sensitive,
206 NULL);
207 if (!result->key_)
208 return NULL;
210 return result.release();
213 // static
214 RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfoWithParams(
215 const std::vector<uint8>& input, bool permanent, bool sensitive) {
216 // This method currently leaks some memory.
217 // See http://crbug.com/34742.
218 ANNOTATE_SCOPED_MEMORY_LEAK;
219 EnsureNSSInit();
221 scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
223 ScopedPK11Slot slot(GetPrivateNSSKeySlot());
224 if (!slot.get())
225 return NULL;
227 SECItem der_private_key_info;
228 der_private_key_info.data = const_cast<unsigned char*>(&input.front());
229 der_private_key_info.len = input.size();
230 // Allow the private key to be used for key unwrapping, data decryption,
231 // and signature generation.
232 const unsigned int key_usage = KU_KEY_ENCIPHERMENT | KU_DATA_ENCIPHERMENT |
233 KU_DIGITAL_SIGNATURE;
234 SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(
235 slot.get(), &der_private_key_info, NULL, NULL, permanent, sensitive,
236 key_usage, &result->key_, NULL);
237 if (rv != SECSuccess) {
238 NOTREACHED();
239 return NULL;
242 result->public_key_ = SECKEY_ConvertToPublicKey(result->key_);
243 if (!result->public_key_) {
244 NOTREACHED();
245 return NULL;
248 return result.release();
251 } // namespace crypto