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.
4
5#include "crypto/rsa_private_key.h"
6
7#include <cryptohi.h>
8#include <keyhi.h>
9#include <pk11pub.h>
10
11#include <list>
12
13#include "base/debug/leak_annotations.h"
14#include "base/logging.h"
15#include "base/memory/scoped_ptr.h"
16#include "base/string_util.h"
17#include "crypto/nss_util.h"
18#include "crypto/nss_util_internal.h"
19
20// TODO(rafaelw): Consider refactoring common functions and definitions from
21// rsa_private_key_win.cc or using NSS's ASN.1 encoder.
22namespace {
23
24static bool ReadAttribute(SECKEYPrivateKey* key,
25                          CK_ATTRIBUTE_TYPE type,
26                          std::vector<uint8>* output) {
27  SECItem item;
28  SECStatus rv;
29  rv = PK11_ReadRawAttribute(PK11_TypePrivKey, key, type, &item);
30  if (rv != SECSuccess) {
31    NOTREACHED();
32    return false;
33  }
34
35  output->assign(item.data, item.data + item.len);
36  SECITEM_FreeItem(&item, PR_FALSE);
37  return true;
38}
39
40}  // namespace
41
42namespace crypto {
43
44RSAPrivateKey::~RSAPrivateKey() {
45  if (key_)
46    SECKEY_DestroyPrivateKey(key_);
47  if (public_key_)
48    SECKEY_DestroyPublicKey(public_key_);
49}
50
51// static
52RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) {
53  return CreateWithParams(num_bits,
54                          PR_FALSE /* not permanent */,
55                          PR_FALSE /* not sensitive */);
56}
57
58// static
59RSAPrivateKey* RSAPrivateKey::CreateSensitive(uint16 num_bits) {
60  return CreateWithParams(num_bits,
61                          PR_TRUE /* permanent */,
62                          PR_TRUE /* sensitive */);
63}
64
65// static
66RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo(
67    const std::vector<uint8>& input) {
68  return CreateFromPrivateKeyInfoWithParams(input,
69                                            PR_FALSE /* not permanent */,
70                                            PR_FALSE /* not sensitive */);
71}
72
73// static
74RSAPrivateKey* RSAPrivateKey::CreateSensitiveFromPrivateKeyInfo(
75    const std::vector<uint8>& input) {
76  return CreateFromPrivateKeyInfoWithParams(input,
77                                            PR_TRUE /* permanent */,
78                                            PR_TRUE /* sensitive */);
79}
80
81// static
82RSAPrivateKey* RSAPrivateKey::FindFromPublicKeyInfo(
83    const std::vector<uint8>& input) {
84  EnsureNSSInit();
85
86  scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
87
88  // First, decode and save the public key.
89  SECItem key_der;
90  key_der.type = siBuffer;
91  key_der.data = const_cast<unsigned char*>(&input[0]);
92  key_der.len = input.size();
93
94  CERTSubjectPublicKeyInfo *spki =
95      SECKEY_DecodeDERSubjectPublicKeyInfo(&key_der);
96  if (!spki) {
97    NOTREACHED();
98    return NULL;
99  }
100
101  result->public_key_ = SECKEY_ExtractPublicKey(spki);
102  SECKEY_DestroySubjectPublicKeyInfo(spki);
103  if (!result->public_key_) {
104    NOTREACHED();
105    return NULL;
106  }
107
108  // Now, look for the associated private key in the user's
109  // hardware-backed NSS DB.  If it's not there, consider that an
110  // error.
111  PK11SlotInfo *slot = GetPrivateNSSKeySlot();
112  if (!slot) {
113    NOTREACHED();
114    return NULL;
115  }
116
117  // Make sure the key is an RSA key.  If not, that's an error
118  if (result->public_key_->keyType != rsaKey) {
119    PK11_FreeSlot(slot);
120    NOTREACHED();
121    return NULL;
122  }
123
124  SECItem *ck_id = PK11_MakeIDFromPubKey(&(result->public_key_->u.rsa.modulus));
125  if (!ck_id) {
126    PK11_FreeSlot(slot);
127    NOTREACHED();
128    return NULL;
129  }
130
131  // Finally...Look for the key!
132  result->key_ = PK11_FindKeyByKeyID(slot, ck_id, NULL);
133
134  // Cleanup...
135  PK11_FreeSlot(slot);
136  SECITEM_FreeItem(ck_id, PR_TRUE);
137
138  // If we didn't find it, that's ok.
139  if (!result->key_)
140    return NULL;
141
142  return result.release();
143}
144
145
146bool RSAPrivateKey::ExportPrivateKey(std::vector<uint8>* output) {
147  PrivateKeyInfoCodec private_key_info(true);
148
149  // Manually read the component attributes of the private key and build up
150  // the PrivateKeyInfo.
151  if (!ReadAttribute(key_, CKA_MODULUS, private_key_info.modulus()) ||
152      !ReadAttribute(key_, CKA_PUBLIC_EXPONENT,
153          private_key_info.public_exponent()) ||
154      !ReadAttribute(key_, CKA_PRIVATE_EXPONENT,
155          private_key_info.private_exponent()) ||
156      !ReadAttribute(key_, CKA_PRIME_1, private_key_info.prime1()) ||
157      !ReadAttribute(key_, CKA_PRIME_2, private_key_info.prime2()) ||
158      !ReadAttribute(key_, CKA_EXPONENT_1, private_key_info.exponent1()) ||
159      !ReadAttribute(key_, CKA_EXPONENT_2, private_key_info.exponent2()) ||
160      !ReadAttribute(key_, CKA_COEFFICIENT, private_key_info.coefficient())) {
161    NOTREACHED();
162    return false;
163  }
164
165  return private_key_info.Export(output);
166}
167
168bool RSAPrivateKey::ExportPublicKey(std::vector<uint8>* output) {
169  SECItem* der_pubkey = SECKEY_EncodeDERSubjectPublicKeyInfo(public_key_);
170  if (!der_pubkey) {
171    NOTREACHED();
172    return false;
173  }
174
175  for (size_t i = 0; i < der_pubkey->len; ++i)
176    output->push_back(der_pubkey->data[i]);
177
178  SECITEM_FreeItem(der_pubkey, PR_TRUE);
179  return true;
180}
181
182RSAPrivateKey::RSAPrivateKey() : key_(NULL), public_key_(NULL) {
183  EnsureNSSInit();
184}
185
186// static
187RSAPrivateKey* RSAPrivateKey::CreateWithParams(uint16 num_bits,
188                                               bool permanent,
189                                               bool sensitive) {
190  EnsureNSSInit();
191
192  scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
193
194  PK11SlotInfo *slot = GetPrivateNSSKeySlot();
195  if (!slot)
196    return NULL;
197
198  PK11RSAGenParams param;
199  param.keySizeInBits = num_bits;
200  param.pe = 65537L;
201  result->key_ = PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN, &param,
202      &result->public_key_, permanent, sensitive, NULL);
203  PK11_FreeSlot(slot);
204  if (!result->key_)
205    return NULL;
206
207  return result.release();
208}
209
210// static
211RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfoWithParams(
212    const std::vector<uint8>& input, bool permanent, bool sensitive) {
213  // This method currently leaks some memory.
214  // See http://crbug.com/34742.
215  ANNOTATE_SCOPED_MEMORY_LEAK;
216  EnsureNSSInit();
217
218  scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
219
220  PK11SlotInfo *slot = GetPrivateNSSKeySlot();
221  if (!slot)
222    return NULL;
223
224  SECItem der_private_key_info;
225  der_private_key_info.data = const_cast<unsigned char*>(&input.front());
226  der_private_key_info.len = input.size();
227  // Allow the private key to be used for key unwrapping, data decryption,
228  // and signature generation.
229  const unsigned int key_usage = KU_KEY_ENCIPHERMENT | KU_DATA_ENCIPHERMENT |
230                                 KU_DIGITAL_SIGNATURE;
231  SECStatus rv =  PK11_ImportDERPrivateKeyInfoAndReturnKey(
232      slot, &der_private_key_info, NULL, NULL, permanent, sensitive,
233      key_usage, &result->key_, NULL);
234  PK11_FreeSlot(slot);
235  if (rv != SECSuccess) {
236    NOTREACHED();
237    return NULL;
238  }
239
240  result->public_key_ = SECKEY_ConvertToPublicKey(result->key_);
241  if (!result->public_key_) {
242    NOTREACHED();
243    return NULL;
244  }
245
246  return result.release();
247}
248
249}  // namespace crypto
250