diff options
29 files changed, 620 insertions, 643 deletions
diff --git a/build/build_config.h b/build/build_config.h index 7137b4b..d8c3db6 100644 --- a/build/build_config.h +++ b/build/build_config.h @@ -61,11 +61,8 @@ #error Please add support for your platform in build/build_config.h #endif -#if defined(USE_OPENSSL) && defined(USE_NSS_CERTS) -// TODO(davidben): This constraint compares somewhat orthogonal things and will -// be fixed when BoringSSL with NSS for certificates is added as a build -// configuration. See https://crbug.com/462040. -#error Cannot use both OpenSSL and NSS +#if defined(USE_OPENSSL_CERTS) && defined(USE_NSS_CERTS) +#error Cannot use both OpenSSL and NSS for certificates #endif // For access to standard BSD features, use OS_BSD instead of a diff --git a/build/common.gypi b/build/common.gypi index c5a8e73..7c3074b 100644 --- a/build/common.gypi +++ b/build/common.gypi @@ -70,7 +70,10 @@ # certificates, use_openssl_certs must be set. 'use_openssl%': 0, - # Typedef X509Certificate::OSCertHandle to OpenSSL's struct X509*. + # Use OpenSSL for representing certificates. When targeting Android, + # the platform certificate library is used for certificate + # verification. On other targets, this flag also enables OpenSSL for + # certificate verification, but this configuration is unsupported. 'use_openssl_certs%': 0, # Disable viewport meta tag by default. @@ -681,20 +684,12 @@ }], # NSS usage. - ['(OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris") and use_openssl==0', { + ['(OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris")', { 'use_nss_certs%': 1, }, { 'use_nss_certs%': 0, }], - # When OpenSSL is used for SSL and crypto on Unix-like systems, use - # OpenSSL's certificate definition. - ['(OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris") and use_openssl==1', { - 'use_openssl_certs%': 1, - }, { - 'use_openssl_certs%': 0, - }], - # libudev usage. This currently only affects the content layer. ['OS=="linux" and embedded==0', { 'use_udev%': 1, diff --git a/build/config/BUILD.gn b/build/config/BUILD.gn index 471994d..22cb45a 100644 --- a/build/config/BUILD.gn +++ b/build/config/BUILD.gn @@ -122,10 +122,11 @@ config("feature_flags") { } if (use_openssl) { defines += [ "USE_OPENSSL=1" ] - if (use_openssl_certs) { - defines += [ "USE_OPENSSL_CERTS=1" ] - } - } else if (use_nss_certs) { + } + if (use_openssl_certs) { + defines += [ "USE_OPENSSL_CERTS=1" ] + } + if (use_nss_certs) { defines += [ "USE_NSS_CERTS=1" ] } if (use_ozone) { diff --git a/build/config/crypto.gni b/build/config/crypto.gni index ee23569..7f090b7 100644 --- a/build/config/crypto.gni +++ b/build/config/crypto.gni @@ -14,10 +14,13 @@ declare_args() { use_openssl = is_android || is_mac || is_nacl || is_win } -# True when we're using OpenSSL for certificate verification and storage. We -# only do this when we're using OpenSSL on desktop Linux systems. For other -# systems (Mac/Win/Android) we use the system certificate features. -use_openssl_certs = use_openssl && (is_linux || is_android) +# True when we're using OpenSSL for representing certificates. When targeting +# Android, the platform certificate library is used for certificate +# verification. On other targets, this flag also enables OpenSSL for certificate +# verification, but this configuration is unsupported. +use_openssl_certs = is_android -# Same meaning as use_openssl_certs but for NSS. -use_nss_certs = !use_openssl && is_linux +# True if NSS is used for certificate verification. Note that this is +# independent from use_openssl. It is possible to use OpenSSL for the crypto +# library, but NSS for the platform certificate library. +use_nss_certs = is_linux diff --git a/build/linux/system.gyp b/build/linux/system.gyp index 5333798..cc6e81b 100644 --- a/build/linux/system.gyp +++ b/build/linux/system.gyp @@ -1180,8 +1180,7 @@ 'dependencies': [ '../../third_party/boringssl/boringssl.gyp:boringssl', ], - }], - ['use_openssl==0', { + }, { 'dependencies': [ '../../net/third_party/nss/ssl.gyp:libssl', ], @@ -1191,6 +1190,13 @@ # before other includes, as we are shadowing system headers. '<(DEPTH)/net/third_party/nss/ssl', ], + }, + }], + # Link in the system NSS if it is used for either the internal + # crypto library (use_openssl==0) or platform certificate + # library (use_nss_certs==1). + ['use_openssl==0 or use_nss_certs==1', { + 'direct_dependent_settings': { 'cflags': [ '<!@(<(pkg-config) --cflags nss)', ], @@ -1203,15 +1209,17 @@ '<!@(<(pkg-config) --libs-only-l nss | sed -e "s/-lssl3//")', ], }, - }], - ['use_openssl==0 and clang==1', { - 'direct_dependent_settings': { - 'cflags': [ - # There is a broken header guard in /usr/include/nss/secmod.h: - # https://bugzilla.mozilla.org/show_bug.cgi?id=884072 - '-Wno-header-guard', - ], - }, + 'conditions': [ + ['clang==1', { + 'direct_dependent_settings': { + 'cflags': [ + # There is a broken header guard in /usr/include/nss/secmod.h: + # https://bugzilla.mozilla.org/show_bug.cgi?id=884072 + '-Wno-header-guard', + ], + }, + }], + ], }], ] }], diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi index 2f7ccad..7faa5e6 100644 --- a/chrome/chrome_common.gypi +++ b/chrome/chrome_common.gypi @@ -634,43 +634,31 @@ }, { # OS == ios 'sources!': [ 'common/net/net_resource_provider.cc', + ], + }], + ['OS == "android" or OS == "ios"', { + 'sources!': [ 'common/net/x509_certificate_model.cc', ], }], - ['os_posix == 1 and OS != "mac" and OS != "ios" and OS != "android"', { + ['use_openssl_certs == 1 and OS != "android"', { 'dependencies': [ - '../build/linux/system.gyp:ssl', + '<(DEPTH)/third_party/boringssl/boringssl.gyp:boringssl', ], - }, - ], - ['os_posix != 1 or OS == "mac" or OS == "ios"', { + }, { 'sources!': [ - 'common/net/x509_certificate_model_nss.cc', 'common/net/x509_certificate_model_openssl.cc', ], }, ], - ['OS == "android"', { + ['use_nss_certs == 1', { 'dependencies': [ - '../third_party/boringssl/boringssl.gyp:boringssl', - ], - 'sources!': [ - 'common/net/x509_certificate_model.cc', - 'common/net/x509_certificate_model_openssl.cc', + '../build/linux/system.gyp:ssl', ], - }], - ['use_openssl==1', { + }, { 'sources!': [ 'common/net/x509_certificate_model_nss.cc', ], - 'dependencies': [ - '<(DEPTH)/third_party/boringssl/boringssl.gyp:boringssl', - ], - }, - { # else !use_openssl: remove the unneeded files - 'sources!': [ - 'common/net/x509_certificate_model_openssl.cc', - ], }, ], ['OS=="win"', { diff --git a/chrome/chrome_utility.gypi b/chrome/chrome_utility.gypi index d076a1b..08d58b2 100644 --- a/chrome/chrome_utility.gypi +++ b/chrome/chrome_utility.gypi @@ -133,26 +133,21 @@ }, }, }], - ['OS!="win" and OS!="mac" and use_openssl==1', { - 'sources!': [ - 'utility/importer/nss_decryptor.cc', - ] - }], - ['OS!="win" and OS!="mac" and use_openssl==0', { + ['OS!="android"', { 'dependencies': [ - '../crypto/crypto.gyp:crypto', + '../net/net.gyp:net_utility_services', ], 'sources': [ - 'utility/importer/nss_decryptor_system_nss.cc', - 'utility/importer/nss_decryptor_system_nss.h', + '<@(chrome_utility_importer_sources)', ], }], - ['OS!="android"', { + ['use_nss_certs==1', { 'dependencies': [ - '../net/net.gyp:net_utility_services', + '../crypto/crypto.gyp:crypto', ], 'sources': [ - '<@(chrome_utility_importer_sources)', + 'utility/importer/nss_decryptor_system_nss.cc', + 'utility/importer/nss_decryptor_system_nss.h', ], }], ['OS=="android" and use_seccomp_bpf==1', { diff --git a/chrome/common/net/BUILD.gn b/chrome/common/net/BUILD.gn index b69512c..b73de58 100644 --- a/chrome/common/net/BUILD.gn +++ b/chrome/common/net/BUILD.gn @@ -30,31 +30,25 @@ static_library("net") { ] if (is_ios) { - sources -= [ - "net_resource_provider.cc", - "x509_certificate_model.cc", - ] + sources -= [ "net_resource_provider.cc" ] } else { deps += [ "//gpu/ipc" ] } - if (is_win || is_mac || is_ios) { - sources -= [ - "x509_certificate_model_nss.cc", - "x509_certificate_model_openssl.cc", - ] - } else if (use_openssl) { - sources -= [ "x509_certificate_model_nss.cc" ] + if (is_android || is_ios) { + sources -= [ "x509_certificate_model.cc" ] + } + + if (use_openssl_certs && !is_android) { + deps += [ "//third_party/boringssl" ] } else { sources -= [ "x509_certificate_model_openssl.cc" ] } - if (is_android) { - sources -= [ - "x509_certificate_model.cc", - "x509_certificate_model_openssl.cc", - ] - deps += [ "//third_party/boringssl" ] + if (use_nss_certs) { + deps += [ "//crypto:platform" ] + } else { + sources -= [ "x509_certificate_model_nss.cc" ] } configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] diff --git a/chrome/utility/BUILD.gn b/chrome/utility/BUILD.gn index c469307..dbf408f 100644 --- a/chrome/utility/BUILD.gn +++ b/chrome/utility/BUILD.gn @@ -83,21 +83,15 @@ static_library("utility") { } } - if (use_openssl) { - if (!is_win && !is_mac && !is_android) { - sources -= [ "importer/nss_decryptor.cc" ] - } - } else { # !use_openssl - if (!is_win && !is_mac) { - sources += [ - "importer/nss_decryptor_system_nss.cc", - "importer/nss_decryptor_system_nss.h", - ] - deps += [ - "//crypto", - "//crypto:platform", - ] - } + if (use_nss_certs) { + sources += [ + "importer/nss_decryptor_system_nss.cc", + "importer/nss_decryptor_system_nss.h", + ] + deps += [ + "//crypto", + "//crypto:platform", + ] } if (!enable_print_preview) { diff --git a/chrome/utility/importer/nss_decryptor.h b/chrome/utility/importer/nss_decryptor.h index 5c36112..d53e640 100644 --- a/chrome/utility/importer/nss_decryptor.h +++ b/chrome/utility/importer/nss_decryptor.h @@ -11,15 +11,10 @@ #include "chrome/utility/importer/nss_decryptor_mac.h" #elif defined(OS_WIN) #include "chrome/utility/importer/nss_decryptor_win.h" -#elif defined(USE_OPENSSL) -// TODO(joth): It should be an error to include this file with USE_OPENSSL -// defined. (Unless there is a way to do nss decrypt with OpenSSL). Ideally -// we remove the importers that depend on NSS when doing USE_OPENSSL builds, but -// that is going to take some non-trivial refactoring so in the meantime we're -// just falling back to a no-op implementation. -#include "chrome/utility/importer/nss_decryptor_null.h" #elif defined(USE_NSS_CERTS) #include "chrome/utility/importer/nss_decryptor_system_nss.h" +#else +#error NSSDecryptor not implemented. #endif #endif // CHROME_UTILITY_IMPORTER_NSS_DECRYPTOR_H_ diff --git a/chrome/utility/importer/nss_decryptor_null.h b/chrome/utility/importer/nss_decryptor_null.h deleted file mode 100644 index e99334b..0000000 --- a/chrome/utility/importer/nss_decryptor_null.h +++ /dev/null @@ -1,44 +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. - -#ifndef CHROME_UTILITY_IMPORTER_NSS_DECRYPTOR_NULL_H_ -#define CHROME_UTILITY_IMPORTER_NSS_DECRYPTOR_NULL_H_ - -#include <string> -#include <vector> - -#include "base/basictypes.h" -#include "base/strings/string16.h" - -namespace autofill { -struct PasswordForm; -} - -namespace base { -class FilePath; -} - -// A NULL wrapper for Firefox NSS decrypt component, for use in builds where -// we do not have the NSS library. -class NSSDecryptor { - public: - NSSDecryptor() {} - bool Init(const base::FilePath& dll_path, const base::FilePath& db_path) { - return false; - } - base::string16 Decrypt(const std::string& crypt) const { - return base::string16(); - } - void ParseSignons(const std::string& content, - std::vector<autofill::PasswordForm>* forms) {} - bool ReadAndParseSignons(const base::FilePath& sqlite_file, - std::vector<autofill::PasswordForm>* forms) { - return false; - } - - private: - DISALLOW_COPY_AND_ASSIGN(NSSDecryptor); -}; - -#endif // CHROME_UTILITY_IMPORTER_NSS_DECRYPTOR_NULL_H_ diff --git a/components/webcrypto/test/test_helpers.cc b/components/webcrypto/test/test_helpers.cc index 39b8196..76da7fa 100644 --- a/components/webcrypto/test/test_helpers.cc +++ b/components/webcrypto/test/test_helpers.cc @@ -124,7 +124,7 @@ bool SupportsRsaOaep() { bool SupportsRsaPrivateKeyImport() { // TODO(eroman): Exclude version test for OS_CHROMEOS -#if defined(USE_NSS_CERTS) +#if !defined(USE_OPENSSL) && defined(USE_NSS_CERTS) crypto::EnsureNSSInit(); if (!NSS_VersionCheck("3.16.2")) { LOG(WARNING) << "RSA key import is not supported by this version of NSS. " diff --git a/crypto/BUILD.gn b/crypto/BUILD.gn index d3456d3..27e786c 100644 --- a/crypto/BUILD.gn +++ b/crypto/BUILD.gn @@ -136,9 +136,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", @@ -170,6 +167,16 @@ component("crypto") { ] } + # Remove nss_util when NSS is used for neither the internal crypto library + # nor the platform certificate library. + if (use_openssl && !use_nss_certs) { + sources -= [ + "nss_util.cc", + "nss_util.h", + "nss_util_internal.h", + ] + } + defines = [ "CRYPTO_IMPLEMENTATION" ] } @@ -229,12 +236,14 @@ test("crypto_unittests") { "symmetric_key_unittest.cc", ] - if (use_openssl || !is_linux) { - sources -= [ "rsa_private_key_nss_unittest.cc" ] + # Remove nss_util when NSS is used for neither the internal crypto library + # nor the platform certificate library. + if (use_openssl && !use_nss_certs) { + sources -= [ "nss_util_unittest.cc" ] } if (use_openssl) { - sources -= [ "nss_util_unittest.cc" ] + sources -= [ "rsa_private_key_nss_unittest.cc" ] } else { sources -= [ "openssl_bio_string_unittest.cc" ] } @@ -286,7 +295,7 @@ source_set("test_support") { } config("platform_config") { - if (!use_openssl && is_clang) { + 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" ] @@ -305,21 +314,26 @@ group("platform") { 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 = [ - ":platform_config", - "//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/crypto/crypto.gyp b/crypto/crypto.gyp index c8551e7..a9cff55 100644 --- a/crypto/crypto.gyp +++ b/crypto/crypto.gyp @@ -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', @@ -143,6 +140,15 @@ 'symmetric_key_openssl.cc', ], },], + [ 'use_openssl==1 and use_nss_certs==0', { + # NSS is used for neither the internal crypto library nor the + # platform certificate library. + 'sources!': [ + 'nss_util.cc', + 'nss_util.h', + 'nss_util_internal.h', + ], + },], ], 'sources': [ '<@(crypto_sources)', @@ -182,7 +188,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 +200,13 @@ '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', { + # nss_util is built if NSS is used for either the internal crypto + # library or the platform certificate library. 'sources!': [ - 'rsa_private_key_nss_unittest.cc', - ] + 'nss_util_unittest.cc', + ], }], [ 'use_openssl == 0 and (OS == "mac" or OS == "ios" or OS == "win")', { 'dependencies': [ @@ -213,7 +222,6 @@ '../third_party/boringssl/boringssl.gyp:boringssl', ], 'sources!': [ - 'nss_util_unittest.cc', 'rsa_private_key_nss_unittest.cc', ], }, { diff --git a/crypto/rsa_private_key.h b/crypto/rsa_private_key.h index 78a660e..9ab9c57 100644 --- a/crypto/rsa_private_key.h +++ b/crypto/rsa_private_key.h @@ -180,7 +180,22 @@ class CRYPTO_EXPORT RSAPrivateKey { static RSAPrivateKey* CreateFromPrivateKeyInfo( const std::vector<uint8>& input); -#if defined(USE_NSS_CERTS) +#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 + + // TODO(davidben): These functions are used when NSS is the platform key + // store, but they also assume that the internal crypto library is NSS. Split + // out the convenience NSS platform key methods from the logic which expects + // an RSAPrivateKey. See https://crbug.com/478777. +#if defined(USE_NSS_CERTS) && !defined(USE_OPENSSL) // 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. @@ -194,10 +209,6 @@ class CRYPTO_EXPORT RSAPrivateKey { 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 @@ -216,13 +227,7 @@ class CRYPTO_EXPORT RSAPrivateKey { static RSAPrivateKey* FindFromPublicKeyInfoInSlot( const std::vector<uint8>& input, PK11SlotInfo* slot); -#elif 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); - -#endif +#endif // USE_NSS_CERTS && !USE_OPENSSL #if defined(USE_OPENSSL) EVP_PKEY* key() { return key_; } diff --git a/crypto/rsa_private_key_nss.cc b/crypto/rsa_private_key_nss.cc index 45b2be7..c9e6a87 100644 --- a/crypto/rsa_private_key_nss.cc +++ b/crypto/rsa_private_key_nss.cc @@ -104,6 +104,22 @@ RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo( false /* not sensitive */); } +// static +RSAPrivateKey* RSAPrivateKey::CreateFromKey(SECKEYPrivateKey* key) { + DCHECK(key); + if (SECKEY_GetPrivateKeyType(key) != rsaKey) + return NULL; + RSAPrivateKey* copy = new RSAPrivateKey(); + copy->key_ = SECKEY_CopyPrivateKey(key); + copy->public_key_ = SECKEY_ConvertToPublicKey(key); + if (!copy->key_ || !copy->public_key_) { + NOTREACHED(); + delete copy; + return NULL; + } + return copy; +} + #if defined(USE_NSS_CERTS) // static RSAPrivateKey* RSAPrivateKey::CreateSensitive(PK11SlotInfo* slot, @@ -125,22 +141,6 @@ RSAPrivateKey* RSAPrivateKey::CreateSensitiveFromPrivateKeyInfo( } // static -RSAPrivateKey* RSAPrivateKey::CreateFromKey(SECKEYPrivateKey* key) { - DCHECK(key); - if (SECKEY_GetPrivateKeyType(key) != rsaKey) - return NULL; - RSAPrivateKey* copy = new RSAPrivateKey(); - copy->key_ = SECKEY_CopyPrivateKey(key); - copy->public_key_ = SECKEY_ConvertToPublicKey(key); - if (!copy->key_ || !copy->public_key_) { - NOTREACHED(); - delete copy; - return NULL; - } - return copy; -} - -// static RSAPrivateKey* RSAPrivateKey::FindFromPublicKeyInfo( const std::vector<uint8>& input) { scoped_ptr<RSAPrivateKey> result(InitPublicPart(input)); diff --git a/crypto/rsa_private_key_nss_unittest.cc b/crypto/rsa_private_key_nss_unittest.cc index 98360e8..dad6688 100644 --- a/crypto/rsa_private_key_nss_unittest.cc +++ b/crypto/rsa_private_key_nss_unittest.cc @@ -13,6 +13,10 @@ namespace crypto { +// TODO(davidben): These tests assume NSS is used for both the internal crypto +// library and the platform key store. See https://crbug.com/478777. +#if defined(USE_NSS_CERTS) + class RSAPrivateKeyNSSTest : public testing::Test { public: RSAPrivateKeyNSSTest() {} @@ -57,4 +61,6 @@ TEST_F(RSAPrivateKeyNSSTest, FailedFindFromPublicKey) { EXPECT_EQ(NULL, crypto::RSAPrivateKey::FindFromPublicKeyInfo(public_key)); } +#endif // USE_NSS_CERTS + } // namespace crypto diff --git a/crypto/rsa_private_key_unittest.cc b/crypto/rsa_private_key_unittest.cc index ee5b121..b231cac 100644 --- a/crypto/rsa_private_key_unittest.cc +++ b/crypto/rsa_private_key_unittest.cc @@ -445,9 +445,6 @@ TEST(RSAPrivateKeyUnitTest, ShortIntegers) { input2.size())); } -// The following test can run if either USE_NSS_CERTS or USE_OPENSSL is defined, -// but not otherwise (since it uses crypto::RSAPrivateKey::CreateFromKey). -#if defined(USE_NSS_CERTS) || defined(USE_OPENSSL) TEST(RSAPrivateKeyUnitTest, CreateFromKeyTest) { scoped_ptr<crypto::RSAPrivateKey> key_pair( crypto::RSAPrivateKey::Create(256)); @@ -469,5 +466,4 @@ TEST(RSAPrivateKeyUnitTest, CreateFromKeyTest) { ASSERT_EQ(privkey, privkey_copy); ASSERT_EQ(pubkey, pubkey_copy); } -#endif diff --git a/net/BUILD.gn b/net/BUILD.gn index 0f6cbbb..130a597 100644 --- a/net/BUILD.gn +++ b/net/BUILD.gn @@ -194,11 +194,7 @@ component("net") { "cert/ct_objects_extractor_nss.cc", "cert/jwk_serializer_nss.cc", "cert/scoped_nss_types.h", - "cert/test_root_certs_nss.cc", "cert/x509_util_nss.cc", - "cert/x509_util_nss.h", - "cert_net/nss_ocsp.cc", - "cert_net/nss_ocsp.h", "quic/crypto/aead_base_decrypter_nss.cc", "quic/crypto/aead_base_encrypter_nss.cc", "quic/crypto/aes_128_gcm_12_decrypter_nss.cc", @@ -214,31 +210,6 @@ component("net") { "socket/ssl_server_socket_nss.cc", "socket/ssl_server_socket_nss.h", ] - if (is_chromeos) { - sources -= [ - "cert/nss_cert_database_chromeos.cc", - "cert/nss_cert_database_chromeos.h", - "cert/nss_profile_filter_chromeos.cc", - "cert/nss_profile_filter_chromeos.h", - ] - } - if (is_linux) { - # These are always removed for non-Linux cases below. - sources -= [ - "base/crypto_module_nss.cc", - "base/keygen_handler_nss.cc", - "cert/cert_database_nss.cc", - "cert/nss_cert_database.cc", - "cert/nss_cert_database.h", - "cert/x509_certificate_nss.cc", - "third_party/mozilla_security_manager/nsKeygenHandler.cpp", - "third_party/mozilla_security_manager/nsKeygenHandler.h", - "third_party/mozilla_security_manager/nsNSSCertificateDB.cpp", - "third_party/mozilla_security_manager/nsNSSCertificateDB.h", - "third_party/mozilla_security_manager/nsPKCS12Blob.cpp", - "third_party/mozilla_security_manager/nsPKCS12Blob.h", - ] - } if (is_ios) { # Always removed for !ios below. sources -= [ @@ -249,9 +220,11 @@ component("net") { if (is_win) { sources -= [ "cert/sha256_legacy_support_nss_win.cc" ] } + if (!use_nss_certs && !is_ios) { + sources -= [ "cert/x509_util_nss.h" ] + } } else { sources -= [ - "base/crypto_module_openssl.cc", "cert/ct_log_verifier_openssl.cc", "cert/ct_objects_extractor_openssl.cc", "cert/jwk_serializer_openssl.cc", @@ -272,6 +245,7 @@ component("net") { "socket/ssl_server_socket_openssl.cc", "socket/ssl_server_socket_openssl.h", "ssl/openssl_platform_key.h", + "ssl/openssl_platform_key_nss.cc", "ssl/openssl_ssl_util.cc", "ssl/openssl_ssl_util.h", "ssl/ssl_client_session_cache_openssl.cc", @@ -290,6 +264,7 @@ component("net") { if (!use_openssl_certs) { sources -= [ + "base/crypto_module_openssl.cc", "base/keygen_handler_openssl.cc", "base/openssl_private_key_store.h", "base/openssl_private_key_store_memory.cc", @@ -321,7 +296,9 @@ component("net") { if (is_linux) { configs += [ "//build/config/linux:libresolv" ] - } else { + } + + if (!use_nss_certs) { sources -= [ "base/crypto_module_nss.cc", "base/keygen_handler_nss.cc", @@ -329,6 +306,8 @@ component("net") { "cert/nss_cert_database.cc", "cert/nss_cert_database.h", "cert/x509_certificate_nss.cc", + "ssl/client_cert_store_nss.cc", + "ssl/client_cert_store_nss.h", "third_party/mozilla_security_manager/nsKeygenHandler.cpp", "third_party/mozilla_security_manager/nsKeygenHandler.h", "third_party/mozilla_security_manager/nsNSSCertificateDB.cpp", @@ -336,38 +315,37 @@ component("net") { "third_party/mozilla_security_manager/nsPKCS12Blob.cpp", "third_party/mozilla_security_manager/nsPKCS12Blob.h", ] - - if (!is_ios && !use_openssl) { - # These files are part of the partial implementation of NSS on iOS so - # keep them in that case. - sources -= [ - "cert/test_root_certs_nss.cc", - "cert_net/nss_ocsp.cc", - "cert_net/nss_ocsp.h", - ] - } - } - - if (!use_nss_certs) { - sources -= [ - "ssl/client_cert_store_nss.cc", - "ssl/client_cert_store_nss.h", - ] if (!is_ios) { # These files are part of the partial implementation of NSS on iOS so # keep them in that case (even though use_nss_certs is not set). sources -= [ "cert/cert_verify_proc_nss.cc", "cert/cert_verify_proc_nss.h", + "cert/test_root_certs_nss.cc", + "cert/x509_util_nss_certs.cc", + "cert_net/nss_ocsp.cc", + "cert_net/nss_ocsp.h", ] } if (is_chromeos) { # These were already removed on non-ChromeOS. sources -= [ + "cert/nss_cert_database_chromeos.cc", + "cert/nss_cert_database_chromeos.h", + "cert/nss_profile_filter_chromeos.cc", + "cert/nss_profile_filter_chromeos.h", "ssl/client_cert_store_chromeos.cc", "ssl/client_cert_store_chromeos.h", ] } + if (use_openssl) { + sources -= [ "ssl/openssl_platform_key_nss.cc" ] + } + } else if (use_openssl) { + # client_cert_store_nss.c requires NSS_CmpCertChainWCANames from NSS's + # libssl, but our bundled copy is not built in OpenSSL ports. Pull that file + # in directly. + sources += [ "third_party/nss/ssl/cmpcert.c" ] } if (!enable_websockets) { @@ -460,8 +438,8 @@ component("net") { } if (is_ios) { - # Add back some sources that were otherwise filtered out. iOS additionally - # doesn't set USE_NSS_CERTS but needs some of the files. + # Add back some sources that were otherwise filtered out. iOS needs some Mac + # files. set_sources_assignment_filter([]) sources += [ "base/net_util_mac.cc", @@ -469,13 +447,6 @@ component("net") { "base/network_change_notifier_mac.cc", "base/network_config_watcher_mac.cc", "base/platform_mime_util_mac.mm", - "cert/cert_verify_proc_nss.cc", - "cert/cert_verify_proc_nss.h", - "cert/test_root_certs_nss.cc", - "cert/x509_util_nss.cc", - "cert/x509_util_nss.h", - "cert_net/nss_ocsp.cc", - "cert_net/nss_ocsp.h", "proxy/proxy_resolver_mac.cc", "proxy/proxy_server_mac.cc", ] @@ -1392,9 +1363,16 @@ if (!is_android && !is_mac) { } if (!use_nss_certs) { - sources -= [ "ssl/client_cert_store_nss_unittest.cc" ] + sources -= [ + "cert/nss_cert_database_unittest.cc", + "ssl/client_cert_store_nss_unittest.cc", + ] if (is_chromeos) { # Already removed for all non-ChromeOS builds. - sources -= [ "ssl/client_cert_store_chromeos_unittest.cc" ] + sources -= [ + "cert/nss_cert_database_chromeos_unittest.cc", + "cert/nss_profile_filter_chromeos_unittest.cc", + "ssl/client_cert_store_chromeos_unittest.cc", + ] } } @@ -1404,17 +1382,9 @@ if (!is_android && !is_mac) { # TODO(bulach): Add equivalent tests when the underlying # functionality is ported to OpenSSL. sources -= [ - "cert/nss_cert_database_unittest.cc", "cert/x509_util_nss_unittest.cc", "quic/test_tools/crypto_test_utils_nss.cc", ] - if (is_chromeos) { - # These were already removed in the non-ChromeOS case. - sources -= [ - "cert/nss_cert_database_chromeos_unittest.cc", - "cert/nss_profile_filter_chromeos_unittest.cc", - ] - } } else { sources -= [ "cert/x509_util_openssl_unittest.cc", @@ -1422,9 +1392,6 @@ if (!is_android && !is_mac) { "socket/ssl_client_socket_openssl_unittest.cc", "ssl/ssl_client_session_cache_openssl_unittest.cc", ] - if (!is_desktop_linux && !is_chromeos) { - sources -= [ "cert/nss_cert_database_unittest.cc" ] - } } if (use_kerberos) { diff --git a/net/cert/ev_root_ca_metadata_unittest.cc b/net/cert/ev_root_ca_metadata_unittest.cc index 39699e26..9da0064 100644 --- a/net/cert/ev_root_ca_metadata_unittest.cc +++ b/net/cert/ev_root_ca_metadata_unittest.cc @@ -9,6 +9,7 @@ #include "testing/gtest/include/gtest/gtest.h" #if defined(USE_NSS_CERTS) +#include "crypto/nss_util.h" #include "crypto/scoped_nss_types.h" #endif @@ -63,6 +64,7 @@ EVOidData::EVOidData() } bool EVOidData::Init() { + crypto::EnsureNSSInit(); crypto::ScopedPLArenaPool pool(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); if (!pool.get()) return false; diff --git a/net/cert/x509_util_nss.cc b/net/cert/x509_util_nss.cc index 9711ef6..ecdf08b 100644 --- a/net/cert/x509_util_nss.cc +++ b/net/cert/x509_util_nss.cc @@ -194,58 +194,6 @@ bool SignCertificate( return true; } -#if defined(USE_NSS_CERTS) || defined(OS_IOS) -// Callback for CERT_DecodeCertPackage(), used in -// CreateOSCertHandlesFromBytes(). -SECStatus PR_CALLBACK CollectCertsCallback(void* arg, - SECItem** certs, - int num_certs) { - X509Certificate::OSCertHandles* results = - reinterpret_cast<X509Certificate::OSCertHandles*>(arg); - - for (int i = 0; i < num_certs; ++i) { - X509Certificate::OSCertHandle handle = - X509Certificate::CreateOSCertHandleFromBytes( - reinterpret_cast<char*>(certs[i]->data), certs[i]->len); - if (handle) - results->push_back(handle); - } - - return SECSuccess; -} - -typedef scoped_ptr< - CERTName, - crypto::NSSDestroyer<CERTName, CERT_DestroyName> > ScopedCERTName; - -// Create a new CERTName object from its encoded representation. -// |arena| is the allocation pool to use. -// |data| points to a DER-encoded X.509 DistinguishedName. -// Return a new CERTName pointer on success, or NULL. -CERTName* CreateCertNameFromEncoded(PLArenaPool* arena, - const base::StringPiece& data) { - if (!arena) - return NULL; - - ScopedCERTName name(PORT_ArenaZNew(arena, CERTName)); - if (!name.get()) - return NULL; - - SECItem item; - item.len = static_cast<unsigned int>(data.length()); - item.data = reinterpret_cast<unsigned char*>( - const_cast<char*>(data.data())); - - SECStatus rv = SEC_ASN1DecodeItem( - arena, name.get(), SEC_ASN1_GET(CERT_NameTemplate), &item); - if (rv != SECSuccess) - return NULL; - - return name.release(); -} - -#endif // defined(USE_NSS_CERTS) || defined(OS_IOS) - } // namespace namespace x509_util { @@ -368,271 +316,6 @@ bool CreateChannelIDEC(crypto::ECPrivateKey* key, return true; } -#if defined(USE_NSS_CERTS) || defined(OS_IOS) -void ParsePrincipal(CERTName* name, CertPrincipal* principal) { -// Starting in NSS 3.15, CERTGetNameFunc takes a const CERTName* argument. -#if NSS_VMINOR >= 15 - typedef char* (*CERTGetNameFunc)(const CERTName* name); -#else - typedef char* (*CERTGetNameFunc)(CERTName* name); -#endif - - // TODO(jcampan): add business_category and serial_number. - // TODO(wtc): NSS has the CERT_GetOrgName, CERT_GetOrgUnitName, and - // CERT_GetDomainComponentName functions, but they return only the most - // general (the first) RDN. NSS doesn't have a function for the street - // address. - static const SECOidTag kOIDs[] = { - SEC_OID_AVA_STREET_ADDRESS, - SEC_OID_AVA_ORGANIZATION_NAME, - SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME, - SEC_OID_AVA_DC }; - - std::vector<std::string>* values[] = { - &principal->street_addresses, - &principal->organization_names, - &principal->organization_unit_names, - &principal->domain_components }; - DCHECK_EQ(arraysize(kOIDs), arraysize(values)); - - CERTRDN** rdns = name->rdns; - for (size_t rdn = 0; rdns[rdn]; ++rdn) { - CERTAVA** avas = rdns[rdn]->avas; - for (size_t pair = 0; avas[pair] != 0; ++pair) { - SECOidTag tag = CERT_GetAVATag(avas[pair]); - for (size_t oid = 0; oid < arraysize(kOIDs); ++oid) { - if (kOIDs[oid] == tag) { - SECItem* decode_item = CERT_DecodeAVAValue(&avas[pair]->value); - if (!decode_item) - break; - // TODO(wtc): Pass decode_item to CERT_RFC1485_EscapeAndQuote. - std::string value(reinterpret_cast<char*>(decode_item->data), - decode_item->len); - values[oid]->push_back(value); - SECITEM_FreeItem(decode_item, PR_TRUE); - break; - } - } - } - } - - // Get CN, L, S, and C. - CERTGetNameFunc get_name_funcs[4] = { - CERT_GetCommonName, CERT_GetLocalityName, - CERT_GetStateName, CERT_GetCountryName }; - std::string* single_values[4] = { - &principal->common_name, &principal->locality_name, - &principal->state_or_province_name, &principal->country_name }; - for (size_t i = 0; i < arraysize(get_name_funcs); ++i) { - char* value = get_name_funcs[i](name); - if (value) { - single_values[i]->assign(value); - PORT_Free(value); - } - } -} - -void ParseDate(const SECItem* der_date, base::Time* result) { - PRTime prtime; - SECStatus rv = DER_DecodeTimeChoice(&prtime, der_date); - DCHECK_EQ(SECSuccess, rv); - *result = crypto::PRTimeToBaseTime(prtime); -} - -std::string ParseSerialNumber(const CERTCertificate* certificate) { - return std::string(reinterpret_cast<char*>(certificate->serialNumber.data), - certificate->serialNumber.len); -} - -void GetSubjectAltName(CERTCertificate* cert_handle, - std::vector<std::string>* dns_names, - std::vector<std::string>* ip_addrs) { - if (dns_names) - dns_names->clear(); - if (ip_addrs) - ip_addrs->clear(); - - SECItem alt_name; - SECStatus rv = CERT_FindCertExtension(cert_handle, - SEC_OID_X509_SUBJECT_ALT_NAME, - &alt_name); - if (rv != SECSuccess) - return; - - PLArenaPool* arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - DCHECK(arena != NULL); - - CERTGeneralName* alt_name_list; - alt_name_list = CERT_DecodeAltNameExtension(arena, &alt_name); - SECITEM_FreeItem(&alt_name, PR_FALSE); - - CERTGeneralName* name = alt_name_list; - while (name) { - // DNSName and IPAddress are encoded as IA5String and OCTET STRINGs - // respectively, both of which can be byte copied from - // SECItemType::data into the appropriate output vector. - if (dns_names && name->type == certDNSName) { - dns_names->push_back(std::string( - reinterpret_cast<char*>(name->name.other.data), - name->name.other.len)); - } else if (ip_addrs && name->type == certIPAddress) { - ip_addrs->push_back(std::string( - reinterpret_cast<char*>(name->name.other.data), - name->name.other.len)); - } - name = CERT_GetNextGeneralName(name); - if (name == alt_name_list) - break; - } - PORT_FreeArena(arena, PR_FALSE); -} - -X509Certificate::OSCertHandles CreateOSCertHandlesFromBytes( - const char* data, - int length, - X509Certificate::Format format) { - X509Certificate::OSCertHandles results; - if (length < 0) - return results; - - crypto::EnsureNSSInit(); - - if (!NSS_IsInitialized()) - return results; - - switch (format) { - case X509Certificate::FORMAT_SINGLE_CERTIFICATE: { - X509Certificate::OSCertHandle handle = - X509Certificate::CreateOSCertHandleFromBytes(data, length); - if (handle) - results.push_back(handle); - break; - } - case X509Certificate::FORMAT_PKCS7: { - // Make a copy since CERT_DecodeCertPackage may modify it - std::vector<char> data_copy(data, data + length); - - SECStatus result = CERT_DecodeCertPackage(&data_copy[0], - length, CollectCertsCallback, &results); - if (result != SECSuccess) - results.clear(); - break; - } - default: - NOTREACHED() << "Certificate format " << format << " unimplemented"; - break; - } - - return results; -} - -X509Certificate::OSCertHandle ReadOSCertHandleFromPickle( - PickleIterator* pickle_iter) { - const char* data; - int length; - if (!pickle_iter->ReadData(&data, &length)) - return NULL; - - return X509Certificate::CreateOSCertHandleFromBytes(data, length); -} - -void GetPublicKeyInfo(CERTCertificate* handle, - size_t* size_bits, - X509Certificate::PublicKeyType* type) { - // Since we might fail, set the output parameters to default values first. - *type = X509Certificate::kPublicKeyTypeUnknown; - *size_bits = 0; - - crypto::ScopedSECKEYPublicKey key(CERT_ExtractPublicKey(handle)); - if (!key.get()) - return; - - *size_bits = SECKEY_PublicKeyStrengthInBits(key.get()); - - switch (key->keyType) { - case rsaKey: - *type = X509Certificate::kPublicKeyTypeRSA; - break; - case dsaKey: - *type = X509Certificate::kPublicKeyTypeDSA; - break; - case dhKey: - *type = X509Certificate::kPublicKeyTypeDH; - break; - case ecKey: - *type = X509Certificate::kPublicKeyTypeECDSA; - break; - default: - *type = X509Certificate::kPublicKeyTypeUnknown; - *size_bits = 0; - break; - } -} - -bool GetIssuersFromEncodedList( - const std::vector<std::string>& encoded_issuers, - PLArenaPool* arena, - std::vector<CERTName*>* out) { - std::vector<CERTName*> result; - for (size_t n = 0; n < encoded_issuers.size(); ++n) { - CERTName* name = CreateCertNameFromEncoded(arena, encoded_issuers[n]); - if (name != NULL) - result.push_back(name); - } - - if (result.size() == encoded_issuers.size()) { - out->swap(result); - return true; - } - - for (size_t n = 0; n < result.size(); ++n) - CERT_DestroyName(result[n]); - return false; -} - - -bool IsCertificateIssuedBy(const std::vector<CERTCertificate*>& cert_chain, - const std::vector<CERTName*>& valid_issuers) { - for (size_t n = 0; n < cert_chain.size(); ++n) { - CERTName* cert_issuer = &cert_chain[n]->issuer; - for (size_t i = 0; i < valid_issuers.size(); ++i) { - if (CERT_CompareName(valid_issuers[i], cert_issuer) == SECEqual) - return true; - } - } - return false; -} - -std::string GetUniqueNicknameForSlot(const std::string& nickname, - const SECItem* subject, - PK11SlotInfo* slot) { - int index = 2; - std::string new_name = nickname; - std::string temp_nickname = new_name; - std::string token_name; - - if (!slot) - return new_name; - - if (!PK11_IsInternalKeySlot(slot)) { - token_name.assign(PK11_GetTokenName(slot)); - token_name.append(":"); - - temp_nickname = token_name + new_name; - } - - while (SEC_CertNicknameConflict(temp_nickname.c_str(), - const_cast<SECItem*>(subject), - CERT_GetDefaultCertDB())) { - base::SStringPrintf(&new_name, "%s #%d", nickname.c_str(), index++); - temp_nickname = token_name + new_name; - } - - return new_name; -} - -#endif // defined(USE_NSS_CERTS) || defined(OS_IOS) - } // namespace x509_util } // namespace net diff --git a/net/cert/x509_util_nss_certs.cc b/net/cert/x509_util_nss_certs.cc new file mode 100644 index 0000000..b308355 --- /dev/null +++ b/net/cert/x509_util_nss_certs.cc @@ -0,0 +1,346 @@ +// 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 <cert.h> // Must be included before certdb.h +#include <certdb.h> +#include <cryptohi.h> +#include <nss.h> +#include <pk11pub.h> +#include <prerror.h> +#include <secder.h> +#include <secmod.h> +#include <secport.h> + +#include "base/debug/leak_annotations.h" +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/singleton.h" +#include "base/pickle.h" +#include "base/strings/stringprintf.h" +#include "crypto/ec_private_key.h" +#include "crypto/nss_util.h" +#include "crypto/nss_util_internal.h" +#include "crypto/rsa_private_key.h" +#include "crypto/scoped_nss_types.h" +#include "crypto/third_party/nss/chromium-nss.h" +#include "net/cert/x509_certificate.h" +#include "net/cert/x509_util.h" +#include "net/cert/x509_util_nss.h" + +namespace net { + +namespace { + +// Callback for CERT_DecodeCertPackage(), used in +// CreateOSCertHandlesFromBytes(). +SECStatus PR_CALLBACK +CollectCertsCallback(void* arg, SECItem** certs, int num_certs) { + X509Certificate::OSCertHandles* results = + reinterpret_cast<X509Certificate::OSCertHandles*>(arg); + + for (int i = 0; i < num_certs; ++i) { + X509Certificate::OSCertHandle handle = + X509Certificate::CreateOSCertHandleFromBytes( + reinterpret_cast<char*>(certs[i]->data), certs[i]->len); + if (handle) + results->push_back(handle); + } + + return SECSuccess; +} + +typedef scoped_ptr<CERTName, crypto::NSSDestroyer<CERTName, CERT_DestroyName>> + ScopedCERTName; + +// Create a new CERTName object from its encoded representation. +// |arena| is the allocation pool to use. +// |data| points to a DER-encoded X.509 DistinguishedName. +// Return a new CERTName pointer on success, or NULL. +CERTName* CreateCertNameFromEncoded(PLArenaPool* arena, + const base::StringPiece& data) { + if (!arena) + return NULL; + + ScopedCERTName name(PORT_ArenaZNew(arena, CERTName)); + if (!name.get()) + return NULL; + + SECItem item; + item.len = static_cast<unsigned int>(data.length()); + item.data = reinterpret_cast<unsigned char*>(const_cast<char*>(data.data())); + + SECStatus rv = SEC_ASN1DecodeItem(arena, name.get(), + SEC_ASN1_GET(CERT_NameTemplate), &item); + if (rv != SECSuccess) + return NULL; + + return name.release(); +} + +} // namespace + +namespace x509_util { + +void ParsePrincipal(CERTName* name, CertPrincipal* principal) { +// Starting in NSS 3.15, CERTGetNameFunc takes a const CERTName* argument. +#if NSS_VMINOR >= 15 + typedef char* (*CERTGetNameFunc)(const CERTName* name); +#else + typedef char* (*CERTGetNameFunc)(CERTName* name); +#endif + + // TODO(jcampan): add business_category and serial_number. + // TODO(wtc): NSS has the CERT_GetOrgName, CERT_GetOrgUnitName, and + // CERT_GetDomainComponentName functions, but they return only the most + // general (the first) RDN. NSS doesn't have a function for the street + // address. + static const SECOidTag kOIDs[] = {SEC_OID_AVA_STREET_ADDRESS, + SEC_OID_AVA_ORGANIZATION_NAME, + SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME, + SEC_OID_AVA_DC}; + + std::vector<std::string>* values[] = {&principal->street_addresses, + &principal->organization_names, + &principal->organization_unit_names, + &principal->domain_components}; + DCHECK_EQ(arraysize(kOIDs), arraysize(values)); + + CERTRDN** rdns = name->rdns; + for (size_t rdn = 0; rdns[rdn]; ++rdn) { + CERTAVA** avas = rdns[rdn]->avas; + for (size_t pair = 0; avas[pair] != 0; ++pair) { + SECOidTag tag = CERT_GetAVATag(avas[pair]); + for (size_t oid = 0; oid < arraysize(kOIDs); ++oid) { + if (kOIDs[oid] == tag) { + SECItem* decode_item = CERT_DecodeAVAValue(&avas[pair]->value); + if (!decode_item) + break; + // TODO(wtc): Pass decode_item to CERT_RFC1485_EscapeAndQuote. + std::string value(reinterpret_cast<char*>(decode_item->data), + decode_item->len); + values[oid]->push_back(value); + SECITEM_FreeItem(decode_item, PR_TRUE); + break; + } + } + } + } + + // Get CN, L, S, and C. + CERTGetNameFunc get_name_funcs[4] = {CERT_GetCommonName, + CERT_GetLocalityName, + CERT_GetStateName, + CERT_GetCountryName}; + std::string* single_values[4] = {&principal->common_name, + &principal->locality_name, + &principal->state_or_province_name, + &principal->country_name}; + for (size_t i = 0; i < arraysize(get_name_funcs); ++i) { + char* value = get_name_funcs[i](name); + if (value) { + single_values[i]->assign(value); + PORT_Free(value); + } + } +} + +void ParseDate(const SECItem* der_date, base::Time* result) { + PRTime prtime; + SECStatus rv = DER_DecodeTimeChoice(&prtime, der_date); + DCHECK_EQ(SECSuccess, rv); + *result = crypto::PRTimeToBaseTime(prtime); +} + +std::string ParseSerialNumber(const CERTCertificate* certificate) { + return std::string(reinterpret_cast<char*>(certificate->serialNumber.data), + certificate->serialNumber.len); +} + +void GetSubjectAltName(CERTCertificate* cert_handle, + std::vector<std::string>* dns_names, + std::vector<std::string>* ip_addrs) { + if (dns_names) + dns_names->clear(); + if (ip_addrs) + ip_addrs->clear(); + + SECItem alt_name; + SECStatus rv = CERT_FindCertExtension( + cert_handle, SEC_OID_X509_SUBJECT_ALT_NAME, &alt_name); + if (rv != SECSuccess) + return; + + PLArenaPool* arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + DCHECK(arena != NULL); + + CERTGeneralName* alt_name_list; + alt_name_list = CERT_DecodeAltNameExtension(arena, &alt_name); + SECITEM_FreeItem(&alt_name, PR_FALSE); + + CERTGeneralName* name = alt_name_list; + while (name) { + // DNSName and IPAddress are encoded as IA5String and OCTET STRINGs + // respectively, both of which can be byte copied from + // SECItemType::data into the appropriate output vector. + if (dns_names && name->type == certDNSName) { + dns_names->push_back( + std::string(reinterpret_cast<char*>(name->name.other.data), + name->name.other.len)); + } else if (ip_addrs && name->type == certIPAddress) { + ip_addrs->push_back( + std::string(reinterpret_cast<char*>(name->name.other.data), + name->name.other.len)); + } + name = CERT_GetNextGeneralName(name); + if (name == alt_name_list) + break; + } + PORT_FreeArena(arena, PR_FALSE); +} + +X509Certificate::OSCertHandles CreateOSCertHandlesFromBytes( + const char* data, + int length, + X509Certificate::Format format) { + X509Certificate::OSCertHandles results; + if (length < 0) + return results; + + crypto::EnsureNSSInit(); + + if (!NSS_IsInitialized()) + return results; + + switch (format) { + case X509Certificate::FORMAT_SINGLE_CERTIFICATE: { + X509Certificate::OSCertHandle handle = + X509Certificate::CreateOSCertHandleFromBytes(data, length); + if (handle) + results.push_back(handle); + break; + } + case X509Certificate::FORMAT_PKCS7: { + // Make a copy since CERT_DecodeCertPackage may modify it + std::vector<char> data_copy(data, data + length); + + SECStatus result = CERT_DecodeCertPackage(&data_copy[0], length, + CollectCertsCallback, &results); + if (result != SECSuccess) + results.clear(); + break; + } + default: + NOTREACHED() << "Certificate format " << format << " unimplemented"; + break; + } + + return results; +} + +X509Certificate::OSCertHandle ReadOSCertHandleFromPickle( + PickleIterator* pickle_iter) { + const char* data; + int length; + if (!pickle_iter->ReadData(&data, &length)) + return NULL; + + return X509Certificate::CreateOSCertHandleFromBytes(data, length); +} + +void GetPublicKeyInfo(CERTCertificate* handle, + size_t* size_bits, + X509Certificate::PublicKeyType* type) { + // Since we might fail, set the output parameters to default values first. + *type = X509Certificate::kPublicKeyTypeUnknown; + *size_bits = 0; + + crypto::ScopedSECKEYPublicKey key(CERT_ExtractPublicKey(handle)); + if (!key.get()) + return; + + *size_bits = SECKEY_PublicKeyStrengthInBits(key.get()); + + switch (key->keyType) { + case rsaKey: + *type = X509Certificate::kPublicKeyTypeRSA; + break; + case dsaKey: + *type = X509Certificate::kPublicKeyTypeDSA; + break; + case dhKey: + *type = X509Certificate::kPublicKeyTypeDH; + break; + case ecKey: + *type = X509Certificate::kPublicKeyTypeECDSA; + break; + default: + *type = X509Certificate::kPublicKeyTypeUnknown; + *size_bits = 0; + break; + } +} + +bool GetIssuersFromEncodedList(const std::vector<std::string>& encoded_issuers, + PLArenaPool* arena, + std::vector<CERTName*>* out) { + std::vector<CERTName*> result; + for (size_t n = 0; n < encoded_issuers.size(); ++n) { + CERTName* name = CreateCertNameFromEncoded(arena, encoded_issuers[n]); + if (name != NULL) + result.push_back(name); + } + + if (result.size() == encoded_issuers.size()) { + out->swap(result); + return true; + } + + for (size_t n = 0; n < result.size(); ++n) + CERT_DestroyName(result[n]); + return false; +} + +bool IsCertificateIssuedBy(const std::vector<CERTCertificate*>& cert_chain, + const std::vector<CERTName*>& valid_issuers) { + for (size_t n = 0; n < cert_chain.size(); ++n) { + CERTName* cert_issuer = &cert_chain[n]->issuer; + for (size_t i = 0; i < valid_issuers.size(); ++i) { + if (CERT_CompareName(valid_issuers[i], cert_issuer) == SECEqual) + return true; + } + } + return false; +} + +std::string GetUniqueNicknameForSlot(const std::string& nickname, + const SECItem* subject, + PK11SlotInfo* slot) { + int index = 2; + std::string new_name = nickname; + std::string temp_nickname = new_name; + std::string token_name; + + if (!slot) + return new_name; + + if (!PK11_IsInternalKeySlot(slot)) { + token_name.assign(PK11_GetTokenName(slot)); + token_name.append(":"); + + temp_nickname = token_name + new_name; + } + + while (SEC_CertNicknameConflict(temp_nickname.c_str(), + const_cast<SECItem*>(subject), + CERT_GetDefaultCertDB())) { + base::SStringPrintf(&new_name, "%s #%d", nickname.c_str(), index++); + temp_nickname = token_name + new_name; + } + + return new_name; +} + +} // namespace x509_util + +} // namespace net diff --git a/net/net.gyp b/net/net.gyp index 9dacd43..2caae5a 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -180,6 +180,9 @@ }], [ 'use_nss_certs != 1', { 'sources!': [ + 'cert/nss_cert_database_unittest.cc', + 'cert/nss_cert_database_chromeos_unittest.cc', + 'cert/nss_profile_filter_chromeos_unittest.cc', 'ssl/client_cert_store_chromeos_unittest.cc', 'ssl/client_cert_store_nss_unittest.cc', ], @@ -189,7 +192,8 @@ 'dependencies': [ '../third_party/boringssl/boringssl.gyp:boringssl', ], - }, { # use_openssl == 0 + }], + [ 'use_nss_certs == 1 or OS == "ios" or use_openssl == 0', { 'conditions': [ [ 'desktop_linux == 1 or chromeos == 1', { 'dependencies': [ @@ -201,9 +205,6 @@ '../third_party/nss/nss.gyp:nss', 'third_party/nss/ssl.gyp:libssl', ], - 'sources!': [ - 'cert/nss_cert_database_unittest.cc', - ], }], ], }], @@ -241,9 +242,6 @@ # TODO(bulach): Add equivalent tests when the underlying # functionality is ported to OpenSSL. 'sources!': [ - 'cert/nss_cert_database_chromeos_unittest.cc', - 'cert/nss_cert_database_unittest.cc', - 'cert/nss_profile_filter_chromeos_unittest.cc', 'cert/x509_util_nss_unittest.cc', 'quic/test_tools/crypto_test_utils_nss.cc', ], diff --git a/net/net.gypi b/net/net.gypi index 9c4a22c..37a5d88 100644 --- a/net/net.gypi +++ b/net/net.gypi @@ -140,6 +140,7 @@ 'ssl/openssl_client_key_store.h', 'ssl/openssl_platform_key.h', 'ssl/openssl_platform_key_mac.cc', + 'ssl/openssl_platform_key_nss.cc', 'ssl/openssl_platform_key_win.cc', 'ssl/openssl_ssl_util.cc', 'ssl/openssl_ssl_util.h', @@ -378,6 +379,7 @@ 'cert/x509_util_mac.h', 'cert/x509_util_nss.cc', 'cert/x509_util_nss.h', + 'cert/x509_util_nss_certs.cc', 'cert_net/cert_net_fetcher_impl.cc', 'cert_net/cert_net_fetcher_impl.h', 'cookies/canonical_cookie.cc', diff --git a/net/net_common.gypi b/net/net_common.gypi index 4bb8235..77134f5 100644 --- a/net/net_common.gypi +++ b/net/net_common.gypi @@ -125,30 +125,14 @@ }], ['use_openssl==1', { 'sources!': [ - 'base/crypto_module_nss.cc', - 'base/keygen_handler_nss.cc', 'base/nss_memio.c', 'base/nss_memio.h', - 'cert/cert_database_nss.cc', - 'cert/cert_verify_proc_nss.cc', - 'cert/cert_verify_proc_nss.h', 'cert/ct_log_verifier_nss.cc', 'cert/ct_objects_extractor_nss.cc', 'cert/jwk_serializer_nss.cc', - 'cert/nss_cert_database.cc', - 'cert/nss_cert_database.h', - 'cert/nss_cert_database_chromeos.cc', - 'cert/nss_cert_database_chromeos.h', - 'cert/nss_profile_filter_chromeos.cc', - 'cert/nss_profile_filter_chromeos.h', 'cert/scoped_nss_types.h', 'cert/sha256_legacy_support_nss_win.cc', - 'cert/test_root_certs_nss.cc', - 'cert/x509_certificate_nss.cc', 'cert/x509_util_nss.cc', - 'cert/x509_util_nss.h', - 'cert_net/nss_ocsp.cc', - 'cert_net/nss_ocsp.h', 'quic/crypto/aead_base_decrypter_nss.cc', 'quic/crypto/aead_base_encrypter_nss.cc', 'quic/crypto/aes_128_gcm_12_decrypter_nss.cc', @@ -163,12 +147,6 @@ 'socket/ssl_client_socket_nss.h', 'socket/ssl_server_socket_nss.cc', 'socket/ssl_server_socket_nss.h', - 'third_party/mozilla_security_manager/nsKeygenHandler.cpp', - 'third_party/mozilla_security_manager/nsKeygenHandler.h', - 'third_party/mozilla_security_manager/nsNSSCertificateDB.cpp', - 'third_party/mozilla_security_manager/nsNSSCertificateDB.h', - 'third_party/mozilla_security_manager/nsPKCS12Blob.cpp', - 'third_party/mozilla_security_manager/nsPKCS12Blob.h', ], 'dependencies': [ '../third_party/boringssl/boringssl.gyp:boringssl', @@ -176,7 +154,6 @@ }, { # else !use_openssl: remove the unneeded files and depend on NSS. 'sources!': [ - 'base/crypto_module_openssl.cc', 'cert/ct_log_verifier_openssl.cc', 'cert/ct_objects_extractor_openssl.cc', 'cert/jwk_serializer_openssl.cc', @@ -199,12 +176,16 @@ 'socket/ssl_server_socket_openssl.h', 'ssl/openssl_platform_key.h', 'ssl/openssl_platform_key_mac.cc', + 'ssl/openssl_platform_key_nss.cc', 'ssl/openssl_platform_key_win.cc', 'ssl/openssl_ssl_util.cc', 'ssl/openssl_ssl_util.h', 'ssl/ssl_client_session_cache_openssl.cc', 'ssl/ssl_client_session_cache_openssl.h', ], + }, + ], + [ 'use_nss_certs == 1 or OS == "ios" or use_openssl == 0', { 'conditions': [ # Pull in the bundled or system NSS as appropriate. [ 'desktop_linux == 1 or chromeos == 1', { @@ -219,10 +200,15 @@ ], }] ], + }, { + 'sources!': [ + 'cert/x509_util_nss.h', + ], }, ], [ 'use_openssl_certs == 0', { 'sources!': [ + 'base/crypto_module_openssl.cc', 'base/keygen_handler_openssl.cc', 'base/openssl_private_key_store.h', 'base/openssl_private_key_store_android.cc', @@ -264,17 +250,30 @@ }], ], }, - { # else: OS is not in the above list + ], + [ 'use_nss_certs != 1', { 'sources!': [ 'base/crypto_module_nss.cc', 'base/keygen_handler_nss.cc', 'cert/cert_database_nss.cc', + 'cert/cert_verify_proc_nss.cc', + 'cert/cert_verify_proc_nss.h', 'cert/nss_cert_database.cc', 'cert/nss_cert_database.h', + 'cert/nss_cert_database_chromeos.cc', + 'cert/nss_cert_database_chromeos.h', + 'cert/nss_profile_filter_chromeos.cc', + 'cert/nss_profile_filter_chromeos.h', 'cert/test_root_certs_nss.cc', 'cert/x509_certificate_nss.cc', + 'cert/x509_util_nss_certs.cc', 'cert_net/nss_ocsp.cc', 'cert_net/nss_ocsp.h', + 'ssl/client_cert_store_chromeos.cc', + 'ssl/client_cert_store_chromeos.h', + 'ssl/client_cert_store_nss.cc', + 'ssl/client_cert_store_nss.h', + 'ssl/openssl_platform_key_nss.cc', 'third_party/mozilla_security_manager/nsKeygenHandler.cpp', 'third_party/mozilla_security_manager/nsKeygenHandler.h', 'third_party/mozilla_security_manager/nsNSSCertificateDB.cpp', @@ -284,14 +283,12 @@ ], }, ], - [ 'use_nss_certs != 1', { - 'sources!': [ - 'cert/cert_verify_proc_nss.cc', - 'cert/cert_verify_proc_nss.h', - 'ssl/client_cert_store_chromeos.cc', - 'ssl/client_cert_store_chromeos.h', - 'ssl/client_cert_store_nss.cc', - 'ssl/client_cert_store_nss.h', + # client_cert_store_nss.c requires NSS_CmpCertChainWCANames from NSS's + # libssl, but our bundled copy is not built in OpenSSL ports. Pull that + # file in directly. + [ 'use_nss_certs == 1 and use_openssl == 1', { + 'sources': [ + 'third_party/nss/ssl/cmpcert.c', ], }], [ 'enable_websockets != 1', { @@ -416,8 +413,7 @@ ['include', '^cert/cert_verify_proc_nss\\.cc$'], ['include', '^cert/cert_verify_proc_nss\\.h$'], ['include', '^cert/test_root_certs_nss\\.cc$'], - ['include', '^cert/x509_util_nss\\.cc$'], - ['include', '^cert/x509_util_nss\\.h$'], + ['include', '^cert/x509_util_nss_certs\\.cc$'], ['include', '^cert_net/nss_ocsp\\.cc$'], ['include', '^cert_net/nss_ocsp\\.h$'], ['include', '^proxy/proxy_resolver_mac\\.cc$'], diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc index e36534c..7b11ddc 100644 --- a/net/socket/ssl_client_socket_openssl.cc +++ b/net/socket/ssl_client_socket_openssl.cc @@ -1196,6 +1196,8 @@ void SSLClientSocketOpenSSL::UpdateServerCert() { << GetLastError(); } #else + // TODO(davidben): Support OCSP stapling when NSS is the system + // certificate verifier. https://crbug.com/479034. NOTREACHED(); #endif } diff --git a/net/ssl/channel_id_service.cc b/net/ssl/channel_id_service.cc index e52d470..7fcbc53 100644 --- a/net/ssl/channel_id_service.cc +++ b/net/ssl/channel_id_service.cc @@ -27,7 +27,7 @@ #include "net/cert/x509_util.h" #include "url/gurl.h" -#if defined(USE_NSS_CERTS) +#if !defined(USE_OPENSSL) #include <private/pprthred.h> // PR_DetachThread #endif @@ -246,7 +246,7 @@ class ChannelIDServiceWorker { scoped_ptr<ChannelIDStore::ChannelID> cert = GenerateChannelID(server_identifier_, serial_number_, &error); DVLOG(1) << "GenerateCert " << server_identifier_ << " returned " << error; -#if defined(USE_NSS_CERTS) +#if !defined(USE_OPENSSL) // Detach the thread from NSPR. // Calling NSS functions attaches the thread to NSPR, which stores // the NSPR thread ID in thread-specific data. diff --git a/net/ssl/openssl_platform_key_nss.cc b/net/ssl/openssl_platform_key_nss.cc new file mode 100644 index 0000000..a9471e4 --- /dev/null +++ b/net/ssl/openssl_platform_key_nss.cc @@ -0,0 +1,17 @@ +// 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 "base/logging.h" +#include "net/ssl/openssl_platform_key.h" + +namespace net { + +crypto::ScopedEVP_PKEY FetchClientCertPrivateKey( + const X509Certificate* certificate) { + // TODO(davidben): Implement client auth for NSS. https://crbug.com/479036 + NOTIMPLEMENTED(); + return nullptr; +} + +} // namespace net diff --git a/net/test/cert_test_util_nss.cc b/net/test/cert_test_util_nss.cc index ee929e5..74884c7 100644 --- a/net/test/cert_test_util_nss.cc +++ b/net/test/cert_test_util_nss.cc @@ -19,6 +19,14 @@ scoped_ptr<crypto::RSAPrivateKey> ImportSensitiveKeyFromFile( const base::FilePath& dir, const std::string& key_filename, PK11SlotInfo* slot) { +#if defined(USE_OPENSSL) + // TODO(davidben): Port RSAPrivateKey::CreateSensitiveFromPrivateKeyInfo away + // from RSAPrivateKey so it doesn't make assumptions about the internal crypto + // library. Instead, return a ScopedSECKEYPrivateKey or have this function + // just return bool. https://crbug.com/478777 + NOTIMPLEMENTED(); + return nullptr; +#else base::FilePath key_path = dir.AppendASCII(key_filename); std::string key_pkcs8; bool success = base::ReadFileToString(key_path, &key_pkcs8); @@ -38,6 +46,7 @@ scoped_ptr<crypto::RSAPrivateKey> ImportSensitiveKeyFromFile( LOG_IF(ERROR, !private_key) << "Could not create key from file " << key_path.value(); return private_key.Pass(); +#endif } bool ImportClientCertToSlot(const scoped_refptr<X509Certificate>& cert, |