- add sources.
[platform/framework/web/crosswalk.git] / src / crypto / rsa_private_key_nss.cc
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 #include <secmod.h>
11
12 #include <list>
13
14 #include "base/debug/leak_annotations.h"
15 #include "base/logging.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "base/strings/string_util.h"
18 #include "crypto/nss_util.h"
19 #include "crypto/nss_util_internal.h"
20 #include "crypto/scoped_nss_types.h"
21
22 // TODO(rafaelw): Consider using NSS's ASN.1 encoder.
23 namespace {
24
25 static bool ReadAttribute(SECKEYPrivateKey* key,
26                           CK_ATTRIBUTE_TYPE type,
27                           std::vector<uint8>* output) {
28   SECItem item;
29   SECStatus rv;
30   rv = PK11_ReadRawAttribute(PK11_TypePrivKey, key, type, &item);
31   if (rv != SECSuccess) {
32     NOTREACHED();
33     return false;
34   }
35
36   output->assign(item.data, item.data + item.len);
37   SECITEM_FreeItem(&item, PR_FALSE);
38   return true;
39 }
40
41 }  // namespace
42
43 namespace crypto {
44
45 RSAPrivateKey::~RSAPrivateKey() {
46   if (key_)
47     SECKEY_DestroyPrivateKey(key_);
48   if (public_key_)
49     SECKEY_DestroyPublicKey(public_key_);
50 }
51
52 // static
53 RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) {
54   return CreateWithParams(num_bits,
55                           false /* not permanent */,
56                           false /* not sensitive */);
57 }
58
59 // static
60 RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo(
61     const std::vector<uint8>& input) {
62   return CreateFromPrivateKeyInfoWithParams(input,
63                                             false /* not permanent */,
64                                             false /* not sensitive */);
65 }
66
67 #if defined(USE_NSS)
68 // static
69 RSAPrivateKey* RSAPrivateKey::CreateSensitive(uint16 num_bits) {
70   return CreateWithParams(num_bits,
71                           true /* permanent */,
72                           true /* sensitive */);
73 }
74
75 // static
76 RSAPrivateKey* RSAPrivateKey::CreateSensitiveFromPrivateKeyInfo(
77     const std::vector<uint8>& input) {
78   return CreateFromPrivateKeyInfoWithParams(input,
79                                             true /* permanent */,
80                                             true /* sensitive */);
81 }
82
83 // static
84 RSAPrivateKey* RSAPrivateKey::CreateFromKey(SECKEYPrivateKey* key) {
85   DCHECK(key);
86   if (SECKEY_GetPrivateKeyType(key) != rsaKey)
87     return NULL;
88   RSAPrivateKey* copy = new RSAPrivateKey();
89   copy->key_ = SECKEY_CopyPrivateKey(key);
90   copy->public_key_ = SECKEY_ConvertToPublicKey(key);
91   if (!copy->key_ || !copy->public_key_) {
92     NOTREACHED();
93     delete copy;
94     return NULL;
95   }
96   return copy;
97 }
98
99 // static
100 RSAPrivateKey* RSAPrivateKey::FindFromPublicKeyInfo(
101     const std::vector<uint8>& input) {
102   EnsureNSSInit();
103
104   scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
105
106   // First, decode and save the public key.
107   SECItem key_der;
108   key_der.type = siBuffer;
109   key_der.data = const_cast<unsigned char*>(&input[0]);
110   key_der.len = input.size();
111
112   CERTSubjectPublicKeyInfo* spki =
113       SECKEY_DecodeDERSubjectPublicKeyInfo(&key_der);
114   if (!spki) {
115     NOTREACHED();
116     return NULL;
117   }
118
119   result->public_key_ = SECKEY_ExtractPublicKey(spki);
120   SECKEY_DestroySubjectPublicKeyInfo(spki);
121   if (!result->public_key_) {
122     NOTREACHED();
123     return NULL;
124   }
125
126   // Make sure the key is an RSA key.  If not, that's an error
127   if (result->public_key_->keyType != rsaKey) {
128     NOTREACHED();
129     return NULL;
130   }
131
132   ScopedSECItem ck_id(
133       PK11_MakeIDFromPubKey(&(result->public_key_->u.rsa.modulus)));
134   if (!ck_id.get()) {
135     NOTREACHED();
136     return NULL;
137   }
138
139   // Search all slots in all modules for the key with the given ID.
140   AutoSECMODListReadLock auto_lock;
141   SECMODModuleList* head = SECMOD_GetDefaultModuleList();
142   for (SECMODModuleList* item = head; item != NULL; item = item->next) {
143     int slot_count = item->module->loaded ? item->module->slotCount : 0;
144     for (int i = 0; i < slot_count; i++) {
145       // Finally...Look for the key!
146       result->key_ = PK11_FindKeyByKeyID(item->module->slots[i],
147                                          ck_id.get(), NULL);
148       if (result->key_)
149         return result.release();
150     }
151   }
152
153   // We didn't find the key.
154   return NULL;
155 }
156 #endif
157
158 RSAPrivateKey* RSAPrivateKey::Copy() const {
159   RSAPrivateKey* copy = new RSAPrivateKey();
160   copy->key_ = SECKEY_CopyPrivateKey(key_);
161   copy->public_key_ = SECKEY_CopyPublicKey(public_key_);
162   return copy;
163 }
164
165 bool RSAPrivateKey::ExportPrivateKey(std::vector<uint8>* output) const {
166   PrivateKeyInfoCodec private_key_info(true);
167
168   // Manually read the component attributes of the private key and build up
169   // the PrivateKeyInfo.
170   if (!ReadAttribute(key_, CKA_MODULUS, private_key_info.modulus()) ||
171       !ReadAttribute(key_, CKA_PUBLIC_EXPONENT,
172           private_key_info.public_exponent()) ||
173       !ReadAttribute(key_, CKA_PRIVATE_EXPONENT,
174           private_key_info.private_exponent()) ||
175       !ReadAttribute(key_, CKA_PRIME_1, private_key_info.prime1()) ||
176       !ReadAttribute(key_, CKA_PRIME_2, private_key_info.prime2()) ||
177       !ReadAttribute(key_, CKA_EXPONENT_1, private_key_info.exponent1()) ||
178       !ReadAttribute(key_, CKA_EXPONENT_2, private_key_info.exponent2()) ||
179       !ReadAttribute(key_, CKA_COEFFICIENT, private_key_info.coefficient())) {
180     NOTREACHED();
181     return false;
182   }
183
184   return private_key_info.Export(output);
185 }
186
187 bool RSAPrivateKey::ExportPublicKey(std::vector<uint8>* output) const {
188   ScopedSECItem der_pubkey(SECKEY_EncodeDERSubjectPublicKeyInfo(public_key_));
189   if (!der_pubkey.get()) {
190     NOTREACHED();
191     return false;
192   }
193
194   output->assign(der_pubkey->data, der_pubkey->data + der_pubkey->len);
195   return true;
196 }
197
198 RSAPrivateKey::RSAPrivateKey() : key_(NULL), public_key_(NULL) {
199   EnsureNSSInit();
200 }
201
202 // static
203 RSAPrivateKey* RSAPrivateKey::CreateWithParams(uint16 num_bits,
204                                                bool permanent,
205                                                bool sensitive) {
206 #if !defined(USE_NSS)
207   if (permanent) {
208     NOTIMPLEMENTED();
209     return NULL;
210   }
211 #endif
212
213   EnsureNSSInit();
214
215   scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
216
217   ScopedPK11Slot slot(permanent ? GetPrivateNSSKeySlot() :
218                       PK11_GetInternalSlot());
219   if (!slot.get())
220     return NULL;
221
222   PK11RSAGenParams param;
223   param.keySizeInBits = num_bits;
224   param.pe = 65537L;
225   result->key_ = PK11_GenerateKeyPair(slot.get(),
226                                       CKM_RSA_PKCS_KEY_PAIR_GEN,
227                                       &param,
228                                       &result->public_key_,
229                                       permanent,
230                                       sensitive,
231                                       NULL);
232   if (!result->key_)
233     return NULL;
234
235   return result.release();
236 }
237
238 // static
239 RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfoWithParams(
240     const std::vector<uint8>& input, bool permanent, bool sensitive) {
241 #if !defined(USE_NSS)
242   if (permanent) {
243     NOTIMPLEMENTED();
244     return NULL;
245   }
246 #endif
247
248   // This method currently leaks some memory.
249   // See http://crbug.com/34742.
250   ANNOTATE_SCOPED_MEMORY_LEAK;
251   EnsureNSSInit();
252
253   scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
254
255   ScopedPK11Slot slot(permanent ? GetPrivateNSSKeySlot() :
256                       PK11_GetInternalSlot());
257   if (!slot.get())
258     return NULL;
259
260   SECItem der_private_key_info;
261   der_private_key_info.data = const_cast<unsigned char*>(&input.front());
262   der_private_key_info.len = input.size();
263   // Allow the private key to be used for key unwrapping, data decryption,
264   // and signature generation.
265   const unsigned int key_usage = KU_KEY_ENCIPHERMENT | KU_DATA_ENCIPHERMENT |
266                                  KU_DIGITAL_SIGNATURE;
267   SECStatus rv =  PK11_ImportDERPrivateKeyInfoAndReturnKey(
268       slot.get(), &der_private_key_info, NULL, NULL, permanent, sensitive,
269       key_usage, &result->key_, NULL);
270   if (rv != SECSuccess) {
271     NOTREACHED();
272     return NULL;
273   }
274
275   result->public_key_ = SECKEY_ConvertToPublicKey(result->key_);
276   if (!result->public_key_) {
277     NOTREACHED();
278     return NULL;
279   }
280
281   return result.release();
282 }
283
284 }  // namespace crypto