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 <algorithm> | 7 #include <algorithm> |
| 8 #include <string> | 8 #include <string> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 87 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( | 87 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( |
| 88 algorithm_id, | 88 algorithm_id, |
| 89 new blink::WebCryptoRsaKeyGenParams( | 89 new blink::WebCryptoRsaKeyGenParams( |
| 90 modulus_length, | 90 modulus_length, |
| 91 webcrypto::Uint8VectorStart(public_exponent), | 91 webcrypto::Uint8VectorStart(public_exponent), |
| 92 public_exponent.size())); | 92 public_exponent.size())); |
| 93 } | 93 } |
| 94 | 94 |
| 95 #endif // #if !defined(USE_OPENSSL) | 95 #endif // #if !defined(USE_OPENSSL) |
| 96 | 96 |
| 97 // Determines if two ArrayBuffers have identical content. | |
| 98 bool ArrayBuffersEqual( | |
| 99 const blink::WebArrayBuffer& a, | |
| 100 const blink::WebArrayBuffer& b) { | |
| 101 if (a.byteLength() != b.byteLength()) | |
| 102 return false; | |
| 103 const uint8* a_begin = static_cast<uint8*>(a.data()); | |
| 104 const uint8* const a_end = a_begin + a.byteLength(); | |
| 105 const uint8* b_begin = static_cast<uint8*>(b.data()); | |
| 106 return std::equal(a_begin, a_end, b_begin); | |
|
eroman
2013/12/05 01:47:53
[no change necessary] My inclination would have be
padolph
2013/12/05 02:45:57
I'm sure std::equal optimizes down to memcmp in th
| |
| 107 } | |
| 108 | |
| 109 // Adapts ArrayBufferEqual() into a unary predicate for use with std::count_if | |
| 110 // in CopiesExist(). | |
| 111 class ArrayBufferEqualTo { | |
| 112 public: | |
| 113 ArrayBufferEqualTo(const blink::WebArrayBuffer& b) : b_(b) {} | |
| 114 bool operator()(const blink::WebArrayBuffer& a) const { | |
| 115 return ArrayBuffersEqual(a, b_); | |
| 116 } | |
| 117 | |
| 118 private: | |
| 119 const blink::WebArrayBuffer& b_; | |
| 120 }; | |
| 121 | |
| 122 // Given a vector of WebArrayBuffers, determines if there are any copies. Not | |
| 123 // the most efficient implementation, but the vector is expected to be small. | |
| 124 bool CopiesExist(std::vector<blink::WebArrayBuffer> bufs) { | |
| 125 for (std::vector<blink::WebArrayBuffer>::const_iterator it = bufs.begin(); | |
|
eroman
2013/12/05 01:47:53
I much prefer the old-fashioned double-for-loop he
padolph
2013/12/05 02:45:57
I can't argue with that. 1/3 the lines and faster.
| |
| 126 it != bufs.end(); | |
| 127 ++it) { | |
| 128 if (std::count_if(bufs.begin(), bufs.end(), ArrayBufferEqualTo(*it)) != 1) | |
| 129 return true; | |
| 130 } | |
| 131 return false; | |
| 132 } | |
| 133 | |
| 97 } // namespace | 134 } // namespace |
| 98 | 135 |
| 99 class WebCryptoImplTest : public testing::Test { | 136 class WebCryptoImplTest : public testing::Test { |
| 100 protected: | 137 protected: |
| 101 blink::WebCryptoKey ImportSecretKeyFromRawHexString( | 138 blink::WebCryptoKey ImportSecretKeyFromRawHexString( |
| 102 const std::string& key_hex, | 139 const std::string& key_hex, |
| 103 const blink::WebCryptoAlgorithm& algorithm, | 140 const blink::WebCryptoAlgorithm& algorithm, |
| 104 blink::WebCryptoKeyUsageMask usage) { | 141 blink::WebCryptoKeyUsageMask usage) { |
| 105 std::vector<uint8> key_raw = HexStringToBytes(key_hex); | 142 std::vector<uint8> key_raw = HexStringToBytes(key_hex); |
| 106 | 143 |
| (...skipping 318 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 425 ++test_index) { | 462 ++test_index) { |
| 426 SCOPED_TRACE(test_index); | 463 SCOPED_TRACE(test_index); |
| 427 const TestCase& test = kTests[test_index]; | 464 const TestCase& test = kTests[test_index]; |
| 428 | 465 |
| 429 blink::WebCryptoAlgorithm algorithm = | 466 blink::WebCryptoAlgorithm algorithm = |
| 430 webcrypto::CreateHmacAlgorithmByHashId(test.algorithm); | 467 webcrypto::CreateHmacAlgorithmByHashId(test.algorithm); |
| 431 | 468 |
| 432 blink::WebCryptoKey key = ImportSecretKeyFromRawHexString( | 469 blink::WebCryptoKey key = ImportSecretKeyFromRawHexString( |
| 433 test.key, algorithm, blink::WebCryptoKeyUsageSign); | 470 test.key, algorithm, blink::WebCryptoKeyUsageSign); |
| 434 | 471 |
| 472 // Verify exported raw key is identical to the imported data | |
| 473 blink::WebArrayBuffer raw_key; | |
| 474 EXPECT_TRUE(ExportKeyInternal(blink::WebCryptoKeyFormatRaw, key, &raw_key)); | |
| 475 ExpectArrayBufferMatchesHex(test.key, raw_key); | |
| 476 | |
| 435 std::vector<uint8> message_raw = HexStringToBytes(test.message); | 477 std::vector<uint8> message_raw = HexStringToBytes(test.message); |
| 436 | 478 |
| 437 blink::WebArrayBuffer output; | 479 blink::WebArrayBuffer output; |
| 438 | 480 |
| 439 ASSERT_TRUE(SignInternal(algorithm, key, message_raw, &output)); | 481 ASSERT_TRUE(SignInternal(algorithm, key, message_raw, &output)); |
| 440 | 482 |
| 441 ExpectArrayBufferMatchesHex(test.mac, output); | 483 ExpectArrayBufferMatchesHex(test.mac, output); |
| 442 | 484 |
| 443 bool signature_match = false; | 485 bool signature_match = false; |
| 444 EXPECT_TRUE(VerifySignatureInternal( | 486 EXPECT_TRUE(VerifySignatureInternal( |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 469 sizeof(kLongSignature), | 511 sizeof(kLongSignature), |
| 470 message_raw, | 512 message_raw, |
| 471 &signature_match)); | 513 &signature_match)); |
| 472 EXPECT_FALSE(signature_match); | 514 EXPECT_FALSE(signature_match); |
| 473 } | 515 } |
| 474 } | 516 } |
| 475 | 517 |
| 476 #if !defined(USE_OPENSSL) | 518 #if !defined(USE_OPENSSL) |
| 477 | 519 |
| 478 TEST_F(WebCryptoImplTest, AesCbcFailures) { | 520 TEST_F(WebCryptoImplTest, AesCbcFailures) { |
| 521 const std::string key_hex = "2b7e151628aed2a6abf7158809cf4f3c"; | |
| 479 blink::WebCryptoKey key = ImportSecretKeyFromRawHexString( | 522 blink::WebCryptoKey key = ImportSecretKeyFromRawHexString( |
| 480 "2b7e151628aed2a6abf7158809cf4f3c", | 523 key_hex, |
| 481 webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), | 524 webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), |
| 482 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt); | 525 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt); |
| 483 | 526 |
| 527 // Verify exported raw key is identical to the imported data | |
| 528 blink::WebArrayBuffer raw_key; | |
| 529 EXPECT_TRUE(ExportKeyInternal(blink::WebCryptoKeyFormatRaw, key, &raw_key)); | |
| 530 ExpectArrayBufferMatchesHex(key_hex, raw_key); | |
| 531 | |
| 484 blink::WebArrayBuffer output; | 532 blink::WebArrayBuffer output; |
| 485 | 533 |
| 486 // Use an invalid |iv| (fewer than 16 bytes) | 534 // Use an invalid |iv| (fewer than 16 bytes) |
| 487 { | 535 { |
| 488 std::vector<uint8> input(32); | 536 std::vector<uint8> input(32); |
| 489 std::vector<uint8> iv; | 537 std::vector<uint8> iv; |
| 490 EXPECT_FALSE(EncryptInternal( | 538 EXPECT_FALSE(EncryptInternal( |
| 491 webcrypto::CreateAesCbcAlgorithm(iv), key, input, &output)); | 539 webcrypto::CreateAesCbcAlgorithm(iv), key, input, &output)); |
| 492 EXPECT_FALSE(DecryptInternal( | 540 EXPECT_FALSE(DecryptInternal( |
| 493 webcrypto::CreateAesCbcAlgorithm(iv), key, input, &output)); | 541 webcrypto::CreateAesCbcAlgorithm(iv), key, input, &output)); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 527 | 575 |
| 528 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); | 576 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
| 529 EXPECT_FALSE(ImportKeyInternal(blink::WebCryptoKeyFormatRaw, | 577 EXPECT_FALSE(ImportKeyInternal(blink::WebCryptoKeyFormatRaw, |
| 530 key_raw, | 578 key_raw, |
| 531 webcrypto::CreateAesCbcAlgorithm(iv), | 579 webcrypto::CreateAesCbcAlgorithm(iv), |
| 532 true, | 580 true, |
| 533 blink::WebCryptoKeyUsageEncrypt, | 581 blink::WebCryptoKeyUsageEncrypt, |
| 534 &key)); | 582 &key)); |
| 535 } | 583 } |
| 536 | 584 |
| 537 // Fail exporting the key in SPKI format (SPKI export not allowed for secret | 585 // Fail exporting the key in SPKI and PKCS#8 formats (not allowed for secret |
| 538 // keys) | 586 // keys). |
| 539 EXPECT_FALSE(ExportKeyInternal(blink::WebCryptoKeyFormatSpki, key, &output)); | 587 EXPECT_FALSE(ExportKeyInternal(blink::WebCryptoKeyFormatSpki, key, &output)); |
| 588 EXPECT_FALSE(ExportKeyInternal(blink::WebCryptoKeyFormatPkcs8, key, &output)); | |
| 540 } | 589 } |
| 541 | 590 |
| 542 TEST_F(WebCryptoImplTest, AesCbcSampleSets) { | 591 TEST_F(WebCryptoImplTest, AesCbcSampleSets) { |
| 543 struct TestCase { | 592 struct TestCase { |
| 544 const char* key; | 593 const char* key; |
| 545 const char* iv; | 594 const char* iv; |
| 546 const char* plain_text; | 595 const char* plain_text; |
| 547 const char* cipher_text; | 596 const char* cipher_text; |
| 548 }; | 597 }; |
| 549 | 598 |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 619 | 668 |
| 620 for (size_t index = 0; index < ARRAYSIZE_UNSAFE(kTests); index++) { | 669 for (size_t index = 0; index < ARRAYSIZE_UNSAFE(kTests); index++) { |
| 621 SCOPED_TRACE(index); | 670 SCOPED_TRACE(index); |
| 622 const TestCase& test = kTests[index]; | 671 const TestCase& test = kTests[index]; |
| 623 | 672 |
| 624 blink::WebCryptoKey key = ImportSecretKeyFromRawHexString( | 673 blink::WebCryptoKey key = ImportSecretKeyFromRawHexString( |
| 625 test.key, | 674 test.key, |
| 626 webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), | 675 webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), |
| 627 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt); | 676 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt); |
| 628 | 677 |
| 678 // Verify exported raw key is identical to the imported data | |
| 679 blink::WebArrayBuffer raw_key; | |
| 680 EXPECT_TRUE(ExportKeyInternal(blink::WebCryptoKeyFormatRaw, key, &raw_key)); | |
| 681 ExpectArrayBufferMatchesHex(test.key, raw_key); | |
| 682 | |
| 629 std::vector<uint8> plain_text = HexStringToBytes(test.plain_text); | 683 std::vector<uint8> plain_text = HexStringToBytes(test.plain_text); |
| 630 std::vector<uint8> iv = HexStringToBytes(test.iv); | 684 std::vector<uint8> iv = HexStringToBytes(test.iv); |
| 631 | 685 |
| 632 blink::WebArrayBuffer output; | 686 blink::WebArrayBuffer output; |
| 633 | 687 |
| 634 // Test encryption. | 688 // Test encryption. |
| 635 EXPECT_TRUE(EncryptInternal(webcrypto::CreateAesCbcAlgorithm(iv), | 689 EXPECT_TRUE(EncryptInternal(webcrypto::CreateAesCbcAlgorithm(iv), |
| 636 key, | 690 key, |
| 637 plain_text, | 691 plain_text, |
| 638 &output)); | 692 &output)); |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 663 if (cipher_text.size() > 3) { | 717 if (cipher_text.size() > 3) { |
| 664 EXPECT_FALSE(DecryptInternal(webcrypto::CreateAesCbcAlgorithm(iv), | 718 EXPECT_FALSE(DecryptInternal(webcrypto::CreateAesCbcAlgorithm(iv), |
| 665 key, | 719 key, |
| 666 &cipher_text[0], | 720 &cipher_text[0], |
| 667 cipher_text.size() - 3, | 721 cipher_text.size() - 3, |
| 668 &output)); | 722 &output)); |
| 669 } | 723 } |
| 670 } | 724 } |
| 671 } | 725 } |
| 672 | 726 |
| 673 // TODO(padolph): Add test to verify generated symmetric keys appear random. | |
| 674 | |
| 675 TEST_F(WebCryptoImplTest, GenerateKeyAes) { | 727 TEST_F(WebCryptoImplTest, GenerateKeyAes) { |
| 676 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); | 728 // Generate a small sample of AES keys. |
| 677 ASSERT_TRUE( | 729 std::vector<blink::WebArrayBuffer> keys; |
| 678 GenerateKeyInternal(webcrypto::CreateAesCbcKeyGenAlgorithm(128), &key)); | 730 blink::WebArrayBuffer key_bytes; |
| 679 EXPECT_TRUE(key.handle()); | 731 for (int i = 0; i < 16; ++i) { |
| 680 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type()); | 732 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
| 733 ASSERT_TRUE( | |
| 734 GenerateKeyInternal(webcrypto::CreateAesCbcKeyGenAlgorithm(128), &key)); | |
| 735 EXPECT_TRUE(key.handle()); | |
| 736 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type()); | |
| 737 ASSERT_TRUE( | |
| 738 ExportKeyInternal(blink::WebCryptoKeyFormatRaw, key, &key_bytes)); | |
| 739 keys.push_back(key_bytes); | |
| 740 } | |
| 741 // Ensure all entries in the key sample set are unique. This is a simplistic | |
| 742 // estimate of whether the generated keys appear random. | |
| 743 EXPECT_FALSE(CopiesExist(keys)); | |
| 681 } | 744 } |
| 682 | 745 |
| 683 TEST_F(WebCryptoImplTest, GenerateKeyAesBadLength) { | 746 TEST_F(WebCryptoImplTest, GenerateKeyAesBadLength) { |
| 684 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); | 747 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
| 685 EXPECT_FALSE( | 748 EXPECT_FALSE( |
| 686 GenerateKeyInternal(webcrypto::CreateAesCbcKeyGenAlgorithm(0), &key)); | 749 GenerateKeyInternal(webcrypto::CreateAesCbcKeyGenAlgorithm(0), &key)); |
| 687 EXPECT_FALSE( | 750 EXPECT_FALSE( |
| 688 GenerateKeyInternal(webcrypto::CreateAesCbcKeyGenAlgorithm(0), &key)); | 751 GenerateKeyInternal(webcrypto::CreateAesCbcKeyGenAlgorithm(0), &key)); |
| 689 EXPECT_FALSE( | 752 EXPECT_FALSE( |
| 690 GenerateKeyInternal(webcrypto::CreateAesCbcKeyGenAlgorithm(129), &key)); | 753 GenerateKeyInternal(webcrypto::CreateAesCbcKeyGenAlgorithm(129), &key)); |
| 691 } | 754 } |
| 692 | 755 |
| 693 TEST_F(WebCryptoImplTest, GenerateKeyHmac) { | 756 TEST_F(WebCryptoImplTest, GenerateKeyHmac) { |
| 694 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); | 757 // Generate a small sample of HMAC keys. |
| 695 blink::WebCryptoAlgorithm algorithm = webcrypto::CreateHmacKeyGenAlgorithm( | 758 std::vector<blink::WebArrayBuffer> keys; |
| 696 blink::WebCryptoAlgorithmIdSha1, 128); | 759 for (int i = 0; i < 16; ++i) { |
| 697 ASSERT_TRUE(GenerateKeyInternal(algorithm, &key)); | 760 blink::WebArrayBuffer key_bytes; |
| 698 EXPECT_FALSE(key.isNull()); | 761 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
| 699 EXPECT_TRUE(key.handle()); | 762 blink::WebCryptoAlgorithm algorithm = webcrypto::CreateHmacKeyGenAlgorithm( |
| 700 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type()); | 763 blink::WebCryptoAlgorithmIdSha1, 128); |
| 764 ASSERT_TRUE(GenerateKeyInternal(algorithm, &key)); | |
| 765 EXPECT_FALSE(key.isNull()); | |
| 766 EXPECT_TRUE(key.handle()); | |
| 767 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type()); | |
| 768 } | |
| 769 // Ensure all entries in the key sample set are unique. This is a simplistic | |
| 770 // estimate of whether the generated keys appear random. | |
| 771 EXPECT_FALSE(CopiesExist(keys)); | |
| 701 } | 772 } |
| 702 | 773 |
| 703 TEST_F(WebCryptoImplTest, GenerateKeyHmacNoLength) { | 774 TEST_F(WebCryptoImplTest, GenerateKeyHmacNoLength) { |
| 704 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); | 775 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
| 705 blink::WebCryptoAlgorithm algorithm = | 776 blink::WebCryptoAlgorithm algorithm = |
| 706 webcrypto::CreateHmacKeyGenAlgorithm(blink::WebCryptoAlgorithmIdSha1, 0); | 777 webcrypto::CreateHmacKeyGenAlgorithm(blink::WebCryptoAlgorithmIdSha1, 0); |
| 707 ASSERT_TRUE(GenerateKeyInternal(algorithm, &key)); | 778 ASSERT_TRUE(GenerateKeyInternal(algorithm, &key)); |
| 708 EXPECT_TRUE(key.handle()); | 779 EXPECT_TRUE(key.handle()); |
| 709 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type()); | 780 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type()); |
| 710 } | 781 } |
| (...skipping 401 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1112 true, | 1183 true, |
| 1113 blink::WebCryptoKeyUsageEncrypt, | 1184 blink::WebCryptoKeyUsageEncrypt, |
| 1114 &key)); | 1185 &key)); |
| 1115 | 1186 |
| 1116 // Passing case: Export a previously imported RSA public key in SPKI format | 1187 // Passing case: Export a previously imported RSA public key in SPKI format |
| 1117 // and compare to original data. | 1188 // and compare to original data. |
| 1118 blink::WebArrayBuffer output; | 1189 blink::WebArrayBuffer output; |
| 1119 ASSERT_TRUE(ExportKeyInternal(blink::WebCryptoKeyFormatSpki, key, &output)); | 1190 ASSERT_TRUE(ExportKeyInternal(blink::WebCryptoKeyFormatSpki, key, &output)); |
| 1120 ExpectArrayBufferMatchesHex(hex_rsa_spki_der, output); | 1191 ExpectArrayBufferMatchesHex(hex_rsa_spki_der, output); |
| 1121 | 1192 |
| 1193 // Failing case: Try to export a previously imported RSA public key in raw | |
| 1194 // format (not allowed for a public key). | |
| 1195 EXPECT_FALSE(ExportKeyInternal(blink::WebCryptoKeyFormatRaw, key, &output)); | |
| 1196 | |
| 1122 // Failing case: Try to export a non-extractable key | 1197 // Failing case: Try to export a non-extractable key |
| 1123 ASSERT_TRUE(ImportKeyInternal( | 1198 ASSERT_TRUE(ImportKeyInternal( |
| 1124 blink::WebCryptoKeyFormatSpki, | 1199 blink::WebCryptoKeyFormatSpki, |
| 1125 HexStringToBytes(hex_rsa_spki_der), | 1200 HexStringToBytes(hex_rsa_spki_der), |
| 1126 webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5), | 1201 webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5), |
| 1127 false, | 1202 false, |
| 1128 blink::WebCryptoKeyUsageEncrypt, | 1203 blink::WebCryptoKeyUsageEncrypt, |
| 1129 &key)); | 1204 &key)); |
| 1130 EXPECT_TRUE(key.handle()); | 1205 EXPECT_TRUE(key.handle()); |
| 1131 EXPECT_FALSE(key.extractable()); | 1206 EXPECT_FALSE(key.extractable()); |
| (...skipping 443 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1575 private_key, | 1650 private_key, |
| 1576 reinterpret_cast<const unsigned char*>(encrypted_data.data()), | 1651 reinterpret_cast<const unsigned char*>(encrypted_data.data()), |
| 1577 encrypted_data.byteLength(), | 1652 encrypted_data.byteLength(), |
| 1578 &decrypted_data)); | 1653 &decrypted_data)); |
| 1579 ExpectArrayBufferMatchesHex(message_hex_str, decrypted_data); | 1654 ExpectArrayBufferMatchesHex(message_hex_str, decrypted_data); |
| 1580 } | 1655 } |
| 1581 | 1656 |
| 1582 #endif // #if !defined(USE_OPENSSL) | 1657 #endif // #if !defined(USE_OPENSSL) |
| 1583 | 1658 |
| 1584 } // namespace content | 1659 } // namespace content |
| OLD | NEW |