Chromium Code Reviews| 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 |