diff options
author | Allan Sandfeld Jensen <allan.jensen@theqtcompany.com> | 2015-06-18 14:10:49 +0200 |
---|---|---|
committer | Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com> | 2015-06-18 13:53:24 +0000 |
commit | 813fbf95af77a531c57a8c497345ad2c61d475b3 (patch) | |
tree | 821b2c8de8365f21b6c9ba17a236fb3006a1d506 /chromium/crypto | |
parent | af6588f8d723931a298c995fa97259bb7f7deb55 (diff) | |
download | qtwebengine-chromium-813fbf95af77a531c57a8c497345ad2c61d475b3.tar.gz |
BASELINE: Update chromium to 44.0.2403.47
Change-Id: Ie056fedba95cf5e5c76b30c4b2c80fca4764aa2f
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>
Diffstat (limited to 'chromium/crypto')
45 files changed, 1321 insertions, 838 deletions
diff --git a/chromium/crypto/BUILD.gn b/chromium/crypto/BUILD.gn index d3d318de50f..f84c4d455d6 100644 --- a/chromium/crypto/BUILD.gn +++ b/chromium/crypto/BUILD.gn @@ -3,10 +3,13 @@ # found in the LICENSE file. import("//build/config/crypto.gni") +import("//testing/test.gni") component("crypto") { output_name = "crcrypto" # Avoid colliding with OpenSSL's libcrypto. sources = [ + "aead_openssl.cc", + "aead_openssl.h", "apple_keychain.h", "apple_keychain_ios.mm", "apple_keychain_mac.mm", @@ -15,8 +18,8 @@ component("crypto") { "crypto_export.h", "cssm_init.cc", "cssm_init.h", - "curve25519.cc", "curve25519-donna.c", + "curve25519.cc", "curve25519.h", "ec_private_key.h", "ec_private_key_nss.cc", @@ -40,12 +43,15 @@ component("crypto") { "hmac_openssl.cc", "mac_security_services_lock.cc", "mac_security_services_lock.h", + # TODO(brettw) these mocks should be moved to a test_support_crypto target # if possible. "mock_apple_keychain.cc", "mock_apple_keychain.h", "mock_apple_keychain_ios.cc", "mock_apple_keychain_mac.cc", + "nss_key_util.cc", + "nss_key_util.h", "nss_util.cc", "nss_util.h", "nss_util_internal.h", @@ -65,8 +71,8 @@ component("crypto") { "rsa_private_key_openssl.cc", "scoped_capi_types.h", "scoped_nss_types.h", - "secure_hash_default.cc", "secure_hash.h", + "secure_hash_default.cc", "secure_hash_openssl.cc", "secure_util.cc", "secure_util.h", @@ -91,6 +97,9 @@ component("crypto") { "third_party/nss/sha512.cc", ] + # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. + configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] + deps = [ ":platform", "//base", @@ -131,9 +140,6 @@ component("crypto") { "ec_signature_creator_nss.cc", "encryptor_nss.cc", "hmac_nss.cc", - "nss_util.cc", - "nss_util.h", - "nss_util_internal.h", "rsa_private_key_nss.cc", "secure_hash_default.cc", "signature_creator_nss.cc", @@ -149,6 +155,8 @@ component("crypto") { } else { # Remove OpenSSL when using NSS. sources -= [ + "aead_openssl.cc", + "aead_openssl.h", "ec_private_key_openssl.cc", "ec_signature_creator_openssl.cc", "encryptor_openssl.cc", @@ -165,10 +173,24 @@ component("crypto") { ] } + # Some files are built when NSS is used at all, either for the internal crypto + # library or the platform certificate library. + if (use_openssl && !use_nss_certs) { + sources -= [ + "nss_key_util.cc", + "nss_key_util.h", + "nss_util.cc", + "nss_util.h", + "nss_util_internal.h", + ] + } + defines = [ "CRYPTO_IMPLEMENTATION" ] } -if (is_win) { +# TODO(GYP): TODO(dpranke), fix the compile errors for this stuff +# and make it work. +if (false && is_win) { # A minimal crypto subset for hmac-related stuff that small standalone # targets can use to reduce code size on Windows. This does not depend on # OpenSSL/NSS but will use Windows APIs for that functionality. @@ -208,13 +230,13 @@ test("crypto_unittests") { "ghash_unittest.cc", "hkdf_unittest.cc", "hmac_unittest.cc", + "nss_key_util_unittest.cc", "nss_util_unittest.cc", "openssl_bio_string_unittest.cc", - "p224_unittest.cc", "p224_spake_unittest.cc", + "p224_unittest.cc", "random_unittest.cc", "rsa_private_key_unittest.cc", - "rsa_private_key_nss_unittest.cc", "secure_hash_unittest.cc", "sha2_unittest.cc", "signature_creator_unittest.cc", @@ -222,18 +244,21 @@ test("crypto_unittests") { "symmetric_key_unittest.cc", ] - if (use_openssl || !is_linux) { + # Some files are built when NSS is used at all, either for the internal crypto + # library or the platform certificate library. + if (use_openssl && !use_nss_certs) { sources -= [ - "rsa_private_key_nss_unittest.cc", + "nss_key_util_unittest.cc", + "nss_util_unittest.cc", ] } - if (use_openssl) { - sources -= [ "nss_util_unittest.cc" ] - } else { + if (!use_openssl) { sources -= [ "openssl_bio_string_unittest.cc" ] } + configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] + deps = [ ":crypto", ":platform", @@ -248,10 +273,10 @@ test("crypto_unittests") { source_set("test_support") { sources = [ - "scoped_test_nss_db.cc", - "scoped_test_nss_db.h", "scoped_test_nss_chromeos_user.cc", "scoped_test_nss_chromeos_user.h", + "scoped_test_nss_db.cc", + "scoped_test_nss_db.h", "scoped_test_system_nss_key_slot.cc", "scoped_test_system_nss_key_slot.h", ] @@ -278,28 +303,46 @@ source_set("test_support") { } } +config("platform_config") { + if ((!use_openssl || use_nss_certs) && is_clang) { + # There is a broken header guard in /usr/include/nss/secmod.h: + # https://bugzilla.mozilla.org/show_bug.cgi?id=884072 + cflags = [ "-Wno-header-guard" ] + } +} + # This is a meta-target that forwards to NSS's SSL library or OpenSSL, # according to the state of the crypto flags. A target just wanting to depend # on the current SSL library should just depend on this. group("platform") { if (use_openssl) { - deps = [ "//third_party/boringssl" ] + deps = [ + "//third_party/boringssl", + ] } else { - deps = [ "//net/third_party/nss/ssl:libssl" ] + deps = [ + "//net/third_party/nss/ssl:libssl", + ] + } + + # Link in NSS if it is used for either the internal crypto library + # (!use_openssl) or platform certificate library (use_nss_certs). + if (!use_openssl || use_nss_certs) { if (is_linux) { # On Linux, we use the system NSS (excepting SSL where we always use our # own). - # - # We always need our SSL header search path to come before the system one - # so our versions are used. The libssl target will add the search path we - # want, but according to GN's ordering rules, public_configs' search path - # will get applied before ones inherited from our dependencies. - # Therefore, we need to explicitly list our custom libssl's config here - # before the system one. - public_configs = [ - "//net/third_party/nss/ssl:ssl_config", - "//third_party/nss:system_nss_no_ssl_config", - ] + public_configs = [ ":platform_config" ] + if (!use_openssl) { + # If using a bundled copy of NSS's SSL library, ensure the bundled SSL + # header search path comes before the system one so our versions are + # used. The libssl target will add the search path we want, but + # according to GN's ordering rules, public_configs' search path will get + # applied before ones inherited from our dependencies. Therefore, we + # need to explicitly list our custom libssl's config here before the + # system one. + public_configs += [ "//net/third_party/nss/ssl:ssl_config" ] + } + public_configs += [ "//third_party/nss:system_nss_no_ssl_config" ] } else { # Non-Linux platforms use the hermetic NSS from the tree. deps += [ diff --git a/chromium/crypto/PRESUBMIT.py b/chromium/crypto/PRESUBMIT.py deleted file mode 100644 index a2a5af9ae7a..00000000000 --- a/chromium/crypto/PRESUBMIT.py +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Chromium presubmit script for src/net. - -See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts -for more details on the presubmit API built into gcl. -""" - -def GetPreferredTryMasters(project, change): - # Changes in crypto often need a corresponding OpenSSL edit. - return { - 'tryserver.chromium.linux': { - 'linux_redux': set(['defaulttests']), - } - } diff --git a/chromium/crypto/aead_openssl.cc b/chromium/crypto/aead_openssl.cc new file mode 100644 index 00000000000..e32168a576b --- /dev/null +++ b/chromium/crypto/aead_openssl.cc @@ -0,0 +1,125 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "crypto/aead_openssl.h" + +#if defined(USE_OPENSSL) + +#include <openssl/aes.h> +#include <openssl/evp.h> +#include <string> + +#include "base/basictypes.h" +#include "base/strings/string_util.h" +#include "crypto/openssl_util.h" + +namespace crypto { + +Aead::Aead(AeadAlgorithm algorithm) : key_(nullptr) { + EnsureOpenSSLInit(); + switch (algorithm) { + case AES_128_CTR_HMAC_SHA256: + aead_ = EVP_aead_aes_128_ctr_hmac_sha256(); + break; + } +} + +Aead::~Aead() { +} + +void Aead::Init(const std::string* key) { + DCHECK(!key_); + DCHECK_EQ(KeyLength(), key->size()); + key_ = key; +} + +bool Aead::Seal(const base::StringPiece& plaintext, + const base::StringPiece& nonce, + const base::StringPiece& additional_data, + std::string* ciphertext) const { + DCHECK(key_); + DCHECK_EQ(NonceLength(), nonce.size()); + EVP_AEAD_CTX ctx; + + if (!EVP_AEAD_CTX_init(&ctx, aead_, + reinterpret_cast<const uint8*>(key_->data()), + key_->size(), EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr)) { + return false; + } + + std::string result; + const size_t max_output_length = + EVP_AEAD_max_overhead(aead_) + plaintext.size(); + size_t output_length; + uint8* out_ptr = + reinterpret_cast<uint8*>(WriteInto(&result, max_output_length + 1)); + + if (!EVP_AEAD_CTX_seal( + &ctx, out_ptr, &output_length, max_output_length, + reinterpret_cast<const uint8*>(nonce.data()), nonce.size(), + reinterpret_cast<const uint8*>(plaintext.data()), plaintext.size(), + reinterpret_cast<const uint8*>(additional_data.data()), + additional_data.size())) { + EVP_AEAD_CTX_cleanup(&ctx); + return false; + } + + DCHECK_LE(output_length, max_output_length); + result.resize(output_length); + + ciphertext->swap(result); + EVP_AEAD_CTX_cleanup(&ctx); + + return true; +} + +bool Aead::Open(const base::StringPiece& ciphertext, + const base::StringPiece& nonce, + const base::StringPiece& additional_data, + std::string* plaintext) const { + DCHECK(key_); + EVP_AEAD_CTX ctx; + + if (!EVP_AEAD_CTX_init(&ctx, aead_, + reinterpret_cast<const uint8*>(key_->data()), + key_->size(), EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr)) { + return false; + } + + std::string result; + const size_t max_output_length = ciphertext.size(); + size_t output_length; + uint8* out_ptr = + reinterpret_cast<uint8*>(WriteInto(&result, max_output_length + 1)); + + if (!EVP_AEAD_CTX_open( + &ctx, out_ptr, &output_length, max_output_length, + reinterpret_cast<const uint8*>(nonce.data()), nonce.size(), + reinterpret_cast<const uint8*>(ciphertext.data()), ciphertext.size(), + reinterpret_cast<const uint8*>(additional_data.data()), + additional_data.size())) { + EVP_AEAD_CTX_cleanup(&ctx); + return false; + } + + DCHECK_LE(output_length, max_output_length); + result.resize(output_length); + + plaintext->swap(result); + EVP_AEAD_CTX_cleanup(&ctx); + + return true; +} + +size_t Aead::KeyLength() const { + return EVP_AEAD_key_length(aead_); +} + +size_t Aead::NonceLength() const { + return EVP_AEAD_nonce_length(aead_); +} + +} // namespace + +#endif diff --git a/chromium/crypto/aead_openssl.h b/chromium/crypto/aead_openssl.h new file mode 100644 index 00000000000..773cce14286 --- /dev/null +++ b/chromium/crypto/aead_openssl.h @@ -0,0 +1,48 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CRYPTO_AEAD_H_ +#define CRYPTO_AEAD_H_ + +#include "base/strings/string_piece.h" +#include "crypto/crypto_export.h" + +struct evp_aead_st; + +namespace crypto { + +// This class exposes the AES-128-CTR-HMAC-SHA256 AEAD, currently only +// for OpenSSL builds. +class CRYPTO_EXPORT Aead { + public: + enum AeadAlgorithm { AES_128_CTR_HMAC_SHA256 }; + + explicit Aead(AeadAlgorithm algorithm); + + ~Aead(); + + void Init(const std::string* key); + + bool Seal(const base::StringPiece& plaintext, + const base::StringPiece& nonce, + const base::StringPiece& additional_data, + std::string* ciphertext) const; + + bool Open(const base::StringPiece& ciphertext, + const base::StringPiece& nonce, + const base::StringPiece& additional_data, + std::string* plaintext) const; + + size_t KeyLength() const; + + size_t NonceLength() const; + + private: + const std::string* key_; + const evp_aead_st* aead_; +}; + +} // namespace crypto + +#endif // CRYPTO_ENCRYPTOR_H_ diff --git a/chromium/crypto/aead_openssl_unittest.cc b/chromium/crypto/aead_openssl_unittest.cc new file mode 100644 index 00000000000..446bca2cb02 --- /dev/null +++ b/chromium/crypto/aead_openssl_unittest.cc @@ -0,0 +1,54 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "crypto/aead_openssl.h" + +#include <string> + +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +#if defined(USE_OPENSSL) + +TEST(AeadTest, SealOpen) { + crypto::Aead aead(crypto::Aead::AES_128_CTR_HMAC_SHA256); + std::string key(aead.KeyLength(), 0); + aead.Init(&key); + std::string nonce(aead.NonceLength(), 0); + std::string plaintext("this is the plaintext"); + std::string ad("this is the additional data"); + std::string ciphertext; + EXPECT_TRUE(aead.Seal(plaintext, nonce, ad, &ciphertext)); + EXPECT_LT(0U, ciphertext.size()); + + std::string decrypted; + EXPECT_TRUE(aead.Open(ciphertext, nonce, ad, &decrypted)); + + EXPECT_EQ(plaintext, decrypted); +} + +TEST(AeadTest, SealOpenWrongKey) { + crypto::Aead aead(crypto::Aead::AES_128_CTR_HMAC_SHA256); + std::string key(aead.KeyLength(), 0); + std::string wrong_key(aead.KeyLength(), 1); + aead.Init(&key); + crypto::Aead aead_wrong_key(crypto::Aead::AES_128_CTR_HMAC_SHA256); + aead_wrong_key.Init(&wrong_key); + + std::string nonce(aead.NonceLength(), 0); + std::string plaintext("this is the plaintext"); + std::string ad("this is the additional data"); + std::string ciphertext; + EXPECT_TRUE(aead.Seal(plaintext, nonce, ad, &ciphertext)); + EXPECT_LT(0U, ciphertext.size()); + + std::string decrypted; + EXPECT_FALSE(aead_wrong_key.Open(ciphertext, nonce, ad, &decrypted)); + EXPECT_EQ(0U, decrypted.size()); +} + +#endif + +} // namespace diff --git a/chromium/crypto/crypto.gyp b/chromium/crypto/crypto.gyp index 6d60f480fed..e6bff0b098b 100644 --- a/chromium/crypto/crypto.gyp +++ b/chromium/crypto/crypto.gyp @@ -49,9 +49,9 @@ ], }], [ 'OS == "android"', { - 'includes': [ - '../build/android/cpufeatures.gypi', - ], + 'dependencies': [ + '../build/android/ndk.gyp:cpu_features', + ], }], [ 'os_bsd==1', { 'link_settings': { @@ -108,9 +108,6 @@ 'ec_signature_creator_nss.cc', 'encryptor_nss.cc', 'hmac_nss.cc', - 'nss_util.cc', - 'nss_util.h', - 'nss_util_internal.h', 'rsa_private_key_nss.cc', 'secure_hash_default.cc', 'signature_creator_nss.cc', @@ -128,6 +125,8 @@ ], }, { 'sources!': [ + 'aead_openssl.cc', + 'aead_openssl.h', 'ec_private_key_openssl.cc', 'ec_signature_creator_openssl.cc', 'encryptor_openssl.cc', @@ -143,6 +142,17 @@ 'symmetric_key_openssl.cc', ], },], + [ 'use_openssl==1 and use_nss_certs==0', { + # Some files are built when NSS is used at all, either for the + # internal crypto library or the platform certificate library. + 'sources!': [ + 'nss_key_util.cc', + 'nss_key_util.h', + 'nss_util.cc', + 'nss_util.h', + 'nss_util_internal.h', + ], + },], ], 'sources': [ '<@(crypto_sources)', @@ -152,6 +162,7 @@ 'target_name': 'crypto_unittests', 'type': 'executable', 'sources': [ + 'aead_openssl_unittest.cc', 'curve25519_unittest.cc', 'ec_private_key_unittest.cc', 'ec_signature_creator_unittest.cc', @@ -159,13 +170,13 @@ 'ghash_unittest.cc', 'hkdf_unittest.cc', 'hmac_unittest.cc', + 'nss_key_util_unittest.cc', 'nss_util_unittest.cc', 'openssl_bio_string_unittest.cc', 'p224_unittest.cc', 'p224_spake_unittest.cc', 'random_unittest.cc', 'rsa_private_key_unittest.cc', - 'rsa_private_key_nss_unittest.cc', 'secure_hash_unittest.cc', 'sha2_unittest.cc', 'signature_creator_unittest.cc', @@ -182,7 +193,7 @@ '../testing/gtest.gyp:gtest', ], 'conditions': [ - [ 'os_posix == 1 and OS != "mac" and OS != "android" and OS != "ios"', { + [ 'use_nss_certs == 1', { 'conditions': [ [ 'use_allocator!="none"', { 'dependencies': [ @@ -194,10 +205,14 @@ 'dependencies': [ '../build/linux/system.gyp:ssl', ], - }, { # os_posix != 1 or OS == "mac" or OS == "android" or OS == "ios" + }], + [ 'use_openssl == 1 and use_nss_certs == 0', { + # Some files are built when NSS is used at all, either for the + # internal crypto library or the platform certificate library. 'sources!': [ - 'rsa_private_key_nss_unittest.cc', - ] + 'nss_key_util_unittest.cc', + 'nss_util_unittest.cc', + ], }], [ 'use_openssl == 0 and (OS == "mac" or OS == "ios" or OS == "win")', { 'dependencies': [ @@ -212,10 +227,6 @@ 'dependencies': [ '../third_party/boringssl/boringssl.gyp:boringssl', ], - 'sources!': [ - 'nss_util_unittest.cc', - 'rsa_private_key_nss_unittest.cc', - ], }, { 'sources!': [ 'openssl_bio_string_unittest.cc', @@ -238,7 +249,7 @@ '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations_win64', ], 'sources': [ - '<@(hmac_win64_related_sources)', + '<@(nacl_win64_sources)', ], 'defines': [ 'CRYPTO_IMPLEMENTATION', @@ -255,7 +266,7 @@ }, ], }], - ['use_nss==1', { + ['use_nss_certs==1', { 'targets': [ { 'target_name': 'crypto_test_support', @@ -273,7 +284,7 @@ 'scoped_test_system_nss_key_slot.h', ], 'conditions': [ - ['use_nss==0', { + ['use_nss_certs==0', { 'sources!': [ 'scoped_test_nss_db.cc', 'scoped_test_nss_db.h', @@ -289,7 +300,7 @@ }], ], } - ]}, { # use_nss==0 + ]}, { # use_nss_certs==0 'targets': [ { 'target_name': 'crypto_test_support', @@ -297,5 +308,22 @@ 'sources': [], } ]}], + ['test_isolation_mode != "noop"', { + 'targets': [ + { + 'target_name': 'crypto_unittests_run', + 'type': 'none', + 'dependencies': [ + 'crypto_unittests', + ], + 'includes': [ + '../build/isolate.gypi', + ], + 'sources': [ + 'crypto_unittests.isolate', + ], + }, + ], + }], ], } diff --git a/chromium/crypto/crypto.gypi b/chromium/crypto/crypto.gypi index 82b5da5dbc8..73b33322605 100644 --- a/chromium/crypto/crypto.gypi +++ b/chromium/crypto/crypto.gypi @@ -23,11 +23,12 @@ 'wincrypt_shim.h', ], }, - 'hmac_win64_related_sources': [ '<@(hmac_win64_related_sources)' ], 'crypto_sources': [ # NOTE: all transitive dependencies of HMAC on windows need # to be placed in the source list above. '<@(hmac_win64_related_sources)', + 'aead_openssl.cc', + 'aead_openssl.h', 'apple_keychain.h', 'apple_keychain_ios.mm', 'apple_keychain_mac.mm', @@ -66,6 +67,8 @@ 'p224_spake.cc', 'p224_spake.h', 'nss_crypto_module_delegate.h', + 'nss_key_util.cc', + 'nss_key_util.h', 'nss_util.cc', 'nss_util.h', 'nss_util_internal.h', @@ -100,6 +103,11 @@ 'third_party/nss/pk11akey.cc', 'third_party/nss/rsawrapr.c', 'third_party/nss/secsign.cc', - ] + ], + 'nacl_win64_sources': [ + '<@(hmac_win64_related_sources)', + 'random.cc', + 'random.h', + ], } } diff --git a/chromium/crypto/crypto_nacl.gyp b/chromium/crypto/crypto_nacl.gyp index 44516109196..255c42c51d3 100644 --- a/chromium/crypto/crypto_nacl.gyp +++ b/chromium/crypto/crypto_nacl.gyp @@ -23,7 +23,6 @@ }, 'dependencies': [ '../third_party/boringssl/boringssl_nacl.gyp:boringssl_nacl', - '../native_client/tools.gyp:prep_toolchain', '../native_client_sdk/native_client_sdk_untrusted.gyp:nacl_io_untrusted', ], 'defines': [ diff --git a/chromium/crypto/crypto_unittests.isolate b/chromium/crypto/crypto_unittests.isolate new file mode 100644 index 00000000000..93272b431ae --- /dev/null +++ b/chromium/crypto/crypto_unittests.isolate @@ -0,0 +1,70 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +{ + 'conditions': [ + ['use_x11==0', { + 'variables': { + 'command': [ + '../testing/test_env.py', + '<(PRODUCT_DIR)/crypto_unittests<(EXECUTABLE_SUFFIX)', + '--brave-new-test-launcher', + '--test-launcher-bot-mode', + '--asan=<(asan)', + '--msan=<(msan)', + '--tsan=<(tsan)', + ], + }, + }], + ['use_x11==1', { + 'variables': { + 'command': [ + '../testing/xvfb.py', + '<(PRODUCT_DIR)', + '<(PRODUCT_DIR)/crypto_unittests<(EXECUTABLE_SUFFIX)', + '--brave-new-test-launcher', + '--test-launcher-bot-mode', + '--asan=<(asan)', + '--msan=<(msan)', + '--tsan=<(tsan)', + ], + 'files': [ + '../testing/xvfb.py', + ], + }, + }], + ['OS=="linux" and use_ozone==0', { + 'variables': { + 'files': [ + '<(PRODUCT_DIR)/xdisplaycheck<(EXECUTABLE_SUFFIX)', + ], + }, + }], + ['OS=="linux" or OS=="mac" or OS=="win"', { + 'variables': { + 'files': [ + '../testing/test_env.py', + '<(PRODUCT_DIR)/crypto_unittests<(EXECUTABLE_SUFFIX)', + ], + 'read_only': 1, + }, + }], + ['OS=="mac" and asan==1 and fastbuild==0', { + 'variables': { + 'files': [ + '<(PRODUCT_DIR)/crypto_unittests.dSYM/', + ], + }, + }], + ['OS=="win" and (fastbuild==0 or fastbuild==1)', { + 'variables': { + 'files': [ + '<(PRODUCT_DIR)/crypto_unittests.exe.pdb', + ], + }, + }], + ], + 'includes': [ + '../base/base.isolate', + ], +} diff --git a/chromium/crypto/ec_private_key.h b/chromium/crypto/ec_private_key.h index 9fd8ffdfb62..87af838904a 100644 --- a/chromium/crypto/ec_private_key.h +++ b/chromium/crypto/ec_private_key.h @@ -42,13 +42,6 @@ class CRYPTO_EXPORT ECPrivateKey { // TODO(mattm): Add a curve parameter. static ECPrivateKey* Create(); -#if defined(USE_NSS) - // Creates a new random instance in |slot|. Can return NULL if initialization - // fails. The created key is permanent and is not exportable in plaintext - // form. - static ECPrivateKey* CreateSensitive(PK11SlotInfo* slot); -#endif - // Creates a new instance by importing an existing key pair. // The key pair is given as an ASN.1-encoded PKCS #8 EncryptedPrivateKeyInfo // block and an X.509 SubjectPublicKeyInfo block. @@ -58,19 +51,6 @@ class CRYPTO_EXPORT ECPrivateKey { const std::vector<uint8>& encrypted_private_key_info, const std::vector<uint8>& subject_public_key_info); -#if defined(USE_NSS) - // Creates a new instance in |slot| by importing an existing key pair. - // The key pair is given as an ASN.1-encoded PKCS #8 EncryptedPrivateKeyInfo - // block and an X.509 SubjectPublicKeyInfo block. - // This can return NULL if initialization fails. The created key is permanent - // and is not exportable in plaintext form. - static ECPrivateKey* CreateSensitiveFromEncryptedPrivateKeyInfo( - PK11SlotInfo* slot, - const std::string& password, - const std::vector<uint8>& encrypted_private_key_info, - const std::vector<uint8>& subject_public_key_info); -#endif - #if !defined(USE_OPENSSL) // Imports the key pair into |slot| and returns in |public_key| and |key|. // Shortcut for code that needs to keep a reference directly to NSS types @@ -86,10 +66,10 @@ class CRYPTO_EXPORT ECPrivateKey { bool sensitive, SECKEYPrivateKey** key, SECKEYPublicKey** public_key); +#endif // Returns a copy of the object. ECPrivateKey* Copy() const; -#endif #if defined(USE_OPENSSL) EVP_PKEY* key() { return key_; } @@ -122,25 +102,6 @@ class CRYPTO_EXPORT ECPrivateKey { // Constructor is private. Use one of the Create*() methods above instead. ECPrivateKey(); -#if !defined(USE_OPENSSL) - // Shared helper for Create() and CreateSensitive(). - // TODO(cmasone): consider replacing |permanent| and |sensitive| with a - // flags arg created by ORing together some enumerated values. - static ECPrivateKey* CreateWithParams(PK11SlotInfo* slot, - bool permanent, - bool sensitive); - - // Shared helper for CreateFromEncryptedPrivateKeyInfo() and - // CreateSensitiveFromEncryptedPrivateKeyInfo(). - static ECPrivateKey* CreateFromEncryptedPrivateKeyInfoWithParams( - PK11SlotInfo* slot, - const std::string& password, - const std::vector<uint8>& encrypted_private_key_info, - const std::vector<uint8>& subject_public_key_info, - bool permanent, - bool sensitive); -#endif - #if defined(USE_OPENSSL) EVP_PKEY* key_; #else diff --git a/chromium/crypto/ec_private_key_nss.cc b/chromium/crypto/ec_private_key_nss.cc index 2daa0c0f4a3..5092010c939 100644 --- a/chromium/crypto/ec_private_key_nss.cc +++ b/chromium/crypto/ec_private_key_nss.cc @@ -91,18 +91,47 @@ ECPrivateKey* ECPrivateKey::Create() { EnsureNSSInit(); ScopedPK11Slot slot(GetTempKeySlot()); - return CreateWithParams(slot.get(), - false /* not permanent */, - false /* not sensitive */); -} + if (!slot) + return nullptr; -#if defined(USE_NSS) -// static -ECPrivateKey* ECPrivateKey::CreateSensitive(PK11SlotInfo* slot) { - return CreateWithParams( - slot, true /* permanent */, true /* sensitive */); + scoped_ptr<ECPrivateKey> result(new ECPrivateKey); + + SECOidData* oid_data = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1); + if (!oid_data) { + DLOG(ERROR) << "SECOID_FindOIDByTag: " << PORT_GetError(); + return nullptr; + } + + // SECKEYECParams is a SECItem containing the DER encoded ASN.1 ECParameters + // value. For a named curve, that is just the OBJECT IDENTIFIER of the curve. + // In addition to the oid data, the encoding requires one byte for the ASN.1 + // tag and one byte for the length (assuming the length is <= 127). + CHECK_LE(oid_data->oid.len, 127U); + std::vector<unsigned char> parameters_buf(2 + oid_data->oid.len); + SECKEYECParams ec_parameters = { + siDEROID, ¶meters_buf[0], + static_cast<unsigned>(parameters_buf.size()) + }; + + ec_parameters.data[0] = SEC_ASN1_OBJECT_ID; + ec_parameters.data[1] = static_cast<unsigned char>(oid_data->oid.len); + memcpy(ec_parameters.data + 2, oid_data->oid.data, oid_data->oid.len); + + result->key_ = PK11_GenerateKeyPair(slot.get(), + CKM_EC_KEY_PAIR_GEN, + &ec_parameters, + &result->public_key_, + PR_FALSE /* not permanent */, + PR_FALSE /* not sensitive */, + NULL); + if (!result->key_) { + DLOG(ERROR) << "PK11_GenerateKeyPair: " << PORT_GetError(); + return nullptr; + } + CHECK_EQ(ecKey, SECKEY_GetPublicKeyType(result->public_key_)); + + return result.release(); } -#endif // static ECPrivateKey* ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( @@ -112,31 +141,43 @@ ECPrivateKey* ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( EnsureNSSInit(); ScopedPK11Slot slot(GetTempKeySlot()); - return CreateFromEncryptedPrivateKeyInfoWithParams( + if (!slot) + return nullptr; + + scoped_ptr<ECPrivateKey> result(new ECPrivateKey); + + SECItem encoded_spki = { + siBuffer, + const_cast<unsigned char*>(&subject_public_key_info[0]), + static_cast<unsigned>(subject_public_key_info.size()) + }; + CERTSubjectPublicKeyInfo* decoded_spki = SECKEY_DecodeDERSubjectPublicKeyInfo( + &encoded_spki); + if (!decoded_spki) { + DLOG(ERROR) << "SECKEY_DecodeDERSubjectPublicKeyInfo: " << PORT_GetError(); + return nullptr; + } + + bool success = ImportFromEncryptedPrivateKeyInfo( slot.get(), password, - encrypted_private_key_info, - subject_public_key_info, + &encrypted_private_key_info[0], + encrypted_private_key_info.size(), + decoded_spki, false /* not permanent */, - false /* not sensitive */); -} + false /* not sensitive */, + &result->key_, + &result->public_key_); -#if defined(USE_NSS) -// static -ECPrivateKey* ECPrivateKey::CreateSensitiveFromEncryptedPrivateKeyInfo( - PK11SlotInfo* slot, - const std::string& password, - const std::vector<uint8>& encrypted_private_key_info, - const std::vector<uint8>& subject_public_key_info) { - return CreateFromEncryptedPrivateKeyInfoWithParams( - slot, - password, - encrypted_private_key_info, - subject_public_key_info, - true /* permanent */, - true /* sensitive */); + SECKEY_DestroySubjectPublicKeyInfo(decoded_spki); + + if (success) { + CHECK_EQ(ecKey, SECKEY_GetPublicKeyType(result->public_key_)); + return result.release(); + } + + return nullptr; } -#endif // static bool ECPrivateKey::ImportFromEncryptedPrivateKeyInfo( @@ -313,93 +354,4 @@ bool ECPrivateKey::ExportECParams(std::vector<uint8>* output) { ECPrivateKey::ECPrivateKey() : key_(NULL), public_key_(NULL) {} -// static -ECPrivateKey* ECPrivateKey::CreateWithParams(PK11SlotInfo* slot, - bool permanent, - bool sensitive) { - if (!slot) - return NULL; - - scoped_ptr<ECPrivateKey> result(new ECPrivateKey); - - SECOidData* oid_data = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1); - if (!oid_data) { - DLOG(ERROR) << "SECOID_FindOIDByTag: " << PORT_GetError(); - return NULL; - } - - // SECKEYECParams is a SECItem containing the DER encoded ASN.1 ECParameters - // value. For a named curve, that is just the OBJECT IDENTIFIER of the curve. - // In addition to the oid data, the encoding requires one byte for the ASN.1 - // tag and one byte for the length (assuming the length is <= 127). - DCHECK_LE(oid_data->oid.len, 127U); - std::vector<unsigned char> parameters_buf(2 + oid_data->oid.len); - SECKEYECParams ec_parameters = { - siDEROID, ¶meters_buf[0], - static_cast<unsigned>(parameters_buf.size()) - }; - - ec_parameters.data[0] = SEC_ASN1_OBJECT_ID; - ec_parameters.data[1] = static_cast<unsigned char>(oid_data->oid.len); - memcpy(ec_parameters.data + 2, oid_data->oid.data, oid_data->oid.len); - - result->key_ = PK11_GenerateKeyPair(slot, - CKM_EC_KEY_PAIR_GEN, - &ec_parameters, - &result->public_key_, - permanent, - sensitive, - NULL); - if (!result->key_) { - DLOG(ERROR) << "PK11_GenerateKeyPair: " << PORT_GetError(); - return NULL; - } - CHECK_EQ(ecKey, SECKEY_GetPublicKeyType(result->public_key_)); - - return result.release(); -} - -// static -ECPrivateKey* ECPrivateKey::CreateFromEncryptedPrivateKeyInfoWithParams( - PK11SlotInfo* slot, - const std::string& password, - const std::vector<uint8>& encrypted_private_key_info, - const std::vector<uint8>& subject_public_key_info, - bool permanent, - bool sensitive) { - scoped_ptr<ECPrivateKey> result(new ECPrivateKey); - - SECItem encoded_spki = { - siBuffer, - const_cast<unsigned char*>(&subject_public_key_info[0]), - static_cast<unsigned>(subject_public_key_info.size()) - }; - CERTSubjectPublicKeyInfo* decoded_spki = SECKEY_DecodeDERSubjectPublicKeyInfo( - &encoded_spki); - if (!decoded_spki) { - DLOG(ERROR) << "SECKEY_DecodeDERSubjectPublicKeyInfo: " << PORT_GetError(); - return NULL; - } - - bool success = ImportFromEncryptedPrivateKeyInfo( - slot, - password, - &encrypted_private_key_info[0], - encrypted_private_key_info.size(), - decoded_spki, - permanent, - sensitive, - &result->key_, - &result->public_key_); - - SECKEY_DestroySubjectPublicKeyInfo(decoded_spki); - - if (success) { - CHECK_EQ(ecKey, SECKEY_GetPublicKeyType(result->public_key_)); - return result.release(); - } - - return NULL; -} - } // namespace crypto diff --git a/chromium/crypto/ec_private_key_openssl.cc b/chromium/crypto/ec_private_key_openssl.cc index 2d44759d8b0..35403f39ce8 100644 --- a/chromium/crypto/ec_private_key_openssl.cc +++ b/chromium/crypto/ec_private_key_openssl.cc @@ -25,9 +25,9 @@ namespace { // style guide, hence the unusual parameter placement / types. typedef int (*ExportBioFunction)(BIO* bio, const void* key); -typedef ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>::Type - ScopedPKCS8_PRIV_KEY_INFO; -typedef ScopedOpenSSL<X509_SIG, X509_SIG_free>::Type ScopedX509_SIG; +using ScopedPKCS8_PRIV_KEY_INFO = + ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>; +using ScopedX509_SIG = ScopedOpenSSL<X509_SIG, X509_SIG_free>; // Helper to export |key| into |output| via the specified ExportBioFunction. bool ExportKeyWithBio(const void* key, @@ -85,6 +85,13 @@ ECPrivateKey::~ECPrivateKey() { EVP_PKEY_free(key_); } +ECPrivateKey* ECPrivateKey::Copy() const { + scoped_ptr<ECPrivateKey> copy(new ECPrivateKey); + if (key_) + copy->key_ = EVP_PKEY_up_ref(key_); + return copy.release(); +} + // static bool ECPrivateKey::IsSupported() { return true; } diff --git a/chromium/crypto/ec_private_key_unittest.cc b/chromium/crypto/ec_private_key_unittest.cc index 6993a20b08f..cfd08f2d92b 100644 --- a/chromium/crypto/ec_private_key_unittest.cc +++ b/chromium/crypto/ec_private_key_unittest.cc @@ -82,7 +82,6 @@ TEST(ECPrivateKeyUnitTest, InitRandomTest) { EXPECT_EQ(raw_pubkey2, raw_pubkey4); } -#if !defined(USE_OPENSSL) TEST(ECPrivateKeyUnitTest, Copy) { scoped_ptr<crypto::ECPrivateKey> keypair1(crypto::ECPrivateKey::Create()); scoped_ptr<crypto::ECPrivateKey> keypair2(keypair1->Copy()); @@ -113,7 +112,6 @@ TEST(ECPrivateKeyUnitTest, Copy) { EXPECT_TRUE(keypair2->ExportRawPublicKey(&raw_pubkey2)); EXPECT_EQ(raw_pubkey1, raw_pubkey2); } -#endif // !defined(USE_OPENSSL) TEST(ECPrivateKeyUnitTest, BadPasswordTest) { const std::string password1; diff --git a/chromium/crypto/ec_signature_creator_impl.h b/chromium/crypto/ec_signature_creator_impl.h index f2ef9d65795..91a60a89963 100644 --- a/chromium/crypto/ec_signature_creator_impl.h +++ b/chromium/crypto/ec_signature_creator_impl.h @@ -13,14 +13,14 @@ namespace crypto { class ECSignatureCreatorImpl : public ECSignatureCreator { public: explicit ECSignatureCreatorImpl(ECPrivateKey* key); - virtual ~ECSignatureCreatorImpl(); + ~ECSignatureCreatorImpl() override; - virtual bool Sign(const uint8* data, - int data_len, - std::vector<uint8>* signature) override; + bool Sign(const uint8* data, + int data_len, + std::vector<uint8>* signature) override; - virtual bool DecodeSignature(const std::vector<uint8>& der_sig, - std::vector<uint8>* out_raw_sig) override; + bool DecodeSignature(const std::vector<uint8>& der_sig, + std::vector<uint8>* out_raw_sig) override; private: ECPrivateKey* key_; diff --git a/chromium/crypto/ec_signature_creator_openssl.cc b/chromium/crypto/ec_signature_creator_openssl.cc index 91e8a6a8d33..c422cef5f27 100644 --- a/chromium/crypto/ec_signature_creator_openssl.cc +++ b/chromium/crypto/ec_signature_creator_openssl.cc @@ -60,24 +60,13 @@ bool ECSignatureCreatorImpl::DecodeSignature(const std::vector<uint8>& der_sig, // The result is made of two 32-byte vectors. const size_t kMaxBytesPerBN = 32; - std::vector<uint8> result; - result.resize(2 * kMaxBytesPerBN); - memset(&result[0], 0, result.size()); + std::vector<uint8> result(2 * kMaxBytesPerBN); - BIGNUM* r = ecdsa_sig.get()->r; - BIGNUM* s = ecdsa_sig.get()->s; - int r_bytes = BN_num_bytes(r); - int s_bytes = BN_num_bytes(s); - // NOTE: Can't really check for equality here since sometimes the value - // returned by BN_num_bytes() will be slightly smaller than kMaxBytesPerBN. - if (r_bytes > static_cast<int>(kMaxBytesPerBN) || - s_bytes > static_cast<int>(kMaxBytesPerBN)) { - DLOG(ERROR) << "Invalid key sizes r(" << r_bytes << ") s(" << s_bytes - << ")"; + if (!BN_bn2bin_padded(&result[0], kMaxBytesPerBN, ecdsa_sig->r) || + !BN_bn2bin_padded(&result[kMaxBytesPerBN], kMaxBytesPerBN, + ecdsa_sig->s)) { return false; } - BN_bn2bin(ecdsa_sig.get()->r, &result[kMaxBytesPerBN - r_bytes]); - BN_bn2bin(ecdsa_sig.get()->s, &result[2 * kMaxBytesPerBN - s_bytes]); out_raw_sig->swap(result); return true; } diff --git a/chromium/crypto/encryptor.h b/chromium/crypto/encryptor.h index ec1498b66fc..8052a9fd574 100644 --- a/chromium/crypto/encryptor.h +++ b/chromium/crypto/encryptor.h @@ -13,7 +13,7 @@ #include "build/build_config.h" #include "crypto/crypto_export.h" -#if defined(USE_NSS) || \ +#if defined(USE_NSS_CERTS) || \ (!defined(USE_OPENSSL) && (defined(OS_WIN) || defined(OS_MACOSX))) #include "crypto/scoped_nss_types.h" #endif @@ -122,7 +122,7 @@ class CRYPTO_EXPORT Encryptor { const base::StringPiece& input, std::string* output); std::string iv_; -#elif defined(USE_NSS) || defined(OS_WIN) || defined(OS_MACOSX) +#elif defined(USE_NSS_CERTS) || defined(OS_WIN) || defined(OS_MACOSX) bool Crypt(PK11Context* context, const base::StringPiece& input, std::string* output); diff --git a/chromium/crypto/encryptor_unittest.cc b/chromium/crypto/encryptor_unittest.cc index 1a99783679f..79fe2cca1a6 100644 --- a/chromium/crypto/encryptor_unittest.cc +++ b/chromium/crypto/encryptor_unittest.cc @@ -92,7 +92,7 @@ TEST(EncryptorTest, DecryptWrongKey) { // determine the padding length without checking every padding byte, // Encryptor::Decrypt() will still return true. This is the case for NSS // (crbug.com/124434). -#if !defined(USE_NSS) && !defined(OS_WIN) && !defined(OS_MACOSX) +#if !defined(USE_NSS_CERTS) && !defined(OS_WIN) && !defined(OS_MACOSX) crypto::Encryptor decryptor; EXPECT_TRUE(decryptor.Init(wrong_key.get(), crypto::Encryptor::CBC, iv)); EXPECT_FALSE(decryptor.Decrypt(ciphertext, &decrypted)); diff --git a/chromium/crypto/hmac_openssl.cc b/chromium/crypto/hmac_openssl.cc index 92eea19d780..ef20290e223 100644 --- a/chromium/crypto/hmac_openssl.cc +++ b/chromium/crypto/hmac_openssl.cc @@ -20,45 +20,37 @@ struct HMACPlatformData { std::vector<unsigned char> key; }; -HMAC::HMAC(HashAlgorithm hash_alg) - : hash_alg_(hash_alg), plat_(new HMACPlatformData()) { +HMAC::HMAC(HashAlgorithm hash_alg) : hash_alg_(hash_alg) { // Only SHA-1 and SHA-256 hash algorithms are supported now. DCHECK(hash_alg_ == SHA1 || hash_alg_ == SHA256); } bool HMAC::Init(const unsigned char* key, size_t key_length) { // Init must not be called more than once on the same HMAC object. - DCHECK(plat_->key.empty()); - + DCHECK(!plat_); + plat_.reset(new HMACPlatformData()); plat_->key.assign(key, key + key_length); - if (key_length == 0) { - // Special-case: if the key is empty, use a key with one zero - // byte. OpenSSL's HMAC function breaks when passed a NULL key. (It calls - // HMAC_Init_ex which treats a NULL key as having already been initialized - // with a key previously.) HMAC pads keys with zeros, so this key is - // equivalent. - plat_->key.push_back(0); - } return true; } HMAC::~HMAC() { - // Zero out key copy. - plat_->key.assign(plat_->key.size(), 0); - STLClearObject(&plat_->key); + if (plat_) { + // Zero out key copy. + plat_->key.assign(plat_->key.size(), 0); + STLClearObject(&plat_->key); + } } bool HMAC::Sign(const base::StringPiece& data, unsigned char* digest, size_t digest_length) const { - DCHECK(!plat_->key.empty()); // Init must be called before Sign. + DCHECK(plat_); // Init must be called before Sign. ScopedOpenSSLSafeSizeBuffer<EVP_MAX_MD_SIZE> result(digest, digest_length); return !!::HMAC(hash_alg_ == SHA1 ? EVP_sha1() : EVP_sha256(), - &plat_->key[0], plat_->key.size(), - reinterpret_cast<const unsigned char*>(data.data()), - data.size(), - result.safe_buffer(), NULL); + vector_as_array(&plat_->key), plat_->key.size(), + reinterpret_cast<const unsigned char*>(data.data()), + data.size(), result.safe_buffer(), NULL); } } // namespace crypto diff --git a/chromium/crypto/mock_apple_keychain.cc b/chromium/crypto/mock_apple_keychain.cc index 1ddfc867946..a1faa65382a 100644 --- a/chromium/crypto/mock_apple_keychain.cc +++ b/chromium/crypto/mock_apple_keychain.cc @@ -3,9 +3,23 @@ // found in the LICENSE file. #include "base/logging.h" +#include "base/metrics/histogram.h" #include "base/time/time.h" #include "crypto/mock_apple_keychain.h" +namespace { + +// Adds an entry to a local histogram to indicate that the Apple Keychain would +// have been accessed, if this class were not a mock of the Apple Keychain. +void IncrementKeychainAccessHistogram() { + // This local histogram is accessed by Telemetry to track the number of times + // the keychain is accessed, since keychain access is known to be synchronous + // and slow. + LOCAL_HISTOGRAM_BOOLEAN("OSX.Keychain.Access", true); +} + +} // namespace + namespace crypto { OSStatus MockAppleKeychain::FindGenericPassword( @@ -17,6 +31,8 @@ OSStatus MockAppleKeychain::FindGenericPassword( UInt32* passwordLength, void** passwordData, SecKeychainItemRef* itemRef) const { + IncrementKeychainAccessHistogram(); + // When simulating |noErr|, return canned |passwordData| and // |passwordLength|. Otherwise, just return given code. if (find_generic_result_ == noErr) { @@ -48,6 +64,8 @@ OSStatus MockAppleKeychain::AddGenericPassword( UInt32 passwordLength, const void* passwordData, SecKeychainItemRef* itemRef) const { + IncrementKeychainAccessHistogram(); + called_add_generic_ = true; DCHECK_GT(passwordLength, 0U); @@ -58,4 +76,9 @@ OSStatus MockAppleKeychain::AddGenericPassword( return noErr; } +std::string MockAppleKeychain::GetEncryptionPassword() const { + IncrementKeychainAccessHistogram(); + return "mock_password"; +} + } // namespace crypto diff --git a/chromium/crypto/mock_apple_keychain.h b/chromium/crypto/mock_apple_keychain.h index d9573162ee6..3948d489755 100644 --- a/chromium/crypto/mock_apple_keychain.h +++ b/chromium/crypto/mock_apple_keychain.h @@ -29,70 +29,70 @@ namespace crypto { class CRYPTO_EXPORT MockAppleKeychain : public AppleKeychain { public: MockAppleKeychain(); - virtual ~MockAppleKeychain(); + ~MockAppleKeychain() override; // AppleKeychain implementation. - virtual OSStatus FindGenericPassword( - CFTypeRef keychainOrArray, - UInt32 serviceNameLength, - const char* serviceName, - UInt32 accountNameLength, - const char* accountName, - UInt32* passwordLength, - void** passwordData, - SecKeychainItemRef* itemRef) const override; - virtual OSStatus ItemFreeContent(SecKeychainAttributeList* attrList, - void* data) const override; - virtual OSStatus AddGenericPassword( - SecKeychainRef keychain, - UInt32 serviceNameLength, - const char* serviceName, - UInt32 accountNameLength, - const char* accountName, - UInt32 passwordLength, - const void* passwordData, - SecKeychainItemRef* itemRef) const override; + OSStatus FindGenericPassword(CFTypeRef keychainOrArray, + UInt32 serviceNameLength, + const char* serviceName, + UInt32 accountNameLength, + const char* accountName, + UInt32* passwordLength, + void** passwordData, + SecKeychainItemRef* itemRef) const override; + OSStatus ItemFreeContent(SecKeychainAttributeList* attrList, + void* data) const override; + OSStatus AddGenericPassword(SecKeychainRef keychain, + UInt32 serviceNameLength, + const char* serviceName, + UInt32 accountNameLength, + const char* accountName, + UInt32 passwordLength, + const void* passwordData, + SecKeychainItemRef* itemRef) const override; + + // Returns the password that OSCrypt uses to generate its encryption key. + std::string GetEncryptionPassword() const; #if !defined(OS_IOS) - virtual OSStatus ItemCopyAttributesAndData( - SecKeychainItemRef itemRef, - SecKeychainAttributeInfo* info, - SecItemClass* itemClass, - SecKeychainAttributeList** attrList, - UInt32* length, - void** outData) const override; + OSStatus ItemCopyAttributesAndData(SecKeychainItemRef itemRef, + SecKeychainAttributeInfo* info, + SecItemClass* itemClass, + SecKeychainAttributeList** attrList, + UInt32* length, + void** outData) const override; // Pass "fail_me" as the data to get errSecAuthFailed. - virtual OSStatus ItemModifyAttributesAndData( - SecKeychainItemRef itemRef, - const SecKeychainAttributeList* attrList, - UInt32 length, - const void* data) const override; - virtual OSStatus ItemFreeAttributesAndData(SecKeychainAttributeList* attrList, - void* data) const override; - virtual OSStatus ItemDelete(SecKeychainItemRef itemRef) const override; - virtual OSStatus SearchCreateFromAttributes( + OSStatus ItemModifyAttributesAndData(SecKeychainItemRef itemRef, + const SecKeychainAttributeList* attrList, + UInt32 length, + const void* data) const override; + OSStatus ItemFreeAttributesAndData(SecKeychainAttributeList* attrList, + void* data) const override; + OSStatus ItemDelete(SecKeychainItemRef itemRef) const override; + OSStatus SearchCreateFromAttributes( CFTypeRef keychainOrArray, SecItemClass itemClass, const SecKeychainAttributeList* attrList, SecKeychainSearchRef* searchRef) const override; - virtual OSStatus SearchCopyNext(SecKeychainSearchRef searchRef, - SecKeychainItemRef* itemRef) const override; + OSStatus SearchCopyNext(SecKeychainSearchRef searchRef, + SecKeychainItemRef* itemRef) const override; // Pass "some.domain.com" as the serverName to get errSecDuplicateItem. - virtual OSStatus AddInternetPassword( - SecKeychainRef keychain, - UInt32 serverNameLength, - const char* serverName, - UInt32 securityDomainLength, - const char* securityDomain, - UInt32 accountNameLength, - const char* accountName, - UInt32 pathLength, const char* path, - UInt16 port, SecProtocolType protocol, - SecAuthenticationType authenticationType, - UInt32 passwordLength, - const void* passwordData, - SecKeychainItemRef* itemRef) const override; - virtual void Free(CFTypeRef ref) const override; + OSStatus AddInternetPassword(SecKeychainRef keychain, + UInt32 serverNameLength, + const char* serverName, + UInt32 securityDomainLength, + const char* securityDomain, + UInt32 accountNameLength, + const char* accountName, + UInt32 pathLength, + const char* path, + UInt16 port, + SecProtocolType protocol, + SecAuthenticationType authenticationType, + UInt32 passwordLength, + const void* passwordData, + SecKeychainItemRef* itemRef) const override; + void Free(CFTypeRef ref) const override; // Return the counts of objects returned by Create/Copy functions but never // Free'd as they should have been. diff --git a/chromium/crypto/nss_crypto_module_delegate.h b/chromium/crypto/nss_crypto_module_delegate.h index 00b2b75335f..6c1da68161d 100644 --- a/chromium/crypto/nss_crypto_module_delegate.h +++ b/chromium/crypto/nss_crypto_module_delegate.h @@ -42,7 +42,7 @@ class CryptoModuleBlockingPasswordDelegate { // slot in which to act. (Eg, which slot to store a generated key in.) class NSSCryptoModuleDelegate : public CryptoModuleBlockingPasswordDelegate { public: - virtual ~NSSCryptoModuleDelegate() {} + ~NSSCryptoModuleDelegate() override {} // Get the slot to store the generated key. virtual ScopedPK11Slot RequestSlot() = 0; diff --git a/chromium/crypto/nss_key_util.cc b/chromium/crypto/nss_key_util.cc new file mode 100644 index 00000000000..77435fba361 --- /dev/null +++ b/chromium/crypto/nss_key_util.cc @@ -0,0 +1,163 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "crypto/nss_key_util.h" + +#include <cryptohi.h> +#include <keyhi.h> +#include <pk11pub.h> + +#include "base/logging.h" +#include "base/stl_util.h" +#include "crypto/nss_util.h" + +#if defined(USE_NSS_CERTS) +#include <secmod.h> +#include "crypto/nss_util_internal.h" +#endif + +namespace crypto { + +namespace { + +#if defined(USE_NSS_CERTS) + +struct PublicKeyInfoDeleter { + inline void operator()(CERTSubjectPublicKeyInfo* spki) { + SECKEY_DestroySubjectPublicKeyInfo(spki); + } +}; + +typedef scoped_ptr<CERTSubjectPublicKeyInfo, PublicKeyInfoDeleter> + ScopedPublicKeyInfo; + +// Decodes |input| as a SubjectPublicKeyInfo and returns a SECItem containing +// the CKA_ID of that public key or nullptr on error. +ScopedSECItem MakeIDFromSPKI(const std::vector<uint8_t>& input) { + // First, decode and save the public key. + SECItem key_der; + key_der.type = siBuffer; + key_der.data = const_cast<unsigned char*>(vector_as_array(&input)); + key_der.len = input.size(); + + ScopedPublicKeyInfo spki(SECKEY_DecodeDERSubjectPublicKeyInfo(&key_der)); + if (!spki) + return nullptr; + + ScopedSECKEYPublicKey result(SECKEY_ExtractPublicKey(spki.get())); + if (!result) + return nullptr; + + // See pk11_MakeIDFromPublicKey from NSS. For now, only RSA keys are + // supported. + if (SECKEY_GetPublicKeyType(result.get()) != rsaKey) + return nullptr; + + return ScopedSECItem(PK11_MakeIDFromPubKey(&result->u.rsa.modulus)); +} + +#endif // defined(USE_NSS_CERTS) + +} // namespace + +bool GenerateRSAKeyPairNSS(PK11SlotInfo* slot, + uint16_t num_bits, + bool permanent, + ScopedSECKEYPublicKey* public_key, + ScopedSECKEYPrivateKey* private_key) { + DCHECK(slot); + + PK11RSAGenParams param; + param.keySizeInBits = num_bits; + param.pe = 65537L; + SECKEYPublicKey* public_key_raw = nullptr; + private_key->reset(PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN, + ¶m, &public_key_raw, permanent, + permanent /* sensitive */, nullptr)); + if (!*private_key) + return false; + + public_key->reset(public_key_raw); + return true; +} + +ScopedSECKEYPrivateKey ImportNSSKeyFromPrivateKeyInfo( + PK11SlotInfo* slot, + const std::vector<uint8_t>& input, + bool permanent) { + DCHECK(slot); + + ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); + DCHECK(arena); + + // Excess data is illegal, but NSS silently accepts it, so first ensure that + // |input| consists of a single ASN.1 element. + SECItem input_item; + input_item.data = const_cast<unsigned char*>(vector_as_array(&input)); + input_item.len = input.size(); + SECItem der_private_key_info; + SECStatus rv = + SEC_QuickDERDecodeItem(arena.get(), &der_private_key_info, + SEC_ASN1_GET(SEC_AnyTemplate), &input_item); + if (rv != SECSuccess) + return nullptr; + + // Allow the private key to be used for key unwrapping, data decryption, + // and signature generation. + const unsigned int key_usage = + KU_KEY_ENCIPHERMENT | KU_DATA_ENCIPHERMENT | KU_DIGITAL_SIGNATURE; + SECKEYPrivateKey* key_raw = nullptr; + rv = PK11_ImportDERPrivateKeyInfoAndReturnKey( + slot, &der_private_key_info, nullptr, nullptr, permanent, + permanent /* sensitive */, key_usage, &key_raw, nullptr); + if (rv != SECSuccess) + return nullptr; + return ScopedSECKEYPrivateKey(key_raw); +} + +#if defined(USE_NSS_CERTS) + +ScopedSECKEYPrivateKey FindNSSKeyFromPublicKeyInfo( + const std::vector<uint8_t>& input) { + EnsureNSSInit(); + + ScopedSECItem cka_id(MakeIDFromSPKI(input)); + if (!cka_id) + return nullptr; + + // Search all slots in all modules for the key with the given ID. + AutoSECMODListReadLock auto_lock; + const SECMODModuleList* head = SECMOD_GetDefaultModuleList(); + for (const SECMODModuleList* item = head; item != nullptr; + item = item->next) { + int slot_count = item->module->loaded ? item->module->slotCount : 0; + for (int i = 0; i < slot_count; i++) { + // Look for the key in slot |i|. + ScopedSECKEYPrivateKey key( + PK11_FindKeyByKeyID(item->module->slots[i], cka_id.get(), nullptr)); + if (key) + return key.Pass(); + } + } + + // The key wasn't found in any module. + return nullptr; +} + +ScopedSECKEYPrivateKey FindNSSKeyFromPublicKeyInfoInSlot( + const std::vector<uint8_t>& input, + PK11SlotInfo* slot) { + DCHECK(slot); + + ScopedSECItem cka_id(MakeIDFromSPKI(input)); + if (!cka_id) + return nullptr; + + return ScopedSECKEYPrivateKey( + PK11_FindKeyByKeyID(slot, cka_id.get(), nullptr)); +} + +#endif // defined(USE_NSS_CERTS) + +} // namespace crypto diff --git a/chromium/crypto/nss_key_util.h b/chromium/crypto/nss_key_util.h new file mode 100644 index 00000000000..12b948d25bb --- /dev/null +++ b/chromium/crypto/nss_key_util.h @@ -0,0 +1,58 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CRYPTO_NSS_KEY_UTIL_H_ +#define CRYPTO_NSS_KEY_UTIL_H_ + +#include <stdint.h> + +#include <vector> + +#include "build/build_config.h" +#include "crypto/crypto_export.h" +#include "crypto/scoped_nss_types.h" + +typedef struct PK11SlotInfoStr PK11SlotInfo; + +namespace crypto { + +// Generates a new RSA keypair of size |num_bits| in |slot|. Returns true on +// success and false on failure. If |permanent| is true, the resulting key is +// permanent and is not exportable in plaintext form. +CRYPTO_EXPORT bool GenerateRSAKeyPairNSS( + PK11SlotInfo* slot, + uint16_t num_bits, + bool permanent, + ScopedSECKEYPublicKey* out_public_key, + ScopedSECKEYPrivateKey* out_private_key); + +// Imports a private key from |input| into |slot|. |input| is interpreted as a +// DER-encoded PrivateKeyInfo block from PKCS #8. Returns nullptr on error. If +// |permanent| is true, the resulting key is permanent and is not exportable in +// plaintext form. +CRYPTO_EXPORT ScopedSECKEYPrivateKey +ImportNSSKeyFromPrivateKeyInfo(PK11SlotInfo* slot, + const std::vector<uint8_t>& input, + bool permanent); + +#if defined(USE_NSS_CERTS) + +// Decodes |input| as a DER-encoded X.509 SubjectPublicKeyInfo and searches for +// the private key half in the key database. Returns the private key on success +// or nullptr on error. +CRYPTO_EXPORT ScopedSECKEYPrivateKey +FindNSSKeyFromPublicKeyInfo(const std::vector<uint8_t>& input); + +// Decodes |input| as a DER-encoded X.509 SubjectPublicKeyInfo and searches for +// the private key half in the slot specified by |slot|. Returns the private key +// on success or nullptr on error. +CRYPTO_EXPORT ScopedSECKEYPrivateKey +FindNSSKeyFromPublicKeyInfoInSlot(const std::vector<uint8_t>& input, + PK11SlotInfo* slot); + +#endif // defined(USE_NSS_CERTS) + +} // namespace crypto + +#endif // CRYPTO_NSS_KEY_UTIL_H_ diff --git a/chromium/crypto/nss_key_util_unittest.cc b/chromium/crypto/nss_key_util_unittest.cc new file mode 100644 index 00000000000..f8de8e236bb --- /dev/null +++ b/chromium/crypto/nss_key_util_unittest.cc @@ -0,0 +1,87 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "crypto/nss_key_util.h" + +#include <keyhi.h> +#include <pk11pub.h> + +#include <vector> + +#include "crypto/nss_util.h" +#include "crypto/scoped_nss_types.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace crypto { + +class NSSKeyUtilTest : public testing::Test { + public: + void SetUp() override { + EnsureNSSInit(); + + internal_slot_.reset(PK11_GetInternalSlot()); + ASSERT_TRUE(internal_slot_); + } + + PK11SlotInfo* internal_slot() { return internal_slot_.get(); } + + private: + ScopedPK11Slot internal_slot_; +}; + +TEST_F(NSSKeyUtilTest, GenerateRSAKeyPairNSS) { + const int kKeySizeBits = 1024; + + ScopedSECKEYPublicKey public_key; + ScopedSECKEYPrivateKey private_key; + ASSERT_TRUE(GenerateRSAKeyPairNSS(internal_slot(), kKeySizeBits, + false /* not permanent */, &public_key, + &private_key)); + + EXPECT_EQ(rsaKey, SECKEY_GetPublicKeyType(public_key.get())); + EXPECT_EQ(rsaKey, SECKEY_GetPrivateKeyType(private_key.get())); + EXPECT_EQ((kKeySizeBits + 7) / 8, + PK11_GetPrivateModulusLen(private_key.get())); +} + +#if defined(USE_NSS_CERTS) +TEST_F(NSSKeyUtilTest, FindNSSKeyFromPublicKeyInfo) { + // Create an NSS keypair, which will put the keys in the user's NSSDB. + ScopedSECKEYPublicKey public_key; + ScopedSECKEYPrivateKey private_key; + ASSERT_TRUE(GenerateRSAKeyPairNSS(internal_slot(), 256, + false /* not permanent */, &public_key, + &private_key)); + + ScopedSECItem item(SECKEY_EncodeDERSubjectPublicKeyInfo(public_key.get())); + ASSERT_TRUE(item); + std::vector<uint8_t> public_key_der(item->data, item->data + item->len); + + ScopedSECKEYPrivateKey private_key2 = + FindNSSKeyFromPublicKeyInfo(public_key_der); + ASSERT_TRUE(private_key2); + EXPECT_EQ(private_key->pkcs11ID, private_key2->pkcs11ID); +} + +TEST_F(NSSKeyUtilTest, FailedFindNSSKeyFromPublicKeyInfo) { + // Create an NSS keypair, which will put the keys in the user's NSSDB. + ScopedSECKEYPublicKey public_key; + ScopedSECKEYPrivateKey private_key; + ASSERT_TRUE(GenerateRSAKeyPairNSS(internal_slot(), 256, + false /* not permanent */, &public_key, + &private_key)); + + ScopedSECItem item(SECKEY_EncodeDERSubjectPublicKeyInfo(public_key.get())); + ASSERT_TRUE(item); + std::vector<uint8_t> public_key_der(item->data, item->data + item->len); + + // Remove the keys from the DB, and make sure we can't find them again. + PK11_DestroyTokenObject(private_key->pkcs11Slot, private_key->pkcs11ID); + PK11_DestroyTokenObject(public_key->pkcs11Slot, public_key->pkcs11ID); + + EXPECT_FALSE(FindNSSKeyFromPublicKeyInfo(public_key_der)); +} +#endif // defined(USE_NSS_CERTS) + +} // namespace crypto diff --git a/chromium/crypto/nss_util.cc b/chromium/crypto/nss_util.cc index 8f9865a3c6c..df9316054e7 100644 --- a/chromium/crypto/nss_util.cc +++ b/chromium/crypto/nss_util.cc @@ -18,6 +18,10 @@ #include <sys/param.h> #endif +#if defined(OS_CHROMEOS) +#include <dlfcn.h> +#endif + #include <map> #include <vector> @@ -43,14 +47,13 @@ #include "base/threading/worker_pool.h" #include "build/build_config.h" -// USE_NSS means we use NSS for everything crypto-related. If USE_NSS is not -// defined, such as on Mac and Windows, we use NSS for SSL only -- we don't -// use NSS for crypto or certificate verification, and we don't use the NSS -// certificate and key databases. -#if defined(USE_NSS) +// USE_NSS_CERTS means NSS is used for certificates and platform integration. +// This requires additional support to manage the platform certificate and key +// stores. +#if defined(USE_NSS_CERTS) #include "base/synchronization/lock.h" #include "crypto/nss_crypto_module_delegate.h" -#endif // defined(USE_NSS) +#endif // defined(USE_NSS_CERTS) namespace crypto { @@ -80,7 +83,7 @@ std::string GetNSSErrorMessage() { return result; } -#if defined(USE_NSS) +#if defined(USE_NSS_CERTS) #if !defined(OS_CHROMEOS) base::FilePath GetDefaultConfigDirectory() { base::FilePath dir; @@ -142,8 +145,8 @@ char* PKCS11PasswordFunc(PK11SlotInfo* slot, PRBool retry, void* arg) { // the NSS environment variable NSS_SDB_USE_CACHE to "yes" to override NSS's // detection when database_dir is on NFS. See http://crbug.com/48585. // -// TODO(wtc): port this function to other USE_NSS platforms. It is defined -// only for OS_LINUX and OS_OPENBSD simply because the statfs structure +// TODO(wtc): port this function to other USE_NSS_CERTS platforms. It is +// defined only for OS_LINUX and OS_OPENBSD simply because the statfs structure // is OS-specific. // // Because this function sets an environment variable it must be run before we @@ -170,7 +173,7 @@ void UseLocalCacheOfNSSDatabaseIfNFS(const base::FilePath& database_dir) { } } -#endif // defined(USE_NSS) +#endif // defined(USE_NSS_CERTS) // A singleton to initialize/deinitialize NSPR. // Separate from the NSS singleton because we initialize NSPR on the UI thread. @@ -268,6 +271,38 @@ class ChromeOSUserData { SlotReadyCallbackList; SlotReadyCallbackList tpm_ready_callback_list_; }; + +class ScopedChapsLoadFixup { + public: + ScopedChapsLoadFixup(); + ~ScopedChapsLoadFixup(); + + private: +#if defined(COMPONENT_BUILD) + void *chaps_handle_; +#endif +}; + +#if defined(COMPONENT_BUILD) + +ScopedChapsLoadFixup::ScopedChapsLoadFixup() { + // HACK: libchaps links the system protobuf and there are symbol conflicts + // with the bundled copy. Load chaps with RTLD_DEEPBIND to workaround. + chaps_handle_ = dlopen(kChapsPath, RTLD_LOCAL | RTLD_NOW | RTLD_DEEPBIND); +} + +ScopedChapsLoadFixup::~ScopedChapsLoadFixup() { + // LoadModule() will have taken a 2nd reference. + if (chaps_handle_) + dlclose(chaps_handle_); +} + +#else + +ScopedChapsLoadFixup::ScopedChapsLoadFixup() {} +ScopedChapsLoadFixup::~ScopedChapsLoadFixup() {} + +#endif // defined(COMPONENT_BUILD) #endif // defined(OS_CHROMEOS) class NSSInitSingleton { @@ -361,6 +396,8 @@ class NSSInitSingleton { // This tries to load the Chaps module so NSS can talk to the hardware // TPM. if (!tpm_args->chaps_module) { + ScopedChapsLoadFixup chaps_loader; + DVLOG(3) << "Loading chaps..."; tpm_args->chaps_module = LoadModule( kChapsModuleName, @@ -628,11 +665,11 @@ class NSSInitSingleton { } #endif -#if defined(USE_NSS) +#if defined(USE_NSS_CERTS) base::Lock* write_lock() { return &write_lock_; } -#endif // defined(USE_NSS) +#endif // defined(USE_NSS_CERTS) // This method is used to force NSS to be initialized without a DB. // Call this method before NSSInitSingleton() is constructed. @@ -659,11 +696,11 @@ class NSSInitSingleton { EnsureNSPRInit(); // We *must* have NSS >= 3.14.3. - COMPILE_ASSERT( + static_assert( (NSS_VMAJOR == 3 && NSS_VMINOR == 14 && NSS_VPATCH >= 3) || (NSS_VMAJOR == 3 && NSS_VMINOR > 14) || (NSS_VMAJOR > 3), - nss_version_check_failed); + "nss version check failed"); // Also check the run-time NSS version. // NSS_VersionCheck is a >= check, not strict equality. if (!NSS_VersionCheck("3.14.3")) { @@ -676,7 +713,7 @@ class NSSInitSingleton { SECStatus status = SECFailure; bool nodb_init = force_nodb_init_; -#if !defined(USE_NSS) +#if !defined(USE_NSS_CERTS) // Use the system certificate store, so initialize NSS without database. nodb_init = true; #endif @@ -691,7 +728,7 @@ class NSSInitSingleton { root_ = InitDefaultRootCerts(); #endif // defined(OS_IOS) } else { -#if defined(USE_NSS) +#if defined(USE_NSS_CERTS) base::FilePath database_dir = GetInitialConfigDirectory(); if (!database_dir.empty()) { // This duplicates the work which should have been done in @@ -738,7 +775,7 @@ class NSSInitSingleton { } root_ = InitDefaultRootCerts(); -#endif // defined(USE_NSS) +#endif // defined(USE_NSS_CERTS) } // Disable MD5 certificate signatures. (They are disabled by default in @@ -783,7 +820,7 @@ class NSSInitSingleton { } } -#if defined(USE_NSS) || defined(OS_IOS) +#if defined(USE_NSS_CERTS) || defined(OS_IOS) // Load nss's built-in root certs. SECMODModule* InitDefaultRootCerts() { SECMODModule* root = LoadModule("Root Certs", "libnssckbi.so", NULL); @@ -835,7 +872,8 @@ class NSSInitSingleton { base::CPU cpu; if (cpu.has_avx_hardware() && !cpu.has_avx()) { - base::Environment::Create()->SetVar("NSS_DISABLE_HW_AES", "1"); + scoped_ptr<base::Environment> env(base::Environment::Create()); + env->SetVar("NSS_DISABLE_HW_AES", "1"); } } } @@ -855,11 +893,11 @@ class NSSInitSingleton { ChromeOSUserMap chromeos_user_map_; ScopedPK11Slot test_system_slot_; #endif -#if defined(USE_NSS) +#if defined(USE_NSS_CERTS) // TODO(davidben): When https://bugzilla.mozilla.org/show_bug.cgi?id=564011 // is fixed, we will no longer need the lock. base::Lock write_lock_; -#endif // defined(USE_NSS) +#endif // defined(USE_NSS_CERTS) base::ThreadChecker thread_checker_; }; @@ -871,7 +909,7 @@ base::LazyInstance<NSSInitSingleton>::Leaky g_nss_singleton = LAZY_INSTANCE_INITIALIZER; } // namespace -#if defined(USE_NSS) +#if defined(USE_NSS_CERTS) ScopedPK11Slot OpenSoftwareNSSDB(const base::FilePath& path, const std::string& description) { const std::string modspec = @@ -930,7 +968,7 @@ void DisableNSSForkCheck() { void LoadNSSLibraries() { // Some NSS libraries are linked dynamically so load them here. -#if defined(USE_NSS) +#if defined(USE_NSS_CERTS) // Try to search for multiple directories to load the libraries. std::vector<base::FilePath> paths; @@ -979,14 +1017,14 @@ void LoadNSSLibraries() { } else { LOG(ERROR) << "Failed to load NSS libraries."; } -#endif // defined(USE_NSS) +#endif // defined(USE_NSS_CERTS) } bool CheckNSSVersion(const char* version) { return !!NSS_VersionCheck(version); } -#if defined(USE_NSS) +#if defined(USE_NSS_CERTS) base::Lock* GetNSSWriteLock() { return g_nss_singleton.Get().write_lock(); } @@ -1012,7 +1050,7 @@ AutoSECMODListReadLock::AutoSECMODListReadLock() AutoSECMODListReadLock::~AutoSECMODListReadLock() { SECMOD_ReleaseReadLock(lock_); } -#endif // defined(USE_NSS) +#endif // defined(USE_NSS_CERTS) #if defined(OS_CHROMEOS) ScopedPK11Slot GetSystemNSSKeySlot( diff --git a/chromium/crypto/nss_util.h b/chromium/crypto/nss_util.h index 56fdfa6b659..1ca0de3e777 100644 --- a/chromium/crypto/nss_util.h +++ b/chromium/crypto/nss_util.h @@ -22,7 +22,7 @@ class Time; // initialization functions. namespace crypto { -#if defined(USE_NSS) +#if defined(USE_NSS_CERTS) // EarlySetupForNSSInit performs lightweight setup which must occur before the // process goes multithreaded. This does not initialise NSS. For test, see // EnsureNSSInit. @@ -127,7 +127,7 @@ CRYPTO_EXPORT base::Time PRTimeToBaseTime(int64 prtime); // We use a int64 instead of PRTime here to avoid depending on NSPR headers. CRYPTO_EXPORT int64 BaseTimeToPRTime(base::Time time); -#if defined(USE_NSS) +#if defined(USE_NSS_CERTS) // NSS has a bug which can cause a deadlock or stall in some cases when writing // to the certDB and keyDB. It also has a bug which causes concurrent key pair // generations to scribble over each other. To work around this, we synchronize @@ -148,7 +148,7 @@ class CRYPTO_EXPORT AutoNSSWriteLock { base::Lock *lock_; DISALLOW_COPY_AND_ASSIGN(AutoNSSWriteLock); }; -#endif // defined(USE_NSS) +#endif // defined(USE_NSS_CERTS) } // namespace crypto diff --git a/chromium/crypto/openssl_util.cc b/chromium/crypto/openssl_util.cc index f41b55a8fff..964d83b8433 100644 --- a/chromium/crypto/openssl_util.cc +++ b/chromium/crypto/openssl_util.cc @@ -48,6 +48,18 @@ class OpenSSLInitSingleton { private: friend struct DefaultSingletonTraits<OpenSSLInitSingleton>; OpenSSLInitSingleton() { +#if defined(OS_ANDROID) && defined(ARCH_CPU_ARMEL) + const bool has_neon = + (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0; + // CRYPTO_set_NEON_capable is called before |SSL_library_init| because this + // stops BoringSSL from probing for NEON support via SIGILL in the case + // that getauxval isn't present. + CRYPTO_set_NEON_capable(has_neon); + // See https://code.google.com/p/chromium/issues/detail?id=341598 + base::CPU cpu; + CRYPTO_set_NEON_functional(!cpu.has_broken_neon()); +#endif + SSL_load_error_strings(); SSL_library_init(); int num_locks = CRYPTO_num_locks(); @@ -56,16 +68,6 @@ class OpenSSLInitSingleton { locks_.push_back(new base::Lock()); CRYPTO_set_locking_callback(LockingCallback); CRYPTO_THREADID_set_callback(CurrentThreadId); - -#if defined(OS_ANDROID) && defined(ARCH_CPU_ARMEL) - const bool has_neon = - (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0; - if (has_neon) - CRYPTO_set_NEON_capable(1); - // See https://code.google.com/p/chromium/issues/detail?id=341598 - base::CPU cpu; - CRYPTO_set_NEON_functional(!cpu.has_broken_neon()); -#endif } ~OpenSSLInitSingleton() { @@ -114,7 +116,7 @@ void EnsureOpenSSLInit() { void ClearOpenSSLERRStack(const tracked_objects::Location& location) { if (logging::DEBUG_MODE && VLOG_IS_ON(1)) { - int error_num = ERR_peek_error(); + uint32_t error_num = ERR_peek_error(); if (error_num == 0) return; diff --git a/chromium/crypto/p224.cc b/chromium/crypto/p224.cc index 5f76fbc259b..11946a9413c 100644 --- a/chromium/crypto/p224.cc +++ b/chromium/crypto/p224.cc @@ -123,6 +123,15 @@ typedef uint64 LargeFieldElement[15]; // ReduceLarge converts a LargeFieldElement to a FieldElement. // // in[i] < 2**62 + +// GCC 4.9 incorrectly vectorizes the first coefficient elimination loop, so +// disable that optimization via pragma. Don't use the pragma under Clang, since +// clang doesn't understand it. +// TODO(wez): Remove this when crbug.com/439566 is fixed. +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC optimize("no-tree-vectorize") +#endif + void ReduceLarge(FieldElement* out, LargeFieldElement* inptr) { LargeFieldElement& in(*inptr); @@ -164,6 +173,12 @@ void ReduceLarge(FieldElement* out, LargeFieldElement* inptr) { // out[5..7] < 2**28 } +// TODO(wez): Remove this when crbug.com/439566 is fixed. +#if defined(__GNUC__) && !defined(__clang__) +// Reenable "tree-vectorize" optimization if it got disabled for ReduceLarge. +#pragma GCC reset_options +#endif + // Mul computes *out = a*b // // a[i] < 2**29, b[i] < 2**30 (or vice versa) @@ -460,8 +475,8 @@ void AddJacobian(Point *out, uint32 x_equal = IsZero(h); // I = (2*H)² - for (int j = 0; j < 8; j++) { - i[j] = h[j] << 1; + for (int k = 0; k < 8; k++) { + i[k] = h[k] << 1; } Reduce(&i); Square(&i, i); @@ -480,8 +495,8 @@ void AddJacobian(Point *out, return; } - for (int i = 0; i < 8; i++) { - r[i] <<= 1; + for (int k = 0; k < 8; k++) { + r[k] <<= 1; } Reduce(&r); @@ -498,8 +513,8 @@ void AddJacobian(Point *out, Mul(&out->z, out->z, h); // X3 = r²-J-2*V - for (int i = 0; i < 8; i++) { - z1z1[i] = v[i] << 1; + for (int k = 0; k < 8; k++) { + z1z1[k] = v[k] << 1; } Add(&z1z1, j, z1z1); Reduce(&z1z1); @@ -508,8 +523,8 @@ void AddJacobian(Point *out, Reduce(&out->x); // Y3 = r*(V-X3)-2*S1*J - for (int i = 0; i < 8; i++) { - s1[i] <<= 1; + for (int k = 0; k < 8; k++) { + s1[k] <<= 1; } Mul(&s1, s1, j); Subtract(&z1z1, v, out->x); @@ -676,7 +691,7 @@ bool Point::SetFromString(const base::StringPiece& in) { } std::string Point::ToString() const { - FieldElement zinv, zinv_sq, x, y; + FieldElement zinv, zinv_sq, xx, yy; // If this is the point at infinity we return a string of all zeros. if (IsZero(this->z)) { @@ -686,16 +701,16 @@ std::string Point::ToString() const { Invert(&zinv, this->z); Square(&zinv_sq, zinv); - Mul(&x, this->x, zinv_sq); + Mul(&xx, x, zinv_sq); Mul(&zinv_sq, zinv_sq, zinv); - Mul(&y, this->y, zinv_sq); + Mul(&yy, y, zinv_sq); - Contract(&x); - Contract(&y); + Contract(&xx); + Contract(&yy); uint32 outwords[14]; - Put224Bits(outwords, x); - Put224Bits(outwords + 7, y); + Put224Bits(outwords, xx); + Put224Bits(outwords + 7, yy); return std::string(reinterpret_cast<const char*>(outwords), sizeof(outwords)); } diff --git a/chromium/crypto/p224_spake.cc b/chromium/crypto/p224_spake.cc index 31109a43503..a6dec40568a 100644 --- a/chromium/crypto/p224_spake.cc +++ b/chromium/crypto/p224_spake.cc @@ -7,6 +7,8 @@ #include <crypto/p224_spake.h> +#include <algorithm> + #include <base/logging.h> #include <crypto/p224.h> #include <crypto/random.h> @@ -80,7 +82,7 @@ const crypto::p224::Point kM = { 33188520, 48266885, 177021753, 81038478}, {104523827, 245682244, 266509668, 236196369, 28372046, 145351378, 198520366, 113345994}, - {1, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 0}, }; const crypto::p224::Point kN = { @@ -88,7 +90,7 @@ const crypto::p224::Point kN = { 5034302, 185981975, 171998428, 11653062}, {197567436, 51226044, 60372156, 175772188, 42075930, 8083165, 160827401, 65097570}, - {1, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 0}, }; } // anonymous namespace @@ -105,14 +107,18 @@ P224EncryptedKeyExchange::P224EncryptedKeyExchange( // x_ is a random scalar. RandBytes(x_, sizeof(x_)); - // X = g**x_ - p224::Point X; - p224::ScalarBaseMult(x_, &X); - // Calculate |password| hash to get SPAKE password value. SHA256HashString(std::string(password.data(), password.length()), pw_, sizeof(pw_)); + Init(); +} + +void P224EncryptedKeyExchange::Init() { + // X = g**x_ + p224::Point X; + p224::ScalarBaseMult(x_, &X); + // The client masks the Diffie-Hellman value, X, by adding M**pw and the // server uses N**pw. p224::Point MNpw; @@ -125,7 +131,7 @@ P224EncryptedKeyExchange::P224EncryptedKeyExchange( next_message_ = Xstar.ToString(); } -const std::string& P224EncryptedKeyExchange::GetMessage() { +const std::string& P224EncryptedKeyExchange::GetNextMessage() { if (state_ == kStateInitial) { state_ = kStateRecvDH; return next_message_; @@ -134,7 +140,7 @@ const std::string& P224EncryptedKeyExchange::GetMessage() { return next_message_; } - LOG(FATAL) << "P224EncryptedKeyExchange::GetMessage called in" + LOG(FATAL) << "P224EncryptedKeyExchange::GetNextMessage called in" " bad state " << state_; next_message_ = ""; return next_message_; @@ -240,9 +246,23 @@ const std::string& P224EncryptedKeyExchange::error() const { return error_; } -const std::string& P224EncryptedKeyExchange::GetKey() { +const std::string& P224EncryptedKeyExchange::GetKey() const { DCHECK_EQ(state_, kStateDone); + return GetUnverifiedKey(); +} + +const std::string& P224EncryptedKeyExchange::GetUnverifiedKey() const { + // Key is already final when state is kStateSendHash. Subsequent states are + // used only for verification of the key. Some users may combine verification + // with sending verifiable data instead of |expected_authenticator_|. + DCHECK_GE(state_, kStateSendHash); return key_; } +void P224EncryptedKeyExchange::SetXForTesting(const std::string& x) { + memset(&x_, 0, sizeof(x_)); + memcpy(&x_, x.data(), std::min(x.size(), sizeof(x_))); + Init(); +} + } // namespace crypto diff --git a/chromium/crypto/p224_spake.h b/chromium/crypto/p224_spake.h index 6905ef2c220..556b15cd09f 100644 --- a/chromium/crypto/p224_spake.h +++ b/chromium/crypto/p224_spake.h @@ -5,6 +5,7 @@ #ifndef CRYPTO_P224_SPAKE_H_ #define CRYPTO_P224_SPAKE_H_ +#include <base/gtest_prod_util.h> #include <base/strings/string_piece.h> #include <crypto/p224.h> #include <crypto/sha2.h> @@ -14,7 +15,7 @@ namespace crypto { // P224EncryptedKeyExchange implements SPAKE2, a variant of Encrypted // Key Exchange. It allows two parties that have a secret common // password to establish a common secure key by exchanging messages -// over unsecure channel without disclosing the password. +// over an insecure channel without disclosing the password. // // The password can be low entropy as authenticating with an attacker only // gives the attacker a one-shot password oracle. No other information about @@ -22,10 +23,10 @@ namespace crypto { // permitted authentication attempts otherwise they get many one-shot oracles.) // // The protocol requires several RTTs (actually two, but you shouldn't assume -// that.) To use the object, call GetMessage() and pass that message to the +// that.) To use the object, call GetNextMessage() and pass that message to the // peer. Get a message from the peer and feed it into ProcessMessage. Then // examine the return value of ProcessMessage: -// kResultPending: Another round is required. Call GetMessage and repeat. +// kResultPending: Another round is required. Call GetNextMessage and repeat. // kResultFailed: The authentication has failed. You can get a human readable // error message by calling error(). // kResultSuccess: The authentication was successful. @@ -54,12 +55,12 @@ class CRYPTO_EXPORT P224EncryptedKeyExchange { P224EncryptedKeyExchange(PeerType peer_type, const base::StringPiece& password); - // GetMessage returns a byte string which must be passed to the other party - // in the authentication. - const std::string& GetMessage(); + // GetNextMessage returns a byte string which must be passed to the other + // party in the authentication. + const std::string& GetNextMessage(); // ProcessMessage processes a message which must have been generated by a - // call to GetMessage() by the other party. + // call to GetNextMessage() by the other party. Result ProcessMessage(const base::StringPiece& message); // In the event that ProcessMessage() returns kResultFailed, error will @@ -68,7 +69,11 @@ class CRYPTO_EXPORT P224EncryptedKeyExchange { // The key established as result of the key exchange. Must be called // at then end after ProcessMessage() returns kResultSuccess. - const std::string& GetKey(); + const std::string& GetKey() const; + + // The key established as result of the key exchange. Can be called after + // the first ProcessMessage() + const std::string& GetUnverifiedKey() const; private: // The authentication state machine is very simple and each party proceeds @@ -81,9 +86,16 @@ class CRYPTO_EXPORT P224EncryptedKeyExchange { kStateDone, }; + FRIEND_TEST_ALL_PREFIXES(MutualAuth, ExpectedValues); + + void Init(); + + // Sets internal random scalar. Should be used by tests only. + void SetXForTesting(const std::string& x); + State state_; const bool is_server_; - // next_message_ contains a value for GetMessage() to return. + // next_message_ contains a value for GetNextMessage() to return. std::string next_message_; std::string error_; @@ -100,7 +112,7 @@ class CRYPTO_EXPORT P224EncryptedKeyExchange { // file). uint8 x_[p224::kScalarBytes]; // pw_ is SHA256(P(password), P(session))[:28] where P() prepends a uint32, - // big-endian length prefix (see paper refereneced in .cc file). + // big-endian length prefix (see paper referenced in .cc file). uint8 pw_[p224::kScalarBytes]; // expected_authenticator_ is used to store the hash value expected from the // other party. diff --git a/chromium/crypto/p224_spake_unittest.cc b/chromium/crypto/p224_spake_unittest.cc index 589cdbfcf0d..15b5be26841 100644 --- a/chromium/crypto/p224_spake_unittest.cc +++ b/chromium/crypto/p224_spake_unittest.cc @@ -2,45 +2,53 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "crypto/p224_spake.h" + #include <string> -#include <crypto/p224_spake.h> #include "base/logging.h" +#include "base/strings/string_number_conversions.h" #include "testing/gtest/include/gtest/gtest.h" namespace crypto { namespace { +std::string HexEncodeString(const std::string& binary_data) { + return base::HexEncode(binary_data.c_str(), binary_data.size()); +} + bool RunExchange(P224EncryptedKeyExchange* client, - P224EncryptedKeyExchange* server) { + P224EncryptedKeyExchange* server, + bool is_password_same) { for (;;) { std::string client_message, server_message; - client_message = client->GetMessage(); - server_message = server->GetMessage(); + client_message = client->GetNextMessage(); + server_message = server->GetNextMessage(); P224EncryptedKeyExchange::Result client_result, server_result; client_result = client->ProcessMessage(server_message); server_result = server->ProcessMessage(client_message); // Check that we never hit the case where only one succeeds. - if ((client_result == P224EncryptedKeyExchange::kResultSuccess) ^ - (server_result == P224EncryptedKeyExchange::kResultSuccess)) { - CHECK(false) << "Parties differ on whether authentication was successful"; - } + EXPECT_EQ(client_result == P224EncryptedKeyExchange::kResultSuccess, + server_result == P224EncryptedKeyExchange::kResultSuccess); if (client_result == P224EncryptedKeyExchange::kResultFailed || server_result == P224EncryptedKeyExchange::kResultFailed) { return false; } + EXPECT_EQ(is_password_same, + client->GetUnverifiedKey() == server->GetUnverifiedKey()); + if (client_result == P224EncryptedKeyExchange::kResultSuccess && server_result == P224EncryptedKeyExchange::kResultSuccess) { return true; } - CHECK_EQ(P224EncryptedKeyExchange::kResultPending, client_result); - CHECK_EQ(P224EncryptedKeyExchange::kResultPending, server_result); + EXPECT_EQ(P224EncryptedKeyExchange::kResultPending, client_result); + EXPECT_EQ(P224EncryptedKeyExchange::kResultPending, server_result); } } @@ -54,7 +62,7 @@ TEST(MutualAuth, CorrectAuth) { P224EncryptedKeyExchange server( P224EncryptedKeyExchange::kPeerTypeServer, kPassword); - EXPECT_TRUE(RunExchange(&client, &server)); + EXPECT_TRUE(RunExchange(&client, &server, true)); EXPECT_EQ(client.GetKey(), server.GetKey()); } @@ -66,7 +74,43 @@ TEST(MutualAuth, IncorrectPassword) { P224EncryptedKeyExchange::kPeerTypeServer, "wrongpassword"); - EXPECT_FALSE(RunExchange(&client, &server)); + EXPECT_FALSE(RunExchange(&client, &server, false)); +} + +TEST(MutualAuth, ExpectedValues) { + P224EncryptedKeyExchange client(P224EncryptedKeyExchange::kPeerTypeClient, + kPassword); + client.SetXForTesting("Client x"); + P224EncryptedKeyExchange server(P224EncryptedKeyExchange::kPeerTypeServer, + kPassword); + server.SetXForTesting("Server x"); + + std::string client_message = client.GetNextMessage(); + EXPECT_EQ( + "3508EF7DECC8AB9F9C439FBB0154288BBECC0A82E8448F4CF29554EB" + "BE9D486686226255EAD1D077C635B1A41F46AC91D7F7F32CED9EC3E0", + HexEncodeString(client_message)); + + std::string server_message = server.GetNextMessage(); + EXPECT_EQ( + "A3088C18B75D2C2B107105661AEC85424777475EB29F1DDFB8C14AFB" + "F1603D0DF38413A00F420ACF2059E7997C935F5A957A193D09A2B584", + HexEncodeString(server_message)); + + EXPECT_EQ(P224EncryptedKeyExchange::kResultPending, + client.ProcessMessage(server_message)); + EXPECT_EQ(P224EncryptedKeyExchange::kResultPending, + server.ProcessMessage(client_message)); + + EXPECT_EQ(client.GetUnverifiedKey(), server.GetUnverifiedKey()); + // Must stay the same. External implementations should be able to pair with. + EXPECT_EQ( + "CE7CCFC435CDA4F01EC8826788B1F8B82EF7D550A34696B371096E64" + "C487D4FE193F7D1A6FF6820BC7F807796BA3889E8F999BBDEFC32FFA", + HexEncodeString(server.GetUnverifiedKey())); + + EXPECT_TRUE(RunExchange(&client, &server, true)); + EXPECT_EQ(client.GetKey(), server.GetKey()); } TEST(MutualAuth, Fuzz) { @@ -85,8 +129,8 @@ TEST(MutualAuth, Fuzz) { for (unsigned round = 0;; round++) { std::string client_message, server_message; - client_message = client.GetMessage(); - server_message = server.GetMessage(); + client_message = client.GetNextMessage(); + server_message = server.GetNextMessage(); if ((rand & 1) == round) { const bool server_or_client = rand & 2; diff --git a/chromium/crypto/rsa_private_key.h b/chromium/crypto/rsa_private_key.h index 221e341a6fe..637be38836f 100644 --- a/chromium/crypto/rsa_private_key.h +++ b/chromium/crypto/rsa_private_key.h @@ -13,7 +13,7 @@ #include "base/basictypes.h" #include "crypto/crypto_export.h" -#if defined(USE_NSS) +#if defined(USE_NSS_CERTS) #include "base/gtest_prod_util.h" #endif @@ -180,48 +180,15 @@ class CRYPTO_EXPORT RSAPrivateKey { static RSAPrivateKey* CreateFromPrivateKeyInfo( const std::vector<uint8>& input); -#if defined(USE_NSS) - // Create a new random instance in |slot|. Can return NULL if initialization - // fails. The created key is permanent and is not exportable in plaintext - // form. - static RSAPrivateKey* CreateSensitive(PK11SlotInfo* slot, uint16 num_bits); - - // Create a new instance in |slot| by importing an existing private key. The - // format is an ASN.1-encoded PrivateKeyInfo block from PKCS #8. This can - // return NULL if initialization fails. - // The created key is permanent and is not exportable in plaintext form. - static RSAPrivateKey* CreateSensitiveFromPrivateKeyInfo( - PK11SlotInfo* slot, - const std::vector<uint8>& input); - - // Create a new instance by referencing an existing private key - // structure. Does not import the key. - static RSAPrivateKey* CreateFromKey(SECKEYPrivateKey* key); - - // Import an existing public key, and then search for the private - // half in the key database. The format of the public key blob is is - // an X509 SubjectPublicKeyInfo block. This can return NULL if - // initialization fails or the private key cannot be found. The - // caller takes ownership of the returned object, but nothing new is - // created in the key database. - static RSAPrivateKey* FindFromPublicKeyInfo( - const std::vector<uint8>& input); - - // Import an existing public key, and then search for the private - // half in the slot specified by |slot|. The format of the public - // key blob is is an X509 SubjectPublicKeyInfo block. This can return - // NULL if initialization fails or the private key cannot be found. - // The caller takes ownership of the returned object, but nothing new - // is created in the slot. - static RSAPrivateKey* FindFromPublicKeyInfoInSlot( - const std::vector<uint8>& input, - PK11SlotInfo* slot); -#elif defined(USE_OPENSSL) +#if defined(USE_OPENSSL) // Create a new instance from an existing EVP_PKEY, taking a // reference to it. |key| must be an RSA key. Returns NULL on // failure. static RSAPrivateKey* CreateFromKey(EVP_PKEY* key); - +#else + // Create a new instance by referencing an existing private key + // structure. Does not import the key. + static RSAPrivateKey* CreateFromKey(SECKEYPrivateKey* key); #endif #if defined(USE_OPENSSL) @@ -241,43 +208,14 @@ class CRYPTO_EXPORT RSAPrivateKey { bool ExportPublicKey(std::vector<uint8>* output) const; private: -#if defined(USE_NSS) +#if defined(USE_NSS_CERTS) FRIEND_TEST_ALL_PREFIXES(RSAPrivateKeyNSSTest, FindFromPublicKey); FRIEND_TEST_ALL_PREFIXES(RSAPrivateKeyNSSTest, FailedFindFromPublicKey); #endif - // Constructor is private. Use one of the Create*() or Find*() - // methods above instead. + // Constructor is private. Use one of the Create*() methods above instead. RSAPrivateKey(); -#if !defined(USE_OPENSSL) - // Shared helper for Create() and CreateSensitive(). - // TODO(cmasone): consider replacing |permanent| and |sensitive| with a - // flags arg created by ORing together some enumerated values. - // Note: |permanent| is only supported when USE_NSS is defined. - static RSAPrivateKey* CreateWithParams(PK11SlotInfo* slot, - uint16 num_bits, - bool permanent, - bool sensitive); - - // Shared helper for CreateFromPrivateKeyInfo() and - // CreateSensitiveFromPrivateKeyInfo(). - // Note: |permanent| is only supported when USE_NSS is defined. - static RSAPrivateKey* CreateFromPrivateKeyInfoWithParams( - PK11SlotInfo* slot, - const std::vector<uint8>& input, - bool permanent, - bool sensitive); -#endif - -#if defined(USE_NSS) - // Import an existing public key. The format of the public key blob - // is an X509 SubjectPublicKeyInfo block. This can return NULL if - // initialization fails. The caller takes ownership of the returned - // object. Note that this method doesn't initialize the |key_| member. - static RSAPrivateKey* InitPublicPart(const std::vector<uint8>& input); -#endif - #if defined(USE_OPENSSL) EVP_PKEY* key_; #else diff --git a/chromium/crypto/rsa_private_key_nss.cc b/chromium/crypto/rsa_private_key_nss.cc index 078544de0c3..88e55fa5768 100644 --- a/chromium/crypto/rsa_private_key_nss.cc +++ b/chromium/crypto/rsa_private_key_nss.cc @@ -7,7 +7,6 @@ #include <cryptohi.h> #include <keyhi.h> #include <pk11pub.h> -#include <secmod.h> #include <list> @@ -15,8 +14,8 @@ #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "base/strings/string_util.h" +#include "crypto/nss_key_util.h" #include "crypto/nss_util.h" -#include "crypto/nss_util_internal.h" #include "crypto/scoped_nss_types.h" // TODO(rafaelw): Consider using NSS's ASN.1 encoder. @@ -38,37 +37,6 @@ static bool ReadAttribute(SECKEYPrivateKey* key, return true; } -#if defined(USE_NSS) -struct PublicKeyInfoDeleter { - inline void operator()(CERTSubjectPublicKeyInfo* spki) { - SECKEY_DestroySubjectPublicKeyInfo(spki); - } -}; - -typedef scoped_ptr<CERTSubjectPublicKeyInfo, PublicKeyInfoDeleter> - ScopedPublicKeyInfo; - -// The function decodes RSA public key from the |input|. -crypto::ScopedSECKEYPublicKey GetRSAPublicKey(const std::vector<uint8>& input) { - // First, decode and save the public key. - SECItem key_der; - key_der.type = siBuffer; - key_der.data = const_cast<unsigned char*>(&input[0]); - key_der.len = input.size(); - - ScopedPublicKeyInfo spki(SECKEY_DecodeDERSubjectPublicKeyInfo(&key_der)); - if (!spki) - return crypto::ScopedSECKEYPublicKey(); - - crypto::ScopedSECKEYPublicKey result(SECKEY_ExtractPublicKey(spki.get())); - - // Make sure the key is an RSA key.. If not, that's an error. - if (!result || result->keyType != rsaKey) - return crypto::ScopedSECKEYPublicKey(); - return result.Pass(); -} -#endif // defined(USE_NSS) - } // namespace namespace crypto { @@ -85,10 +53,22 @@ RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) { EnsureNSSInit(); ScopedPK11Slot slot(PK11_GetInternalSlot()); - return CreateWithParams(slot.get(), - num_bits, - false /* not permanent */, - false /* not sensitive */); + if (!slot) { + NOTREACHED(); + return nullptr; + } + + ScopedSECKEYPublicKey public_key; + ScopedSECKEYPrivateKey private_key; + if (!GenerateRSAKeyPairNSS(slot.get(), num_bits, false /* not permanent */, + &public_key, &private_key)) { + return nullptr; + } + + RSAPrivateKey* rsa_key = new RSAPrivateKey; + rsa_key->public_key_ = public_key.release(); + rsa_key->key_ = private_key.release(); + return rsa_key; } // static @@ -97,31 +77,15 @@ RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo( EnsureNSSInit(); ScopedPK11Slot slot(PK11_GetInternalSlot()); - return CreateFromPrivateKeyInfoWithParams( - slot.get(), - input, - false /* not permanent */, - false /* not sensitive */); -} - -#if defined(USE_NSS) -// static -RSAPrivateKey* RSAPrivateKey::CreateSensitive(PK11SlotInfo* slot, - uint16 num_bits) { - return CreateWithParams(slot, - num_bits, - true /* permanent */, - true /* sensitive */); -} - -// static -RSAPrivateKey* RSAPrivateKey::CreateSensitiveFromPrivateKeyInfo( - PK11SlotInfo* slot, - const std::vector<uint8>& input) { - return CreateFromPrivateKeyInfoWithParams(slot, - input, - true /* permanent */, - true /* sensitive */); + if (!slot) { + NOTREACHED(); + return nullptr; + } + ScopedSECKEYPrivateKey key(ImportNSSKeyFromPrivateKeyInfo( + slot.get(), input, false /* not permanent */)); + if (!key || SECKEY_GetPrivateKeyType(key.get()) != rsaKey) + return nullptr; + return RSAPrivateKey::CreateFromKey(key.get()); } // static @@ -140,63 +104,6 @@ RSAPrivateKey* RSAPrivateKey::CreateFromKey(SECKEYPrivateKey* key) { return copy; } -// static -RSAPrivateKey* RSAPrivateKey::FindFromPublicKeyInfo( - const std::vector<uint8>& input) { - scoped_ptr<RSAPrivateKey> result(InitPublicPart(input)); - if (!result) - return NULL; - - ScopedSECItem ck_id( - PK11_MakeIDFromPubKey(&(result->public_key_->u.rsa.modulus))); - if (!ck_id.get()) { - NOTREACHED(); - return NULL; - } - - // Search all slots in all modules for the key with the given ID. - AutoSECMODListReadLock auto_lock; - SECMODModuleList* head = SECMOD_GetDefaultModuleList(); - for (SECMODModuleList* item = head; item != NULL; item = item->next) { - int slot_count = item->module->loaded ? item->module->slotCount : 0; - for (int i = 0; i < slot_count; i++) { - // Finally...Look for the key! - result->key_ = PK11_FindKeyByKeyID(item->module->slots[i], - ck_id.get(), NULL); - if (result->key_) - return result.release(); - } - } - - // We didn't find the key. - return NULL; -} - -// static -RSAPrivateKey* RSAPrivateKey::FindFromPublicKeyInfoInSlot( - const std::vector<uint8>& input, - PK11SlotInfo* slot) { - if (!slot) - return NULL; - - scoped_ptr<RSAPrivateKey> result(InitPublicPart(input)); - if (!result) - return NULL; - - ScopedSECItem ck_id( - PK11_MakeIDFromPubKey(&(result->public_key_->u.rsa.modulus))); - if (!ck_id.get()) { - NOTREACHED(); - return NULL; - } - - result->key_ = PK11_FindKeyByKeyID(slot, ck_id.get(), NULL); - if (!result->key_) - return NULL; - return result.release(); -} -#endif - RSAPrivateKey* RSAPrivateKey::Copy() const { RSAPrivateKey* copy = new RSAPrivateKey(); copy->key_ = SECKEY_CopyPrivateKey(key_); @@ -241,81 +148,4 @@ RSAPrivateKey::RSAPrivateKey() : key_(NULL), public_key_(NULL) { EnsureNSSInit(); } -// static -RSAPrivateKey* RSAPrivateKey::CreateWithParams(PK11SlotInfo* slot, - uint16 num_bits, - bool permanent, - bool sensitive) { - if (!slot) - return NULL; - - scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey); - - PK11RSAGenParams param; - param.keySizeInBits = num_bits; - param.pe = 65537L; - result->key_ = PK11_GenerateKeyPair(slot, - CKM_RSA_PKCS_KEY_PAIR_GEN, - ¶m, - &result->public_key_, - permanent, - sensitive, - NULL); - if (!result->key_) - return NULL; - - return result.release(); -} - -// static -RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfoWithParams( - PK11SlotInfo* slot, - const std::vector<uint8>& input, - bool permanent, - bool sensitive) { - if (!slot) - return NULL; - - scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey); - - SECItem der_private_key_info; - der_private_key_info.data = const_cast<unsigned char*>(&input.front()); - der_private_key_info.len = input.size(); - // Allow the private key to be used for key unwrapping, data decryption, - // and signature generation. - const unsigned int key_usage = KU_KEY_ENCIPHERMENT | KU_DATA_ENCIPHERMENT | - KU_DIGITAL_SIGNATURE; - SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey( - slot, &der_private_key_info, NULL, NULL, permanent, sensitive, - key_usage, &result->key_, NULL); - if (rv != SECSuccess) { - NOTREACHED(); - return NULL; - } - - result->public_key_ = SECKEY_ConvertToPublicKey(result->key_); - if (!result->public_key_) { - NOTREACHED(); - return NULL; - } - - return result.release(); -} - -#if defined(USE_NSS) -// static -RSAPrivateKey* RSAPrivateKey::InitPublicPart(const std::vector<uint8>& input) { - EnsureNSSInit(); - - scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey()); - result->public_key_ = GetRSAPublicKey(input).release(); - if (!result->public_key_) { - NOTREACHED(); - return NULL; - } - - return result.release(); -} -#endif // defined(USE_NSS) - } // namespace crypto diff --git a/chromium/crypto/rsa_private_key_nss_unittest.cc b/chromium/crypto/rsa_private_key_nss_unittest.cc deleted file mode 100644 index b91b431c3ee..00000000000 --- a/chromium/crypto/rsa_private_key_nss_unittest.cc +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "crypto/rsa_private_key.h" - -#include <keyhi.h> -#include <pk11pub.h> - -#include "base/memory/scoped_ptr.h" -#include "crypto/scoped_test_nss_db.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace crypto { - -class RSAPrivateKeyNSSTest : public testing::Test { - public: - RSAPrivateKeyNSSTest() {} - virtual ~RSAPrivateKeyNSSTest() {} - - private: - ScopedTestNSSDB test_nssdb_; - - DISALLOW_COPY_AND_ASSIGN(RSAPrivateKeyNSSTest); -}; - -TEST_F(RSAPrivateKeyNSSTest, FindFromPublicKey) { - // Create a keypair, which will put the keys in the user's NSSDB. - scoped_ptr<crypto::RSAPrivateKey> key_pair(RSAPrivateKey::Create(256)); - - std::vector<uint8> public_key; - ASSERT_TRUE(key_pair->ExportPublicKey(&public_key)); - - scoped_ptr<crypto::RSAPrivateKey> key_pair_2( - crypto::RSAPrivateKey::FindFromPublicKeyInfo(public_key)); - - EXPECT_EQ(key_pair->key_->pkcs11ID, key_pair_2->key_->pkcs11ID); -} - -TEST_F(RSAPrivateKeyNSSTest, FailedFindFromPublicKey) { - // Create a keypair, which will put the keys in the user's NSSDB. - scoped_ptr<crypto::RSAPrivateKey> key_pair(RSAPrivateKey::Create(256)); - - std::vector<uint8> public_key; - ASSERT_TRUE(key_pair->ExportPublicKey(&public_key)); - - // Remove the keys from the DB, and make sure we can't find them again. - if (key_pair->key_) { - PK11_DestroyTokenObject(key_pair->key_->pkcs11Slot, - key_pair->key_->pkcs11ID); - } - if (key_pair->public_key_) { - PK11_DestroyTokenObject(key_pair->public_key_->pkcs11Slot, - key_pair->public_key_->pkcs11ID); - } - - EXPECT_EQ(NULL, crypto::RSAPrivateKey::FindFromPublicKeyInfo(public_key)); -} - -} // namespace crypto diff --git a/chromium/crypto/rsa_private_key_openssl.cc b/chromium/crypto/rsa_private_key_openssl.cc index 053c4a2f930..52a0a7a1815 100644 --- a/chromium/crypto/rsa_private_key_openssl.cc +++ b/chromium/crypto/rsa_private_key_openssl.cc @@ -19,10 +19,13 @@ namespace crypto { namespace { +using ScopedPKCS8_PRIV_KEY_INFO = + ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>; + // Function pointer definition, for injecting the required key export function // into ExportKey, below. The supplied function should export EVP_PKEY into // the supplied BIO, returning 1 on success or 0 on failure. -typedef int (ExportFunction)(BIO*, EVP_PKEY*); +using ExportFunction = int (*)(BIO*, EVP_PKEY*); // Helper to export |key| into |output| via the specified ExportFunction. bool ExportKey(EVP_PKEY* key, @@ -76,23 +79,19 @@ RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo( return NULL; OpenSSLErrStackTracer err_tracer(FROM_HERE); - // BIO_new_mem_buf is not const aware, but it does not modify the buffer. - char* data = reinterpret_cast<char*>(const_cast<uint8*>(&input[0])); - ScopedBIO bio(BIO_new_mem_buf(data, input.size())); - if (!bio.get()) - return NULL; // Importing is a little more involved than exporting, as we must first // PKCS#8 decode the input, and then import the EVP_PKEY from Private Key // Info structure returned. - ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>::Type p8inf( - d2i_PKCS8_PRIV_KEY_INFO_bio(bio.get(), NULL)); - if (!p8inf.get()) + const uint8_t* ptr = &input[0]; + ScopedPKCS8_PRIV_KEY_INFO p8inf( + d2i_PKCS8_PRIV_KEY_INFO(nullptr, &ptr, input.size())); + if (!p8inf.get() || ptr != &input[0] + input.size()) return NULL; scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey); result->key_ = EVP_PKCS82PKEY(p8inf.get()); - if (!result->key_) + if (!result->key_ || EVP_PKEY_id(result->key_) != EVP_PKEY_RSA) return NULL; return result.release(); @@ -104,7 +103,7 @@ RSAPrivateKey* RSAPrivateKey::CreateFromKey(EVP_PKEY* key) { if (EVP_PKEY_type(key->type) != EVP_PKEY_RSA) return NULL; RSAPrivateKey* copy = new RSAPrivateKey(); - copy->key_ = EVP_PKEY_dup(key); + copy->key_ = EVP_PKEY_up_ref(key); return copy; } diff --git a/chromium/crypto/rsa_private_key_unittest.cc b/chromium/crypto/rsa_private_key_unittest.cc index d53d50228d2..b231cac6cc3 100644 --- a/chromium/crypto/rsa_private_key_unittest.cc +++ b/chromium/crypto/rsa_private_key_unittest.cc @@ -150,6 +150,47 @@ TEST(RSAPrivateKeyUnitTest, CopyTest) { ASSERT_EQ(input, privkey_copy); } +// Test that CreateFromPrivateKeyInfo fails if there is extra data after the RSA +// key. +TEST(RSAPrivateKeyUnitTest, ExtraData) { + std::vector<uint8> input( + kTestPrivateKeyInfo, kTestPrivateKeyInfo + sizeof(kTestPrivateKeyInfo)); + input.push_back(0); + + scoped_ptr<crypto::RSAPrivateKey> key( + crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(input)); + + // Import should fail. + EXPECT_FALSE(key); +} + +TEST(RSAPrivateKeyUnitTest, NotRsaKey) { + // Defines a valid P-256 private key. + const uint8 kTestEcPrivateKeyInfo[] = { + 0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, + 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, + 0x03, 0x01, 0x07, 0x04, 0x6D, 0x30, 0x6B, 0x02, 0x01, 0x01, 0x04, 0x20, + 0x1F, 0xE3, 0x39, 0x50, 0xC5, 0xF4, 0x61, 0x12, 0x4A, 0xE9, 0x92, 0xC2, + 0xBD, 0xFD, 0xF1, 0xC7, 0x3B, 0x16, 0x15, 0xF5, 0x71, 0xBD, 0x56, 0x7E, + 0x60, 0xD1, 0x9A, 0xA1, 0xF4, 0x8C, 0xDF, 0x42, 0xA1, 0x44, 0x03, 0x42, + 0x00, 0x04, 0x7C, 0x11, 0x0C, 0x66, 0xDC, 0xFD, 0xA8, 0x07, 0xF6, 0xE6, + 0x9E, 0x45, 0xDD, 0xB3, 0xC7, 0x4F, 0x69, 0xA1, 0x48, 0x4D, 0x20, 0x3E, + 0x8D, 0xC5, 0xAD, 0xA8, 0xE9, 0xA9, 0xDD, 0x7C, 0xB3, 0xC7, 0x0D, 0xF4, + 0x48, 0x98, 0x6E, 0x51, 0xBD, 0xE5, 0xD1, 0x57, 0x6F, 0x99, 0x90, 0x1F, + 0x9C, 0x2C, 0x6A, 0x80, 0x6A, 0x47, 0xFD, 0x90, 0x76, 0x43, 0xA7, 0x2B, + 0x83, 0x55, 0x97, 0xEF, 0xC8, 0xC6 + }; + + std::vector<uint8> input( + kTestEcPrivateKeyInfo, + kTestEcPrivateKeyInfo + sizeof(kTestEcPrivateKeyInfo)); + + scoped_ptr<crypto::RSAPrivateKey> key( + crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(input)); + + // Import should fail as the given PKCS8 bytes were for an EC key not RSA key. + EXPECT_FALSE(key); +} // Verify that generated public keys look good. This test data was generated // with the openssl command line tool. @@ -404,9 +445,6 @@ TEST(RSAPrivateKeyUnitTest, ShortIntegers) { input2.size())); } -// The following test can run if either USE_NSS or USE_OPENSSL is defined, but -// not otherwise (since it uses crypto::RSAPrivateKey::CreateFromKey). -#if defined(USE_NSS) || defined(USE_OPENSSL) TEST(RSAPrivateKeyUnitTest, CreateFromKeyTest) { scoped_ptr<crypto::RSAPrivateKey> key_pair( crypto::RSAPrivateKey::Create(256)); @@ -428,5 +466,4 @@ TEST(RSAPrivateKeyUnitTest, CreateFromKeyTest) { ASSERT_EQ(privkey, privkey_copy); ASSERT_EQ(pubkey, pubkey_copy); } -#endif diff --git a/chromium/crypto/scoped_openssl_types.h b/chromium/crypto/scoped_openssl_types.h index cc056e49efe..73f763271bb 100644 --- a/chromium/crypto/scoped_openssl_types.h +++ b/chromium/crypto/scoped_openssl_types.h @@ -11,6 +11,7 @@ #include <openssl/ec.h> #include <openssl/ecdsa.h> #include <openssl/evp.h> +#include <openssl/mem.h> #include <openssl/rsa.h> #include "base/memory/scoped_ptr.h" @@ -22,15 +23,13 @@ namespace crypto { // base::internal::RunnableAdapter<>, but that's far too heavy weight. template <typename Type, void (*Destroyer)(Type*)> struct OpenSSLDestroyer { - typedef void AllowSelfReset; + using AllowSelfReset = void; void operator()(Type* ptr) const { Destroyer(ptr); } }; template <typename PointerType, void (*Destroyer)(PointerType*)> -struct ScopedOpenSSL { - typedef scoped_ptr<PointerType, OpenSSLDestroyer<PointerType, Destroyer> > - Type; -}; +using ScopedOpenSSL = + scoped_ptr<PointerType, OpenSSLDestroyer<PointerType, Destroyer>>; struct OpenSSLFree { void operator()(uint8_t* ptr) const { OPENSSL_free(ptr); } @@ -40,19 +39,21 @@ struct OpenSSLFree { // short-hand and prevalence. Note that OpenSSL types related to X.509 are // intentionally not included, as crypto/ does not generally deal with // certificates or PKI. -typedef ScopedOpenSSL<BIGNUM, BN_free>::Type ScopedBIGNUM; -typedef ScopedOpenSSL<EC_KEY, EC_KEY_free>::Type ScopedEC_KEY; -typedef ScopedOpenSSL<BIO, BIO_free_all>::Type ScopedBIO; -typedef ScopedOpenSSL<DSA, DSA_free>::Type ScopedDSA; -typedef ScopedOpenSSL<ECDSA_SIG, ECDSA_SIG_free>::Type ScopedECDSA_SIG; -typedef ScopedOpenSSL<EC_KEY, EC_KEY_free>::Type ScopedEC_KEY; -typedef ScopedOpenSSL<EVP_MD_CTX, EVP_MD_CTX_destroy>::Type ScopedEVP_MD_CTX; -typedef ScopedOpenSSL<EVP_PKEY, EVP_PKEY_free>::Type ScopedEVP_PKEY; -typedef ScopedOpenSSL<EVP_PKEY_CTX, EVP_PKEY_CTX_free>::Type ScopedEVP_PKEY_CTX; -typedef ScopedOpenSSL<RSA, RSA_free>::Type ScopedRSA; +using ScopedBIGNUM = ScopedOpenSSL<BIGNUM, BN_free>; +using ScopedEC_Key = ScopedOpenSSL<EC_KEY, EC_KEY_free>; +using ScopedBIO = ScopedOpenSSL<BIO, BIO_free_all>; +using ScopedDSA = ScopedOpenSSL<DSA, DSA_free>; +using ScopedECDSA_SIG = ScopedOpenSSL<ECDSA_SIG, ECDSA_SIG_free>; +using ScopedEC_GROUP = ScopedOpenSSL<EC_GROUP, EC_GROUP_free>; +using ScopedEC_KEY = ScopedOpenSSL<EC_KEY, EC_KEY_free>; +using ScopedEC_POINT = ScopedOpenSSL<EC_POINT, EC_POINT_free>; +using ScopedEVP_MD_CTX = ScopedOpenSSL<EVP_MD_CTX, EVP_MD_CTX_destroy>; +using ScopedEVP_PKEY = ScopedOpenSSL<EVP_PKEY, EVP_PKEY_free>; +using ScopedEVP_PKEY_CTX = ScopedOpenSSL<EVP_PKEY_CTX, EVP_PKEY_CTX_free>; +using ScopedRSA = ScopedOpenSSL<RSA, RSA_free>; // The bytes must have been allocated with OPENSSL_malloc. -typedef scoped_ptr<uint8_t, OpenSSLFree> ScopedOpenSSLBytes; +using ScopedOpenSSLBytes = scoped_ptr<uint8_t, OpenSSLFree>; } // namespace crypto diff --git a/chromium/crypto/secure_hash_default.cc b/chromium/crypto/secure_hash_default.cc index 1f5e59ba2ab..262beb7fd18 100644 --- a/chromium/crypto/secure_hash_default.cc +++ b/chromium/crypto/secure_hash_default.cc @@ -23,22 +23,20 @@ class SecureHashSHA256NSS : public SecureHash { SHA256_Begin(&ctx_); } - virtual ~SecureHashSHA256NSS() { - memset(&ctx_, 0, sizeof(ctx_)); - } + ~SecureHashSHA256NSS() override { memset(&ctx_, 0, sizeof(ctx_)); } // SecureHash implementation: - virtual void Update(const void* input, size_t len) override { + void Update(const void* input, size_t len) override { SHA256_Update(&ctx_, static_cast<const unsigned char*>(input), len); } - virtual void Finish(void* output, size_t len) override { + void Finish(void* output, size_t len) override { SHA256_End(&ctx_, static_cast<unsigned char*>(output), NULL, static_cast<unsigned int>(len)); } - virtual bool Serialize(Pickle* pickle) override; - virtual bool Deserialize(PickleIterator* data_iterator) override; + bool Serialize(Pickle* pickle) override; + bool Deserialize(PickleIterator* data_iterator) override; private: SHA256Context ctx_; diff --git a/chromium/crypto/secure_hash_openssl.cc b/chromium/crypto/secure_hash_openssl.cc index 61946a8da81..ee1993c58e4 100644 --- a/chromium/crypto/secure_hash_openssl.cc +++ b/chromium/crypto/secure_hash_openssl.cc @@ -4,7 +4,7 @@ #include "crypto/secure_hash.h" -#include <openssl/crypto.h> +#include <openssl/mem.h> #include <openssl/sha.h> #include "base/basictypes.h" @@ -26,22 +26,22 @@ class SecureHashSHA256OpenSSL : public SecureHash { SHA256_Init(&ctx_); } - virtual ~SecureHashSHA256OpenSSL() { + ~SecureHashSHA256OpenSSL() override { OPENSSL_cleanse(&ctx_, sizeof(ctx_)); } - virtual void Update(const void* input, size_t len) override { + void Update(const void* input, size_t len) override { SHA256_Update(&ctx_, static_cast<const unsigned char*>(input), len); } - virtual void Finish(void* output, size_t len) override { + void Finish(void* output, size_t len) override { ScopedOpenSSLSafeSizeBuffer<SHA256_DIGEST_LENGTH> result( static_cast<unsigned char*>(output), len); SHA256_Final(result.safe_buffer(), &ctx_); } - virtual bool Serialize(Pickle* pickle) override; - virtual bool Deserialize(PickleIterator* data_iterator) override; + bool Serialize(Pickle* pickle) override; + bool Deserialize(PickleIterator* data_iterator) override; private: SHA256_CTX ctx_; diff --git a/chromium/crypto/signature_creator.h b/chromium/crypto/signature_creator.h index 840d1ff0b80..ab9d2c1a21b 100644 --- a/chromium/crypto/signature_creator.h +++ b/chromium/crypto/signature_creator.h @@ -14,7 +14,7 @@ #if defined(USE_OPENSSL) // Forward declaration for openssl/*.h typedef struct env_md_ctx_st EVP_MD_CTX; -#elif defined(USE_NSS) || defined(OS_WIN) || defined(OS_MACOSX) +#elif defined(USE_NSS_CERTS) || defined(OS_WIN) || defined(OS_MACOSX) // Forward declaration. struct SGNContextStr; #endif @@ -59,11 +59,9 @@ class CRYPTO_EXPORT SignatureCreator { // Private constructor. Use the Create() method instead. SignatureCreator(); - RSAPrivateKey* key_; - #if defined(USE_OPENSSL) EVP_MD_CTX* sign_context_; -#elif defined(USE_NSS) || defined(OS_WIN) || defined(OS_MACOSX) +#elif defined(USE_NSS_CERTS) || defined(OS_WIN) || defined(OS_MACOSX) SGNContextStr* sign_context_; #endif diff --git a/chromium/crypto/signature_creator_nss.cc b/chromium/crypto/signature_creator_nss.cc index 47728b07563..da03312881d 100644 --- a/chromium/crypto/signature_creator_nss.cc +++ b/chromium/crypto/signature_creator_nss.cc @@ -50,8 +50,6 @@ SignatureCreator::~SignatureCreator() { SignatureCreator* SignatureCreator::Create(RSAPrivateKey* key, HashAlgorithm hash_alg) { scoped_ptr<SignatureCreator> result(new SignatureCreator); - result->key_ = key; - result->sign_context_ = SGN_NewContext(ToNSSSigOid(hash_alg), key->key()); if (!result->sign_context_) { NOTREACHED(); @@ -113,9 +111,7 @@ bool SignatureCreator::Final(std::vector<uint8>* signature) { return true; } -SignatureCreator::SignatureCreator() - : key_(NULL), - sign_context_(NULL) { +SignatureCreator::SignatureCreator() : sign_context_(NULL) { EnsureNSSInit(); } diff --git a/chromium/crypto/signature_creator_openssl.cc b/chromium/crypto/signature_creator_openssl.cc index 7a1349b5a5a..0d90d50044d 100644 --- a/chromium/crypto/signature_creator_openssl.cc +++ b/chromium/crypto/signature_creator_openssl.cc @@ -45,14 +45,15 @@ SignatureCreator* SignatureCreator::Create(RSAPrivateKey* key, HashAlgorithm hash_alg) { OpenSSLErrStackTracer err_tracer(FROM_HERE); scoped_ptr<SignatureCreator> result(new SignatureCreator); - result->key_ = key; const EVP_MD* const digest = ToOpenSSLDigest(hash_alg); DCHECK(digest); if (!digest) { return NULL; } - if (!EVP_SignInit_ex(result->sign_context_, digest, NULL)) + if (!EVP_DigestSignInit(result->sign_context_, NULL, digest, NULL, + key->key())) { return NULL; + } return result.release(); } @@ -87,17 +88,22 @@ SignatureCreator::~SignatureCreator() { bool SignatureCreator::Update(const uint8* data_part, int data_part_len) { OpenSSLErrStackTracer err_tracer(FROM_HERE); - return EVP_SignUpdate(sign_context_, data_part, data_part_len) == 1; + return !!EVP_DigestSignUpdate(sign_context_, data_part, data_part_len); } bool SignatureCreator::Final(std::vector<uint8>* signature) { OpenSSLErrStackTracer err_tracer(FROM_HERE); - EVP_PKEY* key = key_->key(); - signature->resize(EVP_PKEY_size(key)); - unsigned int len = 0; - int rv = EVP_SignFinal(sign_context_, vector_as_array(signature), &len, key); - if (!rv) { + // Determine the maximum length of the signature. + size_t len = 0; + if (!EVP_DigestSignFinal(sign_context_, NULL, &len)) { + signature->clear(); + return false; + } + signature->resize(len); + + // Sign it. + if (!EVP_DigestSignFinal(sign_context_, vector_as_array(signature), &len)) { signature->clear(); return false; } diff --git a/chromium/crypto/signature_verifier_openssl.cc b/chromium/crypto/signature_verifier_openssl.cc index a855120ef83..a33d665ec13 100644 --- a/chromium/crypto/signature_verifier_openssl.cc +++ b/chromium/crypto/signature_verifier_openssl.cc @@ -50,7 +50,7 @@ bool SignatureVerifier::VerifyInit(const uint8* signature_algorithm, const uint8* public_key_info, int public_key_info_len) { OpenSSLErrStackTracer err_tracer(FROM_HERE); - ScopedOpenSSL<X509_ALGOR, X509_ALGOR_free>::Type algorithm( + ScopedOpenSSL<X509_ALGOR, X509_ALGOR_free> algorithm( d2i_X509_ALGOR(NULL, &signature_algorithm, signature_algorithm_len)); if (!algorithm.get()) return false; @@ -122,8 +122,7 @@ bool SignatureVerifier::VerifyFinal() { int rv = EVP_DigestVerifyFinal(verify_context_->ctx.get(), vector_as_array(&signature_), signature_.size()); - // rv is -1 if a DER-encoded ECDSA signature cannot be decoded correctly. - DCHECK_GE(rv, -1); + DCHECK_EQ(static_cast<int>(!!rv), rv); Reset(); return rv == 1; } @@ -141,19 +140,14 @@ bool SignatureVerifier::CommonInit(const EVP_MD* digest, signature_.assign(signature, signature + signature_len); - // BIO_new_mem_buf is not const aware, but it does not modify the buffer. - char* data = reinterpret_cast<char*>(const_cast<uint8*>(public_key_info)); - ScopedBIO bio(BIO_new_mem_buf(data, public_key_info_len)); - if (!bio.get()) - return false; - - ScopedEVP_PKEY public_key(d2i_PUBKEY_bio(bio.get(), NULL)); - if (!public_key.get()) + const uint8_t* ptr = public_key_info; + ScopedEVP_PKEY public_key(d2i_PUBKEY(nullptr, &ptr, public_key_info_len)); + if (!public_key.get() || ptr != public_key_info + public_key_info_len) return false; verify_context_->ctx.reset(EVP_MD_CTX_create()); int rv = EVP_DigestVerifyInit(verify_context_->ctx.get(), pkey_ctx, - digest, NULL, public_key.get()); + digest, nullptr, public_key.get()); return rv == 1; } diff --git a/chromium/crypto/signature_verifier_unittest.cc b/chromium/crypto/signature_verifier_unittest.cc index f6c42e0fdc7..a661ff7f8ab 100644 --- a/chromium/crypto/signature_verifier_unittest.cc +++ b/chromium/crypto/signature_verifier_unittest.cc @@ -258,6 +258,26 @@ TEST(SignatureVerifierTest, BasicTest) { ok = verifier.VerifyFinal(); EXPECT_FALSE(ok); } + + // Test 5: import an invalid key. + uint8_t bad_public_key_info[sizeof(public_key_info)]; + memcpy(bad_public_key_info, public_key_info, sizeof(public_key_info)); + bad_public_key_info[0] += 1; // Corrupt part of the SPKI syntax. + ok = verifier.VerifyInit(signature_algorithm, + sizeof(signature_algorithm), + signature, sizeof(signature), + bad_public_key_info, sizeof(bad_public_key_info)); + EXPECT_FALSE(ok); + + // Test 6: import a key with extra data. + uint8_t long_public_key_info[sizeof(public_key_info) + 5]; + memset(long_public_key_info, 0, sizeof(long_public_key_info)); + memcpy(long_public_key_info, public_key_info, sizeof(public_key_info)); + ok = verifier.VerifyInit(signature_algorithm, + sizeof(signature_algorithm), + signature, sizeof(signature), + long_public_key_info, sizeof(long_public_key_info)); + EXPECT_FALSE(ok); } ////////////////////////////////////////////////////////////////////// @@ -980,6 +1000,23 @@ static bool DecodeTestInput(const char* in, std::vector<uint8>* out) { return true; } +// PrependASN1Length prepends an ASN.1 serialized length to the beginning of +// |out|. +static void PrependASN1Length(std::vector<uint8>* out, size_t len) { + if (len < 128) { + out->insert(out->begin(), static_cast<uint8>(len)); + } else if (len < 256) { + out->insert(out->begin(), static_cast<uint8>(len)); + out->insert(out->begin(), 0x81); + } else if (len < 0x10000) { + out->insert(out->begin(), static_cast<uint8>(len)); + out->insert(out->begin(), static_cast<uint8>(len >> 8)); + out->insert(out->begin(), 0x82); + } else { + CHECK(false) << "ASN.1 length not handled: " << len; + } +} + static bool EncodeRSAPublicKey(const std::vector<uint8>& modulus_n, const std::vector<uint8>& public_exponent_e, std::vector<uint8>* public_key_info) { @@ -1007,37 +1044,28 @@ static bool EncodeRSAPublicKey(const std::vector<uint8>& modulus_n, public_key_info->insert(public_key_info->begin(), public_exponent_e.begin(), public_exponent_e.end()); - uint8 exponent_size = base::checked_cast<uint8>(public_exponent_e.size()); - public_key_info->insert(public_key_info->begin(), exponent_size); + PrependASN1Length(public_key_info, public_exponent_e.size()); public_key_info->insert(public_key_info->begin(), kIntegerTag); // Encode the modulus n as an INTEGER. public_key_info->insert(public_key_info->begin(), modulus_n.begin(), modulus_n.end()); - uint16 modulus_size = base::checked_cast<uint16>(modulus_n.size()); + size_t modulus_size = modulus_n.size(); if (modulus_n[0] & 0x80) { public_key_info->insert(public_key_info->begin(), 0x00); modulus_size++; } - public_key_info->insert(public_key_info->begin(), modulus_size & 0xff); - public_key_info->insert(public_key_info->begin(), (modulus_size >> 8) & 0xff); - public_key_info->insert(public_key_info->begin(), 0x82); + PrependASN1Length(public_key_info, modulus_size); public_key_info->insert(public_key_info->begin(), kIntegerTag); // Encode the RSAPublicKey SEQUENCE. - uint16 info_size = base::checked_cast<uint16>(public_key_info->size()); - public_key_info->insert(public_key_info->begin(), info_size & 0xff); - public_key_info->insert(public_key_info->begin(), (info_size >> 8) & 0xff); - public_key_info->insert(public_key_info->begin(), 0x82); + PrependASN1Length(public_key_info, public_key_info->size()); public_key_info->insert(public_key_info->begin(), kSequenceTag); // Encode the BIT STRING. // Number of unused bits. public_key_info->insert(public_key_info->begin(), 0x00); - info_size = base::checked_cast<uint16>(public_key_info->size()); - public_key_info->insert(public_key_info->begin(), info_size & 0xff); - public_key_info->insert(public_key_info->begin(), (info_size >> 8) & 0xff); - public_key_info->insert(public_key_info->begin(), 0x82); + PrependASN1Length(public_key_info, public_key_info->size()); public_key_info->insert(public_key_info->begin(), kBitStringTag); // Encode the AlgorithmIdentifier. @@ -1051,10 +1079,7 @@ static bool EncodeRSAPublicKey(const std::vector<uint8>& modulus_n, algorithm, algorithm + sizeof(algorithm)); // Encode the outermost SEQUENCE. - info_size = base::checked_cast<uint16>(public_key_info->size()); - public_key_info->insert(public_key_info->begin(), info_size & 0xff); - public_key_info->insert(public_key_info->begin(), (info_size >> 8) & 0xff); - public_key_info->insert(public_key_info->begin(), 0x82); + PrependASN1Length(public_key_info, public_key_info->size()); public_key_info->insert(public_key_info->begin(), kSequenceTag); return true; @@ -1062,6 +1087,7 @@ static bool EncodeRSAPublicKey(const std::vector<uint8>& modulus_n, TEST(SignatureVerifierTest, VerifyRSAPSS) { for (unsigned int i = 0; i < arraysize(pss_test); i++) { + SCOPED_TRACE(i); std::vector<uint8> modulus_n; std::vector<uint8> public_exponent_e; ASSERT_TRUE(DecodeTestInput(pss_test[i].modulus_n, &modulus_n)); @@ -1072,6 +1098,7 @@ TEST(SignatureVerifierTest, VerifyRSAPSS) { &public_key_info)); for (unsigned int j = 0; j < arraysize(pss_test[i].example); j++) { + SCOPED_TRACE(j); std::vector<uint8> message; std::vector<uint8> salt; std::vector<uint8> signature; diff --git a/chromium/crypto/symmetric_key.h b/chromium/crypto/symmetric_key.h index ab105c1754c..996c5923b18 100644 --- a/chromium/crypto/symmetric_key.h +++ b/chromium/crypto/symmetric_key.h @@ -14,7 +14,7 @@ // See comments for crypto_nacl_win64 in crypto.gyp. // Must test for NACL_WIN64 before OS_WIN since former is a subset of latter. #include "crypto/scoped_capi_types.h" -#elif defined(USE_NSS) || \ +#elif defined(USE_NSS_CERTS) || \ (!defined(USE_OPENSSL) && (defined(OS_WIN) || defined(OS_MACOSX))) #include "crypto/scoped_nss_types.h" #endif @@ -61,7 +61,7 @@ class CRYPTO_EXPORT SymmetricKey { HCRYPTKEY key() const { return key_.get(); } #elif defined(USE_OPENSSL) const std::string& key() { return key_; } -#elif defined(USE_NSS) || defined(OS_WIN) || defined(OS_MACOSX) +#elif defined(USE_NSS_CERTS) || defined(OS_WIN) || defined(OS_MACOSX) PK11SymKey* key() const { return key_.get(); } #endif @@ -88,7 +88,7 @@ class CRYPTO_EXPORT SymmetricKey { #elif defined(USE_OPENSSL) SymmetricKey() {} std::string key_; -#elif defined(USE_NSS) || defined(OS_WIN) || defined(OS_MACOSX) +#elif defined(USE_NSS_CERTS) || defined(OS_WIN) || defined(OS_MACOSX) explicit SymmetricKey(PK11SymKey* key); ScopedPK11SymKey key_; #endif |