OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |