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 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 174 buffer_data + output_len, | 174 buffer_data + output_len, |
| 175 &final_output_chunk_len, | 175 &final_output_chunk_len, |
| 176 output_max_len - output_len)) { | 176 output_max_len - output_len)) { |
| 177 return false; | 177 return false; |
| 178 } | 178 } |
| 179 | 179 |
| 180 webcrypto::ShrinkBuffer(buffer, final_output_chunk_len + output_len); | 180 webcrypto::ShrinkBuffer(buffer, final_output_chunk_len + output_len); |
| 181 return true; | 181 return true; |
| 182 } | 182 } |
| 183 | 183 |
| 184 // Constants for RFC 3394 AES Key Wrap / Unwrap. | |
| 185 const CK_MECHANISM_TYPE kAesKwMechanism = CKM_NSS_AES_KEY_WRAP; | |
| 186 // The Default IV. See http://www.ietf.org/rfc/rfc3394.txt Section 2.2.3.1. | |
| 187 const unsigned char kAesIv[] = {0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6}; | |
| 188 | |
| 189 // Performs RFC 3394 AES Key Wrap (encryption) of the input data. | |
| 190 bool AesKwEncrypt( | |
| 191 const blink::WebCryptoKey& key, | |
| 192 const unsigned char* data, | |
| 193 unsigned data_size, | |
| 194 blink::WebArrayBuffer* buffer) { | |
| 195 DCHECK_EQ(blink::WebCryptoAlgorithmIdAesKw, key.algorithm().id()); | |
| 196 DCHECK_EQ(blink::WebCryptoKeyTypeSecret, key.type()); | |
| 197 DCHECK(blink::WebCryptoKeyUsageWrapKey & key.usages()); | |
| 198 | |
| 199 // The data size must be at least 16 bytes and a multiple of 8 bytes. | |
| 200 if (data_size < 16 || data_size % 8) | |
| 201 return false; | |
| 202 DCHECK(data); | |
| 203 | |
| 204 SECItem iv_item = {siBuffer, const_cast<unsigned char*>(kAesIv), | |
| 205 arraysize(kAesIv)}; | |
| 206 crypto::ScopedSECItem param_item(PK11_ParamFromIV(kAesKwMechanism, &iv_item)); | |
| 207 DCHECK(param_item); | |
| 208 | |
| 209 // Turn the data to be wrapped into a PK11SymKey in order to use the NSS | |
| 210 // PK11_WrapSymKey() API. Create the PK11SymKey by importing the data as a | |
| 211 // generic secret blob, since we can't be certain what it is at this point. | |
|
Bryan Eyler
2014/01/15 19:30:17
Will we be hitting any issues with unwrapping a no
padolph
2014/01/15 22:58:52
Good point. I don't think using an asym key as an
eroman
2014/01/15 23:45:03
I have asked rsleevi to comment on this, hopefully
| |
| 212 SECItem data_item = {siBuffer, const_cast<unsigned char*>(data), data_size}; | |
| 213 crypto::ScopedPK11SymKey key_to_be_wrapped( | |
| 214 PK11_ImportSymKey(PK11_GetInternalSlot(), | |
| 215 CKK_GENERIC_SECRET, | |
| 216 PK11_OriginGenerated, | |
| 217 CKA_ENCRYPT, | |
| 218 &data_item, | |
| 219 0)); | |
| 220 if (!key_to_be_wrapped) | |
| 221 return false; | |
| 222 | |
| 223 // AES Key Wrap always adds 8 bytes to the input data size. RFC 3394 does not | |
| 224 // specify a maximum allowed data length, but since we are only wrapping keys, | |
| 225 // which are usually small, a reasonable max size is whatever will fit into an | |
| 226 // unsigned. | |
| 227 if (data_size > UINT_MAX - 8) | |
| 228 return false; | |
| 229 const unsigned int output_length = data_size + 8; | |
| 230 | |
| 231 *buffer = blink::WebArrayBuffer::create(output_length, 1); | |
| 232 unsigned char* buffer_data = reinterpret_cast<unsigned char*>(buffer->data()); | |
| 233 SECItem wrapped_key_item = {siBuffer, buffer_data, output_length}; | |
| 234 | |
| 235 SymKeyHandle* wrapping_key = reinterpret_cast<SymKeyHandle*>(key.handle()); | |
| 236 | |
| 237 if (SECSuccess != PK11_WrapSymKey(kAesKwMechanism, | |
| 238 param_item.get(), | |
| 239 wrapping_key->key(), | |
| 240 key_to_be_wrapped.get(), | |
| 241 &wrapped_key_item)) { | |
| 242 return false; | |
| 243 } | |
| 244 if (output_length != wrapped_key_item.len) { | |
| 245 buffer->reset(); | |
| 246 return false; | |
| 247 } | |
| 248 | |
| 249 return true; | |
| 250 } | |
| 251 | |
| 252 // Performs RFC 3394 AES Key Unwrap (decryption) of the input data. | |
| 253 bool AesKwDecrypt( | |
| 254 const blink::WebCryptoKey& key, | |
| 255 const unsigned char* data, | |
| 256 unsigned data_size, | |
| 257 blink::WebArrayBuffer* buffer) { | |
| 258 DCHECK_EQ(blink::WebCryptoAlgorithmIdAesKw, key.algorithm().id()); | |
| 259 DCHECK_EQ(blink::WebCryptoKeyTypeSecret, key.type()); | |
| 260 DCHECK(blink::WebCryptoKeyUsageUnwrapKey & key.usages()); | |
| 261 | |
| 262 // The ciphertext data size must be at least 24 bytes and a multiple of | |
| 263 // 8 bytes. | |
| 264 if (data_size < 24 || data_size % 8 != 0) | |
| 265 return false; | |
| 266 DCHECK(data); | |
| 267 | |
| 268 SymKeyHandle* wrapping_key = reinterpret_cast<SymKeyHandle*>(key.handle()); | |
| 269 | |
| 270 SECItem iv_item = {siBuffer, const_cast<unsigned char*>(kAesIv), | |
| 271 arraysize(kAesIv)}; | |
| 272 crypto::ScopedSECItem param_item(PK11_ParamFromIV(kAesKwMechanism, &iv_item)); | |
| 273 DCHECK(param_item); | |
| 274 | |
| 275 SECItem cipher_text = {siBuffer, const_cast<unsigned char*>(data), data_size}; | |
| 276 | |
| 277 // The plaintext length is always 64 bits less than the data size. | |
| 278 const unsigned int plaintext_length = data_size - 8; | |
| 279 | |
| 280 crypto::ScopedPK11SymKey unwrapped_key(PK11_UnwrapSymKey( | |
| 281 wrapping_key->key(), | |
| 282 kAesKwMechanism, | |
| 283 param_item.get(), | |
| 284 &cipher_text, | |
| 285 CKK_GENERIC_SECRET, // Import the key material without knowing its kind. | |
| 286 CKA_ENCRYPT, // A safe value since all we're doing is exporting the key. | |
| 287 plaintext_length)); | |
| 288 if (!unwrapped_key) | |
| 289 return false; | |
| 290 | |
| 291 if (PK11_ExtractKeyValue(unwrapped_key.get()) != SECSuccess) | |
| 292 return false; | |
| 293 | |
| 294 const SECItem* key_data = PK11_GetKeyData(unwrapped_key.get()); | |
| 295 if (!key_data || key_data->len != plaintext_length) | |
| 296 return false; | |
| 297 | |
| 298 *buffer = webcrypto::CreateArrayBuffer(key_data->data, key_data->len); | |
| 299 | |
| 300 return true; | |
| 301 } | |
| 302 | |
| 184 CK_MECHANISM_TYPE WebCryptoAlgorithmToGenMechanism( | 303 CK_MECHANISM_TYPE WebCryptoAlgorithmToGenMechanism( |
| 185 const blink::WebCryptoAlgorithm& algorithm) { | 304 const blink::WebCryptoAlgorithm& algorithm) { |
| 186 switch (algorithm.id()) { | 305 switch (algorithm.id()) { |
| 187 case blink::WebCryptoAlgorithmIdAesCbc: | 306 case blink::WebCryptoAlgorithmIdAesCbc: |
| 188 case blink::WebCryptoAlgorithmIdAesGcm: | 307 case blink::WebCryptoAlgorithmIdAesGcm: |
| 189 case blink::WebCryptoAlgorithmIdAesKw: | 308 case blink::WebCryptoAlgorithmIdAesKw: |
| 190 return CKM_AES_KEY_GEN; | 309 return CKM_AES_KEY_GEN; |
| 191 case blink::WebCryptoAlgorithmIdHmac: | 310 case blink::WebCryptoAlgorithmIdHmac: |
| 192 return WebCryptoHashToHMACMechanism(algorithm.hmacKeyParams()->hash()); | 311 return WebCryptoHashToHMACMechanism(algorithm.hmacKeyParams()->hash()); |
| 193 default: | 312 default: |
| (...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 495 const blink::WebCryptoAlgorithm& algorithm, | 614 const blink::WebCryptoAlgorithm& algorithm, |
| 496 const blink::WebCryptoKey& key, | 615 const blink::WebCryptoKey& key, |
| 497 const unsigned char* data, | 616 const unsigned char* data, |
| 498 unsigned data_size, | 617 unsigned data_size, |
| 499 blink::WebArrayBuffer* buffer) { | 618 blink::WebArrayBuffer* buffer) { |
| 500 | 619 |
| 501 DCHECK_EQ(algorithm.id(), key.algorithm().id()); | 620 DCHECK_EQ(algorithm.id(), key.algorithm().id()); |
| 502 DCHECK(key.handle()); | 621 DCHECK(key.handle()); |
| 503 DCHECK(buffer); | 622 DCHECK(buffer); |
| 504 | 623 |
| 624 // TODO(padolph): Convert to switch statement. | |
| 505 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) { | 625 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) { |
| 506 return AesCbcEncryptDecrypt( | 626 return AesCbcEncryptDecrypt( |
| 507 CKA_ENCRYPT, algorithm, key, data, data_size, buffer); | 627 CKA_ENCRYPT, algorithm, key, data, data_size, buffer); |
| 628 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdAesKw) { | |
| 629 return AesKwEncrypt(key, data, data_size, buffer); | |
| 508 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5) { | 630 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5) { |
| 509 | 631 |
| 510 // RSAES encryption does not support empty input | 632 // RSAES encryption does not support empty input |
| 511 if (!data_size) | 633 if (!data_size) |
| 512 return false; | 634 return false; |
| 513 DCHECK(data); | 635 DCHECK(data); |
| 514 | 636 |
| 515 if (key.type() != blink::WebCryptoKeyTypePublic) | 637 if (key.type() != blink::WebCryptoKeyTypePublic) |
| 516 return false; | 638 return false; |
| 517 | 639 |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 547 const blink::WebCryptoAlgorithm& algorithm, | 669 const blink::WebCryptoAlgorithm& algorithm, |
| 548 const blink::WebCryptoKey& key, | 670 const blink::WebCryptoKey& key, |
| 549 const unsigned char* data, | 671 const unsigned char* data, |
| 550 unsigned data_size, | 672 unsigned data_size, |
| 551 blink::WebArrayBuffer* buffer) { | 673 blink::WebArrayBuffer* buffer) { |
| 552 | 674 |
| 553 DCHECK_EQ(algorithm.id(), key.algorithm().id()); | 675 DCHECK_EQ(algorithm.id(), key.algorithm().id()); |
| 554 DCHECK(key.handle()); | 676 DCHECK(key.handle()); |
| 555 DCHECK(buffer); | 677 DCHECK(buffer); |
| 556 | 678 |
| 679 // TODO(padolph): Convert to switch statement. | |
| 557 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) { | 680 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) { |
| 558 return AesCbcEncryptDecrypt( | 681 return AesCbcEncryptDecrypt( |
| 559 CKA_DECRYPT, algorithm, key, data, data_size, buffer); | 682 CKA_DECRYPT, algorithm, key, data, data_size, buffer); |
| 683 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdAesKw) { | |
| 684 return AesKwDecrypt(key, data, data_size, buffer); | |
| 560 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5) { | 685 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5) { |
| 561 | 686 |
| 562 // RSAES decryption does not support empty input | 687 // RSAES decryption does not support empty input |
| 563 if (!data_size) | 688 if (!data_size) |
| 564 return false; | 689 return false; |
| 565 DCHECK(data); | 690 DCHECK(data); |
| 566 | 691 |
| 567 if (key.type() != blink::WebCryptoKeyTypePrivate) | 692 if (key.type() != blink::WebCryptoKeyTypePrivate) |
| 568 return false; | 693 return false; |
| 569 | 694 |
| (...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 992 | 1117 |
| 993 *key = blink::WebCryptoKey::create(new PublicKeyHandle(pubkey.Pass()), | 1118 *key = blink::WebCryptoKey::create(new PublicKeyHandle(pubkey.Pass()), |
| 994 blink::WebCryptoKeyTypePublic, | 1119 blink::WebCryptoKeyTypePublic, |
| 995 extractable, | 1120 extractable, |
| 996 algorithm, | 1121 algorithm, |
| 997 usage_mask); | 1122 usage_mask); |
| 998 return true; | 1123 return true; |
| 999 } | 1124 } |
| 1000 | 1125 |
| 1001 } // namespace content | 1126 } // namespace content |
| OLD | NEW |