Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(112)

Side by Side Diff: content/renderer/webcrypto/webcrypto_impl_nss.cc

Issue 118623002: [webcrypto] Add raw symmetric key AES-KW wrap/unwrap for NSS. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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/renderer/webcrypto/webcrypto_impl.h" 5 #include "content/renderer/webcrypto/webcrypto_impl.h"
6 6
7 #include <cryptohi.h> 7 #include <cryptohi.h>
8 #include <pk11pub.h> 8 #include <pk11pub.h>
9 #include <sechash.h> 9 #include <sechash.h>
10 10
(...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after
362 if (result != SECSuccess) 362 if (result != SECSuccess)
363 return Status::Error(); 363 return Status::Error();
364 364
365 // Unfortunately the buffer needs to be shrunk for decryption (see the NSS bug 365 // Unfortunately the buffer needs to be shrunk for decryption (see the NSS bug
366 // above). 366 // above).
367 webcrypto::ShrinkBuffer(buffer, output_len); 367 webcrypto::ShrinkBuffer(buffer, output_len);
368 368
369 return Status::Success(); 369 return Status::Success();
370 } 370 }
371 371
372 // The Default IV for AES-KW. See http://www.ietf.org/rfc/rfc3394.txt
373 // Section 2.2.3.1.
374 const unsigned char kAesIv[] = {0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6};
375
376 // Performs RFC 3394 AES Key Wrap (encryption) of the input data.
377 Status AesKwEncrypt(
378 const blink::WebCryptoKey& key,
379 const unsigned char* data,
380 unsigned data_size,
381 blink::WebArrayBuffer* buffer) {
382 DCHECK_EQ(blink::WebCryptoAlgorithmIdAesKw, key.algorithm().id());
383 DCHECK_EQ(blink::WebCryptoKeyTypeSecret, key.type());
384 DCHECK(blink::WebCryptoKeyUsageWrapKey & key.usages());
385
386 // The data size must be at least 16 bytes and a multiple of 8 bytes.
387 // RFC 3394 does not specify a maximum allowed data length, but since only
388 // keys are being wrapped in this application (which are small), a reasonable
389 // max limit is whatever will fit into an unsigned. For the max size test,
390 // note that AES Key Wrap always adds 8 bytes to the input data size.
391 if (data_size < 16)
392 return Status::ErrorDataTooSmall();
393 else if (data_size > UINT_MAX - 8)
394 return Status::ErrorDataTooLarge();
395 if (data_size % 8)
396 return Status::ErrorInvalidAesKwDataLength();
397 DCHECK(data);
398
399 SECItem iv_item = {siBuffer, const_cast<unsigned char*>(kAesIv),
eroman 2014/02/26 23:40:22 there is a helper for this once you rebase
padolph 2014/02/28 23:28:40 Done.
400 arraysize(kAesIv)};
401 crypto::ScopedSECItem param_item(PK11_ParamFromIV(
402 CKM_NSS_AES_KEY_WRAP,
403 &iv_item));
404 DCHECK(param_item);
eroman 2014/02/26 23:40:22 Not sure if this can be reached, perhaps make it a
padolph 2014/02/28 23:28:40 PK11_ParamFromIV can return NULL in the case of an
405
406 // Turn the data to be wrapped into a PK11SymKey in order to use the NSS
eroman 2014/02/26 23:40:22 I chatted with Sleevi and he suggested just starti
padolph 2014/02/28 23:28:40 Ok, this is in line with my earlier question to Ry
407 // PK11_WrapSymKey() API. The data to be wrapped can be anything, so the best
408 // choice when creating the PK11SymKey is to import the data as a generic
409 // secret blob.
410 SECItem data_item = {siBuffer, const_cast<unsigned char*>(data), data_size};
eroman 2014/02/26 23:40:22 there is a helper for this once you rebase
padolph 2014/02/28 23:28:40 Done.
411 crypto::ScopedPK11SymKey key_to_be_wrapped(
412 PK11_ImportSymKey(PK11_GetInternalSlot(),
413 CKK_GENERIC_SECRET,
414 PK11_OriginGenerated,
415 CKA_ENCRYPT,
416 &data_item,
417 0));
418 if (!key_to_be_wrapped)
419 return Status::Error();
420
421 const unsigned int output_length = data_size + 8;
422
423 *buffer = blink::WebArrayBuffer::create(output_length, 1);
424 unsigned char* buffer_data = reinterpret_cast<unsigned char*>(buffer->data());
425 SECItem wrapped_key_item = {siBuffer, buffer_data, output_length};
eroman 2014/02/26 23:40:22 there is a helper for this once you rebase
padolph 2014/02/28 23:28:40 Done.
426
427 SymKeyHandle* wrapping_key = reinterpret_cast<SymKeyHandle*>(key.handle());
eroman 2014/02/26 23:40:22 This has changed from my recent refactors. Instead
padolph 2014/02/28 23:28:40 Done.
428
429 if (SECSuccess != PK11_WrapSymKey(CKM_NSS_AES_KEY_WRAP,
430 param_item.get(),
431 wrapping_key->key(),
432 key_to_be_wrapped.get(),
433 &wrapped_key_item)) {
434 return Status::Error();
435 }
436 if (output_length != wrapped_key_item.len) {
437 buffer->reset();
eroman 2014/02/26 23:40:22 I wouldn't worry about calling reset in the error
padolph 2014/02/28 23:28:40 Done.
438 return Status::ErrorUnexpected();
439 }
440
441 return Status::Success();
442 }
443
444 // Performs RFC 3394 AES Key Unwrap (decryption) of the input data.
445 Status AesKwDecrypt(
446 const blink::WebCryptoKey& key,
447 const unsigned char* data,
448 unsigned data_size,
449 blink::WebArrayBuffer* buffer) {
450 DCHECK_EQ(blink::WebCryptoAlgorithmIdAesKw, key.algorithm().id());
451 DCHECK_EQ(blink::WebCryptoKeyTypeSecret, key.type());
452 DCHECK(blink::WebCryptoKeyUsageUnwrapKey & key.usages());
453
454 // The ciphertext data size must be at least 24 bytes and a multiple of
455 // 8 bytes.
456 if (data_size < 24)
457 return Status::ErrorDataTooSmall();
458 else if (data_size % 8 != 0)
eroman 2014/02/26 23:40:22 nit: no "else" after a return. Also above you omit
padolph 2014/02/28 23:28:40 Done.
459 return Status::ErrorInvalidAesKwDataLength();
460 DCHECK(data);
461
462 SymKeyHandle* wrapping_key = reinterpret_cast<SymKeyHandle*>(key.handle());
eroman 2014/02/26 23:40:22 ToPlatformSymKey() after you rebase
padolph 2014/02/28 23:28:40 Done.
463
464 SECItem iv_item = {siBuffer, const_cast<unsigned char*>(kAesIv),
eroman 2014/02/26 23:40:22 there is a helper for this once you rebase
padolph 2014/02/28 23:28:40 Done.
465 arraysize(kAesIv)};
466 crypto::ScopedSECItem param_item(PK11_ParamFromIV(
467 CKM_NSS_AES_KEY_WRAP,
468 &iv_item));
469 DCHECK(param_item);
470
471 SECItem cipher_text = {siBuffer, const_cast<unsigned char*>(data), data_size};
472
473 // The plaintext length is always 64 bits less than the data size.
474 const unsigned int plaintext_length = data_size - 8;
475
476 crypto::ScopedPK11SymKey unwrapped_key(PK11_UnwrapSymKey(
477 wrapping_key->key(),
478 CKM_NSS_AES_KEY_WRAP,
479 param_item.get(),
480 &cipher_text,
481 CKK_GENERIC_SECRET, // Import the key material without knowing its kind.
482 CKA_ENCRYPT, // This is a safe value for a key export operation.
483 plaintext_length));
484 if (!unwrapped_key)
485 return Status::Error();
486
487 if (PK11_ExtractKeyValue(unwrapped_key.get()) != SECSuccess)
eroman 2014/02/26 23:40:22 Per earlier comment, let's restrict this to just s
padolph 2014/02/28 23:28:40 This call is required even on a symkey. Otherwise
488 return Status::Error();
489
490 const SECItem* key_data = PK11_GetKeyData(unwrapped_key.get());
491 if (!key_data || key_data->len != plaintext_length)
492 return Status::Error();
493
494 *buffer = webcrypto::CreateArrayBuffer(key_data->data, key_data->len);
495
496 return Status::Success();
497 }
498
372 CK_MECHANISM_TYPE WebCryptoAlgorithmToGenMechanism( 499 CK_MECHANISM_TYPE WebCryptoAlgorithmToGenMechanism(
373 const blink::WebCryptoAlgorithm& algorithm) { 500 const blink::WebCryptoAlgorithm& algorithm) {
374 switch (algorithm.id()) { 501 switch (algorithm.id()) {
375 case blink::WebCryptoAlgorithmIdAesCbc: 502 case blink::WebCryptoAlgorithmIdAesCbc:
376 case blink::WebCryptoAlgorithmIdAesGcm: 503 case blink::WebCryptoAlgorithmIdAesGcm:
377 case blink::WebCryptoAlgorithmIdAesKw: 504 case blink::WebCryptoAlgorithmIdAesKw:
378 return CKM_AES_KEY_GEN; 505 return CKM_AES_KEY_GEN;
379 case blink::WebCryptoAlgorithmIdHmac: 506 case blink::WebCryptoAlgorithmIdHmac:
380 return WebCryptoHashToHMACMechanism(algorithm.hmacKeyParams()->hash()); 507 return WebCryptoHashToHMACMechanism(algorithm.hmacKeyParams()->hash());
381 default: 508 default:
(...skipping 732 matching lines...) Expand 10 before | Expand all | Expand 10 after
1114 1241
1115 switch (algorithm.id()) { 1242 switch (algorithm.id()) {
1116 case blink::WebCryptoAlgorithmIdAesCbc: 1243 case blink::WebCryptoAlgorithmIdAesCbc:
1117 return AesCbcEncryptDecrypt( 1244 return AesCbcEncryptDecrypt(
1118 CKA_ENCRYPT, algorithm, key, data, data_size, buffer); 1245 CKA_ENCRYPT, algorithm, key, data, data_size, buffer);
1119 case blink::WebCryptoAlgorithmIdAesGcm: 1246 case blink::WebCryptoAlgorithmIdAesGcm:
1120 return AesGcmEncryptDecrypt( 1247 return AesGcmEncryptDecrypt(
1121 true, algorithm, key, data, data_size, buffer); 1248 true, algorithm, key, data, data_size, buffer);
1122 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5: 1249 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5:
1123 return EncryptRsaEsPkcs1v1_5(algorithm, key, data, data_size, buffer); 1250 return EncryptRsaEsPkcs1v1_5(algorithm, key, data, data_size, buffer);
1251 case blink::WebCryptoAlgorithmIdAesKw:
1252 return AesKwEncrypt(key, data, data_size, buffer);
1124 default: 1253 default:
1125 return Status::ErrorUnsupported(); 1254 return Status::ErrorUnsupported();
1126 } 1255 }
1127 } 1256 }
1128 1257
1129 Status WebCryptoImpl::DecryptInternal( 1258 Status WebCryptoImpl::DecryptInternal(
1130 const blink::WebCryptoAlgorithm& algorithm, 1259 const blink::WebCryptoAlgorithm& algorithm,
1131 const blink::WebCryptoKey& key, 1260 const blink::WebCryptoKey& key,
1132 const unsigned char* data, 1261 const unsigned char* data,
1133 unsigned int data_size, 1262 unsigned int data_size,
1134 blink::WebArrayBuffer* buffer) { 1263 blink::WebArrayBuffer* buffer) {
1135 1264
1136 DCHECK_EQ(algorithm.id(), key.algorithm().id()); 1265 DCHECK_EQ(algorithm.id(), key.algorithm().id());
1137 DCHECK(key.handle()); 1266 DCHECK(key.handle());
1138 DCHECK(buffer); 1267 DCHECK(buffer);
1139 1268
1140 switch (algorithm.id()) { 1269 switch (algorithm.id()) {
1141 case blink::WebCryptoAlgorithmIdAesCbc: 1270 case blink::WebCryptoAlgorithmIdAesCbc:
1142 return AesCbcEncryptDecrypt( 1271 return AesCbcEncryptDecrypt(
1143 CKA_DECRYPT, algorithm, key, data, data_size, buffer); 1272 CKA_DECRYPT, algorithm, key, data, data_size, buffer);
1144 case blink::WebCryptoAlgorithmIdAesGcm: 1273 case blink::WebCryptoAlgorithmIdAesGcm:
1145 return AesGcmEncryptDecrypt( 1274 return AesGcmEncryptDecrypt(
1146 false, algorithm, key, data, data_size, buffer); 1275 false, algorithm, key, data, data_size, buffer);
1147 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5: 1276 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5:
1148 return DecryptRsaEsPkcs1v1_5(algorithm, key, data, data_size, buffer); 1277 return DecryptRsaEsPkcs1v1_5(algorithm, key, data, data_size, buffer);
1278 case blink::WebCryptoAlgorithmIdAesKw:
1279 return AesKwDecrypt(key, data, data_size, buffer);
1149 default: 1280 default:
1150 return Status::ErrorUnsupported(); 1281 return Status::ErrorUnsupported();
1151 } 1282 }
1152 } 1283 }
1153 1284
1154 Status WebCryptoImpl::DigestInternal( 1285 Status WebCryptoImpl::DigestInternal(
1155 const blink::WebCryptoAlgorithm& algorithm, 1286 const blink::WebCryptoAlgorithm& algorithm,
1156 const unsigned char* data, 1287 const unsigned char* data,
1157 unsigned int data_size, 1288 unsigned int data_size,
1158 blink::WebArrayBuffer* buffer) { 1289 blink::WebArrayBuffer* buffer) {
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after
1403 1534
1404 *key = blink::WebCryptoKey::create(new PublicKeyHandle(pubkey.Pass()), 1535 *key = blink::WebCryptoKey::create(new PublicKeyHandle(pubkey.Pass()),
1405 blink::WebCryptoKeyTypePublic, 1536 blink::WebCryptoKeyTypePublic,
1406 extractable, 1537 extractable,
1407 algorithm, 1538 algorithm,
1408 usage_mask); 1539 usage_mask);
1409 return Status::Success(); 1540 return Status::Success();
1410 } 1541 }
1411 1542
1412 } // namespace content 1543 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698