OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "content/child/webcrypto/nss/rsa_key_nss.h" | 5 #include "content/child/webcrypto/nss/rsa_key_nss.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "content/child/webcrypto/crypto_data.h" | 8 #include "content/child/webcrypto/crypto_data.h" |
9 #include "content/child/webcrypto/jwk.h" | 9 #include "content/child/webcrypto/jwk.h" |
10 #include "content/child/webcrypto/nss/key_nss.h" | 10 #include "content/child/webcrypto/nss/key_nss.h" |
(...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
264 | 264 |
265 // Helper to add an attribute to a template. | 265 // Helper to add an attribute to a template. |
266 void AddAttribute(CK_ATTRIBUTE_TYPE type, | 266 void AddAttribute(CK_ATTRIBUTE_TYPE type, |
267 void* value, | 267 void* value, |
268 unsigned long length, | 268 unsigned long length, |
269 std::vector<CK_ATTRIBUTE>* templ) { | 269 std::vector<CK_ATTRIBUTE>* templ) { |
270 CK_ATTRIBUTE attribute = {type, value, length}; | 270 CK_ATTRIBUTE attribute = {type, value, length}; |
271 templ->push_back(attribute); | 271 templ->push_back(attribute); |
272 } | 272 } |
273 | 273 |
274 // Helper to optionally add an attribute to a template, if the provided data is | 274 void AddAttribute(CK_ATTRIBUTE_TYPE type, |
275 // non-empty. | 275 const CryptoData& data, |
276 void AddOptionalAttribute(CK_ATTRIBUTE_TYPE type, | 276 std::vector<CK_ATTRIBUTE>* templ) { |
277 const CryptoData& data, | |
278 std::vector<CK_ATTRIBUTE>* templ) { | |
279 if (!data.byte_length()) | |
280 return; | |
281 CK_ATTRIBUTE attribute = {type, const_cast<unsigned char*>(data.bytes()), | 277 CK_ATTRIBUTE attribute = {type, const_cast<unsigned char*>(data.bytes()), |
282 data.byte_length()}; | 278 data.byte_length()}; |
283 templ->push_back(attribute); | 279 templ->push_back(attribute); |
284 } | 280 } |
285 | 281 |
286 void AddOptionalAttribute(CK_ATTRIBUTE_TYPE type, | 282 void AddAttribute(CK_ATTRIBUTE_TYPE type, |
287 const std::string& data, | 283 const std::string& data, |
288 std::vector<CK_ATTRIBUTE>* templ) { | 284 std::vector<CK_ATTRIBUTE>* templ) { |
289 AddOptionalAttribute(type, CryptoData(data), templ); | 285 AddAttribute(type, CryptoData(data), templ); |
290 } | 286 } |
291 | 287 |
292 Status ExportKeyPkcs8Nss(SECKEYPrivateKey* key, std::vector<uint8_t>* buffer) { | 288 Status ExportKeyPkcs8Nss(SECKEYPrivateKey* key, std::vector<uint8_t>* buffer) { |
293 if (key->keyType != rsaKey) | 289 if (key->keyType != rsaKey) |
294 return Status::ErrorUnsupported(); | 290 return Status::ErrorUnsupported(); |
295 | 291 |
296 // TODO(rsleevi): Implement OAEP support according to the spec. | 292 // TODO(rsleevi): Implement OAEP support according to the spec. |
297 | 293 |
298 #if defined(USE_NSS) | 294 #if defined(USE_NSS) |
299 // PK11_ExportDERPrivateKeyInfo isn't available. Use our fallback code. | 295 // PK11_ExportDERPrivateKeyInfo isn't available. Use our fallback code. |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
359 CK_BBOOL ck_false = CK_FALSE; | 355 CK_BBOOL ck_false = CK_FALSE; |
360 | 356 |
361 std::vector<CK_ATTRIBUTE> key_template; | 357 std::vector<CK_ATTRIBUTE> key_template; |
362 | 358 |
363 AddAttribute(CKA_CLASS, &obj_class, sizeof(obj_class), &key_template); | 359 AddAttribute(CKA_CLASS, &obj_class, sizeof(obj_class), &key_template); |
364 AddAttribute(CKA_KEY_TYPE, &key_type, sizeof(key_type), &key_template); | 360 AddAttribute(CKA_KEY_TYPE, &key_type, sizeof(key_type), &key_template); |
365 AddAttribute(CKA_TOKEN, &ck_false, sizeof(ck_false), &key_template); | 361 AddAttribute(CKA_TOKEN, &ck_false, sizeof(ck_false), &key_template); |
366 AddAttribute(CKA_SENSITIVE, &ck_false, sizeof(ck_false), &key_template); | 362 AddAttribute(CKA_SENSITIVE, &ck_false, sizeof(ck_false), &key_template); |
367 AddAttribute(CKA_PRIVATE, &ck_false, sizeof(ck_false), &key_template); | 363 AddAttribute(CKA_PRIVATE, &ck_false, sizeof(ck_false), &key_template); |
368 | 364 |
369 // Required properties. | 365 // Required properties by JWA. |
370 AddOptionalAttribute(CKA_MODULUS, params.n, &key_template); | 366 AddAttribute(CKA_MODULUS, params.n, &key_template); |
371 AddOptionalAttribute(CKA_PUBLIC_EXPONENT, params.e, &key_template); | 367 AddAttribute(CKA_PUBLIC_EXPONENT, params.e, &key_template); |
372 AddOptionalAttribute(CKA_PRIVATE_EXPONENT, params.d, &key_template); | 368 AddAttribute(CKA_PRIVATE_EXPONENT, params.d, &key_template); |
373 | 369 |
374 // Manufacture a CKA_ID so the created key can be retrieved later as a | 370 // Manufacture a CKA_ID so the created key can be retrieved later as a |
375 // SECKEYPrivateKey using FindKeyByKeyID(). Unfortunately there isn't a more | 371 // SECKEYPrivateKey using FindKeyByKeyID(). Unfortunately there isn't a more |
376 // direct way to do this in NSS. | 372 // direct way to do this in NSS. |
377 // | 373 // |
378 // For consistency with other NSS key creation methods, set the CKA_ID to | 374 // For consistency with other NSS key creation methods, set the CKA_ID to |
379 // PK11_MakeIDFromPubKey(). There are some problems with | 375 // PK11_MakeIDFromPubKey(). There are some problems with |
380 // this approach: | 376 // this approach: |
381 // | 377 // |
382 // (1) Prior to NSS 3.16.2, there is no parameter validation when creating | 378 // (1) Prior to NSS 3.16.2, there is no parameter validation when creating |
383 // private keys. It is therefore possible to construct a key using the | 379 // private keys. It is therefore possible to construct a key using the |
384 // known public modulus, and where all the other parameters are bogus. | 380 // known public modulus, and where all the other parameters are bogus. |
385 // FindKeyByKeyID() returns the first key matching the ID. So this would | 381 // FindKeyByKeyID() returns the first key matching the ID. So this would |
386 // effectively allow an attacker to retrieve a private key of their | 382 // effectively allow an attacker to retrieve a private key of their |
387 // choice. | 383 // choice. |
388 // | 384 // |
389 // (2) The ID space is shared by different key types. So theoretically | 385 // (2) The ID space is shared by different key types. So theoretically |
390 // possible to retrieve a key of the wrong type which has a matching | 386 // possible to retrieve a key of the wrong type which has a matching |
391 // CKA_ID. In practice I am told this is not likely except for small key | 387 // CKA_ID. In practice I am told this is not likely except for small key |
392 // sizes, since would require constructing keys with the same public | 388 // sizes, since would require constructing keys with the same public |
393 // data. | 389 // data. |
394 // | 390 // |
395 // (3) FindKeyByKeyID() doesn't necessarily return the object that was just | 391 // (3) FindKeyByKeyID() doesn't necessarily return the object that was just |
396 // created by CreateGenericObject. If the pre-existing key was | 392 // created by CreateGenericObject. If the pre-existing key was |
397 // provisioned with flags incompatible with WebCrypto (for instance | 393 // provisioned with flags incompatible with WebCrypto (for instance |
398 // marked sensitive) then this will break things. | 394 // marked sensitive) then this will break things. |
399 SECItem modulus_item = MakeSECItemForBuffer(CryptoData(params.n)); | 395 SECItem modulus_item = MakeSECItemForBuffer(CryptoData(params.n)); |
400 crypto::ScopedSECItem object_id(PK11_MakeIDFromPubKey(&modulus_item)); | 396 crypto::ScopedSECItem object_id(PK11_MakeIDFromPubKey(&modulus_item)); |
401 AddOptionalAttribute( | 397 AddAttribute( |
402 CKA_ID, CryptoData(object_id->data, object_id->len), &key_template); | 398 CKA_ID, CryptoData(object_id->data, object_id->len), &key_template); |
403 | 399 |
404 // Optional properties (all of these will have been specified or none). | 400 // Optional properties by JWA, however guaranteed to be present by Chromium's |
405 AddOptionalAttribute(CKA_PRIME_1, params.p, &key_template); | 401 // implementation. |
406 AddOptionalAttribute(CKA_PRIME_2, params.q, &key_template); | 402 AddAttribute(CKA_PRIME_1, params.p, &key_template); |
407 AddOptionalAttribute(CKA_EXPONENT_1, params.dp, &key_template); | 403 AddAttribute(CKA_PRIME_2, params.q, &key_template); |
408 AddOptionalAttribute(CKA_EXPONENT_2, params.dq, &key_template); | 404 AddAttribute(CKA_EXPONENT_1, params.dp, &key_template); |
409 AddOptionalAttribute(CKA_COEFFICIENT, params.qi, &key_template); | 405 AddAttribute(CKA_EXPONENT_2, params.dq, &key_template); |
| 406 AddAttribute(CKA_COEFFICIENT, params.qi, &key_template); |
410 | 407 |
411 crypto::ScopedPK11Slot slot(PK11_GetInternalSlot()); | 408 crypto::ScopedPK11Slot slot(PK11_GetInternalSlot()); |
412 | 409 |
413 ScopedPK11GenericObject key_object(PK11_CreateGenericObject( | 410 ScopedPK11GenericObject key_object(PK11_CreateGenericObject( |
414 slot.get(), &key_template[0], key_template.size(), PR_FALSE)); | 411 slot.get(), &key_template[0], key_template.size(), PR_FALSE)); |
415 | 412 |
416 if (!key_object) | 413 if (!key_object) |
417 return Status::OperationError(); | 414 return Status::OperationError(); |
418 | 415 |
419 crypto::ScopedSECKEYPrivateKey private_key_tmp( | 416 crypto::ScopedSECKEYPrivateKey private_key_tmp( |
(...skipping 438 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
858 return Status::Success(); | 855 return Status::Success(); |
859 } | 856 } |
860 default: | 857 default: |
861 return Status::ErrorUnexpected(); | 858 return Status::ErrorUnexpected(); |
862 } | 859 } |
863 } | 860 } |
864 | 861 |
865 } // namespace webcrypto | 862 } // namespace webcrypto |
866 | 863 |
867 } // namespace content | 864 } // namespace content |
OLD | NEW |