blob: 3b8bd4489a2446265d54cebe845b5fe1947ffc29 [file] [log] [blame]
[email protected]3b63f8f42011-03-28 01:54:151// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]71a9f842009-09-24 01:21:122// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]4b559b4d2011-04-14 17:37:145#include "crypto/rsa_private_key.h"
[email protected]71a9f842009-09-24 01:21:126
7#include <cryptohi.h>
8#include <keyhi.h>
9#include <pk11pub.h>
[email protected]dd24ffc2011-06-08 19:46:4210#include <secmod.h>
[email protected]71a9f842009-09-24 01:21:1211
[email protected]71a9f842009-09-24 01:21:1212#include <list>
13
[email protected]58580352010-10-26 04:07:5014#include "base/debug/leak_annotations.h"
[email protected]71a9f842009-09-24 01:21:1215#include "base/logging.h"
[email protected]3b63f8f42011-03-28 01:54:1516#include "base/memory/scoped_ptr.h"
[email protected]71a9f842009-09-24 01:21:1217#include "base/string_util.h"
[email protected]4b559b4d2011-04-14 17:37:1418#include "crypto/nss_util.h"
19#include "crypto/nss_util_internal.h"
[email protected]cfa46c02011-05-25 18:19:0820#include "crypto/scoped_nss_types.h"
[email protected]71a9f842009-09-24 01:21:1221
22// TODO(rafaelw): Consider refactoring common functions and definitions from
23// rsa_private_key_win.cc or using NSS's ASN.1 encoder.
24namespace {
25
[email protected]308379a52009-10-07 02:46:3126static bool ReadAttribute(SECKEYPrivateKey* key,
27 CK_ATTRIBUTE_TYPE type,
28 std::vector<uint8>* output) {
[email protected]71a9f842009-09-24 01:21:1229 SECItem item;
30 SECStatus rv;
31 rv = PK11_ReadRawAttribute(PK11_TypePrivKey, key, type, &item);
32 if (rv != SECSuccess) {
33 NOTREACHED();
34 return false;
35 }
36
[email protected]308379a52009-10-07 02:46:3137 output->assign(item.data, item.data + item.len);
[email protected]71a9f842009-09-24 01:21:1238 SECITEM_FreeItem(&item, PR_FALSE);
39 return true;
40}
41
42} // namespace
43
[email protected]4b559b4d2011-04-14 17:37:1444namespace crypto {
[email protected]71a9f842009-09-24 01:21:1245
[email protected]eae9c062011-01-11 00:50:5946RSAPrivateKey::~RSAPrivateKey() {
47 if (key_)
48 SECKEY_DestroyPrivateKey(key_);
49 if (public_key_)
50 SECKEY_DestroyPublicKey(public_key_);
[email protected]71a9f842009-09-24 01:21:1251}
52
53// static
[email protected]74648052010-08-10 19:37:5154RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) {
55 return CreateWithParams(num_bits,
56 PR_FALSE /* not permanent */,
57 PR_FALSE /* not sensitive */);
58}
59
60// static
61RSAPrivateKey* RSAPrivateKey::CreateSensitive(uint16 num_bits) {
62 return CreateWithParams(num_bits,
63 PR_TRUE /* permanent */,
64 PR_TRUE /* sensitive */);
65}
66
67// static
[email protected]74648052010-08-10 19:37:5168RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo(
69 const std::vector<uint8>& input) {
70 return CreateFromPrivateKeyInfoWithParams(input,
71 PR_FALSE /* not permanent */,
72 PR_FALSE /* not sensitive */);
73}
74
75// static
76RSAPrivateKey* RSAPrivateKey::CreateSensitiveFromPrivateKeyInfo(
77 const std::vector<uint8>& input) {
78 return CreateFromPrivateKeyInfoWithParams(input,
79 PR_TRUE /* permanent */,
[email protected]c64b9142011-04-19 18:49:5480 PR_TRUE /* sensitive */);
[email protected]74648052010-08-10 19:37:5181}
82
83// static
84RSAPrivateKey* RSAPrivateKey::FindFromPublicKeyInfo(
85 const std::vector<uint8>& input) {
[email protected]4b559b4d2011-04-14 17:37:1486 EnsureNSSInit();
[email protected]74648052010-08-10 19:37:5187
88 scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
89
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();
95
[email protected]cfa46c02011-05-25 18:19:0896 CERTSubjectPublicKeyInfo* spki =
[email protected]74648052010-08-10 19:37:5197 SECKEY_DecodeDERSubjectPublicKeyInfo(&key_der);
98 if (!spki) {
99 NOTREACHED();
100 return NULL;
101 }
102
103 result->public_key_ = SECKEY_ExtractPublicKey(spki);
104 SECKEY_DestroySubjectPublicKeyInfo(spki);
105 if (!result->public_key_) {
106 NOTREACHED();
107 return NULL;
108 }
109
[email protected]74648052010-08-10 19:37:51110 // Make sure the key is an RSA key. If not, that's an error
111 if (result->public_key_->keyType != rsaKey) {
[email protected]74648052010-08-10 19:37:51112 NOTREACHED();
113 return NULL;
114 }
115
[email protected]cfa46c02011-05-25 18:19:08116 ScopedSECItem ck_id(
117 PK11_MakeIDFromPubKey(&(result->public_key_->u.rsa.modulus)));
118 if (!ck_id.get()) {
119 NOTREACHED();
120 return NULL;
121 }
122
[email protected]dd24ffc2011-06-08 19:46:42123 // 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();
[email protected]cfa46c02011-05-25 18:19:08134 }
[email protected]cfa46c02011-05-25 18:19:08135 }
[email protected]74648052010-08-10 19:37:51136
[email protected]dd24ffc2011-06-08 19:46:42137 // We didn't find the key.
138 return NULL;
[email protected]74648052010-08-10 19:37:51139}
140
[email protected]58782882011-12-03 01:12:08141RSAPrivateKey* 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;
146}
[email protected]71a9f842009-09-24 01:21:12147
[email protected]58782882011-12-03 01:12:08148bool RSAPrivateKey::ExportPrivateKey(std::vector<uint8>* output) const {
[email protected]308379a52009-10-07 02:46:31149 PrivateKeyInfoCodec private_key_info(true);
[email protected]71a9f842009-09-24 01:21:12150
[email protected]308379a52009-10-07 02:46:31151 // 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())) {
[email protected]71a9f842009-09-24 01:21:12163 NOTREACHED();
164 return false;
165 }
[email protected]71a9f842009-09-24 01:21:12166
[email protected]308379a52009-10-07 02:46:31167 return private_key_info.Export(output);
[email protected]71a9f842009-09-24 01:21:12168}
169
[email protected]58782882011-12-03 01:12:08170bool RSAPrivateKey::ExportPublicKey(std::vector<uint8>* output) const {
[email protected]cfa46c02011-05-25 18:19:08171 ScopedSECItem der_pubkey(SECKEY_EncodeDERSubjectPublicKeyInfo(public_key_));
172 if (!der_pubkey.get()) {
[email protected]71a9f842009-09-24 01:21:12173 NOTREACHED();
174 return false;
175 }
176
[email protected]9dd6a2d2011-11-15 04:45:16177 output->assign(der_pubkey->data, der_pubkey->data + der_pubkey->len);
[email protected]71a9f842009-09-24 01:21:12178 return true;
179}
180
[email protected]eae9c062011-01-11 00:50:59181RSAPrivateKey::RSAPrivateKey() : key_(NULL), public_key_(NULL) {
182 EnsureNSSInit();
183}
184
185// static
186RSAPrivateKey* RSAPrivateKey::CreateWithParams(uint16 num_bits,
187 bool permanent,
188 bool sensitive) {
[email protected]4b559b4d2011-04-14 17:37:14189 EnsureNSSInit();
[email protected]eae9c062011-01-11 00:50:59190
191 scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
192
[email protected]cfa46c02011-05-25 18:19:08193 ScopedPK11Slot slot(GetPrivateNSSKeySlot());
194 if (!slot.get())
[email protected]eae9c062011-01-11 00:50:59195 return NULL;
196
197 PK11RSAGenParams param;
198 param.keySizeInBits = num_bits;
199 param.pe = 65537L;
[email protected]cfa46c02011-05-25 18:19:08200 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);
[email protected]eae9c062011-01-11 00:50:59207 if (!result->key_)
208 return NULL;
209
210 return result.release();
211}
212
213// static
214RSAPrivateKey* 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;
[email protected]4b559b4d2011-04-14 17:37:14219 EnsureNSSInit();
[email protected]eae9c062011-01-11 00:50:59220
221 scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
222
[email protected]cfa46c02011-05-25 18:19:08223 ScopedPK11Slot slot(GetPrivateNSSKeySlot());
224 if (!slot.get())
[email protected]eae9c062011-01-11 00:50:59225 return NULL;
226
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();
[email protected]302b6272011-01-19 01:27:22230 // 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(
[email protected]cfa46c02011-05-25 18:19:08235 slot.get(), &der_private_key_info, NULL, NULL, permanent, sensitive,
[email protected]302b6272011-01-19 01:27:22236 key_usage, &result->key_, NULL);
[email protected]eae9c062011-01-11 00:50:59237 if (rv != SECSuccess) {
238 NOTREACHED();
239 return NULL;
240 }
241
242 result->public_key_ = SECKEY_ConvertToPublicKey(result->key_);
243 if (!result->public_key_) {
244 NOTREACHED();
245 return NULL;
246 }
247
248 return result.release();
249}
250
[email protected]4b559b4d2011-04-14 17:37:14251} // namespace crypto