OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "crypto/ec_private_key.h" | 5 #include "crypto/ec_private_key.h" |
6 | 6 |
7 extern "C" { | 7 extern "C" { |
8 // Work around NSS missing SEC_BEGIN_PROTOS in secmodt.h. This must come before | 8 // Work around NSS missing SEC_BEGIN_PROTOS in secmodt.h. This must come before |
9 // other NSS headers. | 9 // other NSS headers. |
10 #include <secmodt.h> | 10 #include <secmodt.h> |
11 } | 11 } |
12 | 12 |
13 #include <cryptohi.h> | 13 #include <cryptohi.h> |
14 #include <keyhi.h> | 14 #include <keyhi.h> |
15 #include <pk11pub.h> | 15 #include <pk11pub.h> |
16 #include <secmod.h> | 16 #include <secmod.h> |
17 | 17 |
18 #include "base/lazy_instance.h" | 18 #include "base/lazy_instance.h" |
19 #include "base/logging.h" | 19 #include "base/logging.h" |
20 #include "base/memory/scoped_ptr.h" | 20 #include "base/memory/scoped_ptr.h" |
21 #include "crypto/nss_util.h" | 21 #include "crypto/nss_util.h" |
22 #include "crypto/nss_util_internal.h" | 22 #include "crypto/nss_util_internal.h" |
23 #include "crypto/scoped_nss_types.h" | 23 #include "crypto/scoped_nss_types.h" |
24 #include "crypto/third_party/nss/chromium-nss.h" | 24 #include "crypto/third_party/nss/chromium-nss.h" |
25 | 25 |
26 namespace { | 26 namespace { |
27 | 27 |
28 PK11SlotInfo* GetKeySlot() { | 28 PK11SlotInfo* GetTempKeySlot() { |
29 return crypto::GetPublicNSSKeySlot(); | 29 return PK11_GetInternalSlot(); |
30 } | 30 } |
31 | 31 |
32 class EllipticCurveSupportChecker { | 32 class EllipticCurveSupportChecker { |
33 public: | 33 public: |
34 EllipticCurveSupportChecker() { | 34 EllipticCurveSupportChecker() { |
35 // NOTE: we can do this check here only because we use the NSS internal | 35 // NOTE: we can do this check here only because we use the NSS internal |
36 // slot. If we support other slots in the future, checking whether they | 36 // slot. If we support other slots in the future, checking whether they |
37 // support ECDSA may block NSS, and the value may also change as devices are | 37 // support ECDSA may block NSS, and the value may also change as devices are |
38 // inserted/removed, so we would need to re-check on every use. | 38 // inserted/removed, so we would need to re-check on every use. |
39 crypto::EnsureNSSInit(); | 39 crypto::EnsureNSSInit(); |
40 crypto::ScopedPK11Slot slot(GetKeySlot()); | 40 crypto::ScopedPK11Slot slot(GetTempKeySlot()); |
41 supported_ = PK11_DoesMechanism(slot.get(), CKM_EC_KEY_PAIR_GEN) && | 41 supported_ = PK11_DoesMechanism(slot.get(), CKM_EC_KEY_PAIR_GEN) && |
42 PK11_DoesMechanism(slot.get(), CKM_ECDSA); | 42 PK11_DoesMechanism(slot.get(), CKM_ECDSA); |
43 } | 43 } |
44 | 44 |
45 bool Supported() { | 45 bool Supported() { |
46 return supported_; | 46 return supported_; |
47 } | 47 } |
48 | 48 |
49 private: | 49 private: |
50 bool supported_; | 50 bool supported_; |
(...skipping 30 matching lines...) Expand all Loading... |
81 SECKEY_DestroyPublicKey(public_key_); | 81 SECKEY_DestroyPublicKey(public_key_); |
82 } | 82 } |
83 | 83 |
84 // static | 84 // static |
85 bool ECPrivateKey::IsSupported() { | 85 bool ECPrivateKey::IsSupported() { |
86 return g_elliptic_curve_supported.Get().Supported(); | 86 return g_elliptic_curve_supported.Get().Supported(); |
87 } | 87 } |
88 | 88 |
89 // static | 89 // static |
90 ECPrivateKey* ECPrivateKey::Create() { | 90 ECPrivateKey* ECPrivateKey::Create() { |
91 return CreateWithParams(PR_FALSE /* not permanent */, | 91 EnsureNSSInit(); |
92 PR_FALSE /* not sensitive */); | 92 |
| 93 ScopedPK11Slot slot(GetTempKeySlot()); |
| 94 return CreateWithParams(slot.get(), |
| 95 false /* not permanent */, |
| 96 false /* not sensitive */); |
93 } | 97 } |
94 | 98 |
| 99 #if defined(USE_NSS) |
95 // static | 100 // static |
96 ECPrivateKey* ECPrivateKey::CreateSensitive() { | 101 ECPrivateKey* ECPrivateKey::CreateSensitive(PK11SlotInfo* slot) { |
97 #if defined(USE_NSS) | 102 return CreateWithParams( |
98 return CreateWithParams(PR_TRUE /* permanent */, | 103 slot, true /* permanent */, true /* sensitive */); |
99 PR_TRUE /* sensitive */); | 104 } |
100 #else | |
101 // If USE_NSS is not defined, we initialize NSS with no databases, so we can't | |
102 // create permanent keys. | |
103 NOTREACHED(); | |
104 return NULL; | |
105 #endif | 105 #endif |
106 } | |
107 | 106 |
108 // static | 107 // static |
109 ECPrivateKey* ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( | 108 ECPrivateKey* ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( |
110 const std::string& password, | 109 const std::string& password, |
111 const std::vector<uint8>& encrypted_private_key_info, | 110 const std::vector<uint8>& encrypted_private_key_info, |
112 const std::vector<uint8>& subject_public_key_info) { | 111 const std::vector<uint8>& subject_public_key_info) { |
| 112 EnsureNSSInit(); |
| 113 |
| 114 ScopedPK11Slot slot(GetTempKeySlot()); |
113 return CreateFromEncryptedPrivateKeyInfoWithParams( | 115 return CreateFromEncryptedPrivateKeyInfoWithParams( |
| 116 slot.get(), |
114 password, | 117 password, |
115 encrypted_private_key_info, | 118 encrypted_private_key_info, |
116 subject_public_key_info, | 119 subject_public_key_info, |
117 PR_FALSE /* not permanent */, | 120 false /* not permanent */, |
118 PR_FALSE /* not sensitive */); | 121 false /* not sensitive */); |
119 } | 122 } |
120 | 123 |
| 124 #if defined(USE_NSS) |
121 // static | 125 // static |
122 ECPrivateKey* ECPrivateKey::CreateSensitiveFromEncryptedPrivateKeyInfo( | 126 ECPrivateKey* ECPrivateKey::CreateSensitiveFromEncryptedPrivateKeyInfo( |
| 127 PK11SlotInfo* slot, |
123 const std::string& password, | 128 const std::string& password, |
124 const std::vector<uint8>& encrypted_private_key_info, | 129 const std::vector<uint8>& encrypted_private_key_info, |
125 const std::vector<uint8>& subject_public_key_info) { | 130 const std::vector<uint8>& subject_public_key_info) { |
126 #if defined(USE_NSS) | |
127 return CreateFromEncryptedPrivateKeyInfoWithParams( | 131 return CreateFromEncryptedPrivateKeyInfoWithParams( |
| 132 slot, |
128 password, | 133 password, |
129 encrypted_private_key_info, | 134 encrypted_private_key_info, |
130 subject_public_key_info, | 135 subject_public_key_info, |
131 PR_TRUE /* permanent */, | 136 true /* permanent */, |
132 PR_TRUE /* sensitive */); | 137 true /* sensitive */); |
133 #else | 138 } |
134 // If USE_NSS is not defined, we initialize NSS with no databases, so we can't | |
135 // create permanent keys. | |
136 NOTREACHED(); | |
137 return NULL; | |
138 #endif | 139 #endif |
139 } | |
140 | 140 |
141 // static | 141 // static |
142 bool ECPrivateKey::ImportFromEncryptedPrivateKeyInfo( | 142 bool ECPrivateKey::ImportFromEncryptedPrivateKeyInfo( |
| 143 PK11SlotInfo* slot, |
143 const std::string& password, | 144 const std::string& password, |
144 const uint8* encrypted_private_key_info, | 145 const uint8* encrypted_private_key_info, |
145 size_t encrypted_private_key_info_len, | 146 size_t encrypted_private_key_info_len, |
146 CERTSubjectPublicKeyInfo* decoded_spki, | 147 CERTSubjectPublicKeyInfo* decoded_spki, |
147 bool permanent, | 148 bool permanent, |
148 bool sensitive, | 149 bool sensitive, |
149 SECKEYPrivateKey** key, | 150 SECKEYPrivateKey** key, |
150 SECKEYPublicKey** public_key) { | 151 SECKEYPublicKey** public_key) { |
151 ScopedPK11Slot slot(GetKeySlot()); | 152 if (!slot) |
152 if (!slot.get()) | |
153 return false; | 153 return false; |
154 | 154 |
155 *public_key = SECKEY_ExtractPublicKey(decoded_spki); | 155 *public_key = SECKEY_ExtractPublicKey(decoded_spki); |
156 | 156 |
157 if (!*public_key) { | 157 if (!*public_key) { |
158 DLOG(ERROR) << "SECKEY_ExtractPublicKey: " << PORT_GetError(); | 158 DLOG(ERROR) << "SECKEY_ExtractPublicKey: " << PORT_GetError(); |
159 return false; | 159 return false; |
160 } | 160 } |
161 | 161 |
162 SECItem encoded_epki = { | 162 SECItem encoded_epki = { |
(...skipping 18 matching lines...) Expand all Loading... |
181 return false; | 181 return false; |
182 } | 182 } |
183 | 183 |
184 SECItem password_item = { | 184 SECItem password_item = { |
185 siBuffer, | 185 siBuffer, |
186 reinterpret_cast<unsigned char*>(const_cast<char*>(password.data())), | 186 reinterpret_cast<unsigned char*>(const_cast<char*>(password.data())), |
187 static_cast<unsigned>(password.size()) | 187 static_cast<unsigned>(password.size()) |
188 }; | 188 }; |
189 | 189 |
190 rv = ImportEncryptedECPrivateKeyInfoAndReturnKey( | 190 rv = ImportEncryptedECPrivateKeyInfoAndReturnKey( |
191 slot.get(), | 191 slot, |
192 &epki, | 192 &epki, |
193 &password_item, | 193 &password_item, |
194 NULL, // nickname | 194 NULL, // nickname |
195 &(*public_key)->u.ec.publicValue, | 195 &(*public_key)->u.ec.publicValue, |
196 permanent, | 196 permanent, |
197 sensitive, | 197 sensitive, |
198 key, | 198 key, |
199 NULL); // wincx | 199 NULL); // wincx |
200 if (rv != SECSuccess) { | 200 if (rv != SECSuccess) { |
201 DLOG(ERROR) << "ImportEncryptedECPrivateKeyInfoAndReturnKey: " | 201 DLOG(ERROR) << "ImportEncryptedECPrivateKeyInfoAndReturnKey: " |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
268 return ReadAttribute(key_, CKA_VALUE, output); | 268 return ReadAttribute(key_, CKA_VALUE, output); |
269 } | 269 } |
270 | 270 |
271 bool ECPrivateKey::ExportECParams(std::vector<uint8>* output) { | 271 bool ECPrivateKey::ExportECParams(std::vector<uint8>* output) { |
272 return ReadAttribute(key_, CKA_EC_PARAMS, output); | 272 return ReadAttribute(key_, CKA_EC_PARAMS, output); |
273 } | 273 } |
274 | 274 |
275 ECPrivateKey::ECPrivateKey() : key_(NULL), public_key_(NULL) {} | 275 ECPrivateKey::ECPrivateKey() : key_(NULL), public_key_(NULL) {} |
276 | 276 |
277 // static | 277 // static |
278 ECPrivateKey* ECPrivateKey::CreateWithParams(bool permanent, | 278 ECPrivateKey* ECPrivateKey::CreateWithParams(PK11SlotInfo* slot, |
| 279 bool permanent, |
279 bool sensitive) { | 280 bool sensitive) { |
280 EnsureNSSInit(); | 281 if (!slot) |
| 282 return NULL; |
281 | 283 |
282 scoped_ptr<ECPrivateKey> result(new ECPrivateKey); | 284 scoped_ptr<ECPrivateKey> result(new ECPrivateKey); |
283 | 285 |
284 ScopedPK11Slot slot(GetKeySlot()); | |
285 if (!slot.get()) | |
286 return NULL; | |
287 | |
288 SECOidData* oid_data = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1); | 286 SECOidData* oid_data = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1); |
289 if (!oid_data) { | 287 if (!oid_data) { |
290 DLOG(ERROR) << "SECOID_FindOIDByTag: " << PORT_GetError(); | 288 DLOG(ERROR) << "SECOID_FindOIDByTag: " << PORT_GetError(); |
291 return NULL; | 289 return NULL; |
292 } | 290 } |
293 | 291 |
294 // SECKEYECParams is a SECItem containing the DER encoded ASN.1 ECParameters | 292 // SECKEYECParams is a SECItem containing the DER encoded ASN.1 ECParameters |
295 // value. For a named curve, that is just the OBJECT IDENTIFIER of the curve. | 293 // value. For a named curve, that is just the OBJECT IDENTIFIER of the curve. |
296 // In addition to the oid data, the encoding requires one byte for the ASN.1 | 294 // In addition to the oid data, the encoding requires one byte for the ASN.1 |
297 // tag and one byte for the length (assuming the length is <= 127). | 295 // tag and one byte for the length (assuming the length is <= 127). |
298 DCHECK_LE(oid_data->oid.len, 127U); | 296 DCHECK_LE(oid_data->oid.len, 127U); |
299 std::vector<unsigned char> parameters_buf(2 + oid_data->oid.len); | 297 std::vector<unsigned char> parameters_buf(2 + oid_data->oid.len); |
300 SECKEYECParams ec_parameters = { | 298 SECKEYECParams ec_parameters = { |
301 siDEROID, ¶meters_buf[0], | 299 siDEROID, ¶meters_buf[0], |
302 static_cast<unsigned>(parameters_buf.size()) | 300 static_cast<unsigned>(parameters_buf.size()) |
303 }; | 301 }; |
304 | 302 |
305 ec_parameters.data[0] = SEC_ASN1_OBJECT_ID; | 303 ec_parameters.data[0] = SEC_ASN1_OBJECT_ID; |
306 ec_parameters.data[1] = oid_data->oid.len; | 304 ec_parameters.data[1] = oid_data->oid.len; |
307 memcpy(ec_parameters.data + 2, oid_data->oid.data, oid_data->oid.len); | 305 memcpy(ec_parameters.data + 2, oid_data->oid.data, oid_data->oid.len); |
308 | 306 |
309 result->key_ = PK11_GenerateKeyPair(slot.get(), | 307 result->key_ = PK11_GenerateKeyPair(slot, |
310 CKM_EC_KEY_PAIR_GEN, | 308 CKM_EC_KEY_PAIR_GEN, |
311 &ec_parameters, | 309 &ec_parameters, |
312 &result->public_key_, | 310 &result->public_key_, |
313 permanent, | 311 permanent, |
314 sensitive, | 312 sensitive, |
315 NULL); | 313 NULL); |
316 if (!result->key_) { | 314 if (!result->key_) { |
317 DLOG(ERROR) << "PK11_GenerateKeyPair: " << PORT_GetError(); | 315 DLOG(ERROR) << "PK11_GenerateKeyPair: " << PORT_GetError(); |
318 return NULL; | 316 return NULL; |
319 } | 317 } |
320 | 318 |
321 return result.release(); | 319 return result.release(); |
322 } | 320 } |
323 | 321 |
324 // static | 322 // static |
325 ECPrivateKey* ECPrivateKey::CreateFromEncryptedPrivateKeyInfoWithParams( | 323 ECPrivateKey* ECPrivateKey::CreateFromEncryptedPrivateKeyInfoWithParams( |
| 324 PK11SlotInfo* slot, |
326 const std::string& password, | 325 const std::string& password, |
327 const std::vector<uint8>& encrypted_private_key_info, | 326 const std::vector<uint8>& encrypted_private_key_info, |
328 const std::vector<uint8>& subject_public_key_info, | 327 const std::vector<uint8>& subject_public_key_info, |
329 bool permanent, | 328 bool permanent, |
330 bool sensitive) { | 329 bool sensitive) { |
331 EnsureNSSInit(); | |
332 | |
333 scoped_ptr<ECPrivateKey> result(new ECPrivateKey); | 330 scoped_ptr<ECPrivateKey> result(new ECPrivateKey); |
334 | 331 |
335 SECItem encoded_spki = { | 332 SECItem encoded_spki = { |
336 siBuffer, | 333 siBuffer, |
337 const_cast<unsigned char*>(&subject_public_key_info[0]), | 334 const_cast<unsigned char*>(&subject_public_key_info[0]), |
338 static_cast<unsigned>(subject_public_key_info.size()) | 335 static_cast<unsigned>(subject_public_key_info.size()) |
339 }; | 336 }; |
340 CERTSubjectPublicKeyInfo* decoded_spki = SECKEY_DecodeDERSubjectPublicKeyInfo( | 337 CERTSubjectPublicKeyInfo* decoded_spki = SECKEY_DecodeDERSubjectPublicKeyInfo( |
341 &encoded_spki); | 338 &encoded_spki); |
342 if (!decoded_spki) { | 339 if (!decoded_spki) { |
343 DLOG(ERROR) << "SECKEY_DecodeDERSubjectPublicKeyInfo: " << PORT_GetError(); | 340 DLOG(ERROR) << "SECKEY_DecodeDERSubjectPublicKeyInfo: " << PORT_GetError(); |
344 return NULL; | 341 return NULL; |
345 } | 342 } |
346 | 343 |
347 bool success = ECPrivateKey::ImportFromEncryptedPrivateKeyInfo( | 344 bool success = ImportFromEncryptedPrivateKeyInfo( |
| 345 slot, |
348 password, | 346 password, |
349 &encrypted_private_key_info[0], | 347 &encrypted_private_key_info[0], |
350 encrypted_private_key_info.size(), | 348 encrypted_private_key_info.size(), |
351 decoded_spki, | 349 decoded_spki, |
352 permanent, | 350 permanent, |
353 sensitive, | 351 sensitive, |
354 &result->key_, | 352 &result->key_, |
355 &result->public_key_); | 353 &result->public_key_); |
356 | 354 |
357 SECKEY_DestroySubjectPublicKeyInfo(decoded_spki); | 355 SECKEY_DestroySubjectPublicKeyInfo(decoded_spki); |
358 | 356 |
359 if (success) | 357 if (success) |
360 return result.release(); | 358 return result.release(); |
361 | 359 |
362 return NULL; | 360 return NULL; |
363 } | 361 } |
364 | 362 |
365 } // namespace crypto | 363 } // namespace crypto |
OLD | NEW |