Retrieve the authenticated user's e-mail from GAIA during SAML enrollment
[chromium-blink-merge.git] / crypto / rsa_private_key_nss.cc
blobbd54c2e4037131b536a6134305e1027fdf804b73
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/strings/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 using NSS's ASN.1 encoder.
23 namespace {
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;
36 output->assign(item.data, item.data + item.len);
37 SECITEM_FreeItem(&item, PR_FALSE);
38 return true;
41 } // namespace
43 namespace crypto {
45 RSAPrivateKey::~RSAPrivateKey() {
46 if (key_)
47 SECKEY_DestroyPrivateKey(key_);
48 if (public_key_)
49 SECKEY_DestroyPublicKey(public_key_);
52 // static
53 RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) {
54 EnsureNSSInit();
56 ScopedPK11Slot slot(PK11_GetInternalSlot());
57 return CreateWithParams(slot.get(),
58 num_bits,
59 false /* not permanent */,
60 false /* not sensitive */);
63 // static
64 RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo(
65 const std::vector<uint8>& input) {
66 EnsureNSSInit();
68 ScopedPK11Slot slot(PK11_GetInternalSlot());
69 return CreateFromPrivateKeyInfoWithParams(
70 slot.get(),
71 input,
72 false /* not permanent */,
73 false /* not sensitive */);
76 #if defined(USE_NSS)
77 // static
78 RSAPrivateKey* RSAPrivateKey::CreateSensitive(PK11SlotInfo* slot,
79 uint16 num_bits) {
80 return CreateWithParams(slot,
81 num_bits,
82 true /* permanent */,
83 true /* sensitive */);
86 // static
87 RSAPrivateKey* RSAPrivateKey::CreateSensitiveFromPrivateKeyInfo(
88 PK11SlotInfo* slot,
89 const std::vector<uint8>& input) {
90 return CreateFromPrivateKeyInfoWithParams(slot,
91 input,
92 true /* permanent */,
93 true /* sensitive */);
96 // static
97 RSAPrivateKey* RSAPrivateKey::CreateFromKey(SECKEYPrivateKey* key) {
98 DCHECK(key);
99 if (SECKEY_GetPrivateKeyType(key) != rsaKey)
100 return NULL;
101 RSAPrivateKey* copy = new RSAPrivateKey();
102 copy->key_ = SECKEY_CopyPrivateKey(key);
103 copy->public_key_ = SECKEY_ConvertToPublicKey(key);
104 if (!copy->key_ || !copy->public_key_) {
105 NOTREACHED();
106 delete copy;
107 return NULL;
109 return copy;
112 // static
113 RSAPrivateKey* RSAPrivateKey::FindFromPublicKeyInfo(
114 const std::vector<uint8>& input) {
115 EnsureNSSInit();
117 scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
119 // First, decode and save the public key.
120 SECItem key_der;
121 key_der.type = siBuffer;
122 key_der.data = const_cast<unsigned char*>(&input[0]);
123 key_der.len = input.size();
125 CERTSubjectPublicKeyInfo* spki =
126 SECKEY_DecodeDERSubjectPublicKeyInfo(&key_der);
127 if (!spki) {
128 NOTREACHED();
129 return NULL;
132 result->public_key_ = SECKEY_ExtractPublicKey(spki);
133 SECKEY_DestroySubjectPublicKeyInfo(spki);
134 if (!result->public_key_) {
135 NOTREACHED();
136 return NULL;
139 // Make sure the key is an RSA key. If not, that's an error
140 if (result->public_key_->keyType != rsaKey) {
141 NOTREACHED();
142 return NULL;
145 ScopedSECItem ck_id(
146 PK11_MakeIDFromPubKey(&(result->public_key_->u.rsa.modulus)));
147 if (!ck_id.get()) {
148 NOTREACHED();
149 return NULL;
152 // Search all slots in all modules for the key with the given ID.
153 AutoSECMODListReadLock auto_lock;
154 SECMODModuleList* head = SECMOD_GetDefaultModuleList();
155 for (SECMODModuleList* item = head; item != NULL; item = item->next) {
156 int slot_count = item->module->loaded ? item->module->slotCount : 0;
157 for (int i = 0; i < slot_count; i++) {
158 // Finally...Look for the key!
159 result->key_ = PK11_FindKeyByKeyID(item->module->slots[i],
160 ck_id.get(), NULL);
161 if (result->key_)
162 return result.release();
166 // We didn't find the key.
167 return NULL;
169 #endif
171 RSAPrivateKey* RSAPrivateKey::Copy() const {
172 RSAPrivateKey* copy = new RSAPrivateKey();
173 copy->key_ = SECKEY_CopyPrivateKey(key_);
174 copy->public_key_ = SECKEY_CopyPublicKey(public_key_);
175 return copy;
178 bool RSAPrivateKey::ExportPrivateKey(std::vector<uint8>* output) const {
179 PrivateKeyInfoCodec private_key_info(true);
181 // Manually read the component attributes of the private key and build up
182 // the PrivateKeyInfo.
183 if (!ReadAttribute(key_, CKA_MODULUS, private_key_info.modulus()) ||
184 !ReadAttribute(key_, CKA_PUBLIC_EXPONENT,
185 private_key_info.public_exponent()) ||
186 !ReadAttribute(key_, CKA_PRIVATE_EXPONENT,
187 private_key_info.private_exponent()) ||
188 !ReadAttribute(key_, CKA_PRIME_1, private_key_info.prime1()) ||
189 !ReadAttribute(key_, CKA_PRIME_2, private_key_info.prime2()) ||
190 !ReadAttribute(key_, CKA_EXPONENT_1, private_key_info.exponent1()) ||
191 !ReadAttribute(key_, CKA_EXPONENT_2, private_key_info.exponent2()) ||
192 !ReadAttribute(key_, CKA_COEFFICIENT, private_key_info.coefficient())) {
193 NOTREACHED();
194 return false;
197 return private_key_info.Export(output);
200 bool RSAPrivateKey::ExportPublicKey(std::vector<uint8>* output) const {
201 ScopedSECItem der_pubkey(SECKEY_EncodeDERSubjectPublicKeyInfo(public_key_));
202 if (!der_pubkey.get()) {
203 NOTREACHED();
204 return false;
207 output->assign(der_pubkey->data, der_pubkey->data + der_pubkey->len);
208 return true;
211 RSAPrivateKey::RSAPrivateKey() : key_(NULL), public_key_(NULL) {
212 EnsureNSSInit();
215 // static
216 RSAPrivateKey* RSAPrivateKey::CreateWithParams(PK11SlotInfo* slot,
217 uint16 num_bits,
218 bool permanent,
219 bool sensitive) {
220 if (!slot)
221 return NULL;
223 scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
225 PK11RSAGenParams param;
226 param.keySizeInBits = num_bits;
227 param.pe = 65537L;
228 result->key_ = PK11_GenerateKeyPair(slot,
229 CKM_RSA_PKCS_KEY_PAIR_GEN,
230 &param,
231 &result->public_key_,
232 permanent,
233 sensitive,
234 NULL);
235 if (!result->key_)
236 return NULL;
238 return result.release();
241 // static
242 RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfoWithParams(
243 PK11SlotInfo* slot,
244 const std::vector<uint8>& input,
245 bool permanent,
246 bool sensitive) {
247 if (!slot)
248 return NULL;
250 scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
252 SECItem der_private_key_info;
253 der_private_key_info.data = const_cast<unsigned char*>(&input.front());
254 der_private_key_info.len = input.size();
255 // Allow the private key to be used for key unwrapping, data decryption,
256 // and signature generation.
257 const unsigned int key_usage = KU_KEY_ENCIPHERMENT | KU_DATA_ENCIPHERMENT |
258 KU_DIGITAL_SIGNATURE;
259 SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(
260 slot, &der_private_key_info, NULL, NULL, permanent, sensitive,
261 key_usage, &result->key_, NULL);
262 if (rv != SECSuccess) {
263 NOTREACHED();
264 return NULL;
267 result->public_key_ = SECKEY_ConvertToPublicKey(result->key_);
268 if (!result->public_key_) {
269 NOTREACHED();
270 return NULL;
273 return result.release();
276 } // namespace crypto